Commit initial BossHealth, DamageNumbers, Horde, ThirdPerson mods
This commit is contained in:
1 parent
7bd44d1d99
commit
9c123865bc
176 files changed
+10367
No files matched your search
@@ -0,0 +1,485 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Skopje.ThirdPerson
|
||||
{
|
||||
public class ThirdPersonDriver : MonoBehaviour
|
||||
{
|
||||
void Update()
|
||||
{
|
||||
ThirdPersonRig.TickBody();
|
||||
}
|
||||
|
||||
void LateUpdate()
|
||||
{
|
||||
ThirdPersonRig.Apply(ThirdPersonRig.LocalCamera);
|
||||
}
|
||||
}
|
||||
|
||||
static class ThirdPersonRig
|
||||
{
|
||||
const float MoveThreshold = 0.2f;
|
||||
const float ExternalTurn = 35f;
|
||||
|
||||
static readonly List<Renderer> Hidden = new List<Renderer>();
|
||||
static readonly RaycastHit[] Hits = new RaycastHit[24];
|
||||
|
||||
internal static SkopjeFPSCamera LocalCamera;
|
||||
|
||||
static SkopjePlayer _player;
|
||||
static bool _holding;
|
||||
static bool _hasFacing;
|
||||
static Quaternion _facing;
|
||||
static Quaternion _incomingFacing;
|
||||
static bool _hasIncoming;
|
||||
static bool _hasLook;
|
||||
static Quaternion _look = Quaternion.identity;
|
||||
static bool _hasPlacement;
|
||||
static Vector3 _placedPos;
|
||||
static float _baseFov;
|
||||
static float _boom = 2.7f;
|
||||
static float _ads;
|
||||
static bool _capturedIk;
|
||||
static bool _aimWasEnabled;
|
||||
static bool _lookWasEnabled;
|
||||
static bool _followWasEnabled;
|
||||
static bool _disabledFollow;
|
||||
static float _nextScan;
|
||||
static int _errors;
|
||||
static bool _logged;
|
||||
|
||||
public static void OnClientStarted()
|
||||
{
|
||||
}
|
||||
|
||||
public static void OnClientStopped()
|
||||
{
|
||||
Release();
|
||||
_player = null;
|
||||
LocalCamera = null;
|
||||
}
|
||||
|
||||
public static void OnPlayerStarted(SkopjePlayer player)
|
||||
{
|
||||
if (player != null && player.IsOwner)
|
||||
_player = player;
|
||||
}
|
||||
|
||||
public static void OnPlayerStopped(SkopjePlayer player)
|
||||
{
|
||||
if (_player == player)
|
||||
{
|
||||
Release();
|
||||
_player = null;
|
||||
LocalCamera = null;
|
||||
}
|
||||
}
|
||||
|
||||
public static void Shutdown()
|
||||
{
|
||||
Release();
|
||||
_player = null;
|
||||
LocalCamera = null;
|
||||
}
|
||||
|
||||
public static void TickBody()
|
||||
{
|
||||
if (!CanControl(_player))
|
||||
{
|
||||
if (_holding)
|
||||
Release();
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
HoldPresentation(_player);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Fail(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Apply(SkopjeFPSCamera fps)
|
||||
{
|
||||
if (fps == null || !CanControl(fps.Player))
|
||||
return;
|
||||
|
||||
Camera cam = fps.mainCamera != null ? fps.mainCamera : Camera.main;
|
||||
if (cam == null)
|
||||
return;
|
||||
|
||||
LocalCamera = fps;
|
||||
if (_player == null)
|
||||
_player = fps.Player;
|
||||
|
||||
try
|
||||
{
|
||||
Place(fps, cam);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Fail(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static void RememberBody(SkopjeCharacterController controller, Quaternion currentRotation)
|
||||
{
|
||||
if (!CanControl(controller != null ? controller.Player : null))
|
||||
{
|
||||
_hasIncoming = false;
|
||||
return;
|
||||
}
|
||||
|
||||
_incomingFacing = FlatYaw(currentRotation);
|
||||
_hasIncoming = true;
|
||||
}
|
||||
|
||||
public static void HoldBodyFacing(SkopjeCharacterController controller, ref Quaternion currentRotation, float deltaTime)
|
||||
{
|
||||
if (!_hasIncoming || controller == null || !CanControl(controller.Player))
|
||||
return;
|
||||
|
||||
Quaternion held = _hasFacing ? _facing : _incomingFacing;
|
||||
if (!_hasFacing || Quaternion.Angle(held, _incomingFacing) > ExternalTurn)
|
||||
held = _incomingFacing;
|
||||
|
||||
if (ThirdPersonPlugin.FaceMovement.Value)
|
||||
{
|
||||
Vector3 move = controller.moveInputVector;
|
||||
move.y = 0f;
|
||||
if (move.sqrMagnitude > MoveThreshold * MoveThreshold)
|
||||
{
|
||||
float sharp = controller.OrientationSharpness;
|
||||
if (sharp < 0.01f)
|
||||
sharp = 12f;
|
||||
float blend = 1f - Mathf.Exp(-sharp * Mathf.Max(0f, deltaTime));
|
||||
held = Quaternion.Slerp(held, Quaternion.LookRotation(move.normalized, Vector3.up), blend);
|
||||
}
|
||||
}
|
||||
|
||||
_facing = FlatYaw(held);
|
||||
_hasFacing = true;
|
||||
currentRotation = _facing;
|
||||
}
|
||||
|
||||
static void Place(SkopjeFPSCamera fps, Camera cam)
|
||||
{
|
||||
Quaternion look = ReadLook(fps, cam);
|
||||
_look = look;
|
||||
_hasLook = true;
|
||||
|
||||
bool fresh = !_hasPlacement || (cam.transform.position - _placedPos).sqrMagnitude > 0.0004f;
|
||||
if (fresh)
|
||||
_baseFov = cam.fieldOfView;
|
||||
|
||||
float adsTarget = fps.adsMode ? 1f : 0f;
|
||||
_ads = Mathf.MoveTowards(_ads, adsTarget, Time.deltaTime / 0.12f);
|
||||
|
||||
float distance = Mathf.Lerp(Clamp(ThirdPersonPlugin.Distance.Value, 0.8f, 8f), Clamp(ThirdPersonPlugin.AdsDistance.Value, 0.6f, 6f), _ads);
|
||||
float shoulder = Mathf.Lerp(Clamp(ThirdPersonPlugin.Shoulder.Value, 0f, 2f), Clamp(ThirdPersonPlugin.AdsShoulder.Value, 0f, 1.5f), _ads);
|
||||
float height = Clamp(ThirdPersonPlugin.Height.Value, -1f, 2f);
|
||||
float boom = new Vector3(shoulder, height, -distance).magnitude;
|
||||
if (!_hasPlacement)
|
||||
_boom = boom;
|
||||
_boom = Mathf.Lerp(_boom, boom, 1f - Mathf.Exp(-16f * Time.deltaTime));
|
||||
|
||||
Vector3 pivot = Pivot(fps.Player);
|
||||
Vector3 offset = look * new Vector3(shoulder, height, -distance);
|
||||
if (offset.sqrMagnitude < 0.0001f)
|
||||
offset = look * Vector3.back;
|
||||
Vector3 dir = offset.normalized;
|
||||
float allowed = PullIn(fps.Player, pivot, dir, _boom);
|
||||
Vector3 camPos = pivot + dir * allowed;
|
||||
|
||||
Vector3 aim = AimPoint(fps.Player, pivot, look * Vector3.forward);
|
||||
Vector3 toAim = aim - camPos;
|
||||
Vector3 up = look * Vector3.up;
|
||||
if (toAim.sqrMagnitude < 0.0001f || Mathf.Abs(Vector3.Dot(toAim.normalized, up.normalized)) > 0.995f)
|
||||
cam.transform.rotation = look;
|
||||
else
|
||||
cam.transform.rotation = Quaternion.LookRotation(toAim, up);
|
||||
|
||||
cam.transform.position = camPos;
|
||||
cam.fieldOfView = _baseFov + Clamp(ThirdPersonPlugin.FovBonus.Value, 0f, 40f) * (1f - _ads);
|
||||
_placedPos = camPos;
|
||||
_hasPlacement = true;
|
||||
KeepBodyYaw(fps.Player);
|
||||
|
||||
if (!_logged)
|
||||
{
|
||||
_logged = true;
|
||||
ThirdPersonPlugin.LogSource.LogInfo("Right-shoulder camera is active. The body does not turn with the mouse.");
|
||||
}
|
||||
}
|
||||
|
||||
static void KeepBodyYaw(SkopjePlayer player)
|
||||
{
|
||||
if (!_hasFacing || player == null)
|
||||
return;
|
||||
|
||||
Transform body = player.transform;
|
||||
Vector3 up = body.up;
|
||||
Vector3 forward = Vector3.ProjectOnPlane(_facing * Vector3.forward, up);
|
||||
if (forward.sqrMagnitude < 0.0001f)
|
||||
return;
|
||||
|
||||
body.rotation = Quaternion.LookRotation(forward.normalized, up);
|
||||
}
|
||||
|
||||
static Quaternion ReadLook(SkopjeFPSCamera fps, Camera cam)
|
||||
{
|
||||
if (fps.VCamera != null && fps.VCamera.transform != cam.transform)
|
||||
return fps.VCamera.transform.rotation;
|
||||
if (fps.SocketTransform != null && fps.SocketTransform != cam.transform)
|
||||
return fps.SocketTransform.rotation;
|
||||
if (_hasLook && _hasPlacement && (cam.transform.position - _placedPos).sqrMagnitude < 0.0004f)
|
||||
return _look;
|
||||
return cam.transform.rotation;
|
||||
}
|
||||
|
||||
static Vector3 Pivot(SkopjePlayer player)
|
||||
{
|
||||
float height = Clamp(ThirdPersonPlugin.PivotHeight.Value, 0.4f, 2.4f);
|
||||
var body = player.SkopjeCharacterController;
|
||||
if (body != null)
|
||||
{
|
||||
if (body.standingHeight > 0.5f)
|
||||
height = Mathf.Min(height, body.standingHeight * 0.78f);
|
||||
float crouch = body.CrouchedHeightMult > 0.05f ? body.CrouchedHeightMult : 0.55f;
|
||||
height *= Mathf.Lerp(1f, crouch, Mathf.Clamp01(body.currentCrouch01));
|
||||
}
|
||||
|
||||
return player.transform.position + Vector3.up * height;
|
||||
}
|
||||
|
||||
static Vector3 AimPoint(SkopjePlayer player, Vector3 origin, Vector3 direction)
|
||||
{
|
||||
float reach = Clamp(ThirdPersonPlugin.AimDistance.Value, 5f, 200f);
|
||||
if (direction.sqrMagnitude < 0.0001f)
|
||||
direction = Vector3.forward;
|
||||
direction.Normalize();
|
||||
|
||||
int count = Physics.RaycastNonAlloc(origin, direction, Hits, reach, Physics.DefaultRaycastLayers, QueryTriggerInteraction.Ignore);
|
||||
float best = float.MaxValue;
|
||||
Vector3 point = origin + direction * reach;
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
if (Hits[i].collider == null || IsOwn(player, Hits[i].collider))
|
||||
continue;
|
||||
if (Hits[i].distance < best)
|
||||
{
|
||||
best = Hits[i].distance;
|
||||
point = Hits[i].point;
|
||||
}
|
||||
}
|
||||
|
||||
return point;
|
||||
}
|
||||
|
||||
static float PullIn(SkopjePlayer player, Vector3 origin, Vector3 direction, float distance)
|
||||
{
|
||||
const float radius = 0.18f;
|
||||
int count = Physics.SphereCastNonAlloc(origin, radius, direction, Hits, distance, Physics.DefaultRaycastLayers, QueryTriggerInteraction.Ignore);
|
||||
float best = distance;
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
if (Hits[i].collider == null || IsOwn(player, Hits[i].collider))
|
||||
continue;
|
||||
float room = Mathf.Max(0.35f, Hits[i].distance);
|
||||
if (room < best)
|
||||
best = room;
|
||||
}
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
static void HoldPresentation(SkopjePlayer player)
|
||||
{
|
||||
GameObject third = player.ThirdPerson;
|
||||
if (third != null && !third.activeSelf)
|
||||
third.SetActive(true);
|
||||
|
||||
GameObject pack = player.ThirdPersonBackpackParent;
|
||||
if (pack != null && !pack.activeSelf)
|
||||
pack.SetActive(true);
|
||||
|
||||
var anim = player.TPAnimationController;
|
||||
if (anim != null)
|
||||
{
|
||||
if (!_capturedIk)
|
||||
{
|
||||
_aimWasEnabled = anim.AimAtMotor != null && anim.AimAtMotor.enabled;
|
||||
_lookWasEnabled = anim.LookAtMotor != null && anim.LookAtMotor.enabled;
|
||||
_capturedIk = true;
|
||||
}
|
||||
|
||||
if (anim.AimAtMotor != null)
|
||||
anim.AimAtMotor.enabled = false;
|
||||
if (anim.LookAtMotor != null)
|
||||
anim.LookAtMotor.enabled = false;
|
||||
}
|
||||
|
||||
var follow = player.ThirdPersonFollowCam;
|
||||
if (follow != null && follow.Look != null && follow.Look.enabled)
|
||||
{
|
||||
_followWasEnabled = true;
|
||||
follow.Look.enabled = false;
|
||||
_disabledFollow = true;
|
||||
}
|
||||
|
||||
if (Time.unscaledTime >= _nextScan)
|
||||
{
|
||||
_nextScan = Time.unscaledTime + 0.25f;
|
||||
RebuildHidden(player);
|
||||
}
|
||||
|
||||
for (int i = 0; i < Hidden.Count; i++)
|
||||
{
|
||||
if (Hidden[i] != null)
|
||||
Hidden[i].forceRenderingOff = true;
|
||||
}
|
||||
|
||||
_holding = true;
|
||||
}
|
||||
|
||||
static void RebuildHidden(SkopjePlayer player)
|
||||
{
|
||||
var next = new List<Renderer>();
|
||||
Transform third = player.ThirdPerson != null ? player.ThirdPerson.transform : null;
|
||||
Collect(player.FirstPerson, third, next);
|
||||
|
||||
var weapons = player.WeaponsController;
|
||||
if (weapons != null)
|
||||
{
|
||||
if (weapons.Socket != null)
|
||||
Collect(weapons.Socket.gameObject, third, next);
|
||||
if (weapons.ThrowSocket != null)
|
||||
Collect(weapons.ThrowSocket.gameObject, third, next);
|
||||
}
|
||||
|
||||
for (int i = 0; i < Hidden.Count; i++)
|
||||
{
|
||||
Renderer old = Hidden[i];
|
||||
if (old != null && !next.Contains(old))
|
||||
old.forceRenderingOff = false;
|
||||
}
|
||||
|
||||
Hidden.Clear();
|
||||
Hidden.AddRange(next);
|
||||
}
|
||||
|
||||
static void Collect(GameObject root, Transform thirdPerson, List<Renderer> into)
|
||||
{
|
||||
if (root == null)
|
||||
return;
|
||||
if (thirdPerson != null && (root.transform == thirdPerson || root.transform.IsChildOf(thirdPerson)))
|
||||
return;
|
||||
|
||||
Renderer[] found = root.GetComponentsInChildren<Renderer>(true);
|
||||
for (int i = 0; i < found.Length; i++)
|
||||
{
|
||||
Renderer renderer = found[i];
|
||||
if (renderer == null)
|
||||
continue;
|
||||
if (thirdPerson != null && renderer.transform.IsChildOf(thirdPerson))
|
||||
continue;
|
||||
if (!into.Contains(renderer))
|
||||
into.Add(renderer);
|
||||
}
|
||||
}
|
||||
|
||||
static void Release()
|
||||
{
|
||||
for (int i = 0; i < Hidden.Count; i++)
|
||||
{
|
||||
if (Hidden[i] != null)
|
||||
Hidden[i].forceRenderingOff = false;
|
||||
}
|
||||
|
||||
Hidden.Clear();
|
||||
|
||||
if (_player != null)
|
||||
{
|
||||
var anim = _player.TPAnimationController;
|
||||
if (_capturedIk && anim != null)
|
||||
{
|
||||
if (anim.AimAtMotor != null)
|
||||
anim.AimAtMotor.enabled = _aimWasEnabled;
|
||||
if (anim.LookAtMotor != null)
|
||||
anim.LookAtMotor.enabled = _lookWasEnabled;
|
||||
}
|
||||
|
||||
if (_disabledFollow && _player.ThirdPersonFollowCam != null && _player.ThirdPersonFollowCam.Look != null)
|
||||
_player.ThirdPersonFollowCam.Look.enabled = _followWasEnabled;
|
||||
|
||||
try
|
||||
{
|
||||
_player.RefreshActiveModels();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Fail(ex);
|
||||
}
|
||||
}
|
||||
|
||||
_capturedIk = false;
|
||||
_disabledFollow = false;
|
||||
_holding = false;
|
||||
_hasFacing = false;
|
||||
_hasIncoming = false;
|
||||
_hasPlacement = false;
|
||||
_hasLook = false;
|
||||
_ads = 0f;
|
||||
_logged = false;
|
||||
}
|
||||
|
||||
static bool CanControl(SkopjePlayer player)
|
||||
{
|
||||
if (!ThirdPersonPlugin.Enabled.Value || player == null || !player.IsOwner)
|
||||
return false;
|
||||
if (player.IsDead || player.IsFallen || player.IsSpectating || player.IsPaused || player.InInventory)
|
||||
return false;
|
||||
if (player.InsideVehicle != null)
|
||||
return false;
|
||||
|
||||
var cine = player._cinematicController;
|
||||
if (cine != null && cine.PlayingCinematic != null && cine.PlayingCinematic.PlayingCinematic != null)
|
||||
return false;
|
||||
|
||||
return player.SkopjeFPSCamera != null;
|
||||
}
|
||||
|
||||
static bool IsOwn(SkopjePlayer player, Collider collider)
|
||||
{
|
||||
if (player == null || collider == null)
|
||||
return false;
|
||||
Transform transform = collider.transform;
|
||||
Transform root = player.transform;
|
||||
return transform == root || transform.IsChildOf(root);
|
||||
}
|
||||
|
||||
static Quaternion FlatYaw(Quaternion rotation)
|
||||
{
|
||||
Vector3 forward = Vector3.ProjectOnPlane(rotation * Vector3.forward, Vector3.up);
|
||||
if (forward.sqrMagnitude < 0.0001f)
|
||||
forward = Vector3.ProjectOnPlane(rotation * Vector3.up, Vector3.up);
|
||||
if (forward.sqrMagnitude < 0.0001f)
|
||||
forward = Vector3.forward;
|
||||
return Quaternion.LookRotation(forward.normalized, Vector3.up);
|
||||
}
|
||||
|
||||
static float Clamp(float value, float min, float max)
|
||||
{
|
||||
return Mathf.Clamp(value, min, max);
|
||||
}
|
||||
|
||||
static void Fail(Exception ex)
|
||||
{
|
||||
if (_errors++ < 5 && ThirdPersonPlugin.LogSource != null)
|
||||
ThirdPersonPlugin.LogSource.LogWarning("Third person failed: " + ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user