diff --git a/QSB/AssetBundles/network b/QSB/AssetBundles/network index 533c2bcd..8618a11e 100644 Binary files a/QSB/AssetBundles/network and b/QSB/AssetBundles/network differ diff --git a/QSB/Player/RemotePlayerFluidDetector.cs b/QSB/Player/RemotePlayerFluidDetector.cs new file mode 100644 index 00000000..8f804dce --- /dev/null +++ b/QSB/Player/RemotePlayerFluidDetector.cs @@ -0,0 +1,178 @@ +using QSB.Utility; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +namespace QSB.Player; + +public class RemotePlayerFluidDetector : PriorityDetector +{ + private SplashEffect[] _splashEffects; + + [SerializeField] + private Transform _splashSpawnRoot; + + private FluidTypeData[] _fluidDataByType; + + protected RemotePlayerVelocity _velocity; + + public event SpawnSplashEvent OnSpawnSplashEvent; + public event FluidTypeEvent OnEnterFluidType; + public event FluidTypeEvent OnExitFluidType; + public event FluidEvent OnEnterFluid; + public event FluidEvent OnExitFluid; + + public delegate void SpawnSplashEvent(FluidVolume splashFluid); + public delegate void FluidTypeEvent(FluidVolume.Type fluidType); + public delegate void FluidEvent(FluidVolume volume); + + public override void Awake() + { + base.Awake(); + + _velocity = gameObject.GetComponentInParent(); + _fluidDataByType = new FluidTypeData[9]; + _splashSpawnRoot = _velocity.transform; + + _splashEffects = new SplashEffect[4] + { + new SplashEffect() + { + fluidType = FluidVolume.Type.WATER, + minImpactSpeed = 15, + triggerEvent = SplashEffect.TriggerEvent.OnEntry, + splashPrefab = Resources.Load("prefabs/particles/Prefab_OceanEntry_Player"), + ignoreSphereAligment = false + }, + new SplashEffect() + { + fluidType = FluidVolume.Type.CLOUD, + minImpactSpeed = 15, + triggerEvent = SplashEffect.TriggerEvent.OnEntry, + splashPrefab = Resources.Load("prefabs/particles/Prefab_CloudEntry_Player"), + ignoreSphereAligment = false + }, + new SplashEffect() + { + fluidType = FluidVolume.Type.CLOUD, + minImpactSpeed = 15, + triggerEvent = SplashEffect.TriggerEvent.OnExit, + splashPrefab = Resources.Load("prefabs/particles/Prefab_CloudExit_Player"), + ignoreSphereAligment = true + }, + new SplashEffect() + { + fluidType = FluidVolume.Type.SAND, + minImpactSpeed = 15, + triggerEvent = SplashEffect.TriggerEvent.OnEntryOrExit, + splashPrefab = Resources.Load("prefabs/particles/Prefab_HEA_Player_SandSplash"), + ignoreSphereAligment = false + } + }; + } + + public bool InFluidType(FluidVolume.Type fluidType) + { + return _fluidDataByType[(int)fluidType].count > 0; + } + + public override void OnVolumeActivated(PriorityVolume volume) + { + var fluidVolume = volume as FluidVolume; + var fluidType = fluidVolume.GetFluidType(); + var fluidDataByType = _fluidDataByType; + var type = fluidType; + fluidDataByType[(int)type].count = fluidDataByType[(int)type].count + 1; + OnEnterFluid?.Invoke(fluidVolume); + + if (_fluidDataByType[(int)fluidType].count == 1) + { + OnEnterFluidType_Internal(fluidVolume); + OnEnterFluidType?.Invoke(fluidType); + } + } + + public override void OnVolumeDeactivated(PriorityVolume volume) + { + var fluidVolume = volume as FluidVolume; + var fluidType = fluidVolume.GetFluidType(); + var fluidDataByType = _fluidDataByType; + var type = fluidType; + fluidDataByType[(int)type].count = fluidDataByType[(int)type].count - 1; + OnExitFluid?.Invoke(fluidVolume); + + if (_fluidDataByType[(int)fluidType].count == 0) + { + OnExitFluidType_Internal(fluidVolume); + OnExitFluidType?.Invoke(fluidType); + } + } + + protected virtual void OnEnterFluidType_Internal(FluidVolume fluid) + { + SpawnSplash(fluid, SplashEffect.TriggerEvent.OnEntry); + if (fluid is SphereOceanFluidVolume) + { + var component = GetComponent(); + var magnitude = (_velocity.Velocity - fluid._attachedBody.GetVelocity()).magnitude; + if (component != null && magnitude >= component.minSplashSpeed) + { + component.Splash(); + } + } + } + + protected virtual void OnExitFluidType_Internal(FluidVolume fluid) + { + SpawnSplash(fluid, SplashEffect.TriggerEvent.OnExit); + } + + private void SpawnSplash(FluidVolume fluid, SplashEffect.TriggerEvent triggerEvent) + { + if (CompareName(Name.Player) && PlayerState.IsRidingRaft(false) && fluid.GetFluidType() == FluidVolume.Type.WATER) + { + return; + } + + if (fluid.GetFluidType() == FluidVolume.Type.CLOUD && InFluidType(FluidVolume.Type.WATER)) + { + return; + } + + var impactVelocity = _velocity.Velocity - fluid._attachedBody.GetVelocity(); + var magnitude = impactVelocity.magnitude; + var num = -1; + for (var i = 0; i < _splashEffects.Length; i++) + { + if (_splashEffects[i].fluidType == fluid.GetFluidType() && magnitude > _splashEffects[i].minImpactSpeed && (triggerEvent & _splashEffects[i].triggerEvent) > (SplashEffect.TriggerEvent)0 && (num == -1 || _splashEffects[i].minImpactSpeed > _splashEffects[num].minImpactSpeed)) + { + num = i; + } + } + + if (num > -1) + { + var splashPrefab = _splashEffects[num].splashPrefab; + var toDirection = (_splashEffects[num].ignoreSphereAligment ? (-impactVelocity) : fluid.GetSplashAlignment(_splashSpawnRoot.position, impactVelocity)); + var rotation = Quaternion.FromToRotation(_splashSpawnRoot.up, toDirection) * _splashSpawnRoot.rotation; + var gameObject = Instantiate(splashPrefab, _splashSpawnRoot.position, rotation); + if (gameObject.GetComponent() != null) + { + Debug.LogError("SPLASHES SHOULD NO LONGER HAVE RIGIDBODIES!!!", gameObject); + gameObject.GetComponent().MakeKinematic(); + } + + gameObject.transform.parent = fluid.transform; + fluid.RegisterSplashTransform(gameObject.transform); + var component = gameObject.GetComponent(); + if (component != null) + { + component.PlaySplash(); + } + + OnSpawnSplashEvent?.Invoke(fluid); + } + } +}