From 9b5392d3a13e00d880e895522c19ef1e453804b0 Mon Sep 17 00:00:00 2001 From: Nikolay Korolev Date: Sat, 29 Jun 2019 14:38:37 +0300 Subject: [PATCH 1/6] ProcessPedUpdate --- src/World.cpp | 1 + src/World.h | 3 +++ src/control/Replay.cpp | 43 +++++++++++++++++++++++++++++++++++--- src/control/Replay.h | 5 ++--- src/entities/PlayerPed.cpp | 5 +++++ src/entities/PlayerPed.h | 2 ++ src/math/Matrix.h | 20 ++++++++++++++++++ 7 files changed, 73 insertions(+), 6 deletions(-) create mode 100644 src/entities/PlayerPed.cpp diff --git a/src/World.cpp b/src/World.cpp index 0a83c595..05791525 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -8,6 +8,7 @@ #include "World.h" WRAPPER void CWorld::Add(CEntity *entity) { EAXJMP(0x4AE930); } +WRAPPER void CWorld::Remove(CEntity *entity) { EAXJMP(0x4AE9D0); } CPtrList *CWorld::ms_bigBuildingsList = (CPtrList*)0x6FAB60; CPtrList &CWorld::ms_listMovingEntityPtrs = *(CPtrList*)0x8F433C; diff --git a/src/World.h b/src/World.h index e3a6a8f2..d88448fb 100644 --- a/src/World.h +++ b/src/World.h @@ -67,6 +67,7 @@ public: static bool &bForceProcessControl; static bool &bProcessCutsceneOnly; + static void Remove(CEntity *entity); static void Add(CEntity *entity); static CSector *GetSector(int x, int y) { return &ms_aSectors[y][x]; } @@ -103,6 +104,8 @@ public: static int GetSectorIndexY(float f) { return (int)GetSectorY(f); } static float GetWorldX(int x) { return x*SECTOR_SIZE_X + WORLD_MIN_X; } static float GetWorldY(int y) { return y*SECTOR_SIZE_Y + WORLD_MIN_Y; } + + static void Remove(void); }; class CPlayerPed; diff --git a/src/control/Replay.cpp b/src/control/Replay.cpp index 2e0f07ee..a2a47295 100644 --- a/src/control/Replay.cpp +++ b/src/control/Replay.cpp @@ -165,8 +165,6 @@ void CReplay::Init(void) bDoLoadSceneWhenDone = false; } -WRAPPER void CReplay::EmptyReplayBuffer(void) { EAXJMP(0x595BD0); } - void CReplay::DisableReplays(void) { bReplayEnabled = false; @@ -406,7 +404,46 @@ void CReplay::StoreDetailedPedAnimation(CPed *ped, CStoredDetailedAnimationState } } #endif +#if 0 WRAPPER void CReplay::ProcessPedUpdate(CPed *ped, float interpolation, CAddressInReplayBuffer *buffer) { EAXJMP(0x594050); } +#else +void CReplay::ProcessPedUpdate(CPed *ped, float interpolation, CAddressInReplayBuffer *buffer) +{ + tPedUpdatePacket *pp = (tPedUpdatePacket*)&buffer->m_pBase[buffer->m_nOffset]; + if (ped){ + ped->m_fRotationCur = pp->heading * M_PI / 128.0f; + ped->m_fRotationDest = pp->heading * M_PI / 128.0f; + CMatrix ped_matrix; + float coeff = 1.0f - interpolation; + pp->matrix.DecompressIntoFullMatrix(ped_matrix); + ped->GetMatrix() = ped->GetMatrix() * CMatrix(coeff); + *ped->GetMatrix().GetPosition() *= coeff; + ped->GetMatrix() += CMatrix(coeff) * ped_matrix; + if (pp->vehicle_index) { + ped->m_pMyVehicle = CPools::GetVehiclePool()->GetSlot(pp->vehicle_index - 1); + ped->bInVehicle = pp->vehicle_index; + } + else { + ped->m_pMyVehicle = nil; + ped->bInVehicle = false; + } + if (pp->assoc_group_id != ped->m_animGroup) { + ped->m_animGroup = (AssocGroupId)pp->assoc_group_id; + if (ped->IsPlayer()) + ((CPlayerPed*)ped)->ReApplyMoveAnims(); + } + RetrievePedAnimation(ped, &pp->anim_state); + ped->RemoveWeaponModel(-1); + if (pp->weapon_model != -1) + ped->AddWeaponModel(pp->weapon_model); + CWorld::Remove(ped); + CWorld::Add(ped); + }else{ + debug("Replay:Ped wasn't there\n"); + } + buffer->m_nOffset += sizeof(tPedUpdatePacket); +} +#endif WRAPPER void CReplay::RetrievePedAnimation(CPed *ped, CStoredAnimationState *state) { EAXJMP(0x5942A0); } WRAPPER void CReplay::RetrieveDetailedPedAnimation(CPed *ped, CStoredDetailedAnimationState *state) { EAXJMP(0x5944B0); } WRAPPER void CReplay::PlaybackThisFrame(void) { EAXJMP(0x5946B0); } @@ -453,7 +490,7 @@ void CReplay::StoreCarUpdate(CVehicle *vehicle, int id) WRAPPER void CReplay::ProcessCarUpdate(CVehicle *vehicle, float interpolation, CAddressInReplayBuffer *buffer) { EAXJMP(0x594D10); } WRAPPER bool CReplay::PlayBackThisFrameInterpolation(CAddressInReplayBuffer *buffer, float interpolation, uint32 *pTimer) { EAXJMP(0x595240); } WRAPPER void CReplay::FinishPlayback(void) { EAXJMP(0x595B20); } -WRAPPER void CReplay::Shutdown(void) { EAXJMP(0x595BD0); } +WRAPPER void CReplay::EmptyReplayBuffer(void) { EAXJMP(0x595BD0); } WRAPPER void CReplay::ProcessReplayCamera(void) { EAXJMP(0x595C40); } #if 0 diff --git a/src/control/Replay.h b/src/control/Replay.h index c4f3b1a2..0a65c638 100644 --- a/src/control/Replay.h +++ b/src/control/Replay.h @@ -155,7 +155,7 @@ class CReplay int8 vehicle_index; CStoredAnimationState anim_state; CCompressedMatrixNotAligned matrix; - uint8 assoc_group_id; + int8 assoc_group_id; uint8 weapon_model; }; static_assert(sizeof(tPedUpdatePacket) == 40, "tPedUpdatePacket: error"); @@ -244,12 +244,11 @@ private: public: static void Init(void); - static void EmptyReplayBuffer(void); static void DisableReplays(void); static void EnableReplays(void); static void Update(void); static void FinishPlayback(void); - static void Shutdown(void); + static void EmptyReplayBuffer(void); static void Display(void); static void TriggerPlayback(uint8 cam_mode, float cam_x, float cam_y, float cam_z, bool load_scene); static void StreamAllNecessaryCarsAndPeds(void); diff --git a/src/entities/PlayerPed.cpp b/src/entities/PlayerPed.cpp new file mode 100644 index 00000000..2136d3ad --- /dev/null +++ b/src/entities/PlayerPed.cpp @@ -0,0 +1,5 @@ +#include "common.h" +#include "patcher.h" +#include "PlayerPed.h" + +WRAPPER void CPlayerPed::ReApplyMoveAnims(void) { EAXJMP(0x4F07C0); } \ No newline at end of file diff --git a/src/entities/PlayerPed.h b/src/entities/PlayerPed.h index 23e7dae5..d268f61b 100644 --- a/src/entities/PlayerPed.h +++ b/src/entities/PlayerPed.h @@ -38,6 +38,8 @@ public: int32 field_1488[6]; float field_1512; float m_fFPSMoveHeading; + + void ReApplyMoveAnims(void); }; static_assert(sizeof(CPlayerPed) == 0x5F0, "CPlayerPed: error"); diff --git a/src/math/Matrix.h b/src/math/Matrix.h index e2e5394e..bbdc6a70 100644 --- a/src/math/Matrix.h +++ b/src/math/Matrix.h @@ -20,6 +20,11 @@ public: m_attachment = nil; Attach(matrix, owner); } + CMatrix(float scale){ + m_attachment = nil; + m_hasRwMatrix = false; + SetScale(scale); + } ~CMatrix(void){ if(m_hasRwMatrix && m_attachment) RwMatrixDestroy(m_attachment); @@ -57,6 +62,21 @@ public: if(m_attachment) UpdateRW(); } + CMatrix& operator+=(CMatrix const &rhs){ + m_matrix.right.x += rhs.m_matrix.right.x; + m_matrix.up.x += rhs.m_matrix.up.x; + m_matrix.at.x += rhs.m_matrix.at.x; + m_matrix.right.y += rhs.m_matrix.right.y; + m_matrix.up.y += rhs.m_matrix.up.y; + m_matrix.at.y += rhs.m_matrix.at.y; + m_matrix.right.z += rhs.m_matrix.right.z; + m_matrix.up.z += rhs.m_matrix.up.z; + m_matrix.at.z += rhs.m_matrix.at.z; + m_matrix.pos.x += rhs.m_matrix.pos.x; + m_matrix.pos.y += rhs.m_matrix.pos.y; + m_matrix.pos.y += rhs.m_matrix.pos.z; + return *this; + } CVector *GetPosition(void){ return (CVector*)&m_matrix.pos; } CVector *GetRight(void) { return (CVector*)&m_matrix.right; } From 62cfcd5b2709e926d4a53b20bbc366ab5bb5b5ff Mon Sep 17 00:00:00 2001 From: Nikolay Korolev Date: Sat, 29 Jun 2019 15:19:31 +0300 Subject: [PATCH 2/6] RetrievePedAnimation --- src/control/Replay.cpp | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src/control/Replay.cpp b/src/control/Replay.cpp index a2a47295..25fab615 100644 --- a/src/control/Replay.cpp +++ b/src/control/Replay.cpp @@ -444,7 +444,48 @@ void CReplay::ProcessPedUpdate(CPed *ped, float interpolation, CAddressInReplayB buffer->m_nOffset += sizeof(tPedUpdatePacket); } #endif + +#if 0 WRAPPER void CReplay::RetrievePedAnimation(CPed *ped, CStoredAnimationState *state) { EAXJMP(0x5942A0); } +#else +void CReplay::RetrievePedAnimation(CPed *ped, CStoredAnimationState *state) +{ + CAnimBlendAssociation* anim1 = CAnimManager::BlendAnimation( + (RpClump*)ped->m_rwObject, + (state->animId > 3) ? ped->m_animGroup : ASSOCGRP_STD, + (AnimationId)state->animId, 100.0f); + anim1->SetCurrentTime(state->time * 4.0f / 255.0f); + anim1->speed = state->speed * 3.0f / 255.0f; + anim1->SetBlend(1.0f, 1.0f); + anim1->callbackType = CAnimBlendAssociation::CB_NONE; + if (state->blendAmount && state->secAnimId){ + float time = state->secTime * 4.0f / 255.0f; + float speed = state->secSpeed * 3.0f / 255.0f; + float blend = state->blendAmount * 2.0f / 255.0f; + CAnimBlendAssociation* anim2 = CAnimManager::BlendAnimation( + (RpClump*)ped->m_rwObject, + (state->secAnimId > 3) ? ped->m_animGroup : ASSOCGRP_STD, + (AnimationId)state->secAnimId, 100.0f); + anim2->SetCurrentTime(time); + anim2->speed = speed; + anim2->SetBlend(blend, 1.0f); + anim2->callbackType = CAnimBlendAssociation::CB_NONE; + } + RpAnimBlendClumpRemoveAssociations((RpClump*)ped->m_rwObject, 0x10); + if (state->partAnimId){ + float time = state->partAnimTime * 4.0f / 255.0f; + float speed = state->partAnimSpeed * 3.0f / 255.0f; + float blend = state->partBlendAmount * 2.0f / 255.0f; + if (blend > 0.0f && state->partAnimId != ANIM_IDLE_STANCE){ + CAnimBlendAssociation* anim3 = CAnimManager::BlendAnimation( + (RpClump*)ped->m_rwObject, ASSOCGRP_STD, (AnimationId)state->partAnimId, 1000.0f); + anim3->SetCurrentTime(time); + anim3->speed = speed; + anim3->blendDelta = 0.0f; // is it correct? + } + } +} +#endif WRAPPER void CReplay::RetrieveDetailedPedAnimation(CPed *ped, CStoredDetailedAnimationState *state) { EAXJMP(0x5944B0); } WRAPPER void CReplay::PlaybackThisFrame(void) { EAXJMP(0x5946B0); } From ad76379eba3084c15183baaa4cd39192e9a2be7c Mon Sep 17 00:00:00 2001 From: Nikolay Korolev Date: Sat, 29 Jun 2019 18:01:43 +0300 Subject: [PATCH 3/6] more replay stuff, bug fix --- src/control/Replay.cpp | 72 +++++++++++++++++++++++++++++++++++------- src/control/Replay.h | 2 ++ src/math/Matrix.h | 2 +- 3 files changed, 63 insertions(+), 13 deletions(-) diff --git a/src/control/Replay.cpp b/src/control/Replay.cpp index 25fab615..7eb19c79 100644 --- a/src/control/Replay.cpp +++ b/src/control/Replay.cpp @@ -371,7 +371,7 @@ void CReplay::StoreDetailedPedAnimation(CPed *ped, CStoredDetailedAnimationState state->aFunctionCallbackID[i] = 0; } }else{ - state->aAnimId[i] = 173; /* TODO: enum */ + state->aAnimId[i] = NUM_ANIMS; state->aCurTime[i] = 0; state->aSpeed[i] = 85; state->aFunctionCallbackID[i] = 0; @@ -395,7 +395,7 @@ void CReplay::StoreDetailedPedAnimation(CPed *ped, CStoredDetailedAnimationState } } else { - state->aAnimId2[i] = 173; /* TODO: enum */ + state->aAnimId2[i] = NUM_ANIMS; state->aCurTime2[i] = 0; state->aSpeed2[i] = 85; state->aFunctionCallbackID2[i] = 0; @@ -414,11 +414,10 @@ void CReplay::ProcessPedUpdate(CPed *ped, float interpolation, CAddressInReplayB ped->m_fRotationCur = pp->heading * M_PI / 128.0f; ped->m_fRotationDest = pp->heading * M_PI / 128.0f; CMatrix ped_matrix; - float coeff = 1.0f - interpolation; pp->matrix.DecompressIntoFullMatrix(ped_matrix); - ped->GetMatrix() = ped->GetMatrix() * CMatrix(coeff); - *ped->GetMatrix().GetPosition() *= coeff; - ped->GetMatrix() += CMatrix(coeff) * ped_matrix; + ped->GetMatrix() = ped->GetMatrix() * CMatrix(1.0f - interpolation); + *ped->GetMatrix().GetPosition() *= (1.0f - interpolation); + ped->GetMatrix() += CMatrix(interpolation) * ped_matrix; if (pp->vehicle_index) { ped->m_pMyVehicle = CPools::GetVehiclePool()->GetSlot(pp->vehicle_index - 1); ped->bInVehicle = pp->vehicle_index; @@ -429,12 +428,12 @@ void CReplay::ProcessPedUpdate(CPed *ped, float interpolation, CAddressInReplayB } if (pp->assoc_group_id != ped->m_animGroup) { ped->m_animGroup = (AssocGroupId)pp->assoc_group_id; - if (ped->IsPlayer()) + if (ped == FindPlayerPed()) ((CPlayerPed*)ped)->ReApplyMoveAnims(); } RetrievePedAnimation(ped, &pp->anim_state); ped->RemoveWeaponModel(-1); - if (pp->weapon_model != -1) + if (pp->weapon_model != (uint8)-1) ped->AddWeaponModel(pp->weapon_model); CWorld::Remove(ped); CWorld::Add(ped); @@ -452,7 +451,7 @@ void CReplay::RetrievePedAnimation(CPed *ped, CStoredAnimationState *state) { CAnimBlendAssociation* anim1 = CAnimManager::BlendAnimation( (RpClump*)ped->m_rwObject, - (state->animId > 3) ? ped->m_animGroup : ASSOCGRP_STD, + (state->animId > 3) ? ASSOCGRP_STD : ped->m_animGroup, (AnimationId)state->animId, 100.0f); anim1->SetCurrentTime(state->time * 4.0f / 255.0f); anim1->speed = state->speed * 3.0f / 255.0f; @@ -464,7 +463,7 @@ void CReplay::RetrievePedAnimation(CPed *ped, CStoredAnimationState *state) float blend = state->blendAmount * 2.0f / 255.0f; CAnimBlendAssociation* anim2 = CAnimManager::BlendAnimation( (RpClump*)ped->m_rwObject, - (state->secAnimId > 3) ? ped->m_animGroup : ASSOCGRP_STD, + (state->secAnimId > 3) ? ASSOCGRP_STD : ped->m_animGroup, (AnimationId)state->secAnimId, 100.0f); anim2->SetCurrentTime(time); anim2->speed = speed; @@ -481,12 +480,59 @@ void CReplay::RetrievePedAnimation(CPed *ped, CStoredAnimationState *state) (RpClump*)ped->m_rwObject, ASSOCGRP_STD, (AnimationId)state->partAnimId, 1000.0f); anim3->SetCurrentTime(time); anim3->speed = speed; - anim3->blendDelta = 0.0f; // is it correct? + anim3->SetBlend(blend, 0.0f); } } } #endif + +#if 0 WRAPPER void CReplay::RetrieveDetailedPedAnimation(CPed *ped, CStoredDetailedAnimationState *state) { EAXJMP(0x5944B0); } +#else +void CReplay::RetrieveDetailedPedAnimation(CPed *ped, CStoredDetailedAnimationState *state) +{ + for (int i = 0; i < 3; i++){ + if (state->aAnimId[i] == NUM_ANIMS) + continue; + CAnimBlendAssociation* anim = CAnimManager::BlendAnimation( + (RpClump*)ped->m_rwObject, + state->aAnimId[i] > 3 ? ASSOCGRP_STD : ped->m_animGroup, + (AnimationId)state->aAnimId[i], 100.0f); + anim->SetCurrentTime(state->aCurTime[i] * 4.0f / 255.0f); + anim->speed = state->aSpeed[i] * 3.0f / 255.0f; + /* Lack of commented out calculation causes megajump */ + anim->SetBlend(state->aBlendAmount[i] /* * 2.0f / 255.0f */, 1.0f); + anim->flags = state->aFlags[i]; + uint8 callback = state->aFunctionCallbackID[i]; + if (!callback) + anim->callbackType = CAnimBlendAssociation::CB_NONE; + else if (callback & 0x80) + anim->SetFinishCallback(FindCBFunction(callback & 0x7F), ped); + else + anim->SetDeleteCallback(FindCBFunction(callback & 0x7F), ped); + } + for (int i = 0; i < 6; i++) { + if (state->aAnimId2[i] == NUM_ANIMS) + continue; + CAnimBlendAssociation* anim = CAnimManager::BlendAnimation( + (RpClump*)ped->m_rwObject, + state->aAnimId2[i] > 3 ? ASSOCGRP_STD : ped->m_animGroup, + (AnimationId)state->aAnimId2[i], 100.0f); + anim->SetCurrentTime(state->aCurTime2[i] * 4.0f / 255.0f); + anim->speed = state->aSpeed2[i] * 3.0f / 255.0f; + /* Lack of commented out calculation causes megajump */ + anim->SetBlend(state->aBlendAmount2[i] /* * 2.0f / 255.0f */, 1.0f); + anim->flags = state->aFlags2[i]; + uint8 callback = state->aFunctionCallbackID2[i]; + if (!callback) + anim->callbackType = CAnimBlendAssociation::CB_NONE; + else if (callback & 0x80) + anim->SetFinishCallback(FindCBFunction(callback & 0x7F), ped); + else + anim->SetDeleteCallback(FindCBFunction(callback & 0x7F), ped); + } +} +#endif WRAPPER void CReplay::PlaybackThisFrame(void) { EAXJMP(0x5946B0); } #if 0 @@ -834,7 +880,9 @@ STARTPATCHES InjectHook(0x592FC0, PrintElementsInPtrList, PATCH_JUMP); InjectHook(0x592FE0, CReplay::Init, PATCH_JUMP); InjectHook(0x593150, CReplay::DisableReplays, PATCH_JUMP); -InjectHook(0x593150, CReplay::EnableReplays, PATCH_JUMP); +InjectHook(0x593160, CReplay::EnableReplays, PATCH_JUMP); InjectHook(0x593170, CReplay::Update, PATCH_JUMP); +InjectHook(0x594050, CReplay::ProcessPedUpdate, PATCH_JUMP); +InjectHook(0x5944B0, CReplay::RetrieveDetailedPedAnimation, PATCH_JUMP); //InjectHook(0x5966E0, CReplay::RestoreStuffFromMem, PATCH_JUMP); ENDPATCHES diff --git a/src/control/Replay.h b/src/control/Replay.h index 0a65c638..125dfef4 100644 --- a/src/control/Replay.h +++ b/src/control/Replay.h @@ -262,9 +262,11 @@ private: static void StorePedUpdate(CPed *ped, int id); static void StorePedAnimation(CPed *ped, CStoredAnimationState *state); static void StoreDetailedPedAnimation(CPed *ped, CStoredDetailedAnimationState *state); +public: static void ProcessPedUpdate(CPed *ped, float interpolation, CAddressInReplayBuffer *buffer); static void RetrievePedAnimation(CPed *ped, CStoredAnimationState *state); static void RetrieveDetailedPedAnimation(CPed *ped, CStoredDetailedAnimationState *state); +private: static void PlaybackThisFrame(void); static void StoreCarUpdate(CVehicle *vehicle, int id); static void ProcessCarUpdate(CVehicle *vehicle, float interpolation, CAddressInReplayBuffer *buffer); diff --git a/src/math/Matrix.h b/src/math/Matrix.h index bbdc6a70..63cb2753 100644 --- a/src/math/Matrix.h +++ b/src/math/Matrix.h @@ -74,7 +74,7 @@ public: m_matrix.at.z += rhs.m_matrix.at.z; m_matrix.pos.x += rhs.m_matrix.pos.x; m_matrix.pos.y += rhs.m_matrix.pos.y; - m_matrix.pos.y += rhs.m_matrix.pos.z; + m_matrix.pos.z += rhs.m_matrix.pos.z; return *this; } From 01c04f3963bc7d10e1d4d63d5586f3d5e04fdb2c Mon Sep 17 00:00:00 2001 From: Nikolay Korolev Date: Sat, 29 Jun 2019 18:05:23 +0300 Subject: [PATCH 4/6] Fixed merge --- src/World.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/World.h b/src/World.h index fb9b3b7e..90e732a5 100644 --- a/src/World.h +++ b/src/World.h @@ -69,7 +69,6 @@ public: static void Remove(CEntity *entity); static void Add(CEntity *entity); - static void Remove(CEntity *ent); static CSector *GetSector(int x, int y) { return &ms_aSectors[y][x]; } static CPtrList &GetBigBuildingList(eLevelName i) { return ms_bigBuildingsList[i]; } From e0488a7980c3c857431d266f0fd6205ca772315f Mon Sep 17 00:00:00 2001 From: Nikolay Korolev Date: Sat, 29 Jun 2019 18:06:15 +0300 Subject: [PATCH 5/6] fix --- src/World.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/World.h b/src/World.h index 90e732a5..3b7090da 100644 --- a/src/World.h +++ b/src/World.h @@ -104,8 +104,6 @@ public: static int GetSectorIndexY(float f) { return (int)GetSectorY(f); } static float GetWorldX(int x) { return x*SECTOR_SIZE_X + WORLD_MIN_X; } static float GetWorldY(int y) { return y*SECTOR_SIZE_Y + WORLD_MIN_Y; } - - static void Remove(void); }; class CPlayerPed; From 14e0aae1bd3d4d4d2aa1f37d87a472e746e32557 Mon Sep 17 00:00:00 2001 From: Nikolay Korolev Date: Sat, 29 Jun 2019 18:07:57 +0300 Subject: [PATCH 6/6] fix --- src/entities/PlayerPed.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/entities/PlayerPed.cpp b/src/entities/PlayerPed.cpp index 2136d3ad..86312996 100644 --- a/src/entities/PlayerPed.cpp +++ b/src/entities/PlayerPed.cpp @@ -2,4 +2,4 @@ #include "patcher.h" #include "PlayerPed.h" -WRAPPER void CPlayerPed::ReApplyMoveAnims(void) { EAXJMP(0x4F07C0); } \ No newline at end of file +WRAPPER void CPlayerPed::ReApplyMoveAnims(void) { EAXJMP(0x4F07C0); }