using System; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using EntityStates; using EntityStates.GummyClone; using RoR2.CharacterAI; using RoR2.Items; using RoR2.Stats; using UnityEngine; using UnityEngine.Events; using UnityEngine.Networking; using UnityEngine.ResourceManagement.AsyncOperations; using UnityEngine.Serialization; namespace RoR2; [RequireComponent(typeof(MinionOwnership))] [RequireComponent(typeof(Inventory))] [DisallowMultipleComponent] public class CharacterMaster : NetworkBehaviour { private static class CommonAssets { public static GameObject goldOnStageStartEffect; public static void Resolve() { AsyncOperationHandle asyncOperationHandle = LegacyResourcesAPI.LoadAsync("Prefabs/Effects/GoldOnStageStartCoinGain"); asyncOperationHandle.Completed += delegate(AsyncOperationHandle x) { goldOnStageStartEffect = x.Result; }; } } public enum SEEKER_REVIVE_STATUS { UNUSED, USED, BURNED } [Tooltip("This is assigned to the prefab automatically by MasterCatalog at runtime. Do not set this value manually.")] [HideInInspector] [SerializeField] private int _masterIndex; [Tooltip("The prefab of this character's body.")] public GameObject bodyPrefab; [Tooltip("Whether or not to spawn the body at the position of this manager object as soon as Start runs.")] public bool spawnOnStart; [Tooltip("The team of the body.")] [FormerlySerializedAs("teamIndex")] [SerializeField] private TeamIndex _teamIndex; public UnityEvent onBodyDeath; [Tooltip("Whether or not to destroy this master when the body dies.")] public bool destroyOnBodyDeath = true; private static List instancesList; private static ReadOnlyCollection _readOnlyInstancesList; private BaseAI[] aiComponents; private const uint bodyDirtyBit = 1u; private const uint moneyDirtyBit = 2u; private const uint survivalTimeDirtyBit = 4u; private const uint teamDirtyBit = 8u; private const uint loadoutDirtyBit = 16u; private const uint miscFlagsDirtyBit = 32u; private const uint voidCoinsDirtyBit = 64u; private const uint allDirtyBits = 127u; public readonly Loadout loadout = new Loadout(); private NetworkInstanceId _bodyInstanceId = NetworkInstanceId.Invalid; private GameObject resolvedBodyInstance; private bool bodyResolved; private ulong beadExperience; private int numberOfBeadStatsGained; private uint oldBeadLevel = 1u; private uint newBeadLevel; private ulong beadXPNeededForCurrentLevel = 20uL; private uint _money; public uint lssMoneyExp; private uint _voidCoins; public bool isBoss; private Xoroshiro128Plus cloverVoidRng; [NonSerialized] private List deployablesList; public bool preventGameOver = true; private Vector3 deathAimVector = Vector3.zero; private bool killedByUnsafeArea; private const float respawnDelayDuration = 2f; private float _internalSurvivalTime; private BodyIndex killerBodyIndex = BodyIndex.None; private bool preventRespawnUntilNextStageServer; private SEEKER_REVIVE_STATUS seekerUsedRevive; [HideInInspector] public GameObject devotionInventoryPrefab; [HideInInspector] public DevotionInventoryController devotionInventoryUpdaterRef; [HideInInspector] public ItemIndex devotionItem; [HideInInspector] public int devotedEvolutionTracker; [HideInInspector] public bool isDevotedMinion; [HideInInspector] public Interactor summonerRef; private bool godMode; private uint lostBodyToDeathFlag = 1u; private uint _miscFlags; private static int kRpcRpcOnPlayerBodyDamaged; private static int kCmdCmdRespawn; private static int kRpcRpcSetSeekerRevive; public MasterCatalog.MasterIndex masterIndex { get { return (MasterCatalog.MasterIndex)_masterIndex; } set { _masterIndex = (int)value; } } public NetworkIdentity networkIdentity { get; private set; } public bool hasEffectiveAuthority { get; private set; } public TeamIndex teamIndex { get { return _teamIndex; } set { if (_teamIndex != value) { _teamIndex = value; if (NetworkServer.active) { SetDirtyBit(8u); } } } } public static ReadOnlyCollection readOnlyInstancesList => _readOnlyInstancesList; public Inventory inventory { get; private set; } public PlayerCharacterMasterController playerCharacterMasterController { get; private set; } public PlayerStatsComponent playerStatsComponent { get; private set; } public MinionOwnership minionOwnership { get; private set; } private NetworkInstanceId bodyInstanceId { get { return _bodyInstanceId; } set { if (!(value == _bodyInstanceId)) { SetDirtyBit(1u); _bodyInstanceId = value; } } } public BodyIndex backupBodyIndex { get; private set; } private GameObject bodyInstanceObject { get { if (!bodyResolved) { resolvedBodyInstance = Util.FindNetworkObject(bodyInstanceId); if ((bool)resolvedBodyInstance) { bodyResolved = true; StoreBackupBodyIndex(); } } return resolvedBodyInstance; } set { NetworkInstanceId invalid = NetworkInstanceId.Invalid; resolvedBodyInstance = null; bodyResolved = true; if ((bool)value) { NetworkIdentity component = value.GetComponent(); if ((bool)component) { invalid = component.netId; resolvedBodyInstance = value; StoreBackupBodyIndex(); } } bodyInstanceId = invalid; } } public uint money { get { return _money; } set { if (value != _money) { SetDirtyBit(2u); _money = value; } } } public uint voidCoins { get { return _voidCoins; } set { if (value != _voidCoins) { SetDirtyBit(64u); _voidCoins = value; } } } public float luck { get; set; } public bool hasBody => bodyInstanceObject; public Vector3 deathFootPosition { get; private set; } = Vector3.zero; private float internalSurvivalTime { get { return _internalSurvivalTime; } set { if (value != _internalSurvivalTime) { SetDirtyBit(4u); _internalSurvivalTime = value; } } } public float currentLifeStopwatch { get { if (internalSurvivalTime <= 0f) { return 0f - internalSurvivalTime; } if ((bool)Run.instance) { return Run.instance.GetRunStopwatch() - internalSurvivalTime; } return 0f; } } private uint miscFlags { get { return _miscFlags; } set { if (value != _miscFlags) { _miscFlags = value; if (NetworkServer.active) { SetDirtyBit(32u); } } } } public bool lostBodyToDeath { get { return (miscFlags & lostBodyToDeathFlag) != 0; } private set { if (value) { miscFlags |= lostBodyToDeathFlag; } else { miscFlags &= ~lostBodyToDeathFlag; } } } public static event Action onStartGlobal; public static event Action onCharacterMasterDiscovered; public static event Action onCharacterMasterLost; public event Action onBodyStart; public event Action onBodyDestroyed; public event Action onPlayerBodyDamaged; private void UpdateAuthority() { hasEffectiveAuthority = Util.HasEffectiveAuthority(networkIdentity); } public override void OnStartAuthority() { base.OnStartAuthority(); UpdateAuthority(); } public override void OnStopAuthority() { UpdateAuthority(); base.OnStopAuthority(); } [Server] public void SetLoadoutServer(Loadout newLoadout) { if (!NetworkServer.active) { Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterMaster::SetLoadoutServer(RoR2.Loadout)' called on client"); return; } newLoadout.Copy(loadout); SetDirtyBit(16u); } private void StoreBackupBodyIndex() { if ((bool)resolvedBodyInstance) { CharacterBody component = resolvedBodyInstance.GetComponent(); if ((bool)component) { backupBodyIndex = component.bodyIndex; } } } private void OnSyncBodyInstanceId(NetworkInstanceId value) { resolvedBodyInstance = null; bodyResolved = value == NetworkInstanceId.Invalid; _bodyInstanceId = value; } public void TrackBeadExperience(ulong amount) { if (!inventory) { return; } int itemCount = inventory.GetItemCount(DLC2Content.Items.ExtraStatsOnLevelUp); if (itemCount <= 0) { return; } ulong num = amount * (ulong)(0.25f * (float)(itemCount - 1)); ulong num2 = amount * (ulong)(0.025f * (float)numberOfBeadStatsGained); if (num2 >= num + amount) { num2 = (ulong)(0.8f * (float)(num + amount)); } beadExperience += amount + num - num2; newBeadLevel = TeamManager.instance.FindLevelForBeadExperience(beadExperience); if (beadExperience >= beadXPNeededForCurrentLevel) { CharacterBody body = GetBody(); body.SetBuffCount(DLC2Content.Buffs.ExtraStatsOnLevelUpBuff.buffIndex, (int)oldBeadLevel); float num3 = body.GetBuffCount(DLC2Content.Buffs.ExtraStatsOnLevelUpBuff); float num4 = 1f; switch (body.hullClassification) { case HullClassification.Golem: num4 = 2f; break; case HullClassification.BeetleQueen: num4 = 3f; break; } num4 += num3 / (num3 * 0.25f + 1f); EffectManager.SpawnEffect(LegacyResourcesAPI.Load("Prefabs/Effects/ExtraStatsOnLevelUpEffect"), new EffectData { origin = body.footPosition, scale = num4 }, transmit: true); Util.PlaySound("Play_item_proc_extraStatsOnLevelUp", body.gameObject); oldBeadLevel = newBeadLevel; beadXPNeededForCurrentLevel = TeamManager.GetExperienceForLevel(oldBeadLevel + 1); } } public void OnBeadReset(bool gainedStats) { if (gainedStats) { numberOfBeadStatsGained += (int)oldBeadLevel; } oldBeadLevel = 1u; beadExperience = 0uL; beadXPNeededForCurrentLevel = 20uL; } [Server] public void GiveExperience(ulong amount) { if (!NetworkServer.active) { Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterMaster::GiveExperience(System.UInt64)' called on client"); } else { TeamManager.instance.GiveTeamExperience(teamIndex, amount); } } public void GiveMoney(uint amount) { int itemCount = inventory.GetItemCount(DLC2Content.Items.OnLevelUpFreeUnlock); int num = TeamManager.LongstandingSolitudesInParty(); if (itemCount > 0) { double num2 = TeamManager.GetExperienceForLevel((uint)GetBody().level + 1); uint difficultyScaledCost = (uint)Run.instance.GetDifficultyScaledCost(25, Run.instance.difficultyCoefficient); lssMoneyExp += amount; if ((float)lssMoneyExp >= (float)(difficultyScaledCost * num) + GetBody().level) { GiveExperience((ulong)(num2 / (double)(10 + (itemCount - 1) * 15))); lssMoneyExp = 0u; } } else { money += amount; StatManager.OnGoldCollected(this, amount); } } public void GiveVoidCoins(uint amount) { voidCoins += amount; } public int GetDeployableSameSlotLimit(DeployableSlot slot) { int result = 0; int num = 1; if (RunArtifactManager.instance.IsArtifactEnabled(RoR2Content.Artifacts.swarmsArtifactDef)) { num = 2; } switch (slot) { case DeployableSlot.EngiMine: result = 4; if ((bool)bodyInstanceObject) { result = bodyInstanceObject.GetComponent().secondary.maxStock; } break; case DeployableSlot.EngiTurret: result = ((inventory.GetItemCount(DLC1Content.Items.EquipmentMagazineVoid) <= 0) ? 2 : 3); break; case DeployableSlot.BeetleGuardAlly: result = inventory.GetItemCount(RoR2Content.Items.BeetleGland) * num; break; case DeployableSlot.EngiBubbleShield: result = 1; break; case DeployableSlot.LoaderPylon: result = 3; break; case DeployableSlot.EngiSpiderMine: result = 4; if ((bool)bodyInstanceObject) { result = bodyInstanceObject.GetComponent().secondary.maxStock; } break; case DeployableSlot.RoboBallMini: result = 3; break; case DeployableSlot.ParentPodAlly: result = inventory.GetItemCount(JunkContent.Items.Incubator) * num; break; case DeployableSlot.ParentAlly: result = inventory.GetItemCount(JunkContent.Items.Incubator) * num; break; case DeployableSlot.PowerWard: result = 1; break; case DeployableSlot.CrippleWard: result = 5; break; case DeployableSlot.DeathProjectile: result = 3; break; case DeployableSlot.RoboBallRedBuddy: case DeployableSlot.RoboBallGreenBuddy: result = num; break; case DeployableSlot.GummyClone: result = 3; break; case DeployableSlot.LunarSunBomb: result = LunarSunBehavior.GetMaxProjectiles(inventory); break; case DeployableSlot.VendingMachine: result = 1; break; case DeployableSlot.VoidMegaCrabItem: result = VoidMegaCrabItemBehavior.GetMaxProjectiles(inventory); break; case DeployableSlot.DroneWeaponsDrone: result = 1; break; case DeployableSlot.MinorConstructOnKill: result = inventory.GetItemCount(DLC1Content.Items.MinorConstructOnKill) * 4; break; case DeployableSlot.CaptainSupplyDrop: result = 2; break; } return result; } [Server] public void AddDeployable(Deployable deployable, DeployableSlot slot) { if (!NetworkServer.active) { Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterMaster::AddDeployable(RoR2.Deployable,RoR2.DeployableSlot)' called on client"); return; } if ((bool)deployable.ownerMaster) { Debug.LogErrorFormat("Attempted to add deployable {0} which already belongs to master {1} to master {2}.", deployable.gameObject, deployable.ownerMaster.gameObject, base.gameObject); } if (deployablesList == null) { deployablesList = new List(); } int num = 0; int deployableSameSlotLimit = GetDeployableSameSlotLimit(slot); for (int num2 = deployablesList.Count - 1; num2 >= 0; num2--) { if (deployablesList[num2].slot == slot) { num++; if (num >= deployableSameSlotLimit) { Deployable deployable2 = deployablesList[num2].deployable; deployablesList.RemoveAt(num2); deployable2.ownerMaster = null; deployable2.onUndeploy.Invoke(); } } } deployablesList.Add(new DeployableInfo { deployable = deployable, slot = slot }); deployable.ownerMaster = this; } [Server] public int GetDeployableCount(DeployableSlot slot) { if (!NetworkServer.active) { Debug.LogWarning("[Server] function 'System.Int32 RoR2.CharacterMaster::GetDeployableCount(RoR2.DeployableSlot)' called on client"); return 0; } if (deployablesList == null) { return 0; } int num = 0; for (int num2 = deployablesList.Count - 1; num2 >= 0; num2--) { if (deployablesList[num2].slot == slot) { num++; } } return num; } [Server] public bool IsDeployableLimited(DeployableSlot slot) { if (!NetworkServer.active) { Debug.LogWarning("[Server] function 'System.Boolean RoR2.CharacterMaster::IsDeployableLimited(RoR2.DeployableSlot)' called on client"); return false; } return GetDeployableCount(slot) >= GetDeployableSameSlotLimit(slot); } [Server] public void RemoveDeployable(Deployable deployable) { if (!NetworkServer.active) { Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterMaster::RemoveDeployable(RoR2.Deployable)' called on client"); } else { if (deployablesList == null || deployable.ownerMaster != this) { return; } for (int num = deployablesList.Count - 1; num >= 0; num--) { if (deployablesList[num].deployable == deployable) { deployablesList.RemoveAt(num); } } deployable.ownerMaster = null; } } [Server] public bool IsDeployableSlotAvailable(DeployableSlot deployableSlot) { if (!NetworkServer.active) { Debug.LogWarning("[Server] function 'System.Boolean RoR2.CharacterMaster::IsDeployableSlotAvailable(RoR2.DeployableSlot)' called on client"); return false; } return GetDeployableCount(deployableSlot) < GetDeployableSameSlotLimit(deployableSlot); } [Server] public CharacterBody SpawnBody(Vector3 position, Quaternion rotation) { if (!NetworkServer.active) { Debug.LogWarning("[Server] function 'RoR2.CharacterBody RoR2.CharacterMaster::SpawnBody(UnityEngine.Vector3,UnityEngine.Quaternion)' called on client"); return null; } if ((bool)bodyInstanceObject) { Debug.LogError("Character cannot have more than one body at this time."); return null; } if (!bodyPrefab) { Debug.LogErrorFormat("Attempted to spawn body of character master {0} with no body prefab.", base.gameObject); } if (!bodyPrefab.GetComponent()) { Debug.LogErrorFormat("Attempted to spawn body of character master {0} with a body prefab that has no {1} component attached.", base.gameObject, typeof(CharacterBody).Name); } bool flag = bodyPrefab.GetComponent(); GameObject gameObject = UnityEngine.Object.Instantiate(bodyPrefab, position, flag ? Quaternion.identity : rotation); CharacterBody component = gameObject.GetComponent(); component.masterObject = base.gameObject; component.teamComponent.teamIndex = teamIndex; component.SetLoadoutServer(loadout); if (flag) { CharacterDirection component2 = gameObject.GetComponent(); float y = rotation.eulerAngles.y; component2.yaw = y; } NetworkConnection clientAuthorityOwner = GetComponent().clientAuthorityOwner; if (clientAuthorityOwner != null) { clientAuthorityOwner.isReady = true; NetworkServer.SpawnWithClientAuthority(gameObject, clientAuthorityOwner); } else { NetworkServer.Spawn(gameObject); } bodyInstanceObject = gameObject; Run.instance.OnServerCharacterBodySpawned(component); return component; } [Server] public void DestroyBody() { if (!NetworkServer.active) { Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterMaster::DestroyBody()' called on client"); } else if ((bool)bodyInstanceObject) { CharacterBody body = GetBody(); UnityEngine.Object.Destroy(bodyInstanceObject); OnBodyDestroyed(body); bodyInstanceObject = null; } } public GameObject GetBodyObject() { return bodyInstanceObject; } public CharacterBody GetBody() { GameObject bodyObject = GetBodyObject(); if (!bodyObject) { return null; } return bodyObject.GetComponent(); } private void Awake() { networkIdentity = GetComponent(); inventory = GetComponent(); aiComponents = (NetworkServer.active ? GetComponents() : Array.Empty()); playerCharacterMasterController = GetComponent(); playerStatsComponent = GetComponent(); minionOwnership = GetComponent(); inventory.onInventoryChanged += OnInventoryChanged; inventory.onItemAddedClient += OnItemAddedClient; inventory.onEquipmentExternalRestockServer += OnInventoryEquipmentExternalRestockServer; OnInventoryChanged(); Stage.onServerStageBegin += OnServerStageBegin; } private void OnItemAddedClient(ItemIndex itemIndex) { StartCoroutine(HighlightNewItem(itemIndex)); } private IEnumerator HighlightNewItem(ItemIndex itemIndex) { yield return new WaitForSeconds(0.05f); GameObject bodyObject = GetBodyObject(); if (!bodyObject) { yield break; } ModelLocator component = bodyObject.GetComponent(); if (!component) { yield break; } Transform modelTransform = component.modelTransform; if ((bool)modelTransform) { CharacterModel component2 = modelTransform.GetComponent(); if ((bool)component2) { component2.HighlightItemDisplay(itemIndex); } } } private void Start() { UpdateAuthority(); if (NetworkServer.active && spawnOnStart && !bodyInstanceObject) { SpawnBodyHere(); } CharacterMaster.onStartGlobal?.Invoke(this); } public void SetAIUpdateFrequency(bool updateEveryFrame) { BaseAI[] array = aiComponents; for (int i = 0; i < array.Length; i++) { array[i].forceUpdateEveryFrame = updateEveryFrame; } } private void OnInventoryChanged() { luck = 0f; luck += inventory.GetItemCount(RoR2Content.Items.Clover); luck -= inventory.GetItemCount(RoR2Content.Items.LunarBadLuck); if (NetworkServer.active && (bool)inventory) { CharacterBody body = GetBody(); if ((bool)body && body.bodyIndex != BodyCatalog.SpecialCases.HereticBody() && inventory.GetItemCount(RoR2Content.Items.LunarPrimaryReplacement.itemIndex) > 0 && inventory.GetItemCount(RoR2Content.Items.LunarSecondaryReplacement.itemIndex) > 0 && inventory.GetItemCount(RoR2Content.Items.LunarSpecialReplacement.itemIndex) > 0 && inventory.GetItemCount(RoR2Content.Items.LunarUtilityReplacement.itemIndex) > 0) { TransformBody("HereticBody"); } if (inventory.GetItemCount(DLC2Content.Items.OnLevelUpFreeUnlock) > 0 && money != 0) { GiveMoney(money); money = 0u; } } SetUpGummyClone(); } private void OnInventoryEquipmentExternalRestockServer() { CharacterBody body = GetBody(); if ((bool)body) { EffectData effectData = new EffectData(); effectData.origin = body.corePosition; effectData.SetNetworkedObjectReference(body.gameObject); EffectManager.SpawnEffect(LegacyResourcesAPI.Load("Prefabs/Effects/EquipmentRestockEffect"), effectData, transmit: true); } } [Server] public void SpawnBodyHere() { if (!NetworkServer.active) { Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterMaster::SpawnBodyHere()' called on client"); } else { SpawnBody(base.transform.position, base.transform.rotation); } } private void OnEnable() { instancesList.Add(this); CharacterMaster.onCharacterMasterDiscovered?.Invoke(this); } private void OnDisable() { try { CharacterMaster.onCharacterMasterLost?.Invoke(this); } catch (Exception message) { Debug.LogError(message); } instancesList.Remove(this); } private void OnDestroy() { if (isBoss) { isBoss = false; } Stage.onServerStageBegin -= OnServerStageBegin; } public void OnBodyStart(CharacterBody body) { if (NetworkServer.active) { lostBodyToDeath = false; } preventGameOver = true; killerBodyIndex = BodyIndex.None; killedByUnsafeArea = false; body.RecalculateStats(); if (NetworkServer.active) { BaseAI[] array = aiComponents; for (int i = 0; i < array.Length; i++) { array[i].OnBodyStart(body); } } if ((bool)playerCharacterMasterController) { if ((bool)playerCharacterMasterController.networkUserObject) { _ = playerCharacterMasterController.networkUserObject.GetComponent().isLocalPlayer; } playerCharacterMasterController.OnBodyStart(); } if (inventory.GetItemCount(RoR2Content.Items.Ghost) > 0) { Util.PlaySound("Play_item_proc_ghostOnKill", body.gameObject); } if (NetworkServer.active) { HealthComponent healthComponent = body.healthComponent; if ((bool)healthComponent) { if (teamIndex == TeamIndex.Player && Run.instance.selectedDifficulty >= DifficultyIndex.Eclipse1) { healthComponent.Networkhealth = healthComponent.fullHealth * 0.5f; } else { healthComponent.Networkhealth = healthComponent.fullHealth; } } UpdateBodyGodMode(); StartLifeStopwatch(); } SetUpGummyClone(); this.onBodyStart?.Invoke(body); if (inventory.GetItemCount(DLC2Content.Items.ExtraStatsOnLevelUp) > 0) { uint num = TeamManager.instance.FindLevelForBeadExperience(beadExperience); body.SetBuffCount(DLC2Content.Buffs.ExtraStatsOnLevelUpBuff.buffIndex, (int)(num - 1)); } } [Server] public bool IsExtraLifePendingServer() { if (!NetworkServer.active) { Debug.LogWarning("[Server] function 'System.Boolean RoR2.CharacterMaster::IsExtraLifePendingServer()' called on client"); return false; } if (!IsInvoking("RespawnExtraLife") && !IsInvoking("RespawnExtraLifeVoid") && !IsInvoking("RespawnExtraLifeShrine")) { return IsInvoking("RespawnExtraLifeHealAndRevive"); } return true; } [Server] public bool IsDeadAndOutOfLivesServer() { if (!NetworkServer.active) { Debug.LogWarning("[Server] function 'System.Boolean RoR2.CharacterMaster::IsDeadAndOutOfLivesServer()' called on client"); return false; } CharacterBody body = GetBody(); if (body != null) { if (body.healthComponent.alive) { return false; } if (body.HasBuff(DLC2Content.Buffs.ExtraLifeBuff)) { return false; } bool flag = false; if (body.equipmentSlot != null && body.equipmentSlot.equipmentIndex == DLC2Content.Equipment.HealAndRevive.equipmentIndex) { flag = true; } if (flag) { return false; } } return inventory.GetItemCount(RoR2Content.Items.ExtraLife) <= 0 && inventory.GetItemCount(DLC1Content.Items.ExtraLifeVoid) <= 0 && !IsExtraLifePendingServer(); } public void OnBodyDeath(CharacterBody body) { if (NetworkServer.active) { lostBodyToDeath = true; deathFootPosition = body.footPosition; BaseAI[] array = aiComponents; for (int i = 0; i < array.Length; i++) { array[i].OnBodyDeath(body); } if ((bool)playerCharacterMasterController) { playerCharacterMasterController.OnBodyDeath(); } if (body.HasBuff(DLC2Content.Buffs.ExtraLifeBuff)) { body.RemoveBuff(DLC2Content.Buffs.ExtraLifeBuff); Invoke("RespawnExtraLifeShrine", 2f); Invoke("PlayExtraLifeSFX", 1f); } else { bool flag = false; if ((bool)body.equipmentSlot && body.equipmentSlot.equipmentIndex == DLC2Content.Equipment.HealAndRevive.equipmentIndex) { flag = true; } if (flag) { CharacterMasterNotificationQueue.SendTransformNotification(this, inventory.currentEquipmentIndex, DLC2Content.Equipment.HealAndReviveConsumed.equipmentIndex, CharacterMasterNotificationQueue.TransformationType.Default); inventory.SetEquipmentIndex(DLC2Content.Equipment.HealAndReviveConsumed.equipmentIndex); Invoke("RespawnExtraLifeHealAndRevive", 2f); Invoke("PlayExtraLifeSFX", 1f); } else if (inventory.GetItemCount(RoR2Content.Items.ExtraLife) > 0) { inventory.RemoveItem(RoR2Content.Items.ExtraLife); Invoke("RespawnExtraLife", 2f); Invoke("PlayExtraLifeSFX", 1f); } else if (inventory.GetItemCount(DLC1Content.Items.ExtraLifeVoid) > 0) { inventory.RemoveItem(DLC1Content.Items.ExtraLifeVoid); Invoke("RespawnExtraLifeVoid", 2f); Invoke("PlayExtraLifeVoidSFX", 1f); } else { if (destroyOnBodyDeath) { UnityEngine.Object.Destroy(base.gameObject, 1f); } preventGameOver = false; preventRespawnUntilNextStageServer = true; } } if (TryGetComponent(out var component)) { component.OnDevotedBodyDead(); } if ((bool)devotionInventoryPrefab) { devotionInventoryPrefab.GetComponent().RemoveItem(devotionItem, devotedEvolutionTracker + 1); devotionInventoryUpdaterRef.DropScrapOnDeath(devotionItem, body); devotionInventoryUpdaterRef.UpdateAllMinions(); } ResetLifeStopwatch(); } onBodyDeath?.Invoke(); } public void TrueKill() { TrueKill(null, null, DamageType.Generic); } public void TrueKill(GameObject killerOverride = null, GameObject inflictorOverride = null, DamageTypeCombo damageTypeOverride = default(DamageTypeCombo)) { int itemCount = inventory.GetItemCount(RoR2Content.Items.ExtraLife); if (itemCount > 0) { inventory.ResetItem(RoR2Content.Items.ExtraLife); inventory.GiveItem(RoR2Content.Items.ExtraLifeConsumed, itemCount); CharacterMasterNotificationQueue.SendTransformNotification(this, RoR2Content.Items.ExtraLife.itemIndex, RoR2Content.Items.ExtraLifeConsumed.itemIndex, CharacterMasterNotificationQueue.TransformationType.Default); } if (inventory.GetItemCount(DLC1Content.Items.ExtraLifeVoid) > 0) { inventory.ResetItem(DLC1Content.Items.ExtraLifeVoid); inventory.GiveItem(DLC1Content.Items.ExtraLifeVoidConsumed, itemCount); CharacterMasterNotificationQueue.SendTransformNotification(this, DLC1Content.Items.ExtraLifeVoid.itemIndex, DLC1Content.Items.ExtraLifeVoidConsumed.itemIndex, CharacterMasterNotificationQueue.TransformationType.Default); } if (GetBody().HasBuff(DLC2Content.Buffs.ExtraLifeBuff)) { GetBody().RemoveBuff(DLC2Content.Buffs.ExtraLifeBuff); } bool flag = false; if ((bool)GetBody().equipmentSlot && GetBody().equipmentSlot.equipmentIndex == DLC2Content.Equipment.HealAndRevive.equipmentIndex) { flag = true; } if (flag) { CharacterMasterNotificationQueue.SendTransformNotification(this, inventory.currentEquipmentIndex, DLC2Content.Equipment.HealAndReviveConsumed.equipmentIndex, CharacterMasterNotificationQueue.TransformationType.Default); inventory.SetEquipmentIndex(DLC2Content.Equipment.HealAndReviveConsumed.equipmentIndex); } CancelInvoke("RespawnExtraLife"); CancelInvoke("PlayExtraLifeSFX"); CancelInvoke("RespawnExtraLifeVoid"); CancelInvoke("PlayExtraLifeVoidSFX"); CancelInvoke("RespawnExtraLifeShrine"); CharacterBody body = GetBody(); if ((bool)body) { body.healthComponent.Suicide(killerOverride, inflictorOverride, damageTypeOverride); } } private void PlayExtraLifeSFX() { GameObject gameObject = bodyInstanceObject; if ((bool)gameObject) { Util.PlaySound("Play_item_proc_extraLife", gameObject); } } private void PlayExtraLifeVoidSFX() { GameObject gameObject = bodyInstanceObject; if ((bool)gameObject) { Util.PlaySound("Play_item_void_extraLife", gameObject); } } public void RespawnExtraLife() { inventory.GiveItem(RoR2Content.Items.ExtraLifeConsumed); CharacterMasterNotificationQueue.SendTransformNotification(this, RoR2Content.Items.ExtraLife.itemIndex, RoR2Content.Items.ExtraLifeConsumed.itemIndex, CharacterMasterNotificationQueue.TransformationType.Default); Vector3 vector = deathFootPosition; if (killedByUnsafeArea) { vector = TeleportHelper.FindSafeTeleportDestination(deathFootPosition, bodyPrefab.GetComponent(), RoR2Application.rng) ?? deathFootPosition; } Respawn(vector, Quaternion.Euler(0f, UnityEngine.Random.Range(0f, 360f), 0f), wasRevivedMidStage: true); GetBody().AddTimedBuff(RoR2Content.Buffs.Immune, 3f); if (NetworkServer.active) { inventory.SetEquipmentDisabled(_active: false); } GameObject gameObject = LegacyResourcesAPI.Load("Prefabs/Effects/HippoRezEffect"); if ((bool)bodyInstanceObject) { EntityStateMachine[] components = bodyInstanceObject.GetComponents(); foreach (EntityStateMachine obj in components) { obj.initialStateType = obj.mainStateType; } if ((bool)gameObject) { EffectManager.SpawnEffect(gameObject, new EffectData { origin = vector, rotation = bodyInstanceObject.transform.rotation }, transmit: true); } } } public void RespawnExtraLifeVoid() { inventory.GiveItem(DLC1Content.Items.ExtraLifeVoidConsumed); CharacterMasterNotificationQueue.SendTransformNotification(this, DLC1Content.Items.ExtraLifeVoid.itemIndex, DLC1Content.Items.ExtraLifeVoidConsumed.itemIndex, CharacterMasterNotificationQueue.TransformationType.Default); Vector3 vector = deathFootPosition; if (killedByUnsafeArea) { vector = TeleportHelper.FindSafeTeleportDestination(deathFootPosition, bodyPrefab.GetComponent(), RoR2Application.rng) ?? deathFootPosition; } Respawn(vector, Quaternion.Euler(0f, UnityEngine.Random.Range(0f, 360f), 0f), wasRevivedMidStage: true); GetBody().AddTimedBuff(RoR2Content.Buffs.Immune, 3f); if (NetworkServer.active) { inventory.SetEquipmentDisabled(_active: false); } if ((bool)bodyInstanceObject) { EntityStateMachine[] components = bodyInstanceObject.GetComponents(); foreach (EntityStateMachine obj in components) { obj.initialStateType = obj.mainStateType; } if ((bool)ExtraLifeVoidManager.rezEffectPrefab) { EffectManager.SpawnEffect(ExtraLifeVoidManager.rezEffectPrefab, new EffectData { origin = vector, rotation = bodyInstanceObject.transform.rotation }, transmit: true); } } foreach (ContagiousItemManager.TransformationInfo transformationInfo in ContagiousItemManager.transformationInfos) { ContagiousItemManager.TryForceReplacement(inventory, transformationInfo.originalItem); } } public void RespawnExtraLifeShrine() { Vector3 vector = deathFootPosition; if (killedByUnsafeArea) { vector = TeleportHelper.FindSafeTeleportDestination(deathFootPosition, bodyPrefab.GetComponent(), RoR2Application.rng) ?? deathFootPosition; } Respawn(vector, Quaternion.Euler(0f, UnityEngine.Random.Range(0f, 360f), 0f), wasRevivedMidStage: true); GetBody().AddTimedBuff(RoR2Content.Buffs.Immune, 3f); GameObject gameObject = LegacyResourcesAPI.Load("Prefabs/Effects/fxHealAndReviveGold"); if ((bool)bodyInstanceObject) { EntityStateMachine[] components = bodyInstanceObject.GetComponents(); foreach (EntityStateMachine obj in components) { obj.initialStateType = obj.mainStateType; } if ((bool)gameObject) { EffectManager.SpawnEffect(gameObject, new EffectData { origin = vector, rotation = bodyInstanceObject.transform.rotation }, transmit: true); Util.PlaySound("Play_item_use_healAndRevive_activate", base.gameObject); } } } public void RespawnExtraLifeHealAndRevive() { Vector3 vector = deathFootPosition; if (killedByUnsafeArea) { vector = TeleportHelper.FindSafeTeleportDestination(deathFootPosition, bodyPrefab.GetComponent(), RoR2Application.rng) ?? deathFootPosition; } Respawn(vector, Quaternion.Euler(0f, UnityEngine.Random.Range(0f, 360f), 0f), wasRevivedMidStage: true); GetBody().AddTimedBuff(RoR2Content.Buffs.Immune, 3f); GameObject gameObject = LegacyResourcesAPI.Load("Prefabs/Effects/fxHealAndReviveGold"); if ((bool)bodyInstanceObject) { EntityStateMachine[] components = bodyInstanceObject.GetComponents(); foreach (EntityStateMachine obj in components) { obj.initialStateType = obj.mainStateType; } if ((bool)gameObject) { EffectManager.SpawnEffect(gameObject, new EffectData { origin = vector, rotation = bodyInstanceObject.transform.rotation }, transmit: true); Util.PlaySound("Play_item_use_healAndRevive_activate", base.gameObject); } } } public void OnBodyDamaged(DamageReport damageReport) { BaseAI[] array = aiComponents; for (int i = 0; i < array.Length; i++) { array[i].OnBodyDamaged(damageReport); } if ((bool)playerCharacterMasterController) { HandleOnPlayerBodyDamaged(); CallRpcOnPlayerBodyDamaged(); } } [ClientRpc] private void RpcOnPlayerBodyDamaged() { HandleOnPlayerBodyDamaged(); } private void HandleOnPlayerBodyDamaged() { this.onPlayerBodyDamaged?.Invoke(playerCharacterMasterController); } public void OnBodyDestroyed(CharacterBody characterBody) { if ((object)characterBody != GetBody()) { return; } if (NetworkServer.active) { BaseAI[] array = aiComponents; for (int i = 0; i < array.Length; i++) { array[i].OnBodyDestroyed(characterBody); } PauseLifeStopwatch(); } this.onBodyDestroyed?.Invoke(characterBody); } [Server] private void StartLifeStopwatch() { if (!NetworkServer.active) { Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterMaster::StartLifeStopwatch()' called on client"); } else if (!(internalSurvivalTime > 0f)) { internalSurvivalTime = Run.instance.GetRunStopwatch() - currentLifeStopwatch; } } [Server] private void PauseLifeStopwatch() { if (!NetworkServer.active) { Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterMaster::PauseLifeStopwatch()' called on client"); } else if (!(internalSurvivalTime <= 0f)) { internalSurvivalTime = 0f - currentLifeStopwatch; } } [Server] private void ResetLifeStopwatch() { if (!NetworkServer.active) { Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterMaster::ResetLifeStopwatch()' called on client"); } else { internalSurvivalTime = 0f; } } [Server] public BodyIndex GetKillerBodyIndex() { if (!NetworkServer.active) { Debug.LogWarning("[Server] function 'RoR2.BodyIndex RoR2.CharacterMaster::GetKillerBodyIndex()' called on client"); return default(BodyIndex); } return killerBodyIndex; } [InitDuringStartup] private static void Init() { GlobalEventManager.onCharacterDeathGlobal += delegate(DamageReport damageReport) { CharacterMaster victimMaster = damageReport.victimMaster; if ((bool)victimMaster) { victimMaster.killerBodyIndex = BodyCatalog.FindBodyIndex(damageReport.damageInfo.attacker); victimMaster.killedByUnsafeArea = (bool)damageReport.damageInfo.inflictor && (bool)damageReport.damageInfo.inflictor.GetComponent(); } }; Stage.onServerStageBegin += delegate { foreach (CharacterMaster instances in instancesList) { instances.preventRespawnUntilNextStageServer = false; } }; CommonAssets.Resolve(); } [Command] public void CmdRespawn(string bodyName) { if (preventRespawnUntilNextStageServer) { return; } if (!string.IsNullOrEmpty(bodyName)) { bodyPrefab = BodyCatalog.FindBodyPrefab(bodyName); if (!bodyPrefab) { Debug.LogError("CmdRespawn failed to find bodyPrefab for name '" + bodyName + "'."); } } if ((bool)Stage.instance) { Stage.instance.RespawnCharacter(this); } } [Server] public void TransformBody(string bodyName) { if (!NetworkServer.active) { Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterMaster::TransformBody(System.String)' called on client"); } else if (!string.IsNullOrEmpty(bodyName)) { bodyPrefab = BodyCatalog.FindBodyPrefab(bodyName); if (bodyPrefab != null) { Transform component = bodyInstanceObject.GetComponent(); Vector3 position = component.position; Quaternion rotation = component.rotation; DestroyBody(); CharacterBody component2 = bodyPrefab.GetComponent(); if ((bool)component2) { position = CalculateSafeGroundPosition(position, component2); SpawnBody(position, rotation).GetComponent()?.PrepareTransformation(); } else { Debug.LogErrorFormat("Trying to respawn as object {0} who has no Character Body!", bodyPrefab); } } else { Debug.LogError("Can't TransformBody because there's no prefab for body named '" + bodyName + "'"); } } else { Debug.LogError("Can't TransformBody with null or empty body name."); } } [Server] private void OnServerStageBegin(Stage stage) { if (!NetworkServer.active) { Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterMaster::OnServerStageBegin(RoR2.Stage)' called on client"); return; } TryCloverVoidUpgrades(); TryRegenerateScrap(); TrySaleStar(); } [ClientRpc] public void RpcSetSeekerRevive(SEEKER_REVIVE_STATUS s) { seekerUsedRevive = s; } public SEEKER_REVIVE_STATUS getSeekerUsedRevive() { return seekerUsedRevive; } private void TryRegenerateScrap() { int itemCount = inventory.GetItemCount(DLC1Content.Items.RegeneratingScrapConsumed); if (itemCount > 0) { inventory.RemoveItem(DLC1Content.Items.RegeneratingScrapConsumed, itemCount); inventory.GiveItem(DLC1Content.Items.RegeneratingScrap, itemCount); CharacterMasterNotificationQueue.SendTransformNotification(this, DLC1Content.Items.RegeneratingScrapConsumed.itemIndex, DLC1Content.Items.RegeneratingScrap.itemIndex, CharacterMasterNotificationQueue.TransformationType.RegeneratingScrapRegen); } } private void TrySaleStar() { int itemCount = inventory.GetItemCount(DLC2Content.Items.LowerPricedChestsConsumed); if (itemCount > 0) { inventory.RemoveItem(DLC2Content.Items.LowerPricedChestsConsumed, itemCount); inventory.GiveItem(DLC2Content.Items.LowerPricedChests, itemCount); CharacterMasterNotificationQueue.SendTransformNotification(this, DLC2Content.Items.LowerPricedChestsConsumed.itemIndex, DLC2Content.Items.LowerPricedChests.itemIndex, CharacterMasterNotificationQueue.TransformationType.SaleStarRegen); } } private void TryTeleportOnLowHealthRegen() { int itemCount = inventory.GetItemCount(DLC2Content.Items.TeleportOnLowHealthConsumed); if (itemCount > 0) { inventory.RemoveItem(DLC2Content.Items.TeleportOnLowHealthConsumed, itemCount); inventory.GiveItem(DLC2Content.Items.TeleportOnLowHealth, itemCount); CharacterMasterNotificationQueue.SendTransformNotification(this, DLC2Content.Items.TeleportOnLowHealthConsumed.itemIndex, DLC2Content.Items.TeleportOnLowHealth.itemIndex, CharacterMasterNotificationQueue.TransformationType.TeleportOnLowHealthRegen); } } [Server] public void TrackDevotionItem(ItemIndex itemIndex, Interactor summoner, GameObject devotedInventoryRef, DevotionInventoryController devotionInventoryUpdater) { if (!NetworkServer.active) { Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterMaster::TrackDevotionItem(RoR2.ItemIndex,RoR2.Interactor,UnityEngine.GameObject,RoR2.DevotionInventoryController)' called on client"); return; } _ = summoner == null; devotionItem = itemIndex; summonerRef = summoner; devotionInventoryPrefab = devotedInventoryRef; isDevotedMinion = true; devotionInventoryUpdaterRef = devotionInventoryUpdater; } [Server] private void TryCloverVoidUpgrades() { if (!NetworkServer.active) { Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterMaster::TryCloverVoidUpgrades()' called on client"); return; } if (cloverVoidRng == null) { cloverVoidRng = new Xoroshiro128Plus(Run.instance.seed); } int itemCount = inventory.GetItemCount(DLC1Content.Items.CloverVoid); List list = new List(Run.instance.availableTier2DropList); List list2 = new List(Run.instance.availableTier3DropList); List list3 = new List(inventory.itemAcquisitionOrder); Util.ShuffleList(list3, cloverVoidRng); int num = itemCount * 3; int num2 = 0; int num3 = 0; while (num2 < num && num3 < list3.Count) { ItemDef startingItemDef = ItemCatalog.GetItemDef(list3[num3]); ItemDef itemDef = null; List list4 = null; switch (startingItemDef.tier) { case ItemTier.Tier1: list4 = list; break; case ItemTier.Tier2: list4 = list2; break; } if (list4 != null && list4.Count > 0) { Util.ShuffleList(list4, cloverVoidRng); list4.Sort(CompareTags); itemDef = ItemCatalog.GetItemDef(list4[0].itemIndex); } if (itemDef != null) { if (inventory.GetItemCount(itemDef.itemIndex) == 0) { list3.Add(itemDef.itemIndex); } num2++; int itemCount2 = inventory.GetItemCount(startingItemDef.itemIndex); inventory.RemoveItem(startingItemDef.itemIndex, itemCount2); inventory.GiveItem(itemDef.itemIndex, itemCount2); CharacterMasterNotificationQueue.SendTransformNotification(this, startingItemDef.itemIndex, itemDef.itemIndex, CharacterMasterNotificationQueue.TransformationType.CloverVoid); } num3++; int CompareTags(PickupIndex lhs, PickupIndex rhs) { int num4 = 0; int num5 = 0; ItemDef itemDef2 = ItemCatalog.GetItemDef(lhs.itemIndex); ItemDef itemDef3 = ItemCatalog.GetItemDef(rhs.itemIndex); if (startingItemDef.ContainsTag(ItemTag.Damage)) { if (itemDef2.ContainsTag(ItemTag.Damage)) { num4 = 1; } if (itemDef3.ContainsTag(ItemTag.Damage)) { num5 = 1; } } if (startingItemDef.ContainsTag(ItemTag.Healing)) { if (itemDef2.ContainsTag(ItemTag.Healing)) { num4 = 1; } if (itemDef3.ContainsTag(ItemTag.Healing)) { num5 = 1; } } if (startingItemDef.ContainsTag(ItemTag.Utility)) { if (itemDef2.ContainsTag(ItemTag.Utility)) { num4 = 1; } if (itemDef3.ContainsTag(ItemTag.Utility)) { num5 = 1; } } return num5 - num4; } } if (num2 > 0) { GameObject gameObject = bodyInstanceObject; if ((bool)gameObject) { Util.PlaySound("Play_item_proc_extraLife", gameObject); } } } private static GameObject PickRandomSurvivorBodyPrefab(Xoroshiro128Plus rng, NetworkUser networkUser, bool allowHidden) { SurvivorDef[] array = SurvivorCatalog.allSurvivorDefs.Where(SurvivorIsUnlockedAndAvailable).ToArray(); return rng.NextElementUniform(array).bodyPrefab; bool SurvivorIsUnlockedAndAvailable(SurvivorDef survivorDef) { if (allowHidden || !survivorDef.hidden) { if (!survivorDef.CheckRequiredExpansionEnabled(networkUser)) { return false; } UnlockableDef unlockableDef = survivorDef.unlockableDef; if ((object)unlockableDef != null) { return networkUser.unlockables.Contains(unlockableDef); } return true; } return false; } } [Server] public CharacterBody Respawn(Vector3 footPosition, Quaternion rotation, bool wasRevivedMidStage = false) { if (!NetworkServer.active) { Debug.LogWarning("[Server] function 'RoR2.CharacterBody RoR2.CharacterMaster::Respawn(UnityEngine.Vector3,UnityEngine.Quaternion,System.Boolean)' called on client"); return null; } if (!wasRevivedMidStage) { CallRpcSetSeekerRevive(SEEKER_REVIVE_STATUS.UNUSED); } else if (seekerUsedRevive == SEEKER_REVIVE_STATUS.USED) { CallRpcSetSeekerRevive(SEEKER_REVIVE_STATUS.BURNED); } DestroyBody(); if ((bool)playerCharacterMasterController && RunArtifactManager.instance.IsArtifactEnabled(RoR2Content.Artifacts.randomSurvivorOnRespawnArtifactDef)) { bodyPrefab = PickRandomSurvivorBodyPrefab(Run.instance.randomSurvivorOnRespawnRng, playerCharacterMasterController.networkUser, allowHidden: false); } if ((bool)bodyPrefab) { CharacterBody component = bodyPrefab.GetComponent(); if ((bool)component) { Vector3 position = footPosition; if (true) { position = CalculateSafeGroundPosition(footPosition, component); } return SpawnBody(position, rotation); } Debug.LogErrorFormat("Trying to respawn as object {0} who has no Character Body!", bodyPrefab); } else { Debug.LogErrorFormat("CharacterMaster.Respawn failed. {0} does not have a valid body prefab assigned.", base.gameObject.name); } return null; } private Vector3 CalculateSafeGroundPosition(Vector3 desiredFootPos, CharacterBody body) { if ((bool)body) { Vector3 result = desiredFootPos; RaycastHit hitInfo = default(RaycastHit); Ray ray = new Ray(desiredFootPos + Vector3.up * 2f, Vector3.down); float maxDistance = 4f; if (Physics.SphereCast(ray, body.radius, out hitInfo, maxDistance, LayerIndex.world.mask)) { result.y = ray.origin.y - hitInfo.distance; } float bodyPrefabFootOffset = Util.GetBodyPrefabFootOffset(bodyPrefab); result.y += bodyPrefabFootOffset; return result; } Debug.LogError("Can't calculate safe ground position if the CharacterBody is null"); return desiredFootPos; } private void SetUpGummyClone() { if (!NetworkServer.active || !inventory || inventory.GetItemCount(DLC1Content.Items.GummyCloneIdentifier.itemIndex) <= 0) { return; } if (!base.gameObject.GetComponent()) { base.gameObject.AddComponent().lifeTimer = 30f; } CharacterBody body = GetBody(); if ((bool)body) { CharacterDeathBehavior component = body.GetComponent(); if ((bool)component && component.deathState.stateType != typeof(GummyCloneDeathState)) { component.deathState = new SerializableEntityStateType(typeof(GummyCloneDeathState)); } body.portraitIcon = LegacyResourcesAPI.Load("Textures/BodyIcons/texGummyCloneBody"); } } public void SetMasterBodyDirtyBit() { SetDirtyBit(1u); } private void ToggleGod() { godMode = !godMode; UpdateBodyGodMode(); } private void UpdateBodyGodMode() { if ((bool)bodyInstanceObject) { HealthComponent component = bodyInstanceObject.GetComponent(); if ((bool)component) { component.godMode = godMode; } } } public override bool OnSerialize(NetworkWriter writer, bool initialState) { uint num = base.syncVarDirtyBits; if (initialState) { num = 127u; } bool num2 = (num & 1) != 0; bool flag = (num & 2) != 0; bool flag2 = (num & 0x40) != 0; bool flag3 = (num & 4) != 0; bool flag4 = (num & 8) != 0; bool flag5 = (num & 0x10) != 0; bool flag6 = (num & 0x20) != 0; writer.Write((byte)num); if (num2) { writer.Write(_bodyInstanceId); } if (flag) { writer.WritePackedUInt32(_money); } if (flag2) { writer.WritePackedUInt32(_voidCoins); } if (flag3) { writer.Write(_internalSurvivalTime); } if (flag4) { writer.Write(teamIndex); } if (flag5) { loadout.Serialize(writer); } if (flag6) { writer.WritePackedUInt32(miscFlags); } return num != 0; } public override void OnDeserialize(NetworkReader reader, bool initialState) { byte num = reader.ReadByte(); bool flag = (num & 1) != 0; bool flag2 = (num & 2) != 0; bool flag3 = (num & 0x40) != 0; bool flag4 = (num & 4) != 0; bool flag5 = (num & 8) != 0; bool flag6 = (num & 0x10) != 0; bool num2 = (num & 0x20) != 0; if (flag) { NetworkInstanceId value = reader.ReadNetworkId(); OnSyncBodyInstanceId(value); } if (flag2) { _money = reader.ReadPackedUInt32(); } if (flag3) { _voidCoins = reader.ReadPackedUInt32(); } if (flag4) { _internalSurvivalTime = reader.ReadSingle(); } if (flag5) { teamIndex = reader.ReadTeamIndex(); } if (flag6) { loadout.Deserialize(reader); } if (num2) { miscFlags = reader.ReadPackedUInt32(); } } static CharacterMaster() { instancesList = new List(); _readOnlyInstancesList = new ReadOnlyCollection(instancesList); kCmdCmdRespawn = 1097984413; NetworkBehaviour.RegisterCommandDelegate(typeof(CharacterMaster), kCmdCmdRespawn, InvokeCmdCmdRespawn); kRpcRpcOnPlayerBodyDamaged = -1070481806; NetworkBehaviour.RegisterRpcDelegate(typeof(CharacterMaster), kRpcRpcOnPlayerBodyDamaged, InvokeRpcRpcOnPlayerBodyDamaged); kRpcRpcSetSeekerRevive = 458435899; NetworkBehaviour.RegisterRpcDelegate(typeof(CharacterMaster), kRpcRpcSetSeekerRevive, InvokeRpcRpcSetSeekerRevive); NetworkCRC.RegisterBehaviour("CharacterMaster", 0); } private void UNetVersion() { } protected static void InvokeCmdCmdRespawn(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkServer.active) { Debug.LogError("Command CmdRespawn called on client."); } else { ((CharacterMaster)obj).CmdRespawn(reader.ReadString()); } } public void CallCmdRespawn(string bodyName) { if (!NetworkClient.active) { Debug.LogError("Command function CmdRespawn called on server."); return; } if (base.isServer) { CmdRespawn(bodyName); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)5); networkWriter.WritePackedUInt32((uint)kCmdCmdRespawn); networkWriter.Write(GetComponent().netId); networkWriter.Write(bodyName); SendCommandInternal(networkWriter, 0, "CmdRespawn"); } protected static void InvokeRpcRpcOnPlayerBodyDamaged(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkClient.active) { Debug.LogError("RPC RpcOnPlayerBodyDamaged called on server."); } else { ((CharacterMaster)obj).RpcOnPlayerBodyDamaged(); } } protected static void InvokeRpcRpcSetSeekerRevive(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkClient.active) { Debug.LogError("RPC RpcSetSeekerRevive called on server."); } else { ((CharacterMaster)obj).RpcSetSeekerRevive((SEEKER_REVIVE_STATUS)reader.ReadInt32()); } } public void CallRpcOnPlayerBodyDamaged() { if (!NetworkServer.active) { Debug.LogError("RPC Function RpcOnPlayerBodyDamaged called on client."); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)2); networkWriter.WritePackedUInt32((uint)kRpcRpcOnPlayerBodyDamaged); networkWriter.Write(GetComponent().netId); SendRPCInternal(networkWriter, 0, "RpcOnPlayerBodyDamaged"); } public void CallRpcSetSeekerRevive(SEEKER_REVIVE_STATUS s) { if (!NetworkServer.active) { Debug.LogError("RPC Function RpcSetSeekerRevive called on client."); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)2); networkWriter.WritePackedUInt32((uint)kRpcRpcSetSeekerRevive); networkWriter.Write(GetComponent().netId); networkWriter.Write((int)s); SendRPCInternal(networkWriter, 0, "RpcSetSeekerRevive"); } public override void PreStartClient() { } }