1528 lines
44 KiB
C#
1528 lines
44 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Collections.ObjectModel;
|
|
using System.Diagnostics;
|
|
using System.Globalization;
|
|
using System.Linq;
|
|
using System.Runtime.CompilerServices;
|
|
using System.Text;
|
|
using System.Text.RegularExpressions;
|
|
using Facepunch.Steamworks;
|
|
using JetBrains.Annotations;
|
|
using Rewired;
|
|
using RoR2.Networking;
|
|
using RoR2.Projectile;
|
|
using UnityEngine;
|
|
using UnityEngine.Networking;
|
|
|
|
namespace RoR2;
|
|
|
|
public static class Util
|
|
{
|
|
private struct EasyTargetCandidate
|
|
{
|
|
public Transform transform;
|
|
|
|
public float score;
|
|
|
|
public float distance;
|
|
}
|
|
|
|
public const string attackSpeedRtpcName = "attackSpeed";
|
|
|
|
private static readonly string strBackslash = "\\";
|
|
|
|
private static readonly string strBackslashBackslash = strBackslash + strBackslash;
|
|
|
|
private static readonly string strQuote = "\"";
|
|
|
|
private static readonly string strBackslashQuote = strBackslash + strQuote;
|
|
|
|
private static readonly Regex backlashSearch = new Regex(strBackslashBackslash);
|
|
|
|
private static readonly Regex quoteSearch = new Regex(strQuote);
|
|
|
|
public static readonly DateTime dateZero = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
|
|
|
|
public static bool useCachedNetWriter = false;
|
|
|
|
public static bool breakInVerify = true;
|
|
|
|
public static bool logVerify = true;
|
|
|
|
public static bool cacheBulletHitHurtBox = true;
|
|
|
|
private static readonly StringBuilder sharedStringBuilder = new StringBuilder();
|
|
|
|
private static readonly Stack<string> sharedStringStack = new Stack<string>();
|
|
|
|
private static readonly string cloneString = "(Clone)";
|
|
|
|
public static void CleanseBody(CharacterBody characterBody, bool removeDebuffs, bool removeBuffs, bool removeCooldownBuffs, bool removeDots, bool removeStun, bool removeNearbyProjectiles)
|
|
{
|
|
if (removeDebuffs || removeBuffs || removeCooldownBuffs)
|
|
{
|
|
BuffIndex buffIndex = (BuffIndex)0;
|
|
for (BuffIndex buffCount = (BuffIndex)BuffCatalog.buffCount; buffIndex < buffCount; buffIndex++)
|
|
{
|
|
BuffDef buffDef = BuffCatalog.GetBuffDef(buffIndex);
|
|
if ((buffDef.isDebuff && removeDebuffs) || (buffDef.isCooldown && removeCooldownBuffs) || (!buffDef.isDebuff && !buffDef.isCooldown && removeBuffs))
|
|
{
|
|
characterBody.ClearTimedBuffs(buffIndex);
|
|
}
|
|
}
|
|
}
|
|
if (removeDots)
|
|
{
|
|
DotController.RemoveAllDots(characterBody.gameObject);
|
|
}
|
|
if (removeStun)
|
|
{
|
|
SetStateOnHurt component = characterBody.GetComponent<SetStateOnHurt>();
|
|
if ((bool)component)
|
|
{
|
|
component.Cleanse();
|
|
}
|
|
}
|
|
if (!removeNearbyProjectiles)
|
|
{
|
|
return;
|
|
}
|
|
float num = 6f * 6f;
|
|
TeamIndex teamIndex = characterBody.teamComponent.teamIndex;
|
|
List<ProjectileController> instancesList = InstanceTracker.GetInstancesList<ProjectileController>();
|
|
List<ProjectileController> list = new List<ProjectileController>();
|
|
int i = 0;
|
|
for (int count = instancesList.Count; i < count; i++)
|
|
{
|
|
ProjectileController projectileController = instancesList[i];
|
|
if (!projectileController.cannotBeDeleted && projectileController.teamFilter.teamIndex != teamIndex && (projectileController.transform.position - characterBody.corePosition).sqrMagnitude < num)
|
|
{
|
|
list.Add(projectileController);
|
|
}
|
|
}
|
|
int j = 0;
|
|
for (int count2 = list.Count; j < count2; j++)
|
|
{
|
|
ProjectileController projectileController2 = list[j];
|
|
if ((bool)projectileController2)
|
|
{
|
|
UnityEngine.Object.Destroy(projectileController2.gameObject);
|
|
}
|
|
}
|
|
}
|
|
|
|
public static WeightedSelection<DirectorCard> CreateReasonableDirectorCardSpawnList(float availableCredit, int maximumNumberToSpawnBeforeSkipping, int minimumToSpawn)
|
|
{
|
|
WeightedSelection<DirectorCard> monsterSelection = ClassicStageInfo.instance.monsterSelection;
|
|
WeightedSelection<DirectorCard> weightedSelection = new WeightedSelection<DirectorCard>();
|
|
for (int i = 0; i < monsterSelection.Count; i++)
|
|
{
|
|
DirectorCard value = monsterSelection.choices[i].value;
|
|
float combatDirectorHighestEliteCostMultiplier = CombatDirector.CalcHighestEliteCostMultiplier(value.spawnCard.eliteRules);
|
|
if (DirectorCardIsReasonableChoice(availableCredit, maximumNumberToSpawnBeforeSkipping, minimumToSpawn, value, combatDirectorHighestEliteCostMultiplier))
|
|
{
|
|
weightedSelection.AddChoice(value, monsterSelection.choices[i].weight);
|
|
}
|
|
}
|
|
return weightedSelection;
|
|
}
|
|
|
|
public static bool DirectorCardIsReasonableChoice(float availableCredit, int maximumNumberToSpawnBeforeSkipping, int minimumToSpawn, DirectorCard card, float combatDirectorHighestEliteCostMultiplier)
|
|
{
|
|
float num = (float)(card.cost * maximumNumberToSpawnBeforeSkipping) * ((card.spawnCard as CharacterSpawnCard).noElites ? 1f : combatDirectorHighestEliteCostMultiplier);
|
|
if (card.IsAvailable() && (float)card.cost * (float)minimumToSpawn <= availableCredit)
|
|
{
|
|
return num / 2f > availableCredit;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public static CharacterBody HurtBoxColliderToBody(Collider collider)
|
|
{
|
|
HurtBox component = collider.GetComponent<HurtBox>();
|
|
if ((bool)component && (bool)component.healthComponent)
|
|
{
|
|
return component.healthComponent.body;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static float ConvertAmplificationPercentageIntoReductionPercentage(float amplificationPercentage)
|
|
{
|
|
return (1f - 100f / (100f + amplificationPercentage)) * 100f;
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static float ConvertAmplificationPercentageIntoReductionNormalized(float amplificationNormal)
|
|
{
|
|
return (1f - 1f / (1f + amplificationNormal)) * 1f;
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static float NonlinearLerp(float min, float max, float amplifactionNormalixed)
|
|
{
|
|
return Mathf.Lerp(min, max, ConvertAmplificationPercentageIntoReductionNormalized(amplifactionNormalixed));
|
|
}
|
|
|
|
public static Vector3 ClosestPointOnLine(Vector3 vA, Vector3 vB, Vector3 vPoint)
|
|
{
|
|
Vector3 rhs = vPoint - vA;
|
|
Vector3 normalized = (vB - vA).normalized;
|
|
float num = Vector3.Distance(vA, vB);
|
|
float num2 = Vector3.Dot(normalized, rhs);
|
|
if (num2 <= 0f)
|
|
{
|
|
return vA;
|
|
}
|
|
if (num2 >= num)
|
|
{
|
|
return vB;
|
|
}
|
|
Vector3 vector = normalized * num2;
|
|
return vA + vector;
|
|
}
|
|
|
|
public static CharacterBody TryToCreateGhost(CharacterBody targetBody, CharacterBody ownerBody, int duration)
|
|
{
|
|
if (!NetworkServer.active)
|
|
{
|
|
UnityEngine.Debug.LogWarning("[Server] function 'RoR2.CharacterBody RoR2.Util::TryToCreateGhost(RoR2.CharacterBody, RoR2.CharacterBody, int)' called on client");
|
|
return null;
|
|
}
|
|
if (!targetBody)
|
|
{
|
|
return null;
|
|
}
|
|
GameObject bodyPrefab = BodyCatalog.FindBodyPrefab(targetBody);
|
|
if (!bodyPrefab)
|
|
{
|
|
return null;
|
|
}
|
|
CharacterMaster characterMaster = MasterCatalog.allAiMasters.FirstOrDefault((CharacterMaster master) => master.bodyPrefab == bodyPrefab);
|
|
if (!characterMaster)
|
|
{
|
|
return null;
|
|
}
|
|
MasterSummon obj = new MasterSummon
|
|
{
|
|
masterPrefab = characterMaster.gameObject,
|
|
ignoreTeamMemberLimit = false,
|
|
position = targetBody.footPosition
|
|
};
|
|
CharacterDirection component = targetBody.GetComponent<CharacterDirection>();
|
|
obj.rotation = (component ? Quaternion.Euler(0f, component.yaw, 0f) : targetBody.transform.rotation);
|
|
obj.summonerBodyObject = (ownerBody ? ownerBody.gameObject : null);
|
|
obj.inventoryToCopy = targetBody.inventory;
|
|
obj.useAmbientLevel = null;
|
|
obj.preSpawnSetupCallback = (Action<CharacterMaster>)Delegate.Combine(obj.preSpawnSetupCallback, new Action<CharacterMaster>(PreSpawnSetup));
|
|
CharacterMaster characterMaster2 = obj.Perform();
|
|
if (!characterMaster2)
|
|
{
|
|
return null;
|
|
}
|
|
CharacterBody body = characterMaster2.GetBody();
|
|
if ((bool)body)
|
|
{
|
|
EntityStateMachine[] components = body.GetComponents<EntityStateMachine>();
|
|
foreach (EntityStateMachine obj2 in components)
|
|
{
|
|
obj2.initialStateType = obj2.mainStateType;
|
|
}
|
|
}
|
|
return body;
|
|
void PreSpawnSetup(CharacterMaster newMaster)
|
|
{
|
|
newMaster.inventory.GiveItem(RoR2Content.Items.Ghost);
|
|
newMaster.inventory.GiveItem(RoR2Content.Items.HealthDecay, duration);
|
|
newMaster.inventory.GiveItem(RoR2Content.Items.BoostDamage, 150);
|
|
}
|
|
}
|
|
|
|
public static float OnHitProcDamage(float damageThatProccedIt, float damageStat, float damageCoefficient)
|
|
{
|
|
float b = damageThatProccedIt * damageCoefficient;
|
|
return Mathf.Max(1f, b);
|
|
}
|
|
|
|
public static float OnKillProcDamage(float baseDamage, float damageCoefficient)
|
|
{
|
|
return baseDamage * damageCoefficient;
|
|
}
|
|
|
|
public static Quaternion QuaternionSafeLookRotation(Vector3 forward)
|
|
{
|
|
Quaternion result = Quaternion.identity;
|
|
if (forward.sqrMagnitude > Mathf.Epsilon && forward != Vector3.zero)
|
|
{
|
|
result = Quaternion.LookRotation(forward);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public static Quaternion QuaternionSafeLookRotation(Vector3 forward, Vector3 upwards)
|
|
{
|
|
Quaternion result = Quaternion.identity;
|
|
if (forward.sqrMagnitude > Mathf.Epsilon)
|
|
{
|
|
result = Quaternion.LookRotation(forward, upwards);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public static bool HasParameterOfType(Animator animator, string name, AnimatorControllerParameterType type)
|
|
{
|
|
AnimatorControllerParameter[] parameters = animator.parameters;
|
|
foreach (AnimatorControllerParameter animatorControllerParameter in parameters)
|
|
{
|
|
if (animatorControllerParameter.type == type && animatorControllerParameter.name == name)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public static uint PlaySound(string soundString, GameObject gameObject)
|
|
{
|
|
if (string.IsNullOrEmpty(soundString))
|
|
{
|
|
return 0u;
|
|
}
|
|
if (gameObject == null)
|
|
{
|
|
return AkSoundEngine.PostEvent(soundString, ulong.MaxValue);
|
|
}
|
|
return AkSoundEngine.PostEvent(soundString, gameObject);
|
|
}
|
|
|
|
public static uint PlaySound(string soundString, GameObject gameObject, string RTPCstring, float RTPCvalue)
|
|
{
|
|
uint num = PlaySound(soundString, gameObject);
|
|
if (num != 0)
|
|
{
|
|
AkSoundEngine.SetRTPCValueByPlayingID(RTPCstring, RTPCvalue, num);
|
|
}
|
|
return num;
|
|
}
|
|
|
|
public static uint PlayAttackSpeedSound(string soundString, GameObject gameObject, float attackSpeedStat)
|
|
{
|
|
uint num = PlaySound(soundString, gameObject);
|
|
if (num != 0)
|
|
{
|
|
float in_value = CalculateAttackSpeedRtpcValue(attackSpeedStat);
|
|
AkSoundEngine.SetRTPCValueByPlayingID("attackSpeed", in_value, num);
|
|
}
|
|
return num;
|
|
}
|
|
|
|
public static float CalculateAttackSpeedRtpcValue(float attackSpeedStat)
|
|
{
|
|
float num = Mathf.Log(attackSpeedStat, 2f);
|
|
return 1200f * num / 96f + 50f;
|
|
}
|
|
|
|
public static void RotateAwayFromWalls(float raycastLength, int raycastCount, Vector3 raycastOrigin, Transform referenceTransform)
|
|
{
|
|
float num = 360f / (float)raycastCount;
|
|
float angle = 0f;
|
|
float num2 = 0f;
|
|
for (int i = 0; i < raycastCount; i++)
|
|
{
|
|
Vector3 direction = Quaternion.Euler(0f, num * (float)i, 0f) * Vector3.forward;
|
|
float num3 = raycastLength;
|
|
if (Physics.Raycast(raycastOrigin, direction, out var hitInfo, raycastLength, LayerIndex.world.mask))
|
|
{
|
|
num3 = hitInfo.distance;
|
|
}
|
|
if (hitInfo.distance > num2)
|
|
{
|
|
angle = num * (float)i;
|
|
num2 = num3;
|
|
}
|
|
}
|
|
referenceTransform.Rotate(Vector3.up, angle, Space.Self);
|
|
}
|
|
|
|
public static string GetActionDisplayString(ActionElementMap actionElementMap)
|
|
{
|
|
if (actionElementMap == null)
|
|
{
|
|
return "";
|
|
}
|
|
return actionElementMap.elementIdentifierName switch
|
|
{
|
|
"Left Mouse Button" => "M1",
|
|
"Right Mouse Button" => "M2",
|
|
"Left Shift" => "Shift",
|
|
_ => actionElementMap.elementIdentifierName,
|
|
};
|
|
}
|
|
|
|
public static float AngleSigned(Vector3 v1, Vector3 v2, Vector3 n)
|
|
{
|
|
return Mathf.Atan2(Vector3.Dot(n, Vector3.Cross(v1, v2)), Vector3.Dot(v1, v2)) * 57.29578f;
|
|
}
|
|
|
|
public static float Remap(float value, float inMin, float inMax, float outMin, float outMax)
|
|
{
|
|
return outMin + (value - inMin) / (inMax - inMin) * (outMax - outMin);
|
|
}
|
|
|
|
public static bool HasAnimationParameter(string paramName, Animator animator)
|
|
{
|
|
AnimatorControllerParameter[] parameters = animator.parameters;
|
|
for (int i = 0; i < parameters.Length; i++)
|
|
{
|
|
if (parameters[i].name == paramName)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public static bool HasAnimationParameter(int paramHash, AnimatorControllerParameter[] parameters)
|
|
{
|
|
int i = 0;
|
|
for (int num = parameters.Length; i < num; i++)
|
|
{
|
|
if (parameters[i].nameHash == paramHash)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public static bool HasAnimationParameter(int paramHash, Animator animator)
|
|
{
|
|
return HasAnimationParameter(paramHash, animator.parameters);
|
|
}
|
|
|
|
public static bool CheckRoll(float percentChance, float luck = 0f, CharacterMaster effectOriginMaster = null)
|
|
{
|
|
if (percentChance <= 0f)
|
|
{
|
|
return false;
|
|
}
|
|
int num = Mathf.CeilToInt(Mathf.Abs(luck));
|
|
float num2 = UnityEngine.Random.Range(0f, 100f);
|
|
float num3 = num2;
|
|
for (int i = 0; i < num; i++)
|
|
{
|
|
float b = UnityEngine.Random.Range(0f, 100f);
|
|
num2 = ((luck > 0f) ? Mathf.Min(num2, b) : Mathf.Max(num2, b));
|
|
}
|
|
if (num2 <= percentChance)
|
|
{
|
|
if (num3 > percentChance && (bool)effectOriginMaster)
|
|
{
|
|
GameObject bodyObject = effectOriginMaster.GetBodyObject();
|
|
if ((bool)bodyObject)
|
|
{
|
|
CharacterBody component = bodyObject.GetComponent<CharacterBody>();
|
|
if ((bool)component)
|
|
{
|
|
component.wasLucky = true;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public static bool CheckRoll(float percentChance, CharacterMaster master)
|
|
{
|
|
return CheckRoll(percentChance, master ? master.luck : 0f, master);
|
|
}
|
|
|
|
public static float EstimateSurfaceDistance(Collider a, Collider b)
|
|
{
|
|
Vector3 center = a.bounds.center;
|
|
Vector3 center2 = b.bounds.center;
|
|
RaycastHit hitInfo;
|
|
Vector3 a2 = ((!b.Raycast(new Ray(center, center2 - center), out hitInfo, float.PositiveInfinity)) ? b.ClosestPointOnBounds(center) : hitInfo.point);
|
|
Vector3 b2 = ((!a.Raycast(new Ray(center2, center - center2), out hitInfo, float.PositiveInfinity)) ? a.ClosestPointOnBounds(center2) : hitInfo.point);
|
|
return Vector3.Distance(a2, b2);
|
|
}
|
|
|
|
public static bool HasEffectiveAuthority(GameObject gameObject)
|
|
{
|
|
if ((bool)gameObject)
|
|
{
|
|
return HasEffectiveAuthority(gameObject.GetComponent<NetworkIdentity>());
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public static bool HasEffectiveAuthority(NetworkIdentity networkIdentity)
|
|
{
|
|
if ((bool)networkIdentity)
|
|
{
|
|
if (!networkIdentity.hasAuthority)
|
|
{
|
|
if (NetworkServer.active)
|
|
{
|
|
return networkIdentity.clientAuthorityOwner == null;
|
|
}
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public static float CalculateSphereVolume(float radius)
|
|
{
|
|
return 4.1887903f * radius * radius * radius;
|
|
}
|
|
|
|
public static float CalculateCylinderVolume(float radius, float height)
|
|
{
|
|
return MathF.PI * radius * radius * height;
|
|
}
|
|
|
|
public static float CalculateColliderVolume(Collider collider)
|
|
{
|
|
Vector3 lossyScale = collider.transform.lossyScale;
|
|
float num = lossyScale.x * lossyScale.y * lossyScale.z;
|
|
float num2 = 0f;
|
|
if (collider is BoxCollider)
|
|
{
|
|
Vector3 size = ((BoxCollider)collider).size;
|
|
num2 = size.x * size.y * size.z;
|
|
}
|
|
else if (collider is SphereCollider)
|
|
{
|
|
num2 = CalculateSphereVolume(((SphereCollider)collider).radius);
|
|
}
|
|
else if (collider is CapsuleCollider)
|
|
{
|
|
CapsuleCollider obj = (CapsuleCollider)collider;
|
|
float radius = obj.radius;
|
|
float num3 = CalculateSphereVolume(radius);
|
|
float num4 = Mathf.Max(obj.height - num3, 0f);
|
|
float num5 = MathF.PI * radius * radius * num4;
|
|
num2 = num3 + num5;
|
|
}
|
|
else if (collider is CharacterController)
|
|
{
|
|
CharacterController obj2 = (CharacterController)collider;
|
|
float radius2 = obj2.radius;
|
|
float num6 = CalculateSphereVolume(radius2);
|
|
float num7 = Mathf.Max(obj2.height - num6, 0f);
|
|
float num8 = MathF.PI * radius2 * radius2 * num7;
|
|
num2 = num6 + num8;
|
|
}
|
|
return num2 * num;
|
|
}
|
|
|
|
public static Vector3 RandomColliderVolumePoint(Collider collider)
|
|
{
|
|
Transform transform = collider.transform;
|
|
Vector3 position = Vector3.zero;
|
|
if (collider is BoxCollider)
|
|
{
|
|
BoxCollider obj = (BoxCollider)collider;
|
|
Vector3 size = obj.size;
|
|
Vector3 center = obj.center;
|
|
position = new Vector3(center.x + UnityEngine.Random.Range(size.x * -0.5f, size.x * 0.5f), center.y + UnityEngine.Random.Range(size.y * -0.5f, size.y * 0.5f), center.z + UnityEngine.Random.Range(size.z * -0.5f, size.z * 0.5f));
|
|
}
|
|
else if (collider is SphereCollider)
|
|
{
|
|
SphereCollider sphereCollider = (SphereCollider)collider;
|
|
position = sphereCollider.center + UnityEngine.Random.insideUnitSphere * sphereCollider.radius;
|
|
}
|
|
else if (collider is CapsuleCollider)
|
|
{
|
|
CapsuleCollider capsuleCollider = (CapsuleCollider)collider;
|
|
float radius = capsuleCollider.radius;
|
|
float num = Mathf.Max(capsuleCollider.height - radius, 0f);
|
|
float num2 = CalculateSphereVolume(radius);
|
|
float num3 = CalculateCylinderVolume(radius, num);
|
|
float maxInclusive = num2 + num3;
|
|
if (UnityEngine.Random.Range(0f, maxInclusive) <= num2)
|
|
{
|
|
position = UnityEngine.Random.insideUnitSphere * radius;
|
|
float num4 = ((float)UnityEngine.Random.Range(0, 2) * 2f - 1f) * num * 0.5f;
|
|
switch (capsuleCollider.direction)
|
|
{
|
|
case 0:
|
|
position.x += num4;
|
|
break;
|
|
case 1:
|
|
position.y += num4;
|
|
break;
|
|
case 2:
|
|
position.z += num4;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Vector2 vector = UnityEngine.Random.insideUnitCircle * radius;
|
|
float num5 = UnityEngine.Random.Range(num * -0.5f, num * 0.5f);
|
|
switch (capsuleCollider.direction)
|
|
{
|
|
case 0:
|
|
position = new Vector3(num5, vector.x, vector.y);
|
|
break;
|
|
case 1:
|
|
position = new Vector3(vector.x, num5, vector.y);
|
|
break;
|
|
case 2:
|
|
position = new Vector3(vector.x, vector.y, num5);
|
|
break;
|
|
}
|
|
}
|
|
position += capsuleCollider.center;
|
|
}
|
|
else if (collider is CharacterController)
|
|
{
|
|
CharacterController characterController = (CharacterController)collider;
|
|
float radius2 = characterController.radius;
|
|
float num6 = Mathf.Max(characterController.height - radius2, 0f);
|
|
float num7 = CalculateSphereVolume(radius2);
|
|
float num8 = CalculateCylinderVolume(radius2, num6);
|
|
float maxInclusive2 = num7 + num8;
|
|
if (UnityEngine.Random.Range(0f, maxInclusive2) <= num7)
|
|
{
|
|
position = UnityEngine.Random.insideUnitSphere * radius2;
|
|
float num9 = ((float)UnityEngine.Random.Range(0, 2) * 2f - 1f) * num6 * 0.5f;
|
|
position.y += num9;
|
|
}
|
|
else
|
|
{
|
|
Vector2 vector2 = UnityEngine.Random.insideUnitCircle * radius2;
|
|
float y = UnityEngine.Random.Range(num6 * -0.5f, num6 * 0.5f);
|
|
position = new Vector3(vector2.x, y, vector2.y);
|
|
}
|
|
position += characterController.center;
|
|
}
|
|
return transform.TransformPoint(position);
|
|
}
|
|
|
|
public static CharacterBody GetFriendlyEasyTarget(CharacterBody casterBody, Ray aimRay, float maxDistance, float maxDeviation = 20f)
|
|
{
|
|
TeamIndex teamIndex = TeamIndex.Neutral;
|
|
TeamComponent component = casterBody.GetComponent<TeamComponent>();
|
|
if ((bool)component)
|
|
{
|
|
teamIndex = component.teamIndex;
|
|
}
|
|
ReadOnlyCollection<TeamComponent> teamMembers = TeamComponent.GetTeamMembers(teamIndex);
|
|
Vector3 origin = aimRay.origin;
|
|
Vector3 direction = aimRay.direction;
|
|
List<EasyTargetCandidate> candidatesList = new List<EasyTargetCandidate>(teamMembers.Count);
|
|
List<int> list = new List<int>(teamMembers.Count);
|
|
float num = Mathf.Cos(maxDeviation * (MathF.PI / 180f));
|
|
for (int i = 0; i < teamMembers.Count; i++)
|
|
{
|
|
Transform transform = teamMembers[i].transform;
|
|
Vector3 vector = transform.position - origin;
|
|
float magnitude = vector.magnitude;
|
|
float num2 = Vector3.Dot(vector * (1f / magnitude), direction);
|
|
CharacterBody component2 = transform.GetComponent<CharacterBody>();
|
|
if (num2 >= num && component2 != casterBody)
|
|
{
|
|
float num3 = 1f / magnitude;
|
|
float score = num2 + num3;
|
|
candidatesList.Add(new EasyTargetCandidate
|
|
{
|
|
transform = transform,
|
|
score = score,
|
|
distance = magnitude
|
|
});
|
|
list.Add(list.Count);
|
|
}
|
|
}
|
|
list.Sort(delegate(int a, int b)
|
|
{
|
|
float score2 = candidatesList[a].score;
|
|
float score3 = candidatesList[b].score;
|
|
return (score2 != score3) ? ((!(score2 > score3)) ? 1 : (-1)) : 0;
|
|
});
|
|
for (int j = 0; j < list.Count; j++)
|
|
{
|
|
int index = list[j];
|
|
CharacterBody component3 = candidatesList[index].transform.GetComponent<CharacterBody>();
|
|
if ((bool)component3 && component3 != casterBody)
|
|
{
|
|
return component3;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public static CharacterBody GetEnemyEasyTarget(CharacterBody casterBody, Ray aimRay, float maxDistance, float maxDeviation = 20f)
|
|
{
|
|
TeamIndex teamIndex = TeamIndex.Neutral;
|
|
TeamComponent component = casterBody.GetComponent<TeamComponent>();
|
|
if ((bool)component)
|
|
{
|
|
teamIndex = component.teamIndex;
|
|
}
|
|
List<TeamComponent> list = new List<TeamComponent>();
|
|
for (TeamIndex teamIndex2 = TeamIndex.Neutral; teamIndex2 < TeamIndex.Count; teamIndex2++)
|
|
{
|
|
if (teamIndex2 != teamIndex)
|
|
{
|
|
list.AddRange(TeamComponent.GetTeamMembers(teamIndex2));
|
|
}
|
|
}
|
|
Vector3 origin = aimRay.origin;
|
|
Vector3 direction = aimRay.direction;
|
|
List<EasyTargetCandidate> candidatesList = new List<EasyTargetCandidate>(list.Count);
|
|
List<int> list2 = new List<int>(list.Count);
|
|
float num = Mathf.Cos(maxDeviation * (MathF.PI / 180f));
|
|
for (int i = 0; i < list.Count; i++)
|
|
{
|
|
Transform transform = list[i].transform;
|
|
Vector3 vector = transform.position - origin;
|
|
float magnitude = vector.magnitude;
|
|
float num2 = Vector3.Dot(vector * (1f / magnitude), direction);
|
|
CharacterBody component2 = transform.GetComponent<CharacterBody>();
|
|
if (num2 >= num && component2 != casterBody && magnitude < maxDistance)
|
|
{
|
|
float num3 = 1f / magnitude;
|
|
float score = num2 + num3;
|
|
candidatesList.Add(new EasyTargetCandidate
|
|
{
|
|
transform = transform,
|
|
score = score,
|
|
distance = magnitude
|
|
});
|
|
list2.Add(list2.Count);
|
|
}
|
|
}
|
|
list2.Sort(delegate(int a, int b)
|
|
{
|
|
float score2 = candidatesList[a].score;
|
|
float score3 = candidatesList[b].score;
|
|
return (score2 != score3) ? ((!(score2 > score3)) ? 1 : (-1)) : 0;
|
|
});
|
|
for (int j = 0; j < list2.Count; j++)
|
|
{
|
|
int index = list2[j];
|
|
CharacterBody component3 = candidatesList[index].transform.GetComponent<CharacterBody>();
|
|
if ((bool)component3 && component3 != casterBody)
|
|
{
|
|
return component3;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public static float GetBodyPrefabFootOffset(GameObject prefab)
|
|
{
|
|
CapsuleCollider component = prefab.GetComponent<CapsuleCollider>();
|
|
if ((bool)component)
|
|
{
|
|
return component.height * 0.5f - component.center.y;
|
|
}
|
|
return 0f;
|
|
}
|
|
|
|
public static void ShuffleList<T>(List<T> list)
|
|
{
|
|
for (int num = list.Count - 1; num > 0; num--)
|
|
{
|
|
int index = UnityEngine.Random.Range(0, num + 1);
|
|
T value = list[num];
|
|
list[num] = list[index];
|
|
list[index] = value;
|
|
}
|
|
}
|
|
|
|
public static void ShuffleList<T>(List<T> list, Xoroshiro128Plus rng)
|
|
{
|
|
for (int num = list.Count - 1; num > 0; num--)
|
|
{
|
|
int index = rng.RangeInt(0, num + 1);
|
|
T value = list[num];
|
|
list[num] = list[index];
|
|
list[index] = value;
|
|
}
|
|
}
|
|
|
|
public static void ShuffleArray<T>(T[] array)
|
|
{
|
|
for (int num = array.Length - 1; num > 0; num--)
|
|
{
|
|
int num2 = UnityEngine.Random.Range(0, num + 1);
|
|
T val = array[num];
|
|
array[num] = array[num2];
|
|
array[num2] = val;
|
|
}
|
|
}
|
|
|
|
public static void ShuffleArray<T>(T[] array, Xoroshiro128Plus rng)
|
|
{
|
|
for (int num = array.Length - 1; num > 0; num--)
|
|
{
|
|
int num2 = rng.RangeInt(0, num + 1);
|
|
T val = array[num];
|
|
array[num] = array[num2];
|
|
array[num2] = val;
|
|
}
|
|
}
|
|
|
|
public static Transform FindNearest(Vector3 position, List<Transform> transformsList, float range = float.PositiveInfinity)
|
|
{
|
|
Transform result = null;
|
|
float num = range * range;
|
|
for (int i = 0; i < transformsList.Count; i++)
|
|
{
|
|
float sqrMagnitude = (transformsList[i].position - position).sqrMagnitude;
|
|
if (sqrMagnitude < num)
|
|
{
|
|
num = sqrMagnitude;
|
|
result = transformsList[i];
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public static Vector3 ApplySpread(Vector3 aimDirection, float minSpread, float maxSpread, float spreadYawScale, float spreadPitchScale, float bonusYaw = 0f, float bonusPitch = 0f)
|
|
{
|
|
Vector3 up = Vector3.up;
|
|
Vector3 axis = Vector3.Cross(up, aimDirection);
|
|
float x = UnityEngine.Random.Range(minSpread, maxSpread);
|
|
float z = UnityEngine.Random.Range(0f, 360f);
|
|
Vector3 vector = Quaternion.Euler(0f, 0f, z) * (Quaternion.Euler(x, 0f, 0f) * Vector3.forward);
|
|
float y = vector.y;
|
|
vector.y = 0f;
|
|
float angle = (Mathf.Atan2(vector.z, vector.x) * 57.29578f - 90f + bonusYaw) * spreadYawScale;
|
|
float angle2 = (Mathf.Atan2(y, vector.magnitude) * 57.29578f + bonusPitch) * spreadPitchScale;
|
|
return Quaternion.AngleAxis(angle, up) * (Quaternion.AngleAxis(angle2, axis) * aimDirection);
|
|
}
|
|
|
|
public static string GenerateColoredString(string str, Color32 color)
|
|
{
|
|
return string.Format(CultureInfo.InvariantCulture, "<color=#{0:X2}{1:X2}{2:X2}>{3}</color>", color.r, color.g, color.b, str);
|
|
}
|
|
|
|
public static bool GuessRenderBounds(GameObject gameObject, out Bounds bounds)
|
|
{
|
|
Renderer[] componentsInChildren = gameObject.GetComponentsInChildren<Renderer>();
|
|
if (componentsInChildren.Length != 0)
|
|
{
|
|
bounds = componentsInChildren[0].bounds;
|
|
for (int i = 1; i < componentsInChildren.Length; i++)
|
|
{
|
|
bounds.Encapsulate(componentsInChildren[i].bounds);
|
|
}
|
|
return true;
|
|
}
|
|
bounds = new Bounds(gameObject.transform.position, Vector3.zero);
|
|
return false;
|
|
}
|
|
|
|
public static bool GuessRenderBoundsMeshOnly(GameObject gameObject, out Bounds bounds)
|
|
{
|
|
Renderer[] array = (from renderer in gameObject.GetComponentsInChildren<Renderer>()
|
|
where renderer is MeshRenderer || renderer is SkinnedMeshRenderer
|
|
select renderer).ToArray();
|
|
if (array.Length != 0)
|
|
{
|
|
bounds = array[0].bounds;
|
|
for (int i = 1; i < array.Length; i++)
|
|
{
|
|
bounds.Encapsulate(array[i].bounds);
|
|
}
|
|
return true;
|
|
}
|
|
bounds = new Bounds(gameObject.transform.position, Vector3.zero);
|
|
return false;
|
|
}
|
|
|
|
public static GameObject FindNetworkObject(NetworkInstanceId networkInstanceId)
|
|
{
|
|
if (NetworkServer.active)
|
|
{
|
|
return NetworkServer.FindLocalObject(networkInstanceId);
|
|
}
|
|
return ClientScene.FindLocalObject(networkInstanceId);
|
|
}
|
|
|
|
public static string GetGameObjectHierarchyName(GameObject gameObject)
|
|
{
|
|
int num = 0;
|
|
Transform transform = gameObject.transform;
|
|
while ((bool)transform)
|
|
{
|
|
num++;
|
|
transform = transform.parent;
|
|
}
|
|
string[] array = new string[num];
|
|
Transform transform2 = gameObject.transform;
|
|
while ((bool)transform2)
|
|
{
|
|
array[--num] = transform2.gameObject.name;
|
|
transform2 = transform2.parent;
|
|
}
|
|
return string.Join("/", array);
|
|
}
|
|
|
|
public static string GetBestBodyName(GameObject bodyObject)
|
|
{
|
|
CharacterBody characterBody = null;
|
|
string text = "???";
|
|
if ((bool)bodyObject)
|
|
{
|
|
characterBody = bodyObject.GetComponent<CharacterBody>();
|
|
if ((bool)characterBody)
|
|
{
|
|
text = characterBody.GetUserName();
|
|
}
|
|
else
|
|
{
|
|
IDisplayNameProvider component = bodyObject.GetComponent<IDisplayNameProvider>();
|
|
if (component != null)
|
|
{
|
|
text = component.GetDisplayName();
|
|
}
|
|
}
|
|
}
|
|
string text2 = text;
|
|
if ((bool)characterBody)
|
|
{
|
|
if (characterBody.isElite)
|
|
{
|
|
BuffIndex[] eliteBuffIndices = BuffCatalog.eliteBuffIndices;
|
|
foreach (BuffIndex buffIndex in eliteBuffIndices)
|
|
{
|
|
if (characterBody.HasBuff(buffIndex))
|
|
{
|
|
text2 = Language.GetStringFormatted(BuffCatalog.GetBuffDef(buffIndex).eliteDef.modifierToken, text2);
|
|
}
|
|
}
|
|
}
|
|
if ((bool)characterBody.inventory)
|
|
{
|
|
if (characterBody.inventory.GetItemCount(RoR2Content.Items.InvadingDoppelganger) > 0)
|
|
{
|
|
text2 = Language.GetStringFormatted("BODY_MODIFIER_DOPPELGANGER", text2);
|
|
}
|
|
if (characterBody.inventory.GetItemCount(DLC1Content.Items.GummyCloneIdentifier) > 0)
|
|
{
|
|
text2 = Language.GetStringFormatted("BODY_MODIFIER_GUMMYCLONE", text2);
|
|
}
|
|
}
|
|
}
|
|
return text2;
|
|
}
|
|
|
|
public static string GetBestBodyNameColored(GameObject bodyObject)
|
|
{
|
|
if ((bool)bodyObject)
|
|
{
|
|
CharacterBody component = bodyObject.GetComponent<CharacterBody>();
|
|
if ((bool)component)
|
|
{
|
|
CharacterMaster master = component.master;
|
|
if ((bool)master)
|
|
{
|
|
PlayerCharacterMasterController component2 = master.GetComponent<PlayerCharacterMasterController>();
|
|
if ((bool)component2)
|
|
{
|
|
GameObject networkUserObject = component2.networkUserObject;
|
|
if ((bool)networkUserObject)
|
|
{
|
|
NetworkUser component3 = networkUserObject.GetComponent<NetworkUser>();
|
|
if ((bool)component3)
|
|
{
|
|
return GenerateColoredString(component3.userName, component3.userColor);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
IDisplayNameProvider component4 = bodyObject.GetComponent<IDisplayNameProvider>();
|
|
if (component4 != null)
|
|
{
|
|
return component4.GetDisplayName();
|
|
}
|
|
}
|
|
return "???";
|
|
}
|
|
|
|
public static string GetBestMasterName(CharacterMaster characterMaster)
|
|
{
|
|
if ((bool)characterMaster)
|
|
{
|
|
string text = characterMaster.playerCharacterMasterController?.networkUser?.userName;
|
|
if (text == null)
|
|
{
|
|
string text2 = characterMaster.bodyPrefab?.GetComponent<CharacterBody>().baseNameToken;
|
|
if (text2 != null)
|
|
{
|
|
text = Language.GetString(text2);
|
|
}
|
|
}
|
|
return text;
|
|
}
|
|
return "Null Master";
|
|
}
|
|
|
|
public static NetworkUser LookUpBodyNetworkUser(GameObject bodyObject)
|
|
{
|
|
if ((bool)bodyObject)
|
|
{
|
|
return LookUpBodyNetworkUser(bodyObject.GetComponent<CharacterBody>());
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public static NetworkUser LookUpBodyNetworkUser(CharacterBody characterBody)
|
|
{
|
|
if ((bool)characterBody)
|
|
{
|
|
CharacterMaster master = characterBody.master;
|
|
if ((bool)master)
|
|
{
|
|
PlayerCharacterMasterController component = master.GetComponent<PlayerCharacterMasterController>();
|
|
if ((bool)component)
|
|
{
|
|
GameObject networkUserObject = component.networkUserObject;
|
|
if ((bool)networkUserObject)
|
|
{
|
|
NetworkUser component2 = networkUserObject.GetComponent<NetworkUser>();
|
|
if ((bool)component2)
|
|
{
|
|
return component2;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
private static bool HandleCharacterPhysicsCastResults(GameObject bodyObject, Ray ray, int numHits, RaycastHit[] hits, out RaycastHit hitInfo)
|
|
{
|
|
int num = -1;
|
|
float num2 = float.PositiveInfinity;
|
|
for (int i = 0; i < numHits; i++)
|
|
{
|
|
if (bodyObject == hits[i].collider.gameObject)
|
|
{
|
|
continue;
|
|
}
|
|
float distance = hits[i].distance;
|
|
if (!(distance < num2))
|
|
{
|
|
continue;
|
|
}
|
|
HurtBox component = hits[i].collider.GetComponent<HurtBox>();
|
|
if ((bool)component)
|
|
{
|
|
HealthComponent healthComponent = component.healthComponent;
|
|
if ((bool)healthComponent && healthComponent.gameObject == bodyObject)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
if (distance == 0f)
|
|
{
|
|
hitInfo = hits[i];
|
|
hitInfo.point = ray.origin;
|
|
return true;
|
|
}
|
|
num = i;
|
|
num2 = distance;
|
|
}
|
|
if (num == -1)
|
|
{
|
|
hitInfo = default(RaycastHit);
|
|
return false;
|
|
}
|
|
hitInfo = hits[num];
|
|
return true;
|
|
}
|
|
|
|
public static bool CharacterRaycast(GameObject bodyObject, Ray ray, out RaycastHit hitInfo, float maxDistance, LayerMask layerMask, QueryTriggerInteraction queryTriggerInteraction)
|
|
{
|
|
int num = 0;
|
|
num = HGPhysics.RaycastAll(out var hits, ray.origin, ray.direction, maxDistance, layerMask, queryTriggerInteraction);
|
|
bool result = HandleCharacterPhysicsCastResults(bodyObject, ray, num, hits, out hitInfo);
|
|
HGPhysics.ReturnResults(hits);
|
|
return result;
|
|
}
|
|
|
|
public static bool CharacterSpherecast(GameObject bodyObject, Ray ray, float radius, out RaycastHit hitInfo, float maxDistance, LayerMask layerMask, QueryTriggerInteraction queryTriggerInteraction)
|
|
{
|
|
RaycastHit[] hits;
|
|
int numHits = HGPhysics.SphereCastAll(out hits, ray.origin, radius, ray.direction, maxDistance, layerMask, queryTriggerInteraction);
|
|
bool result = HandleCharacterPhysicsCastResults(bodyObject, ray, numHits, hits, out hitInfo);
|
|
HGPhysics.ReturnResults(hits);
|
|
return result;
|
|
}
|
|
|
|
public static bool ConnectionIsLocal([NotNull] NetworkConnection conn)
|
|
{
|
|
if (conn is SteamNetworkConnection)
|
|
{
|
|
return false;
|
|
}
|
|
if (conn is EOSNetworkConnection)
|
|
{
|
|
return false;
|
|
}
|
|
return conn.GetType() != typeof(NetworkConnection);
|
|
}
|
|
|
|
public static string EscapeRichTextForTextMeshPro(string rtString)
|
|
{
|
|
string text = rtString;
|
|
text = text.Replace("<", "</noparse><noparse><</noparse><noparse>");
|
|
return "<noparse>" + text + "</noparse>";
|
|
}
|
|
|
|
public static string EscapeQuotes(string str)
|
|
{
|
|
str = backlashSearch.Replace(str, strBackslashBackslash);
|
|
str = quoteSearch.Replace(str, strBackslashQuote);
|
|
return str;
|
|
}
|
|
|
|
public static string RGBToHex(Color32 rgb)
|
|
{
|
|
return string.Format(CultureInfo.InvariantCulture, "{0:X2}{1:X2}{2:X2}", rgb.r, rgb.g, rgb.b);
|
|
}
|
|
|
|
public static Vector2 Vector3XZToVector2XY(Vector3 vector3)
|
|
{
|
|
return new Vector2(vector3.x, vector3.z);
|
|
}
|
|
|
|
public static Vector2 Vector3XZToVector2XY(ref Vector3 vector3)
|
|
{
|
|
return new Vector2(vector3.x, vector3.z);
|
|
}
|
|
|
|
public static void Vector3XZToVector2XY(Vector3 vector3, out Vector2 vector2)
|
|
{
|
|
vector2.x = vector3.x;
|
|
vector2.y = vector3.z;
|
|
}
|
|
|
|
public static void Vector3XZToVector2XY(ref Vector3 vector3, out Vector2 vector2)
|
|
{
|
|
vector2.x = vector3.x;
|
|
vector2.y = vector3.z;
|
|
}
|
|
|
|
public static Vector2 RotateVector2(Vector2 vector2, float degrees)
|
|
{
|
|
float num = Mathf.Sin(degrees * (MathF.PI / 180f));
|
|
float num2 = Mathf.Cos(degrees * (MathF.PI / 180f));
|
|
return new Vector2(num2 * vector2.x - num * vector2.y, num * vector2.x + num2 * vector2.y);
|
|
}
|
|
|
|
public static Quaternion SmoothDampQuaternion(Quaternion current, Quaternion target, ref float currentVelocity, float smoothTime, float maxSpeed, float deltaTime)
|
|
{
|
|
float target2 = Quaternion.Angle(current, target);
|
|
target2 = Mathf.SmoothDamp(0f, target2, ref currentVelocity, smoothTime, maxSpeed, deltaTime);
|
|
return Quaternion.RotateTowards(current, target, target2);
|
|
}
|
|
|
|
public static Quaternion SmoothDampQuaternion(Quaternion current, Quaternion target, ref float currentVelocity, float smoothTime)
|
|
{
|
|
float target2 = Quaternion.Angle(current, target);
|
|
target2 = Mathf.SmoothDamp(0f, target2, ref currentVelocity, smoothTime);
|
|
return Quaternion.RotateTowards(current, target, target2);
|
|
}
|
|
|
|
public static HurtBox FindBodyMainHurtBox(CharacterBody characterBody)
|
|
{
|
|
return characterBody.mainHurtBox;
|
|
}
|
|
|
|
public static HurtBox FindBodyMainHurtBox(GameObject bodyObject)
|
|
{
|
|
CharacterBody component = bodyObject.GetComponent<CharacterBody>();
|
|
if ((bool)component)
|
|
{
|
|
return FindBodyMainHurtBox(component);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public static Vector3 GetCorePosition(CharacterBody characterBody)
|
|
{
|
|
return characterBody.corePosition;
|
|
}
|
|
|
|
public static Vector3 GetCorePosition(GameObject bodyObject)
|
|
{
|
|
CharacterBody component = bodyObject.GetComponent<CharacterBody>();
|
|
if ((bool)component)
|
|
{
|
|
return GetCorePosition(component);
|
|
}
|
|
return bodyObject.transform.position;
|
|
}
|
|
|
|
public static Transform GetCoreTransform(GameObject bodyObject)
|
|
{
|
|
CharacterBody component = bodyObject.GetComponent<CharacterBody>();
|
|
if ((bool)component)
|
|
{
|
|
return component.coreTransform;
|
|
}
|
|
return bodyObject.transform;
|
|
}
|
|
|
|
public static float SphereRadiusToVolume(float radius)
|
|
{
|
|
return 4.1887903f * (radius * radius * radius);
|
|
}
|
|
|
|
public static float SphereVolumeToRadius(float volume)
|
|
{
|
|
return Mathf.Pow(3f * volume / (MathF.PI * 4f), 1f / 3f);
|
|
}
|
|
|
|
public static void CopyList<T>(List<T> src, List<T> dest)
|
|
{
|
|
dest.Clear();
|
|
foreach (T item in src)
|
|
{
|
|
dest.Add(item);
|
|
}
|
|
}
|
|
|
|
public static float ScanCharacterAnimationClipForMomentOfRootMotionStop(GameObject characterPrefab, string clipName, string rootBoneNameInChildLocator)
|
|
{
|
|
GameObject gameObject = UnityEngine.Object.Instantiate(characterPrefab);
|
|
Transform modelTransform = gameObject.GetComponent<ModelLocator>().modelTransform;
|
|
Transform transform = modelTransform.GetComponent<ChildLocator>().FindChild(rootBoneNameInChildLocator);
|
|
AnimationClip animationClip = modelTransform.GetComponent<Animator>().runtimeAnimatorController.animationClips.FirstOrDefault((AnimationClip c) => c.name == clipName);
|
|
float result = 1f;
|
|
animationClip.SampleAnimation(gameObject, 0f);
|
|
Vector3 vector = transform.position;
|
|
for (float num = 0.1f; num < 1f; num += 0.1f)
|
|
{
|
|
animationClip.SampleAnimation(gameObject, num);
|
|
Vector3 position = transform.position;
|
|
if ((position - vector).magnitude == 0f)
|
|
{
|
|
result = num;
|
|
break;
|
|
}
|
|
vector = position;
|
|
}
|
|
UnityEngine.Object.Destroy(gameObject);
|
|
return result;
|
|
}
|
|
|
|
public static void DebugCross(Vector3 position, float radius, UnityEngine.Color color, float duration)
|
|
{
|
|
UnityEngine.Debug.DrawLine(position - Vector3.right * radius, position + Vector3.right * radius, color, duration);
|
|
UnityEngine.Debug.DrawLine(position - Vector3.up * radius, position + Vector3.up * radius, color, duration);
|
|
UnityEngine.Debug.DrawLine(position - Vector3.forward * radius, position + Vector3.forward * radius, color, duration);
|
|
}
|
|
|
|
public static void DebugBounds(Bounds bounds, UnityEngine.Color color, float duration)
|
|
{
|
|
Vector3 min = bounds.min;
|
|
Vector3 max = bounds.max;
|
|
Vector3 start = new Vector3(min.x, min.y, min.z);
|
|
Vector3 vector = new Vector3(min.x, min.y, max.z);
|
|
Vector3 vector2 = new Vector3(min.x, max.y, min.z);
|
|
Vector3 end = new Vector3(min.x, max.y, max.z);
|
|
Vector3 vector3 = new Vector3(max.x, min.y, min.z);
|
|
Vector3 vector4 = new Vector3(max.x, min.y, max.z);
|
|
Vector3 end2 = new Vector3(max.x, max.y, min.z);
|
|
Vector3 start2 = new Vector3(max.x, max.y, max.z);
|
|
UnityEngine.Debug.DrawLine(start, vector, color, duration);
|
|
UnityEngine.Debug.DrawLine(start, vector3, color, duration);
|
|
UnityEngine.Debug.DrawLine(start, vector2, color, duration);
|
|
UnityEngine.Debug.DrawLine(vector2, end, color, duration);
|
|
UnityEngine.Debug.DrawLine(vector2, end2, color, duration);
|
|
UnityEngine.Debug.DrawLine(start2, end, color, duration);
|
|
UnityEngine.Debug.DrawLine(start2, end2, color, duration);
|
|
UnityEngine.Debug.DrawLine(start2, vector4, color, duration);
|
|
UnityEngine.Debug.DrawLine(vector4, vector3, color, duration);
|
|
UnityEngine.Debug.DrawLine(vector4, vector, color, duration);
|
|
UnityEngine.Debug.DrawLine(vector, end, color, duration);
|
|
UnityEngine.Debug.DrawLine(vector3, end2, color, duration);
|
|
}
|
|
|
|
public static bool PositionIsValid(Vector3 value)
|
|
{
|
|
float f = value.x + value.y + value.z;
|
|
if (!float.IsInfinity(f))
|
|
{
|
|
return !float.IsNaN(f);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public static void Swap<T>(ref T a, ref T b)
|
|
{
|
|
T val = a;
|
|
a = b;
|
|
b = val;
|
|
}
|
|
|
|
public static DateTime UnixTimeStampToDateTimeUtc(uint unixTimeStamp)
|
|
{
|
|
DateTime dateTime = dateZero;
|
|
return dateTime.AddSeconds(unixTimeStamp).ToUniversalTime();
|
|
}
|
|
|
|
public static double GetCurrentUnixEpochTimeInSeconds()
|
|
{
|
|
return Client.Instance.Utils.GetServerRealTime();
|
|
}
|
|
|
|
public static bool IsValid(UnityEngine.Object o)
|
|
{
|
|
return o;
|
|
}
|
|
|
|
[Conditional("VERIFY_COMPONENTS")]
|
|
public static void VerifyComponent<T>(T a, T b) where T : Component
|
|
{
|
|
if (a != b)
|
|
{
|
|
if (logVerify)
|
|
{
|
|
UnityEngine.Debug.LogErrorFormat("Components are not the same! {0} != {1}", (a != null) ? a.ToString() : "null", (b != null) ? b.ToString() : "null");
|
|
}
|
|
if (breakInVerify)
|
|
{
|
|
UnityEngine.Debug.DebugBreak();
|
|
}
|
|
}
|
|
}
|
|
|
|
[Conditional("VERIFY_COMPONENTS")]
|
|
public static void VerifyNullComponent(Component a)
|
|
{
|
|
if (a != null)
|
|
{
|
|
if (logVerify)
|
|
{
|
|
UnityEngine.Debug.LogErrorFormat("Components is not null! {0} != null", a.ToString());
|
|
}
|
|
if (breakInVerify)
|
|
{
|
|
UnityEngine.Debug.DebugBreak();
|
|
}
|
|
}
|
|
}
|
|
|
|
[Conditional("VERIFY_COMPONENTS")]
|
|
public static void VerifyNonNullComponent<T>(T a, string desc) where T : Component
|
|
{
|
|
if (a == null)
|
|
{
|
|
if (logVerify)
|
|
{
|
|
UnityEngine.Debug.LogErrorFormat("Component is null! {0}: {1}", typeof(T).ToString(), string.IsNullOrEmpty(desc) ? "" : desc);
|
|
}
|
|
if (breakInVerify)
|
|
{
|
|
UnityEngine.Debug.DebugBreak();
|
|
}
|
|
}
|
|
}
|
|
|
|
[Conditional("VERIFY_COMPONENTS")]
|
|
public static void VerifyComponent<T>(T a, GameObject b) where T : Component
|
|
{
|
|
_ = b != null;
|
|
}
|
|
|
|
[Conditional("VERIFY_COMPONENTS")]
|
|
public static void VerifyComponent<T, X>(T a, X b) where T : Component where X : Component
|
|
{
|
|
_ = b != null;
|
|
}
|
|
|
|
[Conditional("VERIFY_COMPONENTS")]
|
|
public static void VerifyObject(GameObject a, GameObject b)
|
|
{
|
|
if (a != b)
|
|
{
|
|
if (logVerify)
|
|
{
|
|
UnityEngine.Debug.LogErrorFormat("Objects are not the same! {0} != {1}", a.ToString(), b.ToString());
|
|
}
|
|
if (breakInVerify)
|
|
{
|
|
UnityEngine.Debug.DebugBreak();
|
|
}
|
|
}
|
|
}
|
|
|
|
[Conditional("VERIFY_COMPONENTS")]
|
|
public static void VerifyTeam(TeamIndex a, Component b)
|
|
{
|
|
if (a != TeamComponent.GetObjectTeam(b.gameObject))
|
|
{
|
|
if (logVerify)
|
|
{
|
|
UnityEngine.Debug.LogErrorFormat("Objects are not the same! {0} != {1}", a.ToString(), b.ToString());
|
|
}
|
|
if (breakInVerify)
|
|
{
|
|
UnityEngine.Debug.DebugBreak();
|
|
}
|
|
}
|
|
}
|
|
|
|
public static string BuildPrefabTransformPath(Transform root, Transform transform, bool appendCloneSuffix = false, bool includeRoot = false)
|
|
{
|
|
if (!root)
|
|
{
|
|
throw new ArgumentException("Value provided as 'root' is an invalid object.", "root");
|
|
}
|
|
if (!transform)
|
|
{
|
|
throw new ArgumentException("Value provided as 'transform' is an invalid object.", "transform");
|
|
}
|
|
try
|
|
{
|
|
Transform transform2 = transform;
|
|
while ((object)transform2 != root)
|
|
{
|
|
if (!transform2)
|
|
{
|
|
string arg = TakeResult();
|
|
throw new ArgumentException($"\"{arg}\" is not a child of \"{root}\".");
|
|
}
|
|
if (sharedStringStack.Count > 0)
|
|
{
|
|
sharedStringStack.Push("/");
|
|
}
|
|
sharedStringStack.Push(transform2.gameObject.name);
|
|
transform2 = transform2.parent;
|
|
}
|
|
if (includeRoot)
|
|
{
|
|
if (sharedStringStack.Count > 0)
|
|
{
|
|
sharedStringStack.Push("/");
|
|
}
|
|
sharedStringStack.Push(root.gameObject.name);
|
|
}
|
|
return TakeResult();
|
|
}
|
|
finally
|
|
{
|
|
sharedStringBuilder.Clear();
|
|
sharedStringStack.Clear();
|
|
}
|
|
string TakeResult()
|
|
{
|
|
while (sharedStringStack.Count > 0)
|
|
{
|
|
sharedStringBuilder.Append(sharedStringStack.Pop());
|
|
}
|
|
if (appendCloneSuffix)
|
|
{
|
|
sharedStringBuilder.Append(cloneString);
|
|
}
|
|
return sharedStringBuilder.Take();
|
|
}
|
|
}
|
|
|
|
public static int GetItemCountForTeam(TeamIndex teamIndex, ItemIndex itemIndex, bool requiresAlive, bool requiresConnected = true)
|
|
{
|
|
int num = 0;
|
|
ReadOnlyCollection<CharacterMaster> readOnlyInstancesList = CharacterMaster.readOnlyInstancesList;
|
|
int i = 0;
|
|
for (int count = readOnlyInstancesList.Count; i < count; i++)
|
|
{
|
|
CharacterMaster characterMaster = readOnlyInstancesList[i];
|
|
if (characterMaster.teamIndex == teamIndex && (!requiresAlive || characterMaster.hasBody) && (!requiresConnected || !characterMaster.playerCharacterMasterController || characterMaster.playerCharacterMasterController.isConnected))
|
|
{
|
|
num += characterMaster.inventory.GetItemCount(itemIndex);
|
|
}
|
|
}
|
|
return num;
|
|
}
|
|
|
|
public static int GetItemCountGlobal(ItemIndex itemIndex, bool requiresAlive, bool requiresConnected = true)
|
|
{
|
|
int num = 0;
|
|
ReadOnlyCollection<CharacterMaster> readOnlyInstancesList = CharacterMaster.readOnlyInstancesList;
|
|
int i = 0;
|
|
for (int count = readOnlyInstancesList.Count; i < count; i++)
|
|
{
|
|
CharacterMaster characterMaster = readOnlyInstancesList[i];
|
|
if ((!requiresAlive || characterMaster.hasBody) && (!requiresConnected || !characterMaster.playerCharacterMasterController || characterMaster.playerCharacterMasterController.isConnected))
|
|
{
|
|
num += characterMaster.inventory.GetItemCount(itemIndex);
|
|
}
|
|
}
|
|
return num;
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static void NullifyIfInvalid<T>(ref T objRef) where T : UnityEngine.Object
|
|
{
|
|
if ((object)objRef != null && !objRef)
|
|
{
|
|
objRef = null;
|
|
}
|
|
}
|
|
|
|
public static bool IsPrefab(GameObject gameObject)
|
|
{
|
|
if ((bool)gameObject)
|
|
{
|
|
return !gameObject.scene.IsValid();
|
|
}
|
|
return false;
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static uint IntToUintPlusOne(int value)
|
|
{
|
|
return (uint)(value + 1);
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static int UintToIntMinusOne(uint value)
|
|
{
|
|
return (int)(value - 1);
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static ulong LongToUlongPlusOne(long value)
|
|
{
|
|
return (ulong)(value + 1);
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static long UlongToLongMinusOne(ulong value)
|
|
{
|
|
return (long)(value - 1);
|
|
}
|
|
|
|
public static float GetExpAdjustedDropChancePercent(float baseChancePercent, GameObject characterBodyObject)
|
|
{
|
|
int num = 0;
|
|
DeathRewards component = characterBodyObject.GetComponent<DeathRewards>();
|
|
if ((bool)component)
|
|
{
|
|
num = component.spawnValue;
|
|
}
|
|
return baseChancePercent * Mathf.Log((float)num + 1f, 2f);
|
|
}
|
|
|
|
public static bool IsDontDestroyOnLoad(GameObject go)
|
|
{
|
|
return go.scene.name == "DontDestroyOnLoad";
|
|
}
|
|
}
|