r2mods/ilspy_dump/ror2_csproj/RoR2.Projectile/ProjectileController.cs

413 lines
10 KiB
C#

using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using RoR2.Audio;
using UnityEngine;
using UnityEngine.Networking;
namespace RoR2.Projectile;
[RequireComponent(typeof(TeamFilter))]
public class ProjectileController : NetworkBehaviour
{
[HideInInspector]
[Tooltip("This is assigned to the prefab automatically by ProjectileCatalog at runtime. Do not set this value manually.")]
public int catalogIndex = -1;
[Tooltip("The prefab to instantiate as the visual representation of this projectile. The prefab must have a ProjectileGhostController attached.")]
public GameObject ghostPrefab;
[Tooltip("The transform for the ghost to follow. If null, the transform of this object will be used instead.")]
public Transform ghostTransformAnchor;
[Tooltip("The sound to play on Start(). Use this field to ensure the sound only plays once when prediction creates two instances.")]
public string startSound;
[Tooltip("Prevents this projectile from being deleted by gameplay events, like Captain's defense matrix.")]
public bool cannotBeDeleted;
[Tooltip("Check this if you want collision events to only run on the local authority (which may be a client instead of the host). 99% of projectiles should have this set to false.")]
public bool authorityHandlesCollisionEvents;
[SerializeField]
[Tooltip("The sound loop to play while this object exists. Use this field to ensure the sound only plays once when prediction creates two instances.")]
private LoopSoundDef flightSoundLoop;
protected Rigidbody rigidbody;
public bool canImpactOnTrigger;
public bool allowPrediction = true;
[NonSerialized]
[SyncVar]
public ushort predictionId;
[SyncVar]
[HideInInspector]
public GameObject owner;
[HideInInspector]
public bool localCollisionHappened;
public float procCoefficient = 1f;
private Collider[] myColliders;
protected EffectManagerHelper _efhGhost;
public bool CheckChildrenForCollidersAndIncludeDisabled;
private NetworkInstanceId ___ownerNetId;
public TeamFilter teamFilter { get; private set; }
public ProjectileGhostController ghost { get; set; }
public bool isPrediction { get; set; }
public bool shouldPlaySounds { get; set; }
public ProcChainMask procChainMask { get; set; }
public NetworkConnection clientAuthorityOwner { get; private set; }
public ushort NetworkpredictionId
{
get
{
return predictionId;
}
[param: In]
set
{
SetSyncVar(value, ref predictionId, 1u);
}
}
public GameObject Networkowner
{
get
{
return owner;
}
[param: In]
set
{
SetSyncVarGameObject(value, ref owner, 2u, ref ___ownerNetId);
}
}
public event Action<ProjectileController> onInitialized;
private void Awake()
{
rigidbody = GetComponent<Rigidbody>();
teamFilter = GetComponent<TeamFilter>();
if (CheckChildrenForCollidersAndIncludeDisabled)
{
myColliders = GetComponentsInChildren<Collider>(includeInactive: true);
}
else
{
myColliders = GetComponents<Collider>();
}
for (int i = 0; i < myColliders.Length; i++)
{
myColliders[i].enabled = false;
}
}
private void Start()
{
for (int i = 0; i < myColliders.Length; i++)
{
myColliders[i].enabled = true;
}
IgnoreCollisionsWithOwner(shouldIgnore: true);
if (!isPrediction && !NetworkServer.active)
{
ProjectileManager.instance.OnClientProjectileReceived(this);
}
GameObject gameObject = ProjectileGhostReplacementManager.FindProjectileGhostPrefab(this);
shouldPlaySounds = false;
if (isPrediction || !allowPrediction || !base.hasAuthority)
{
shouldPlaySounds = true;
if ((bool)gameObject)
{
Transform transform = base.transform;
if ((bool)ghostTransformAnchor)
{
transform = ghostTransformAnchor;
}
if (!EffectManager.ShouldUsePooledEffect(gameObject))
{
ghost = UnityEngine.Object.Instantiate(gameObject, transform.position, transform.rotation).GetComponent<ProjectileGhostController>();
}
else
{
_efhGhost = EffectManager.GetAndActivatePooledEffect(gameObject, transform.position, transform.rotation);
ghost = _efhGhost.gameObject.GetComponent<ProjectileGhostController>();
}
if (isPrediction)
{
ghost.predictionTransform = transform;
}
else
{
ghost.authorityTransform = transform;
}
ghost.enabled = true;
}
}
clientAuthorityOwner = GetComponent<NetworkIdentity>().clientAuthorityOwner;
if (shouldPlaySounds)
{
PointSoundManager.EmitSoundLocal((AkEventIdArg)startSound, base.transform.position);
if ((bool)flightSoundLoop)
{
Util.PlaySound(flightSoundLoop.startSoundName, base.gameObject);
}
}
}
private void OnDestroy()
{
if (NetworkServer.active && ProjectileManager.instance != null)
{
ProjectileManager.instance.OnServerProjectileDestroyed(this);
}
if (shouldPlaySounds && (bool)flightSoundLoop)
{
Util.PlaySound(flightSoundLoop.stopSoundName, base.gameObject);
}
DisconnectFromGhost();
}
public void DisconnectFromGhost()
{
if (!ghost || (isPrediction && (bool)ghost.authorityTransform))
{
return;
}
RunGhostParentProjectileDestroyedMethod();
if (!EffectManager.UsePools)
{
UnityEngine.Object.Destroy(ghost.gameObject);
}
else
{
if (!isPrediction && _efhGhost == null)
{
_efhGhost = ghost.emh;
}
if (_efhGhost != null && _efhGhost.OwningPool != null)
{
if (!_efhGhost.HasDestroyOnTimer && !_efhGhost.HasAnimateShaderAlphas)
{
_efhGhost.OwningPool.ReturnObject(_efhGhost);
}
}
else
{
if (_efhGhost != null)
{
Debug.LogFormat("efhGhost has no owning pool {0} {1}", _efhGhost.gameObject.name, _efhGhost.gameObject.GetInstanceID());
}
UnityEngine.Object.Destroy(ghost.gameObject);
}
}
_efhGhost = null;
ghost = null;
}
public void RunGhostParentProjectileDestroyedMethod()
{
if ((bool)ghost)
{
ghost.OnParentProjectileDestroyed();
}
}
private void OnEnable()
{
InstanceTracker.Add(this);
IgnoreCollisionsWithOwner(shouldIgnore: true);
}
private void OnDisable()
{
InstanceTracker.Remove(this);
}
public void IgnoreCollisionsWithOwner(bool shouldIgnore)
{
if (!owner)
{
return;
}
ModelLocator component = owner.GetComponent<ModelLocator>();
if (!component)
{
return;
}
Transform modelTransform = component.modelTransform;
if (!modelTransform)
{
return;
}
HurtBoxGroup component2 = modelTransform.GetComponent<HurtBoxGroup>();
if (!component2)
{
return;
}
HurtBox[] hurtBoxes = component2.hurtBoxes;
for (int i = 0; i < hurtBoxes.Length; i++)
{
List<Collider> gameObjectComponents = GetComponentsCache<Collider>.GetGameObjectComponents(hurtBoxes[i].gameObject);
int j = 0;
for (int count = gameObjectComponents.Count; j < count; j++)
{
Collider collider = gameObjectComponents[j];
for (int k = 0; k < myColliders.Length; k++)
{
Collider collider2 = myColliders[k];
Physics.IgnoreCollision(collider, collider2, shouldIgnore);
}
}
GetComponentsCache<Collider>.ReturnBuffer(gameObjectComponents);
}
}
private static Vector3 EstimateContactPoint(ContactPoint[] contacts, Collider collider)
{
if (contacts.Length == 0)
{
return collider.transform.position;
}
return contacts[0].point;
}
private static Vector3 EstimateContactNormal(ContactPoint[] contacts)
{
if (contacts.Length == 0)
{
return Vector3.zero;
}
return contacts[0].normal;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool CanProcessCollisionEvents()
{
if ((authorityHandlesCollisionEvents || !NetworkServer.active) && (!authorityHandlesCollisionEvents || !Util.HasEffectiveAuthority(base.gameObject)))
{
return isPrediction;
}
return true;
}
public void OnCollisionEnter(Collision collision)
{
localCollisionHappened = true;
if (CanProcessCollisionEvents())
{
ContactPoint[] contacts = collision.contacts;
ProjectileImpactInfo projectileImpactInfo = default(ProjectileImpactInfo);
projectileImpactInfo.collider = collision.collider;
projectileImpactInfo.estimatedPointOfImpact = EstimateContactPoint(contacts, collision.collider);
projectileImpactInfo.estimatedImpactNormal = EstimateContactNormal(contacts);
ProjectileImpactInfo impactInfo = projectileImpactInfo;
IProjectileImpactBehavior[] components = GetComponents<IProjectileImpactBehavior>();
for (int i = 0; i < components.Length; i++)
{
components[i].OnProjectileImpact(impactInfo);
}
}
}
public void DispatchOnInitialized()
{
this.onInitialized?.Invoke(this);
}
private void OnValidate()
{
if (!Application.IsPlaying(this))
{
bool flag = GetComponent<NetworkIdentity>().localPlayerAuthority;
if (allowPrediction && !flag)
{
Debug.LogWarningFormat(base.gameObject, "ProjectileController: {0} allows predictions, so it should have localPlayerAuthority=true", base.gameObject);
}
}
}
private void UNetVersion()
{
}
public override bool OnSerialize(NetworkWriter writer, bool forceAll)
{
if (forceAll)
{
writer.WritePackedUInt32(predictionId);
writer.Write(owner);
return true;
}
bool flag = false;
if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
{
if (!flag)
{
writer.WritePackedUInt32(base.syncVarDirtyBits);
flag = true;
}
writer.WritePackedUInt32(predictionId);
}
if ((base.syncVarDirtyBits & 2u) != 0)
{
if (!flag)
{
writer.WritePackedUInt32(base.syncVarDirtyBits);
flag = true;
}
writer.Write(owner);
}
if (!flag)
{
writer.WritePackedUInt32(base.syncVarDirtyBits);
}
return flag;
}
public override void OnDeserialize(NetworkReader reader, bool initialState)
{
if (initialState)
{
predictionId = (ushort)reader.ReadPackedUInt32();
___ownerNetId = reader.ReadNetworkId();
return;
}
int num = (int)reader.ReadPackedUInt32();
if (((uint)num & (true ? 1u : 0u)) != 0)
{
predictionId = (ushort)reader.ReadPackedUInt32();
}
if (((uint)num & 2u) != 0)
{
owner = reader.ReadGameObject();
}
}
public override void PreStartClient()
{
if (!___ownerNetId.IsEmpty())
{
Networkowner = ClientScene.FindLocalObject(___ownerNetId);
}
}
}