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 v1.0.3
DropInMultiplayer.dll
Decompiled 7 months agousing System; using System.Collections; 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.Security; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using DropInMultiplayerPlugin.Helpers; using Microsoft.CodeAnalysis; using On.RoR2; using R2API.Utils; using RiskOfOptions; using RiskOfOptions.Options; using RoR2; using UnityEngine; using UnityEngine.Networking; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("DropInMultiplayer")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("DropInMultiplayer")] [assembly: AssemblyTitle("DropInMultiplayer")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace DropInMultiplayerPlugin { [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInPlugin("MengHu.DropInMultiplayerPlugin", "DropInMultiplayerPlugin", "1.0.3")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] public class DropInMultiplayerPlugin : BaseUnityPlugin { public const string PluginGUID = "MengHu.DropInMultiplayerPlugin"; public const string PluginAuthor = "MengHu"; public const string PluginName = "DropInMultiplayerPlugin"; public const string PluginVersion = "1.0.3"; public static List<IBasePlugin> basePlugins = new List<IBasePlugin>(); public static byte[] logo; public static Sprite logo2; public static DropInMultiplayerPlugin Instance { get; set; } public static ConfigFile PluginConfig { get; set; } public void Awake() { Instance = this; Console.OutputEncoding = Encoding.UTF8; Log.Init(((BaseUnityPlugin)this).Logger); PluginConfig = ((BaseUnityPlugin)this).Config; ModSettingsManager.SetModDescription("Describe your mod in incredible detail over the course of the next 2 hours"); SetLogo(); DropInMultiplayer item = new DropInMultiplayer(); basePlugins.Add(item); InitPlugins(); } private void InitPlugins() { foreach (IBasePlugin basePlugin in basePlugins) { basePlugin.Init(PluginConfig); Log.Info(basePlugin.GetType().Name + " initialized"); } } public void OnEnable() { foreach (IBasePlugin basePlugin in basePlugins) { basePlugin.OnEnable(); } } public void OnDisable() { foreach (IBasePlugin basePlugin in basePlugins) { basePlugin.OnDisable(); } } private void Start() { foreach (IBasePlugin basePlugin in basePlugins) { basePlugin.Start(); } } private void Update() { foreach (IBasePlugin basePlugin in basePlugins) { basePlugin.Update(); } } public void OnDestroy() { foreach (IBasePlugin basePlugin in basePlugins) { basePlugin.OnDestroy(); } } private void SetLogo() { //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) try { string path = Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location), "icon"); int num = Random.Range(0, Directory.GetFiles(path).Length); int num2 = 0; string[] files = Directory.GetFiles(path); foreach (string path2 in files) { if (num2 == num) { logo = File.ReadAllBytes(path2); } num2++; } Texture2D val = LoadTexture(logo, 256, 256); logo2 = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0f, 0f), 100f, 1u, (SpriteMeshType)1, new Vector4(0f, 0f, 0f, 0f), true); ModSettingsManager.SetModIcon(logo2); } catch (Exception) { } } public static Texture2D LoadTexture(byte[] bytes, int width, int height) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Expected O, but got Unknown Texture2D val = new Texture2D(width, height, (TextureFormat)5, false, false); ImageConversion.LoadImage(val, bytes); ((Texture)val).filterMode = (FilterMode)0; return val; } private Texture2D LoadTexture(string name) { //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_0028: Expected O, but got Unknown //IL_002a: Expected O, but got Unknown Texture2D val = new Texture2D(2, 2); ImageConversion.LoadImage(val, File.ReadAllBytes(Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location), name))); return val; } private Sprite LoadTexture() { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Expected O, but got Unknown //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) string path = "icon.png"; Texture2D val = new Texture2D(2, 2); ImageConversion.LoadImage(val, File.ReadAllBytes(Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location), path))); return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0f, 0f)); } } 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; } } public class DropInMultiplayer : IBasePlugin { [CompilerGenerated] private sealed class <SendChatMessageInternal>d__43 : IEnumerator<object>, IEnumerator, IDisposable { 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__43(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__39 : IEnumerator<object>, IEnumerator, IDisposable { 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__39(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(); } } 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 void Init(ConfigFile config) { DropInConfig = new DropInMultiplayerConfig(config); SetupEventHandlers(); } private 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 void Run_onRunStartGlobal(Run obj) { captainBlacklistInventories = new HashSet<Inventory>(); } private void Run_SetupUserCharacterMaster(orig_SetupUserCharacterMaster orig, Run self, NetworkUser user) { try { orig.Invoke(self, user); } catch (Exception ex) { Debug.LogException(ex); Log.Error(ex); Log.Message("SetupUserCharacterMaster threw an exception and was caught"); } } private 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_009e: 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("/")) { 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"); } string text3 = value.Handler(sender.networkUser, arg); if (!string.IsNullOrWhiteSpace(text3)) { SendChatMessage(text3); } } } private void NetworkUser_onPostNetworkUserStart(NetworkUser networkUser) { if (NetworkServer.active && (Object)(object)Run.instance != (Object)null) { bool flag = (Object)(object)networkUser.master != (Object)null; Log.Message(networkUser.userName + " has joined " + (flag ? "as a previously connected player" : "as a new player")); GreetNewPlayer(networkUser); if (DropInConfig.JoinAsRandomByDefault.Value && !flag) { Log.Message("Spawning new player as random, since JoinAsRandomByDefault is true"); ((MonoBehaviour)DropInMultiplayerPlugin.Instance).StartCoroutine(SpawnPlayerAsRandomInternal(networkUser)); } if (DropInConfig.GiveCatchUpItems.Value && DropInConfig.GiveRejoiningPlayersCatchUpItems.Value && flag) { GiveCatchUpItems(networkUser); } } } private static JoinAsResult SpawnPlayerWithBody(NetworkUser player, BodyIndex newBodyIndex) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0019: 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) if ((Object)(object)player.master == (Object)null) { Log.Message($"Spawning new player {player.userName} with bodyIndex = {newBodyIndex}"); return SpawnNewPlayerWithBody(player, newBodyIndex); } Log.Message($"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_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0074: 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_004c: 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 && !DropInConfig.AllowRespawn.Value) { Log.Message($"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; if (!(text == "CaptainBody")) { if (text == "HereticBody" && DropInConfig.GiveHereticItems.Value) { inventory.RemoveItem(Items.LunarPrimaryReplacement, 1); inventory.RemoveItem(Items.LunarSecondaryReplacement, 1); inventory.RemoveItem(Items.LunarSpecialReplacement, 1); inventory.RemoveItem(Items.LunarUtilityReplacement, 1); } } else { if (inventory.GetItemCount(Items.CaptainDefenseMatrix) <= 0 && DropInConfig.PreventCaptainScrapAbuse.Value) { captainBlacklistInventories.Add(inventory); } if (!captainBlacklistInventories.Contains(inventory)) { inventory.RemoveItem(Items.CaptainDefenseMatrix, 1); } } if (!(text2 == "CaptainBody")) { if (text2 == "HereticBody" && DropInConfig.GiveHereticItems.Value) { inventory.GiveItem(Items.LunarPrimaryReplacement, 1); inventory.GiveItem(Items.LunarSecondaryReplacement, 1); inventory.GiveItem(Items.LunarSpecialReplacement, 1); inventory.GiveItem(Items.LunarUtilityReplacement, 1); } } else if (!captainBlacklistInventories.Contains(inventory) || !DropInConfig.PreventCaptainScrapAbuse.Value) { inventory.GiveItem(Items.CaptainDefenseMatrix, 1); } } catch (Exception ex) { Debug.LogException(ex); Log.Error(ex); Log.Message("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_0166: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_01e1: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_01be: Unknown result type (might be due to invalid IL or missing references) //IL_01c0: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: Invalid comparison between Unknown and I4 //IL_01cb: Unknown result type (might be due to invalid IL or missing references) //IL_01cd: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: 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"; } Log.Error("Player " + val.userName + " is attempting to join as " + args[0]); Log.Error($"Player {val.userName} is attempting to join as GetCurrentBody: {(Object)(object)val.GetCurrentBody() != (Object)null}"); Log.Error($"Player {val.userName} is attempting to join as lostBodyToDeath: {val.master.lostBodyToDeath}"); Log.Error($"Player {val.userName} is attempting to join as hasBody: {val.master.hasBody}"); if (!DropInConfig.RepetitionRespawn.Value) { if ((Object)(object)val.GetCurrentBody() != (Object)null) { return "Player is already spawned in, cannot use join as"; } if ((Object)(object)val.master != (Object)null && !val.master.lostBodyToDeath) { return "Player is not dead, cannot use join as"; } if ((Object)(object)val.master != (Object)null && val.master.hasBody) { return "Player is not dead, cannot use join as"; } } if (DropInConfig.RejoinOnlyAfterDeath.Value && (Object)(object)val.master != (Object)null && !val.master.lostBodyToDeath) { return "Player is not dead, cannot use join as"; } 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); Log.Error(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 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 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 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 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) { Log.Message("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); Log.Message($"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.GetItemCount(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.GiveItem(val2, 1); } catch (Exception ex) { Debug.LogException(ex); Log.Error(ex); Log.Message("Exception occured giving player an item"); } } } private static Transform GetSpawnTransformForPlayer(NetworkUser player) { Transform val = player.GetCurrentBody()?.transform; if ((Object)(object)val == (Object)null) { Log.Message(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) ? obj.GetCurrentBody().transform : null); } if ((Object)(object)val == (Object)null) { Log.Message("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__39))] private IEnumerator SpawnPlayerAsRandomInternal(NetworkUser player) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <SpawnPlayerAsRandomInternal>d__39(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 void GreetNewPlayer(NetworkUser player) { //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Expected O, but got Unknown if (DropInConfig.SendWelcomeMessage.Value) { string value = DropInConfig.CustomWelcomeMessage.Value; if (value.Length > 1000) { Log.Message($"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 void SendChatMessage(string message) { ((MonoBehaviour)DropInMultiplayerPlugin.Instance).StartCoroutine(SendChatMessageInternal(message)); } [IteratorStateMachine(typeof(<SendChatMessageInternal>d__43))] private IEnumerator SendChatMessageInternal(string message) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <SendChatMessageInternal>d__43(0) { message = message }; } } public class DropInMultiplayerConfig { private const string DefaultWelcomeMessage = "你好{username}! 在聊天中输入“/join_as {幸存者姓名}”(或“/join_as random”)加入游戏。要获取可用幸存者的列表,请在聊天中输入“/list_survivors”"; public ConfigEntry<bool> AllowRespawn { get; } public ConfigEntry<bool> RepetitionRespawn { get; } public ConfigEntry<bool> RejoinOnlyAfterDeath { 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> 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) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Expected O, but got Unknown //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Expected O, but got Unknown //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Expected O, but got Unknown //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Expected O, but got Unknown //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Expected O, but got Unknown //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Expected O, but got Unknown //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Expected O, but got Unknown //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Expected O, but got Unknown //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Expected O, but got Unknown //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_01be: Expected O, but got Unknown //IL_01e0: Unknown result type (might be due to invalid IL or missing references) //IL_01ea: Expected O, but got Unknown //IL_020c: Unknown result type (might be due to invalid IL or missing references) //IL_0216: Expected O, but got Unknown //IL_0238: Unknown result type (might be due to invalid IL or missing references) //IL_0242: Expected O, but got Unknown //IL_0268: Unknown result type (might be due to invalid IL or missing references) //IL_0272: Expected O, but got Unknown AllowRespawn = config.Bind<bool>("General", "AllowRespawn", true, "启用后,使用 /join_as 命令的死亡玩家将立即重生"); ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(AllowRespawn)); RepetitionRespawn = config.Bind<bool>("General", "RepetitionRespawn", false, "启用后,玩家可以多次使用 /join_as 命令重新生成"); ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(RepetitionRespawn)); RejoinOnlyAfterDeath = config.Bind<bool>("General", "RejoinOnlyAfterDeath", true, "启用后,玩家只能在死亡后使用 /join_as 命令重新生成"); ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(RejoinOnlyAfterDeath)); JoinAsRandomByDefault = config.Bind<bool>("General", "JoinAsRandomByDefault", false, "启用后,新加入的玩家将默认生成为随机幸存者"); ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(JoinAsRandomByDefault)); AllowJoinAsHiddenSurvivors = config.Bind<bool>("Survivors", "AllowJoinAsHiddenSurvivors", true, "启用后,允许玩家以隐藏角色的身份加入,例如异端"); ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(AllowJoinAsHiddenSurvivors)); AllowJoinAsAllBodies = config.Bind<bool>("General", "AllowJoinAsAllBodies", false, "启用后,使用 /join_as 命令将尝试与任何身体匹配,例如甲虫,警告:非常未经测试join_as!"); ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(AllowJoinAsAllBodies)); GiveHereticItems = config.Bind<bool>("Survivors", "GiveHereticItems", true, "启用后,以异端身份加入将自动获得所有 4 个异端物品。"); ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(GiveHereticItems)); PreventCaptainScrapAbuse = config.Bind<bool>("Survivors", "PreventCaptainScrapAbuse", true, "启用后,如果 船长 被报废或移除,则不会收到替换的微型机器人。"); ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(PreventCaptainScrapAbuse)); GiveCatchUpItems = config.Bind<bool>("Items", "GiveCatchUpItems", true, "启用后,玩家将在加入时获得追赶物品"); ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(GiveCatchUpItems)); GiveRejoiningPlayersCatchUpItems = config.Bind<bool>("Items", "GiveRejoiningPlayersCatchUpItems", true, "启用后,离开并重新加入的玩家将获得追赶物品,警告:可以通过将所有物品交给一名玩家,然后离开并重新加入来利用"); ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(GiveRejoiningPlayersCatchUpItems)); GiveCatchUpVoidItems = config.Bind<bool>("Items", "GiveCatchUpVoidItems", false, "启用后,月球物品将在玩家开始时掉落(需要启用 GiveCatchUpItems)"); ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(GiveCatchUpVoidItems)); GiveCatchUpLunarItems = config.Bind<bool>("Items", "GiveCatchUpLunarItems", false, "启用后,月球物品将在玩家开始时掉落(需要启用 GiveCatchUpItems)"); ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(GiveCatchUpLunarItems)); SendWelcomeMessage = config.Bind<bool>("Chat Messages", "SendWelcomeMessage", true, "当新玩家加入时发送欢迎消息。"); ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(SendWelcomeMessage)); CustomWelcomeMessage = config.Bind<string>("Chat Messages", "CustomWelcomeMessage", "你好{username}! 在聊天中输入“/join_as {幸存者姓名}”(或“/join_as random”)加入游戏。要获取可用幸存者的列表,请在聊天中输入“/list_survivors”", "欢迎信息的格式。 {username} 将替换为加入用户名, {survivorlist} 将被可用幸存者名单取代。"); ModSettingsManager.AddOption((BaseOption)new StringInputFieldOption(CustomWelcomeMessage)); } } public interface IBasePlugin { void Init(ConfigFile config) { } void OnEnable() { } void OnDisable() { } void Start() { } void Update() { } void OnDestroy() { } } internal static class Log { private static ManualLogSource _logSource; internal static void Init(ManualLogSource logSource) { _logSource = logSource; } internal static void Debug(object data) { _logSource.LogDebug(data); } internal static void Error(object data) { _logSource.LogError(data); } internal static void Fatal(object data) { _logSource.LogFatal(data); } internal static void Info(object data) { _logSource.LogInfo(data); } internal static void Message(object data) { _logSource.LogMessage(data); } internal static void Warning(object data) { _logSource.LogWarning(data); } } } namespace DropInMultiplayerPlugin.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; } } }