2021-10-15 20:06:51 +00:00
using HarmonyLib ;
using OWML.Common ;
2021-12-26 07:03:23 +00:00
using QSB.Animation.NPC.Messages ;
2021-04-29 17:30:45 +00:00
using QSB.Animation.NPC.WorldObjects ;
using QSB.ConversationSync ;
2021-12-23 21:49:04 +00:00
using QSB.Messaging ;
2021-04-26 13:30:21 +00:00
using QSB.Patches ;
using QSB.Player ;
2022-01-13 04:58:38 +00:00
using QSB.TriggerSync.WorldObjects ;
2021-04-26 13:30:21 +00:00
using QSB.Utility ;
using QSB.WorldSync ;
2021-04-29 17:30:45 +00:00
using System.Linq ;
2021-04-26 13:30:21 +00:00
using UnityEngine ;
2022-02-27 12:40:44 +00:00
namespace QSB.Animation.NPC.Patches
2021-04-26 13:30:21 +00:00
{
2022-02-27 12:40:44 +00:00
[HarmonyPatch]
public class CharacterAnimationPatches : QSBPatch
2022-02-25 06:04:54 +00:00
{
2022-02-27 12:40:44 +00:00
public override QSBPatchTypes Type = > QSBPatchTypes . OnClientConnect ;
[HarmonyPrefix]
[HarmonyPatch(typeof(CharacterAnimController), nameof(CharacterAnimController.OnAnimatorIK))]
public static bool AnimatorIKReplacement (
CharacterAnimController __instance )
2021-04-26 13:30:21 +00:00
{
2022-02-27 12:40:44 +00:00
if ( ! QSBWorldSync . AllObjectsReady | | ConversationManager . Instance = = null )
{
return true ;
}
2021-04-26 13:30:21 +00:00
2022-02-27 12:40:44 +00:00
var playerId = ConversationManager . Instance . GetPlayerTalkingToTree ( __instance . _dialogueTree ) ;
var player = QSBPlayerManager . GetPlayer ( playerId ) ;
2022-01-13 12:13:47 +00:00
2022-02-27 12:40:44 +00:00
if ( __instance . playerTrackingZone = = null )
{
return true ;
}
2022-01-13 12:13:47 +00:00
2022-02-27 12:40:44 +00:00
var qsbObj = __instance . playerTrackingZone . GetWorldObject < QSBCharacterTrigger > ( ) ; // OPTIMIZE : maybe cache this somewhere... or assess how slow this is
2021-04-26 13:30:21 +00:00
2022-02-27 12:40:44 +00:00
PlayerInfo playerToUse = null ;
if ( __instance . _inConversation )
2021-04-26 13:30:21 +00:00
{
2022-02-27 12:40:44 +00:00
if ( playerId = = uint . MaxValue )
{
DebugLog . ToConsole ( $"Error - {__instance.name} is in conversation with a null player! Defaulting to active camera." , MessageType . Error ) ;
playerToUse = QSBPlayerManager . LocalPlayer ;
}
else
{
playerToUse = player . CameraBody = = null
? QSBPlayerManager . LocalPlayer
: player ;
}
2021-04-26 13:30:21 +00:00
}
2022-02-27 12:40:44 +00:00
else if ( ! __instance . lookOnlyWhenTalking & & qsbObj . Occupants . Count ! = 0 ) // IDEA : maybe this would be more fun if characters looked between players at random times? :P
2021-04-26 13:30:21 +00:00
{
2022-02-27 12:40:44 +00:00
playerToUse = QSBPlayerManager . GetClosestPlayerToWorldPoint ( qsbObj . Occupants , __instance . transform . position ) ;
}
else if ( QSBPlayerManager . PlayerList . Count ! = 0 )
{
playerToUse = QSBPlayerManager . GetClosestPlayerToWorldPoint ( __instance . transform . position , true ) ;
2021-04-26 13:30:21 +00:00
}
2022-02-27 12:40:44 +00:00
var localPosition = playerToUse ! = null
? __instance . _animator . transform . InverseTransformPoint ( playerToUse . CameraBody . transform . position )
: Vector3 . zero ;
2021-04-26 13:30:21 +00:00
2022-02-27 12:40:44 +00:00
var targetWeight = __instance . headTrackingWeight ;
if ( __instance . lookOnlyWhenTalking )
2021-04-26 13:30:21 +00:00
{
2022-02-27 12:40:44 +00:00
if ( ! __instance . _inConversation
| | qsbObj . Occupants . Count = = 0
| | ! qsbObj . Occupants . Contains ( playerToUse ) )
{
targetWeight * = 0 ;
}
2021-04-26 13:30:21 +00:00
}
2022-02-27 12:40:44 +00:00
else
2021-04-29 17:30:45 +00:00
{
2022-02-27 12:40:44 +00:00
if ( qsbObj . Occupants . Count = = 0
| | ! qsbObj . Occupants . Contains ( playerToUse ) )
{
targetWeight * = 0 ;
}
2021-04-29 17:30:45 +00:00
}
2021-06-18 21:38:32 +00:00
2022-02-27 12:40:44 +00:00
__instance . _currentLookWeight = Mathf . Lerp ( __instance . _currentLookWeight , targetWeight , Time . deltaTime * 2f ) ;
__instance . _currentLookTarget = __instance . lookSpring . Update ( __instance . _currentLookTarget , localPosition , Time . deltaTime ) ;
__instance . _animator . SetLookAtPosition ( __instance . _animator . transform . TransformPoint ( __instance . _currentLookTarget ) ) ;
__instance . _animator . SetLookAtWeight ( __instance . _currentLookWeight ) ;
return false ;
2021-04-29 17:30:45 +00:00
2022-02-27 12:40:44 +00:00
}
2021-04-29 17:30:45 +00:00
2022-02-27 12:40:44 +00:00
[HarmonyPrefix]
[HarmonyPatch(typeof(FacePlayerWhenTalking), nameof(FacePlayerWhenTalking.OnStartConversation))]
public static bool OnStartConversation ( FacePlayerWhenTalking __instance )
2022-02-25 06:04:54 +00:00
{
2022-02-27 12:40:44 +00:00
var playerId = ConversationManager . Instance . GetPlayerTalkingToTree ( __instance . _dialogueTree ) ;
if ( playerId = = uint . MaxValue )
{
DebugLog . ToConsole ( $"Error - No player talking to {__instance._dialogueTree.name}!" , MessageType . Error ) ;
return false ;
}
2021-04-29 17:30:45 +00:00
2022-02-27 12:40:44 +00:00
var player = QSBPlayerManager . GetPlayer ( playerId ) ;
2022-02-25 06:04:54 +00:00
2022-02-27 12:40:44 +00:00
var distance = player . Body . transform . position - __instance . transform . position ;
var vector2 = distance - Vector3 . Project ( distance , __instance . transform . up ) ;
var angle = Vector3 . Angle ( __instance . transform . forward , vector2 ) * Mathf . Sign ( Vector3 . Dot ( vector2 , __instance . transform . right ) ) ;
var axis = __instance . transform . parent . InverseTransformDirection ( __instance . transform . up ) ;
var lhs = Quaternion . AngleAxis ( angle , axis ) ;
__instance . FaceLocalRotation ( lhs * __instance . transform . localRotation ) ;
2021-06-18 21:38:32 +00:00
2022-02-27 12:40:44 +00:00
return false ;
}
2022-02-25 06:04:54 +00:00
2022-02-27 12:40:44 +00:00
[HarmonyPrefix]
[HarmonyPatch(typeof(CharacterDialogueTree), nameof(CharacterDialogueTree.StartConversation))]
public static bool StartConversation ( CharacterDialogueTree __instance )
2022-02-25 06:04:54 +00:00
{
2022-02-27 12:40:44 +00:00
var allNpcAnimControllers = QSBWorldSync . GetWorldObjects < INpcAnimController > ( ) ;
var ownerOfThis = allNpcAnimControllers . FirstOrDefault ( x = > x . GetDialogueTree ( ) = = __instance ) ;
if ( ownerOfThis = = default )
{
return true ;
}
ownerOfThis . SendMessage ( new NpcAnimationMessage ( true ) ) ;
2021-04-29 17:30:45 +00:00
return true ;
}
2022-02-27 12:40:44 +00:00
[HarmonyPrefix]
[HarmonyPatch(typeof(CharacterDialogueTree), nameof(CharacterDialogueTree.EndConversation))]
public static bool EndConversation ( CharacterDialogueTree __instance )
2022-02-25 06:04:54 +00:00
{
2022-02-27 12:40:44 +00:00
var allNpcAnimControllers = QSBWorldSync . GetWorldObjects < INpcAnimController > ( ) ;
var ownerOfThis = allNpcAnimControllers . FirstOrDefault ( x = > x . GetDialogueTree ( ) = = __instance ) ;
if ( ownerOfThis = = default )
{
return true ;
}
ownerOfThis . SendMessage ( new NpcAnimationMessage ( false ) ) ;
2021-04-29 17:30:45 +00:00
return true ;
}
2021-04-29 19:59:25 +00:00
2022-02-27 12:40:44 +00:00
[HarmonyPrefix]
[HarmonyPatch(typeof(KidRockController), nameof(KidRockController.Update))]
public static bool UpdateReplacement ( KidRockController __instance )
2022-02-25 06:04:54 +00:00
{
2022-02-27 12:40:44 +00:00
if ( ! QSBWorldSync . AllObjectsReady )
{
return true ;
}
2021-04-29 19:59:25 +00:00
2022-02-27 12:40:44 +00:00
var qsbObj = QSBWorldSync . GetWorldObjects < QSBCharacterAnimController > ( ) . First ( x = > x . GetDialogueTree ( ) = = __instance . _dialogueTree ) ;
2021-06-18 21:38:32 +00:00
2022-02-27 12:40:44 +00:00
if ( ! __instance . _throwingRock & & ! qsbObj . InConversation ( ) & & Time . time > __instance . _nextThrowTime )
{
__instance . StartRockThrow ( ) ;
}
2022-02-25 06:04:54 +00:00
2022-02-27 12:40:44 +00:00
return false ;
}
2021-04-26 13:30:21 +00:00
}
}