Some mods may be broken due to the recent Alloyed Collective update.
Decompiled source of DropinMultiplayer v4.2.0
DropInMultiplayer.dll
Decompiled a week 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 BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using DropInMultiplayer.Helpers; using HG.Reflection; 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("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("1.0.0.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 lunar 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.2.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] public class DropInMultiplayer : BaseUnityPlugin { [CompilerGenerated] private sealed class <SendChatMessageInternal>d__54 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public string message; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <SendChatMessageInternal>d__54(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown //IL_0037: 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_004d: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(0.1f); <>1__state = 1; return true; case 1: <>1__state = -1; Chat.SendBroadcastChat((ChatMessageBase)new SimpleChatMessage { baseToken = message }); return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <SpawnPlayerAsRandomInternal>d__50 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public NetworkUser player; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <SpawnPlayerAsRandomInternal>d__50(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown //IL_0052: Unknown result type (might be due to invalid IL or missing references) switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(0.1f); <>1__state = 1; return true; case 1: <>1__state = -1; SpawnPlayerWithBody(player, BodyCatalog.FindBodyIndex(GetAvailibleSurvivorForPlayerByName(player, "random").bodyPrefab)); return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } public const string PluginGUID = "com.niwith.DropInMultiplayer"; public const string PluginName = "Drop In Multiplayer"; public const string PluginVersion = "4.2.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(); } private static void SetupEventHandlers() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected O, but got Unknown //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Expected O, but got Unknown Run.onRunStartGlobal += Run_onRunStartGlobal; Console.RunCmd += new hook_RunCmd(Console_RunCmd); Run.SetupUserCharacterMaster += new hook_SetupUserCharacterMaster(Run_SetupUserCharacterMaster); NetworkUser.onPostNetworkUserStart += new NetworkUserGenericDelegate(NetworkUser_onPostNetworkUserStart); } 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_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0096: 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) GameObject bodyPrefab = player.master.bodyPrefab; player.CmdSetBodyPreference(newBodyIndex); JoinAsResult result = JoinAsResult.Success; if ((((Object)(object)player.GetCurrentBody() == (Object)null && player.master.lostBodyToDeath) | 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 { 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_00bb: 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_0098: 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_009d: Invalid comparison between Unknown and I4 //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: 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) 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 given name"; } BodyIndex val3 = BodyCatalog.FindBodyIndexCaseInsensitive(text.EndsWith("Body", StringComparison.InvariantCultureIgnoreCase) ? text : (text + "Body")); 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)]; } return availibleSurvivorsForPlayer.Where(NameStringMatches).FirstOrDefault(); bool NameStringMatches(SurvivorDef survivorDef) { if (!string.Equals(survivorDef.cachedName, name, StringComparison.InvariantCultureIgnoreCase)) { return string.Equals(Language.GetString(survivorDef.displayNameToken).Replace(" ", ""), name.Replace(" ", ""), StringComparison.InvariantCultureIgnoreCase); } return true; } } 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; } [IteratorStateMachine(typeof(<SpawnPlayerAsRandomInternal>d__50))] private static IEnumerator SpawnPlayerAsRandomInternal(NetworkUser player) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <SpawnPlayerAsRandomInternal>d__50(0) { player = player }; } 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)); } [IteratorStateMachine(typeof(<SendChatMessageInternal>d__54))] private static IEnumerator SendChatMessageInternal(string message) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <SendChatMessageInternal>d__54(0) { message = 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 string.Equals(survivorDef.cachedName, 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; } } }