using System; using System.Collections.Generic; using System.Runtime.InteropServices; using EntityStates; using EntityStates.LightningStorm; using UnityEngine; using UnityEngine.Networking; using UnityEngine.Serialization; namespace RoR2; [RequireComponent(typeof(EntityStateMachine))] public class LightningStormController : NetworkBehaviour { [Serializable] public struct LightningStrikePoint { [Tooltip("Just for identifying points - not used in code")] public string description; [Tooltip("How far from the target's position should this point appear.")] public float distanceFromTargetPosition; [FormerlySerializedAs("speedMultiplier")] [Tooltip("How much the projected position should take into account the player's current velocity. 1.8 tends to work if you want it to go off right as they pass by it.")] [FormerlySerializedAs("distanceProjectionMultiplier")] public float velocityMultiplier; [Tooltip("Degrees to offset the prstrike position (0 = forward, 180 = behind, 90 = right, 270 / -90 = left, etc)")] public float directionOffset; [Tooltip("A randomized number of degrees (+/-) to adjust direction offset by.")] public float randomDegreeOffset; } public static LightningStrikePattern lightningPattern; [SyncVar(hook = "Client_HandleStormActiveChanged")] public bool stormActive; [SyncVar(hook = "Client_SetStormStrikePattern")] private int strikePatternID = -1; [SerializeField] private List strikePatterns = new List(); [SerializeField] [Space(20f)] private EntityStateMachine stormStateMachine; [SerializeField] public GameObject startPostProcessingObject; [SerializeField] public PostProcessDuration startPostProcessDuration; [SerializeField] public GameObject endPostProcessingObject; [SerializeField] public PostProcessDuration endPostProcessDuration; [SerializeField] [FormerlySerializedAs("serializedlightningPattern")] public LightningStrikePattern fallbackLightningPattern; private static int kCmdCmdSetStormActive; private static int kCmdCmdSetStrikePattern; public static LightningStormController instance { get; private set; } public bool NetworkstormActive { get { return stormActive; } [param: In] set { if (NetworkServer.localClientActive && !base.syncVarHookGuard) { base.syncVarHookGuard = true; Client_HandleStormActiveChanged(value); base.syncVarHookGuard = false; } SetSyncVar(value, ref stormActive, 1u); } } public int NetworkstrikePatternID { get { return strikePatternID; } [param: In] set { if (NetworkServer.localClientActive && !base.syncVarHookGuard) { base.syncVarHookGuard = true; Client_SetStormStrikePattern(value); base.syncVarHookGuard = false; } SetSyncVar(value, ref strikePatternID, 2u); } } public static void SetStormActive(bool b) { if (!(instance == null) && b != instance.stormActive) { if (!NetworkServer.active) { instance.CallCmdSetStormActive(b); } else { instance.ServerSetStormActive(b); } } } public static void SetStormStrikePattern(LightningStrikePattern _pattern) { if (!(instance == null) && !(_pattern == null) && !(_pattern == lightningPattern) && _pattern != null) { if (NetworkServer.active) { instance.ServerSetStrikePattern(_pattern.ID); } else { instance.CallCmdSetStrikePattern(_pattern.ID); } } } public static LightningStrikeInstance FireLightningBolt(Vector3 position, GameObject lightningPrefab, BlastAttack _blastInfo = null) { if (instance != null && !instance.stormActive) { return null; } GameObject gameObject = UnityEngine.Object.Instantiate(lightningPrefab); LightningStrikeInstance component = gameObject.GetComponent(); if (!component) { UnityEngine.Object.Destroy(gameObject); return null; } component.Initialize(position, _blastInfo); return component; } public static bool ShouldFireLighting() { if (instance == null) { return false; } return instance.stormActive; } public static Vector3 PredictPosition(Vector3 position, Vector3 forwardDirection, float maxSpeed, LightningStrikePoint strikePointData) { forwardDirection = Quaternion.AngleAxis(strikePointData.directionOffset, Vector3.up) * forwardDirection; if (strikePointData.randomDegreeOffset != 0f) { forwardDirection = Quaternion.AngleAxis(UnityEngine.Random.Range(0f - strikePointData.randomDegreeOffset, strikePointData.randomDegreeOffset), Vector3.up) * forwardDirection; } position += forwardDirection * maxSpeed * strikePointData.velocityMultiplier; position += forwardDirection * strikePointData.distanceFromTargetPosition; return position; } public static float GetMaxDistance(Vector3 forwardDirection, float maxSpeed, LightningStrikePoint strikePointData) { return (forwardDirection * maxSpeed * strikePointData.velocityMultiplier).magnitude + strikePointData.distanceFromTargetPosition; } [ContextMenu("Load Current Lightning Pattern Scrob into Memory")] public void LoadCurrentLightningPatternScrob() { SetStormStrikePattern(fallbackLightningPattern); } [Command] private void CmdSetStormActive(bool b) { ServerSetStormActive(b); } [Server] private void ServerSetStormActive(bool b) { if (!NetworkServer.active) { Debug.LogWarning("[Server] function 'System.Void RoR2.LightningStormController::ServerSetStormActive(System.Boolean)' called on client"); return; } if (b != stormActive) { if (b) { HandleStormBegins(); } else { HandleStormEnds(); } } NetworkstormActive = b; } private void Client_HandleStormActiveChanged(bool newValue) { if (NetworkServer.active) { return; } if (newValue != stormActive) { if (newValue) { HandleStormBegins(); } else { HandleStormEnds(); } } NetworkstormActive = newValue; } [Server] private void ServerSetStrikePattern(int patternID) { if (!NetworkServer.active) { Debug.LogWarning("[Server] function 'System.Void RoR2.LightningStormController::ServerSetStrikePattern(System.Int32)' called on client"); return; } if (patternID >= strikePatterns.Count || patternID < 0) { patternID = 0; } if (patternID != strikePatternID) { NetworkstrikePatternID = patternID; lightningPattern = strikePatterns[patternID]; } } [Command] private void CmdSetStrikePattern(int patternID) { ServerSetStrikePattern(patternID); } private void Client_SetStormStrikePattern(int newPatternIndex) { if (NetworkServer.active) { return; } if (newPatternIndex >= strikePatterns.Count || newPatternIndex < 0) { newPatternIndex = 0; if (strikePatterns.Count < 1) { return; } } lightningPattern = strikePatterns[newPatternIndex]; NetworkstrikePatternID = newPatternIndex; } private void Awake() { if (strikePatterns.Count >= 1) { for (int i = 0; i < strikePatterns.Count; i++) { strikePatterns[i].ID = i; } int num = ((fallbackLightningPattern != null) ? fallbackLightningPattern.ID : 0); if (NetworkServer.active) { ServerSetStrikePattern(num); } else { lightningPattern = strikePatterns[num]; } } } private void OnEnable() { instance = SingletonHelper.Assign(instance, this); if (stormActive) { HandleStormBegins(); } } private void OnDisable() { instance = SingletonHelper.Unassign(instance, this); HandleStormEnds(); } private void HandleStormBegins() { if (!(lightningPattern == null)) { SetStormStrikePattern(fallbackLightningPattern); stormStateMachine.SetNextState(new LightningStormState()); } } private void HandleStormEnds() { stormStateMachine.SetNextState(new Idle()); } private void UNetVersion() { } protected static void InvokeCmdCmdSetStormActive(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkServer.active) { Debug.LogError("Command CmdSetStormActive called on client."); } else { ((LightningStormController)obj).CmdSetStormActive(reader.ReadBoolean()); } } protected static void InvokeCmdCmdSetStrikePattern(NetworkBehaviour obj, NetworkReader reader) { if (!NetworkServer.active) { Debug.LogError("Command CmdSetStrikePattern called on client."); } else { ((LightningStormController)obj).CmdSetStrikePattern((int)reader.ReadPackedUInt32()); } } public void CallCmdSetStormActive(bool b) { if (!NetworkClient.active) { Debug.LogError("Command function CmdSetStormActive called on server."); return; } if (base.isServer) { CmdSetStormActive(b); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)5); networkWriter.WritePackedUInt32((uint)kCmdCmdSetStormActive); networkWriter.Write(GetComponent().netId); networkWriter.Write(b); SendCommandInternal(networkWriter, 0, "CmdSetStormActive"); } public void CallCmdSetStrikePattern(int patternID) { if (!NetworkClient.active) { Debug.LogError("Command function CmdSetStrikePattern called on server."); return; } if (base.isServer) { CmdSetStrikePattern(patternID); return; } NetworkWriter networkWriter = new NetworkWriter(); networkWriter.Write((short)0); networkWriter.Write((short)5); networkWriter.WritePackedUInt32((uint)kCmdCmdSetStrikePattern); networkWriter.Write(GetComponent().netId); networkWriter.WritePackedUInt32((uint)patternID); SendCommandInternal(networkWriter, 0, "CmdSetStrikePattern"); } static LightningStormController() { kCmdCmdSetStormActive = 753869832; NetworkBehaviour.RegisterCommandDelegate(typeof(LightningStormController), kCmdCmdSetStormActive, InvokeCmdCmdSetStormActive); kCmdCmdSetStrikePattern = 1007190007; NetworkBehaviour.RegisterCommandDelegate(typeof(LightningStormController), kCmdCmdSetStrikePattern, InvokeCmdCmdSetStrikePattern); NetworkCRC.RegisterBehaviour("LightningStormController", 0); } public override bool OnSerialize(NetworkWriter writer, bool forceAll) { if (forceAll) { writer.Write(stormActive); writer.WritePackedUInt32((uint)strikePatternID); return true; } bool flag = false; if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.Write(stormActive); } if ((base.syncVarDirtyBits & 2u) != 0) { if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); flag = true; } writer.WritePackedUInt32((uint)strikePatternID); } if (!flag) { writer.WritePackedUInt32(base.syncVarDirtyBits); } return flag; } public override void OnDeserialize(NetworkReader reader, bool initialState) { if (initialState) { stormActive = reader.ReadBoolean(); strikePatternID = (int)reader.ReadPackedUInt32(); return; } int num = (int)reader.ReadPackedUInt32(); if (((uint)num & (true ? 1u : 0u)) != 0) { Client_HandleStormActiveChanged(reader.ReadBoolean()); } if (((uint)num & 2u) != 0) { Client_SetStormStrikePattern((int)reader.ReadPackedUInt32()); } } public override void PreStartClient() { } }