using 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> 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.1.0")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
public class DropInMultiplayer : BaseUnityPlugin
{
public const string PluginGUID = "com.niwith.DropInMultiplayer";
public const string PluginName = "Drop In Multiplayer";
public const string PluginVersion = "4.1.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_0073: Unknown result type (might be due to invalid IL or missing references)
//IL_0079: Unknown result type (might be due to invalid IL or missing references)
//IL_0087: 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)
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)
{
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;
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);
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.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);
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 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;
}
}
}