using System; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using EntityStates; using EntityStates.Barrel; using RoR2.Networking; using Unity; using UnityEngine; using UnityEngine.Events; using UnityEngine.Networking; namespace RoR2; public class ChestBehavior : NetworkBehaviour, IChestBehavior { public PickupDropTable dropTable; public Transform dropTransform; public float dropUpVelocityStrength = 20f; public float dropForwardVelocityStrength = 2f; public int minDropCount = 1; public int maxDropCount = 1; public SerializableEntityStateType openState = new SerializableEntityStateType(typeof(Opening)); public SerializableEntityStateType closingState = new SerializableEntityStateType(typeof(Closing)); [Tooltip("Deprecated. Use DropTable instead.")] [Header("Deprecated")] public float tier1Chance = 0.8f; [Tooltip("Deprecated. Use DropTable instead.")] public float tier2Chance = 0.2f; [Tooltip("Deprecated. Use DropTable instead.")] public float tier3Chance = 0.01f; [Tooltip("Deprecated. Use DropTable instead.")] public float lunarChance; [Tooltip("Deprecated. Use DropTable instead.")] public ItemTag requiredItemTag; [Tooltip("Deprecated. Use DropTable instead.")] public float lunarCoinChance; [Tooltip("Deprecated. Use DropTable instead.")] public UnityEvent dropRoller; private Xoroshiro128Plus rng; public int dropCount; [SyncVar] public bool isCommandChest; [SyncVar] private bool isChestOpened; [HideInInspector] public PickupPickerController ppc; private static int kRpcRpcResetChests; private static int kRpcRpcSetDelusionPickupIndex; public PickupIndex dropPickup { get; private set; } = PickupIndex.none; public bool NetworkisCommandChest { get { return isCommandChest; } [param: In] set { SetSyncVar(value, ref isCommandChest, 1u); } } public bool NetworkisChestOpened { get { return isChestOpened; } [param: In] set { SetSyncVar(value, ref isChestOpened, 2u); } } public override int GetNetworkChannel() { return QosChannelIndex.defaultReliable.intVal; } [Server] public void Roll() { if (!NetworkServer.active) { Debug.LogWarning("[Server] function 'System.Void RoR2.ChestBehavior::Roll()' called on client"); } else if ((bool)dropTable) { dropPickup = dropTable.GenerateDrop(rng); } else { dropRoller?.Invoke(); } } public PickupIndex GetRandomPickupIndex() { return dropTable.GenerateDrop(rng); } [Server] private void PickFromList(List dropList) { if (!NetworkServer.active) { Debug.LogWarning("[Server] function 'System.Void RoR2.ChestBehavior::PickFromList(System.Collections.Generic.List`1)' called on client"); return; } dropPickup = PickupIndex.none; if (dropList != null && dropList.Count > 0) { dropPickup = rng.NextElementUniform(dropList); } } [Server] [Obsolete("Just use a drop table")] public void RollItem() { if (!NetworkServer.active) { Debug.LogWarning("[Server] function 'System.Void RoR2.ChestBehavior::RollItem()' called on client"); return; } WeightedSelection> selector = new WeightedSelection>(); List sourceDropList2 = new List { PickupCatalog.FindPickupIndex(RoR2Content.MiscPickups.LunarCoin.miscPickupIndex) }; Add(Run.instance.availableTier1DropList, tier1Chance); Add(Run.instance.availableTier2DropList, tier2Chance); Add(Run.instance.availableTier3DropList, tier3Chance); Add(Run.instance.availableLunarCombinedDropList, lunarChance); Add(sourceDropList2, lunarCoinChance); List dropList = selector.Evaluate(rng.nextNormalizedFloat); PickFromList(dropList); void Add(List sourceDropList, float chance) { if (!(chance <= 0f)) { selector.AddChoice(sourceDropList.Where(PassesFilter).ToList(), chance); } } bool PassesFilter(PickupIndex pickupIndex) { if (requiredItemTag == ItemTag.Any) { return true; } PickupDef pickupDef = PickupCatalog.GetPickupDef(pickupIndex); if (pickupDef.itemIndex != ItemIndex.None) { return ItemCatalog.GetItemDef(pickupDef.itemIndex).ContainsTag(requiredItemTag); } return true; } } [Server] [Obsolete("Just use a drop table")] public void RollEquipment() { if (!NetworkServer.active) { Debug.LogWarning("[Server] function 'System.Void RoR2.ChestBehavior::RollEquipment()' called on client"); } else { PickFromList(Run.instance.availableEquipmentDropList); } } private void Awake() { if (dropTransform == null) { dropTransform = base.transform; } } private void Start() { if (NetworkServer.active) { rng = new Xoroshiro128Plus(Run.instance.treasureRng.nextUlong); dropCount = rng.RangeInt(minDropCount, Math.Max(minDropCount + 1, maxDropCount + 1)); Roll(); } } public void OnEnable() { InstanceTracker.Add(this); } public void OnDisable() { InstanceTracker.Remove(this); } [Server] public void Open() { if (!NetworkServer.active) { Debug.LogWarning("[Server] function 'System.Void RoR2.ChestBehavior::Open()' called on client"); return; } EntityStateMachine component = GetComponent(); if ((bool)component) { component.SetNextState(EntityStateCatalog.InstantiateState(ref openState)); } } [ClientRpc] public void RpcResetChests() { if (TryGetComponent(out var component) && isChestOpened) { component.ResetChestForDelusion(); } } [ClientRpc] public void RpcSetDelusionPickupIndex(PickupIndex pickupIndex) { if (TryGetComponent(out var component)) { component.DelusionPickupIndex = pickupIndex; } } [Server] public void ItemDrop() { DelusionChestController component; if (!NetworkServer.active) { Debug.LogWarning("[Server] function 'System.Void RoR2.ChestBehavior::ItemDrop()' called on client"); } else if (DelusionChestController.isDelusionEnable && TryGetComponent(out component) && component.SelectedPickupIndex != PickupIndex.none) { if (component.IsSelectedCorrectly()) { Util.PlaySound("Play_ui_artifact_delusion_success", base.gameObject); DelusionItemDrop(); } else { Util.PlaySound("Play_ui_artifact_delusion_failure", base.gameObject); component.RemoveDelusionChoice(); } } else { BaseItemDrop(); } } private void DelusionItemDrop(DelusionChestController delusionChestController) { if (delusionChestController.isDelusionSelected) { if (delusionChestController.IsSelectedCorrectly()) { Vector3 velocity = Vector3.up * dropUpVelocityStrength + dropTransform.forward * dropForwardVelocityStrength; GenericPickupController.CreatePickupInfo createPickupInfo = default(GenericPickupController.CreatePickupInfo); createPickupInfo.pickupIndex = delusionChestController.DelusionPickupIndex; createPickupInfo.position = dropTransform.position + Vector3.up * 1.5f; createPickupInfo.chest = this; createPickupInfo.artifactFlag = GenericPickupController.PickupArtifactFlag.DELUSION; GenericPickupController.CreatePickupInfo pickupInfo = createPickupInfo; PickupDropletController.CreatePickupDroplet(pickupInfo, pickupInfo.position, velocity); Util.PlaySound("Play_ui_artifact_delusion_success", base.gameObject); } else { Util.PlaySound("Play_ui_artifact_delusion_failure", base.gameObject); delusionChestController.RemoveDelusionChoice(); } } } private void DelusionItemDrop() { if (TryGetComponent(out var component) && component.SelectedPickupIndex == component.DelusionPickupIndex) { Vector3 velocity = Vector3.up * dropUpVelocityStrength + dropTransform.forward * dropForwardVelocityStrength; PickupDropletController.CreatePickupDroplet(component.DelusionPickupIndex, dropTransform.position + Vector3.up * 1.5f, velocity); } } private void BaseItemDrop() { if (!(dropPickup == PickupIndex.none) && dropCount >= 1) { float angle = 360f / (float)dropCount; Vector3 vector = Vector3.up * dropUpVelocityStrength + dropTransform.forward * dropForwardVelocityStrength; Quaternion quaternion = Quaternion.AngleAxis(angle, Vector3.up); GetComponent(); for (int i = 0; i < dropCount; i++) { GenericPickupController.CreatePickupInfo createPickupInfo = default(GenericPickupController.CreatePickupInfo); createPickupInfo.pickupIndex = dropPickup; createPickupInfo.position = dropTransform.position + Vector3.up * 1.5f; createPickupInfo.chest = this; createPickupInfo.artifactFlag = (isCommandChest ? GenericPickupController.PickupArtifactFlag.COMMAND : GenericPickupController.PickupArtifactFlag.NONE); GenericPickupController.CreatePickupInfo pickupInfo = createPickupInfo; PickupDropletController.CreatePickupDroplet(pickupInfo, pickupInfo.position, vector); vector = quaternion * vector; Roll(); } dropPickup = PickupIndex.none; NetworkisChestOpened = true; } } public bool HasRolledPickup(PickupIndex pickupIndex) { return dropPickup == pickupIndex; } private void UNetVersion() { } protected static void InvokeRpcRpcResetChests(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkClient.active) { Debug.LogError("RPC RpcResetChests called on server."); } else { ((ChestBehavior)obj).RpcResetChests(); } } protected static void InvokeRpcRpcSetDelusionPickupIndex(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkClient.active) { Debug.LogError("RPC RpcSetDelusionPickupIndex called on server."); } else { ((ChestBehavior)obj).RpcSetDelusionPickupIndex(GeneratedNetworkCode._ReadPickupIndex_None(reader)); } } public void CallRpcResetChests() { if (!NetworkServer.active) { Debug.LogError("RPC Function RpcResetChests called on client."); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)2); networkWriter.WritePackedUInt32((uint)kRpcRpcResetChests); networkWriter.Write(GetComponent().netId); SendRPCInternal(networkWriter, 0, "RpcResetChests"); } public void CallRpcSetDelusionPickupIndex(PickupIndex pickupIndex) { if (!NetworkServer.active) { Debug.LogError("RPC Function RpcSetDelusionPickupIndex called on client."); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)2); networkWriter.WritePackedUInt32((uint)kRpcRpcSetDelusionPickupIndex); networkWriter.Write(GetComponent().netId); GeneratedNetworkCode._WritePickupIndex_None(networkWriter, pickupIndex); SendRPCInternal(networkWriter, 0, "RpcSetDelusionPickupIndex"); } static ChestBehavior() { kRpcRpcResetChests = -115962472; NetworkBehaviour.RegisterRpcDelegate(typeof(ChestBehavior), kRpcRpcResetChests, InvokeRpcRpcResetChests); kRpcRpcSetDelusionPickupIndex = -2130336578; NetworkBehaviour.RegisterRpcDelegate(typeof(ChestBehavior), kRpcRpcSetDelusionPickupIndex, InvokeRpcRpcSetDelusionPickupIndex); NetworkCRC.RegisterBehaviour("ChestBehavior", 0); } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { if (forceAll) { writer.Write(isCommandChest); writer.Write(isChestOpened); return true; } bool flag = false; if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.Write(isCommandChest); } if ((base.syncVarDirtyBits & 2u) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.Write(isChestOpened); } if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); } return flag; } public override void OnDeserialize(NetworkReader reader, bool initialState) { if (initialState) { isCommandChest = reader.ReadBoolean(); isChestOpened = reader.ReadBoolean(); return; } int num = (int)reader.ReadPackedUInt32(); if (((uint)num & (true ? 1u : 0u)) != 0) { isCommandChest = reader.ReadBoolean(); } if (((uint)num & 2u) != 0) { isChestOpened = reader.ReadBoolean(); } } public override void PreStartClient() { } }