2021-04-26 14:30:21 +01:00
using OWML.Common ;
2021-04-29 18:30:45 +01:00
using QSB.Animation.NPC.WorldObjects ;
using QSB.ConversationSync ;
2021-04-26 14:30:21 +01:00
using QSB.Events ;
using QSB.Patches ;
using QSB.Player ;
using QSB.Utility ;
using QSB.WorldSync ;
2021-04-29 18:30:45 +01:00
using System.Linq ;
using System.Reflection ;
2021-04-26 14:30:21 +01:00
using UnityEngine ;
2021-04-29 18:30:45 +01:00
namespace QSB.Animation.NPC.Patches
2021-04-26 14:30:21 +01:00
{
public class CharacterAnimationPatches : QSBPatch
{
public override QSBPatchTypes Type = > QSBPatchTypes . OnClientConnect ;
public override void DoPatches ( )
{
2021-06-18 21:54:32 +01:00
Prefix ( nameof ( CharacterAnimController_OnAnimatorIK ) ) ;
Prefix ( nameof ( CharacterAnimController_OnZoneEntry ) ) ;
Prefix ( nameof ( CharacterAnimController_OnZoneExit ) ) ;
Prefix ( nameof ( FacePlayerWhenTalking_OnStartConversation ) ) ;
Prefix ( nameof ( CharacterDialogueTree_StartConversation ) ) ;
Prefix ( nameof ( CharacterDialogueTree_EndConversation ) ) ;
Prefix ( nameof ( KidRockController_Update ) ) ;
2021-04-26 14:30:21 +01:00
}
2021-06-18 21:54:32 +01:00
public static bool CharacterAnimController_OnAnimatorIK (
2021-04-26 14:30:21 +01:00
CharacterAnimController __instance ,
float ___headTrackingWeight ,
bool ___lookOnlyWhenTalking ,
bool ____playerInHeadZone ,
bool ____inConversation ,
ref float ____currentLookWeight ,
ref Vector3 ____currentLookTarget ,
DampedSpring3D ___lookSpring ,
Animator ____animator ,
CharacterDialogueTree ____dialogueTree )
{
2021-05-02 08:54:00 +01:00
if ( ! WorldObjectManager . AllReady )
{
return false ;
}
2021-04-26 14:30:21 +01:00
var playerId = ConversationManager . Instance . GetPlayerTalkingToTree ( ____dialogueTree ) ;
2021-04-29 20:59:25 +01:00
var player = QSBPlayerManager . GetPlayer ( playerId ) ;
2021-04-26 14:30:21 +01:00
var qsbObj = QSBWorldSync . GetWorldFromUnity < QSBCharacterAnimController , CharacterAnimController > ( __instance ) ; // TODO : maybe cache this somewhere... or assess how slow this is
2021-06-10 23:21:19 +01:00
PlayerInfo playerToUse = null ;
2021-04-26 14:30:21 +01:00
if ( ____inConversation )
{
if ( playerId = = uint . MaxValue )
{
DebugLog . DebugWrite ( $"Error - {__instance.name} is in conversation with a null player! Defaulting to active camera." , MessageType . Error ) ;
2021-04-29 20:59:25 +01:00
playerToUse = QSBPlayerManager . LocalPlayer ;
2021-04-26 14:30:21 +01:00
}
else
{
2021-04-29 20:59:25 +01:00
playerToUse = player . CameraBody = = null
? QSBPlayerManager . LocalPlayer
: player ;
2021-04-26 14:30:21 +01:00
}
}
2021-04-29 23:57:55 +01:00
else if ( ! ___lookOnlyWhenTalking & & qsbObj . GetPlayersInHeadZone ( ) . Count ! = 0 ) // TODO : maybe this would be more fun if characters looked between players at random times? :P
2021-04-26 14:30:21 +01:00
{
2021-04-29 20:59:25 +01:00
playerToUse = QSBPlayerManager . GetClosestPlayerToWorldPoint ( qsbObj . GetPlayersInHeadZone ( ) , __instance . transform . position ) ;
2021-04-26 14:30:21 +01:00
}
2021-06-10 23:21:19 +01:00
else if ( QSBPlayerManager . PlayerList . Count ! = 0 )
2021-04-26 14:30:21 +01:00
{
2021-04-29 20:59:25 +01:00
playerToUse = QSBPlayerManager . GetClosestPlayerToWorldPoint ( __instance . transform . position , true ) ;
2021-04-26 14:30:21 +01:00
}
2021-06-19 11:26:05 +01:00
var localPosition = playerToUse ! = null
? ____animator . transform . InverseTransformPoint ( playerToUse . CameraBody . transform . position )
2021-06-10 23:21:19 +01:00
: Vector3 . zero ;
2021-04-26 14:30:21 +01:00
var targetWeight = ___headTrackingWeight ;
if ( ___lookOnlyWhenTalking )
{
2021-06-19 11:26:05 +01:00
if ( ! ____inConversation
| | qsbObj . GetPlayersInHeadZone ( ) . Count = = 0
2021-04-29 20:59:25 +01:00
| | ! qsbObj . GetPlayersInHeadZone ( ) . Contains ( playerToUse ) )
2021-04-26 14:30:21 +01:00
{
targetWeight * = 0 ;
}
}
else
{
2021-06-19 11:26:05 +01:00
if ( qsbObj . GetPlayersInHeadZone ( ) . Count = = 0
2021-04-29 20:59:25 +01:00
| | ! qsbObj . GetPlayersInHeadZone ( ) . Contains ( playerToUse ) )
2021-04-26 14:30:21 +01:00
{
targetWeight * = 0 ;
}
}
____currentLookWeight = Mathf . Lerp ( ____currentLookWeight , targetWeight , Time . deltaTime * 2f ) ;
____currentLookTarget = ___lookSpring . Update ( ____currentLookTarget , localPosition , Time . deltaTime ) ;
____animator . SetLookAtPosition ( ____animator . transform . TransformPoint ( ____currentLookTarget ) ) ;
____animator . SetLookAtWeight ( ____currentLookWeight ) ;
return false ;
}
2021-06-18 21:54:32 +01:00
public static bool CharacterAnimController_OnZoneExit ( CharacterAnimController __instance )
2021-04-26 14:30:21 +01:00
{
var qsbObj = QSBWorldSync . GetWorldFromUnity < QSBCharacterAnimController , CharacterAnimController > ( __instance ) ;
QSBEventManager . FireEvent ( EventNames . QSBExitHeadZone , qsbObj . ObjectId ) ;
return false ;
}
2021-06-18 21:54:32 +01:00
public static bool CharacterAnimController_OnZoneEntry ( CharacterAnimController __instance )
2021-04-26 14:30:21 +01:00
{
var qsbObj = QSBWorldSync . GetWorldFromUnity < QSBCharacterAnimController , CharacterAnimController > ( __instance ) ;
QSBEventManager . FireEvent ( EventNames . QSBEnterHeadZone , qsbObj . ObjectId ) ;
return false ;
}
2021-04-29 18:30:45 +01:00
public static bool FacePlayerWhenTalking_OnStartConversation (
FacePlayerWhenTalking __instance ,
CharacterDialogueTree ____dialogueTree )
{
var playerId = ConversationManager . Instance . GetPlayerTalkingToTree ( ____dialogueTree ) ;
if ( playerId = = uint . MaxValue )
{
DebugLog . ToConsole ( $"Error - No player talking to {____dialogueTree.name}!" , MessageType . Error ) ;
return false ;
}
2021-06-18 22:38:32 +01:00
2021-04-29 18:30:45 +01:00
var player = QSBPlayerManager . GetPlayer ( playerId ) ;
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 . GetType ( ) . GetMethod ( "FaceLocalRotation" , BindingFlags . NonPublic | BindingFlags . Instance ) . Invoke ( __instance , new object [ ] { lhs * __instance . transform . localRotation } ) ;
return false ;
}
public static bool CharacterDialogueTree_StartConversation ( CharacterDialogueTree __instance )
{
var allNpcAnimControllers = QSBWorldSync . GetWorldObjects < INpcAnimController > ( ) ;
var ownerOfThis = allNpcAnimControllers . FirstOrDefault ( x = > x . GetDialogueTree ( ) = = __instance ) ;
if ( ownerOfThis = = default )
{
return true ;
}
2021-06-18 22:38:32 +01:00
2021-04-29 18:30:45 +01:00
var id = QSBWorldSync . GetIdFromTypeSubset ( ownerOfThis ) ;
QSBEventManager . FireEvent ( EventNames . QSBNpcAnimEvent , AnimationEvent . StartConversation , id ) ;
return true ;
}
public static bool CharacterDialogueTree_EndConversation ( CharacterDialogueTree __instance )
{
var allNpcAnimControllers = QSBWorldSync . GetWorldObjects < INpcAnimController > ( ) ;
var ownerOfThis = allNpcAnimControllers . FirstOrDefault ( x = > x . GetDialogueTree ( ) = = __instance ) ;
if ( ownerOfThis = = default )
{
return true ;
}
2021-06-18 22:38:32 +01:00
2021-04-29 18:30:45 +01:00
var id = QSBWorldSync . GetIdFromTypeSubset ( ownerOfThis ) ;
QSBEventManager . FireEvent ( EventNames . QSBNpcAnimEvent , AnimationEvent . EndConversation , id ) ;
return true ;
}
2021-04-29 20:59:25 +01:00
public static bool KidRockController_Update (
KidRockController __instance ,
bool ____throwingRock ,
CharacterDialogueTree ____dialogueTree ,
float ____nextThrowTime )
{
2021-05-02 08:54:00 +01:00
if ( ! WorldObjectManager . AllReady )
{
return true ;
}
2021-06-18 22:38:32 +01:00
2021-04-29 20:59:25 +01:00
var qsbObj = QSBWorldSync . GetWorldObjects < QSBCharacterAnimController > ( ) . First ( x = > x . GetDialogueTree ( ) = = ____dialogueTree ) ;
if ( ! ____throwingRock & & ! qsbObj . InConversation ( ) & & Time . time > ____nextThrowTime )
{
__instance . GetType ( ) . GetMethod ( "StartRockThrow" , BindingFlags . NonPublic | BindingFlags . Instance ) . Invoke ( __instance , null ) ;
}
2021-06-18 22:38:32 +01:00
2021-04-29 20:59:25 +01:00
return false ;
}
2021-04-26 14:30:21 +01:00
}
}