diff options
-rw-r--r-- | src/BulletTrace.h | 12 | ||||
-rw-r--r-- | src/BulletTraces.cpp | 3 | ||||
-rw-r--r-- | src/BulletTraces.h | 9 | ||||
-rw-r--r-- | src/Pad.cpp | 2 | ||||
-rw-r--r-- | src/Pickup.h | 33 | ||||
-rw-r--r-- | src/Radar.cpp | 140 | ||||
-rw-r--r-- | src/Radar.h | 7 | ||||
-rw-r--r-- | src/User.cpp | 2 | ||||
-rw-r--r-- | src/audio/MusicManager.cpp | 2 | ||||
-rw-r--r-- | src/control/Replay.cpp | 239 | ||||
-rw-r--r-- | src/control/Replay.h | 207 | ||||
-rw-r--r-- | src/entities/CutsceneObject.cpp | 2 | ||||
-rw-r--r-- | src/entities/Entity.cpp | 2 | ||||
-rw-r--r-- | src/entities/Entity.h | 15 | ||||
-rw-r--r-- | src/entities/Ped.h | 2 | ||||
-rw-r--r-- | src/math/Matrix.h | 3 | ||||
-rw-r--r-- | src/render/Hud.cpp | 4 | ||||
-rw-r--r-- | src/templates.h | 21 |
18 files changed, 673 insertions, 32 deletions
diff --git a/src/BulletTrace.h b/src/BulletTrace.h new file mode 100644 index 00000000..d6831ef1 --- /dev/null +++ b/src/BulletTrace.h @@ -0,0 +1,12 @@ +#pragma once + +#include "common.h" + +struct CBulletTrace +{ + CVector m_vecInf; + CVector m_vecSup; + bool m_bInUse; + uint8 m_bFramesInUse; + uint8 m_bLifeTime; +}; diff --git a/src/BulletTraces.cpp b/src/BulletTraces.cpp new file mode 100644 index 00000000..a873875c --- /dev/null +++ b/src/BulletTraces.cpp @@ -0,0 +1,3 @@ +#include "BulletTraces.h" + +CBulletTrace (&CBulletTraces::aTraces)[16] = *(CBulletTrace(*)[16])*(uintptr*)0x72B1B8; diff --git a/src/BulletTraces.h b/src/BulletTraces.h new file mode 100644 index 00000000..34d2bcc6 --- /dev/null +++ b/src/BulletTraces.h @@ -0,0 +1,9 @@ +#pragma once + +#include "BulletTrace.h" + +class CBulletTraces +{ +public: + static CBulletTrace(&aTraces)[16]; +}; diff --git a/src/Pad.cpp b/src/Pad.cpp index a563e26c..5c151bf4 100644 --- a/src/Pad.cpp +++ b/src/Pad.cpp @@ -525,7 +525,7 @@ void CPad::UpdatePads(void) ControlsManager.AffectPadFromKeyBoard(); ControlsManager.AffectPadFromMouse(); - if ( CReplay::bPlayingBackFromFile ) + if ( CReplay::IsPlayingBackFromFile() ) bUpdate = false; if ( bUpdate ) diff --git a/src/Pickup.h b/src/Pickup.h new file mode 100644 index 00000000..efef15fe --- /dev/null +++ b/src/Pickup.h @@ -0,0 +1,33 @@ +#pragma once +#include "common.h" +#include "Object.h" + +enum ePickupType +{ + PICKUP_NONE = 0, + PICKUP_IN_SHOP = 1, + PICKUP_ON_STREET = 2, + PICKUP_ONCE = 3, + PICKUP_ONCE_TIMEOUT = 4, + PICKUP_COLLECTABLE1 = 5, + PICKUP_IN_SHOP_OUT_OF_STOCK = 6, + PICKUP_MONEY = 7, + PICKUP_MINE_INACTIVE = 8, + PICKUP_MINE_ARMED = 9, + PICKUP_NAUTICAL_MINE_INACTIVE = 10, + PICKUP_NAUTICAL_MINE_ARMED = 11, + PICKUP_FLOATINGPACKAGE = 12, + PICKUP_FLOATINGPACKAGE_FLOATING = 13, + PICKUP_ON_STREET_SLOW = 14, +}; + +class CPickup +{ + ePickupType m_eType; + uint16 m_wQuantity; + CObject *m_pObject; + uint32 m_nTimer; + int16 m_eModelIndex; + int16 m_wIndex; + CVector m_vecPos; +}; diff --git a/src/Radar.cpp b/src/Radar.cpp index 41ca0780..e9fce51e 100644 --- a/src/Radar.cpp +++ b/src/Radar.cpp @@ -10,14 +10,11 @@ #include "Pools.h" #include "Script.h" #include "TxdStore.h" +#include "World.h" +#include "Streaming.h" -WRAPPER void CRadar::ClearBlipForEntity(eBlipType type, int32 id) { EAXJMP(0x4A56C0); } WRAPPER void CRadar::Draw3dMarkers() { EAXJMP(0x4A4C70); } -WRAPPER float CRadar::LimitRadarPoint(CVector2D *point) { EAXJMP(0x4A4F30); } -WRAPPER void CRadar::ShowRadarTrace(float x, float y, uint32 size, uint32 red, uint32 green, uint32 blue, uint32 alpha) { EAXJMP(0x4A5870); } -WRAPPER void CRadar::StreamRadarSections(int x, int y) { EAXJMP(0x4A6100); } WRAPPER int CRadar::ClipRadarPoly(CVector2D *out, CVector2D *in) { EAXJMP(0x4A64A0); } -WRAPPER void CRadar::TransformRealWorldToTexCoordSpace(CVector2D *out, CVector2D *in, int x, int y) { EAXJMP(0x4A5530); } WRAPPER void CRadar::TransformRadarPointToRealWorldSpace(CVector2D *out, CVector2D *in) { EAXJMP(0x4A5300); } float &CRadar::m_RadarRange = *(float*)0x8E281C; @@ -148,6 +145,49 @@ void CRadar::DrawRadarMask() } #endif +#if 0 +WRAPPER void CRadar::SetRadarMarkerState(int counter, int flag) { EAXJMP(0x4A5C60); } +#else +void CRadar::SetRadarMarkerState(int counter, int flag) +{ + CEntity *e; + switch (ms_RadarTrace[counter].m_eBlipType) { + case BLIP_CAR: + e = CPools::GetVehiclePool()->GetAt(ms_RadarTrace[counter].m_nEntityHandle); + break; + case BLIP_CHAR: + e = CPools::GetPedPool()->GetAt(ms_RadarTrace[counter].m_nEntityHandle); + break; + case BLIP_OBJECT: + e = CPools::GetObjectPool()->GetAt(ms_RadarTrace[counter].m_nEntityHandle); + break; + default: + return; + }; + + if (e) + e->bHasBlip = flag; + +} +#endif + +#if 0 +WRAPPER void CRadar::ClearBlipForEntity(eBlipType type, int32 id) { EAXJMP(0x4A56C0); } +#else +void CRadar::ClearBlipForEntity(eBlipType type, int32 id) +{ + for (int i = 0; i < 32; i++) { + if (type == ms_RadarTrace[i].m_eBlipType && id == ms_RadarTrace[i].m_nEntityHandle) { + CRadar::SetRadarMarkerState(i, 0); + ms_RadarTrace[i].m_bInUse = 0; + ms_RadarTrace[i].m_eBlipType = 0; + ms_RadarTrace[i].m_eBlipDisplay = 0; + ms_RadarTrace[i].m_IconID = 0; + } + }; +} +#endif + #if 1 WRAPPER void CRadar::DrawRadarSection(int x, int y) { EAXJMP(0x4A67E0); } #else @@ -157,6 +197,61 @@ void CRadar::DrawRadarSection(int x, int y) } #endif +void CRadar::RequestMapSection(int x, int y) +{ + ClipRadarTileCoords(&x, &y); + CStreaming::RequestModel(gRadarTxdIds[x + 8 * y] + 5500, 5); +} + +void CRadar::RemoveMapSection(int x, int y) +{ + if (x >= 0 && x <= 7 && y >= 0 && y <= 7) + CStreaming::RemoveModel(gRadarTxdIds[x + 8 * y] + 5500); +} + +#if 0 +WRAPPER void CRadar::StreamRadarSections(int x, int y) { EAXJMP(0x4A6100); } +#else +void CRadar::StreamRadarSections(int x, int y) +{ + for (int i = 0; i < 8; ++i) { + for (int j = 0; j < 8; ++j) { + if (i >= x - 1 && i <= x + 1 && j >= y - 1 && j <= y + 1) + RequestMapSection(x, y); + else + RemoveMapSection(x, y); + }; + }; +} +#endif + +#if 0 +WRAPPER float CRadar::LimitRadarPoint(CVector2D *point) { EAXJMP(0x4A4F30); } +#else +float CRadar::LimitRadarPoint(CVector2D *point) +{ + float div; + + if (point->Magnitude() > 1.0f) { + div = 1.0f / point->Magnitude(); + point->x *= div; + point->y *= div; + } + return point->Magnitude(); +} +#endif + +#if 0 +WRAPPER void CRadar::TransformRealWorldToTexCoordSpace(CVector2D *out, CVector2D *in, int x, int y) { EAXJMP(0x4A5530); } +#else +void CRadar::TransformRealWorldToTexCoordSpace(CVector2D *out, CVector2D *in, int x, int y) { + out->x = in->x - (x * 500.0f - WORLD_MAX_X); + out->y = -(in->y - ((8 - y) * 500.0f - WORLD_MAX_Y)); + out->x *= 0.002f; + out->y *= 0.002f; +} +#endif + #if 0 WRAPPER void CRadar::DrawRadarMap() { EAXJMP(0x4A6C20); } #else @@ -164,8 +259,8 @@ void CRadar::DrawRadarMap() { CRadar::DrawRadarMask(); - int x = floorf((2000.0f + vec2DRadarOrigin.x) * 0.002f); - int y = round(7.0f - (2000.0f + vec2DRadarOrigin.y) * 0.002f); + int x = floorf((WORLD_MAX_X + vec2DRadarOrigin.x) * 0.002f); + int y = round(7.0f - (WORLD_MAX_Y + vec2DRadarOrigin.y) * 0.002f); CRadar::StreamRadarSections(x, y); RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)FALSE); @@ -407,10 +502,17 @@ WRAPPER void CRadar::DrawRadarSprite(int sprite, float x, float y, int alpha) { #else void CRadar::DrawRadarSprite(int sprite, float x, float y, int alpha) { - float w = SCREEN_SCALE_X(8.0f); - float h = SCREEN_SCALE_Y(8.0f); + RadarSprites[sprite]->Draw(CRect(x - SCREEN_SCALE_X(8.0f), y - SCREEN_SCALE_Y(8.0f), x + SCREEN_SCALE_X(8.0f), y + SCREEN_SCALE_Y(8.0f)), CRGBA(255, 255, 255, alpha)); +} +#endif - RadarSprites[sprite]->Draw(CRect(x - w, y - h, x + w, y + h), CRGBA(255, 255, 255, alpha)); +#if 0 +WRAPPER void CRadar::ShowRadarTrace(float x, float y, uint32 size, uint32 red, uint32 green, uint32 blue, uint32 alpha) { EAXJMP(0x4A5870); } +#else +void CRadar::ShowRadarTrace(float x, float y, uint32 size, uint32 red, uint32 green, uint32 blue, uint32 alpha) +{ + CSprite2d::DrawRect(CRect(x - SCREEN_SCALE_X(size + 1.0f), y - SCREEN_SCALE_Y(size + 1.0f), SCREEN_SCALE_X(size + 1.0f) + x, SCREEN_SCALE_Y(size + 1.0f) + y), CRGBA(0, 0, 0, alpha)); + CSprite2d::DrawRect(CRect(x - SCREEN_SCALE_X(size), y - SCREEN_SCALE_Y(size), SCREEN_SCALE_X(size) + x, SCREEN_SCALE_Y(size) + y), CRGBA(red, green, blue, alpha)); } #endif @@ -511,16 +613,16 @@ void CRadar::GetTextureCorners(int x, int y, CVector2D *out) } #endif -void CRadar::ClipRadarTileCoords(int x, int y) +void CRadar::ClipRadarTileCoords(int *x, int *y) { - if (x < 0) - x = 0; - if (x > 7) - x = 7; - if (y < 0) - y = 0; - if (y > 7) - y = 7; + if (*x < 0) + *x = 0; + if (*x > 7) + *x = 7; + if (*y < 0) + *y = 0; + if (*y > 7) + *y = 7; } STARTPATCHES diff --git a/src/Radar.h b/src/Radar.h index 5a63a83b..19fc9038 100644 --- a/src/Radar.h +++ b/src/Radar.h @@ -102,8 +102,10 @@ public: static void StreamRadarSections(int x, int y); static int ClipRadarPoly(CVector2D *out, CVector2D *in); static void TransformRealWorldToTexCoordSpace(CVector2D *out, CVector2D *in, int x, int y); - static void CRadar::TransformRadarPointToRealWorldSpace(CVector2D *out, CVector2D *in); + static void TransformRadarPointToRealWorldSpace(CVector2D *out, CVector2D *in); static void DrawRadarSection(int x, int y); + static void RequestMapSection(int x, int y); + static void RemoveMapSection(int x, int y); static void TransformRadarPointToScreenSpace(CVector2D * out, CVector2D * in); static void DrawBlips(); static int CalculateBlipAlpha(float dist); @@ -116,7 +118,8 @@ public: static void ShowRadarMarker(CVector pos, CRGBA color, float radius); static void ShowRadarTrace(float x, float y, uint32 size, uint32 red, uint32 green, uint32 blue, uint32 alpha); static void DrawRadarMask(); + static void SetRadarMarkerState(int counter, int flag); static bool DisplayThisBlip(int counter); static void GetTextureCorners(int x, int y, CVector2D * out); - static void ClipRadarTileCoords(int x, int y); + static void ClipRadarTileCoords(int *x, int *y); }; diff --git a/src/User.cpp b/src/User.cpp index c9ab761d..c9cb97cc 100644 --- a/src/User.cpp +++ b/src/User.cpp @@ -31,7 +31,7 @@ void COnscreenTimer::Init() { } void COnscreenTimer::Process() { - if(CReplay::Mode != CReplay::MODE_1 && !m_bDisabled) { + if(!CReplay::IsPlayingBack() && !m_bDisabled) { for(uint32 i = 0; i < NUMONSCREENTIMERENTRIES; i++) { m_sEntries[i].Process(); } diff --git a/src/audio/MusicManager.cpp b/src/audio/MusicManager.cpp index cc86b584..f9c02739 100644 --- a/src/audio/MusicManager.cpp +++ b/src/audio/MusicManager.cpp @@ -51,7 +51,7 @@ void cMusicManager::DisplayRadioStationName() int8 gStreamedSound; int8 gRetuneCounter; - if (!CTimer::GetIsPaused() && !TheCamera.m_WideScreenOn && cMusicManager::PlayerInCar() && CReplay::Mode != 1) { + if (!CTimer::GetIsPaused() && !TheCamera.m_WideScreenOn && cMusicManager::PlayerInCar() && !CReplay::IsPlayingBack()) { if (MusicManager.m_bPlayerInCar && !MusicManager.m_bPreviousPlayerInCar) pCurrentStation = nullptr; diff --git a/src/control/Replay.cpp b/src/control/Replay.cpp index 80edf097..a8d87302 100644 --- a/src/control/Replay.cpp +++ b/src/control/Replay.cpp @@ -1,8 +1,247 @@ #include "common.h" #include "patcher.h" +#include "BulletTraces.h" +#include "Clock.h" +#include "Draw.h" +#include "math/Matrix.h" +#include "ModelIndices.h" #include "Replay.h" +#include "Pad.h" +#include "Pools.h" +#include "CutsceneMgr.h" +#include "Timer.h" +#include "Weather.h" uint8 &CReplay::Mode = *(uint8*)0x95CD5B; +CAddressInReplayBuffer &CReplay::Record = *(CAddressInReplayBuffer*)0x942F7C; +CAddressInReplayBuffer &CReplay::Playback = *(CAddressInReplayBuffer*)0x8F5F48; +uint8 *&CReplay::pBuf0 = *(uint8**)0x8E2C64; +CAutomobile *&CReplay::pBuf1 = *(CAutomobile**)0x8E2C68; +uint8 *&CReplay::pBuf2 = *(uint8**)0x8E2C6C; +CPlayerPed *&CReplay::pBuf3 = *(CPlayerPed**)0x8E2C70; +uint8 *&CReplay::pBuf4 = *(uint8**)0x8E2C74; +CCutsceneHead *&CReplay::pBuf5 = *(CCutsceneHead**)0x8E2C78; +uint8 *&CReplay::pBuf6 = *(uint8**)0x8E2C80; +CPtrNode *&CReplay::pBuf7 = *(CPtrNode**)0x8E2C84; +uint8 *&CReplay::pBuf8 = *(uint8**)0x8E2C54; +CEntryInfoNode *&CReplay::pBuf9 = *(CEntryInfoNode**)0x8E2C58; +uint8 *&CReplay::pBuf10 = *(uint8**)0x8F2C28; +CDummyPed *&CReplay::pBuf11 = *(CDummyPed**)0x8F2C2C; +CBlip *&CReplay::pRadarBlips = *(CBlip**)0x8F29F8; +CCamera *&CReplay::pStoredCam = *(CCamera**)0x8F2C34; +CSector *&CReplay::pWorld1 = *(CSector**)0x8E29C4; +CReference *&CReplay::pEmptyReferences = *(CReference**)0x8F256C; +CStoredDetailedAnimationState *&CReplay::pPedAnims = *(CStoredDetailedAnimationState**)0x8F6260; +CPickup *&CReplay::pPickups = *(CPickup**)0x8F1A48; +CReference *&CReplay::pReferences = *(CReference**)0x880FAC; +uint8(&CReplay::BufferStatus)[8] = *(uint8(*)[8])*(uintptr*)0x8804D8; +uint8(&CReplay::Buffers)[8][100000] = *(uint8(*)[8][100000])*(uintptr*)0x779958; bool &CReplay::bPlayingBackFromFile = *(bool*)0x95CD58; +bool &CReplay::bReplayEnabled = *(bool*)0x617CAC; +uint32 &CReplay::SlowMotion = *(uint32*)0x9414D4; +uint32 &CReplay::FramesActiveLookAroundCam = *(uint32*)0x880F84; +bool &CReplay::bDoLoadSceneWhenDone = *(bool*)0x95CD76; +void PrintElementsInPtrList(void) +{ + for (CPtrNode* node = CWorld::GetBigBuildingList(LEVEL_NONE).first; node; node = node->next) { + // Most likely debug print was present here + } +} + +void CReplay::Init(void) +{ + pBuf0 = nil; + pBuf1 = nil; + pBuf2 = nil; + pBuf3 = nil; + pBuf4 = nil; + pBuf5 = nil; + pBuf6 = nil; + pBuf7 = nil; + pBuf8 = nil; + pBuf9 = nil; + pBuf10 = nil; + pBuf11 = nil; + pRadarBlips = nil; + pStoredCam = nil; + pWorld1 = nil; + pEmptyReferences = nil; + pPedAnims = nil; + pPickups = nil; + pReferences = nil; + Mode = MODE_RECORD; + Playback.m_nOffset = 0; + Playback.m_pBase = nil; + Playback.m_bSlot = 0; + Record.m_nOffset = 0; + Record.m_pBase = nil; + Record.m_bSlot = 0; + for (int i = 0; i < 8; i++) + BufferStatus[i] = REPLAYBUFFER_UNUSED; + Record.m_bSlot = 0; + Record.m_pBase = Buffers[0]; + BufferStatus[0] = REPLAYBUFFER_RECORD; + Buffers[0][Record.m_nOffset] = REPLAYPACKET_END; + bPlayingBackFromFile = false; + bReplayEnabled = true; + SlowMotion = 1; + FramesActiveLookAroundCam = 0; + bDoLoadSceneWhenDone = false; +} + +void CReplay::DisableReplays(void) +{ + bReplayEnabled = false; +} + +void CReplay::EnableReplays(void) +{ + bReplayEnabled = true; +} + +void PlayReplayFromHD(void); +void CReplay::Update(void) +{ + if (CCutsceneMgr::IsCutsceneProcessing() || CTimer::GetIsPaused()) + return; + switch (Mode){ + case MODE_RECORD: + RecordThisFrame(); + break; + case MODE_PLAYBACK: + PlaybackThisFrame(); + break; + } + if (CDraw::FadeValue || !bReplayEnabled) + return; + if (Mode == MODE_PLAYBACK){ + if (CPad::NewKeyState.F[0] && !CPad::OldKeyState.F[0]) + FinishPlayback(); + } + else if (Mode == MODE_RECORD){ + if (CPad::NewKeyState.F[0] && !CPad::OldKeyState.F[0]) + TriggerPlayback(REPLAYCAMMODE_ASSTORED, 0.0f, 0.0f, 0.0f, false); + if (CPad::NewKeyState.F[1] && !CPad::OldKeyState.F[1]) + SaveReplayToHD(); + if (CPad::NewKeyState.F[2] && !CPad::OldKeyState.F[2]) + PlayReplayFromHD(); + } +} + +#if 0 +WRAPPER void CReplay::RecordThisFrame(void) { EAXJMP(0x5932B0); } +#else + +void CReplay::RecordThisFrame(void) +{ + tGeneralPacket* general = (tGeneralPacket*)&Record.m_pBase[Record.m_nOffset]; + general->type = REPLAYPACKET_GENERAL; + general->camera_pos.CopyOnlyMatrix(&TheCamera.GetMatrix()); + FindPlayerCoors(general->player_pos); + general->in_rcvehicle = CWorld::Players[CWorld::PlayerInFocus].m_pRemoteVehicle ? true : false; + Record.m_nOffset += sizeof(*general); + tClockPacket* clock = (tClockPacket*)&Record.m_pBase[Record.m_nOffset]; + clock->type = REPLAYPACKET_CLOCK; + clock->hours = CClock::GetHours(); + clock->minutes = CClock::GetMinutes(); + Record.m_nOffset += sizeof(*clock); + tWeatherPacket* weather = (tWeatherPacket*)&Record.m_pBase[Record.m_nOffset]; + weather->type = REPLAYPACKET_WEATHER; + weather->old_weather = CWeather::OldWeatherType; + weather->new_weather = CWeather::NewWeatherType; + weather->interpolation = CWeather::InterpolationValue; + Record.m_nOffset += sizeof(*weather); + tTimerPacket* timer = (tTimerPacket*)&Record.m_pBase[Record.m_nOffset]; + timer->type = REPLAYPACKET_TIMER; + timer->timer = CTimer::GetTimeInMilliseconds(); + Record.m_nOffset += sizeof(*timer); + CVehiclePool* vehicles = CPools::GetVehiclePool(); + for (int i = 0; i < vehicles->GetSize(); i++){ + CVehicle* v = vehicles->GetSlot(i); + if (v && v->m_rwObject && v->GetModelIndex() != MI_AIRTRAIN && v->GetModelIndex() != MI_TRAIN) + StoreCarUpdate(v, i); + } + CPedPool* peds = CPools::GetPedPool(); + for (int i = 0; i < peds->GetSize(); i++) { + CPed* p = peds->GetSlot(i); + if (!p || !p->m_rwObject) + continue; + if (!p->bRecordedForReplay){ + tPedHeaderPacket* ph = (tPedHeaderPacket*)&Record.m_pBase[Record.m_nOffset]; + ph->type = REPLAYPACKET_PED_HEADER; + ph->index = i; + ph->mi = p->GetModelIndex(); + ph->pedtype = p->m_nPedType; + Record.m_nOffset += sizeof(*ph); + p->bRecordedForReplay = true; + } + StorePedUpdate(p, i); + } + for (uint8 i = 0; i < 16; i++){ + if (!CBulletTraces::aTraces[i].m_bInUse) + continue; + tBulletTracePacket* bt = (tBulletTracePacket*)&Record.m_pBase[Record.m_nOffset]; + bt->type = REPLAYPACKET_BULLETTRACES; + bt->index = i; + bt->frames = CBulletTraces::aTraces[i].m_bFramesInUse; + bt->lifetime = CBulletTraces::aTraces[i].m_bLifeTime; + bt->inf = CBulletTraces::aTraces[i].m_vecInf; + bt->sup = CBulletTraces::aTraces[i].m_vecSup; + Record.m_nOffset += sizeof(*bt); + } + tEndOfFramePacket* eof = (tEndOfFramePacket*)&Record.m_pBase[Record.m_nOffset]; + eof->type = REPLAYPACKET_ENDOFFRAME; + Record.m_nOffset += sizeof(*eof); + if (Record.m_nOffset <= 97000){ + /* Unsafe assumption which can cause buffer overflow + * if size of next frame exceeds 3000 bytes. + * Most notably it causes various timecyc errors. */ + Record.m_pBase[Record.m_nOffset] = REPLAYPACKET_END; + return; + } + Record.m_pBase[Record.m_nOffset] = REPLAYPACKET_END; + BufferStatus[Record.m_bSlot] = REPLAYBUFFER_PLAYBACK; + Record.m_bSlot = (Record.m_bSlot + 1) % 8; + BufferStatus[Record.m_bSlot] = REPLAYBUFFER_RECORD; + Record.m_pBase = Buffers[Record.m_bSlot]; + Record.m_nOffset = 0; + *Record.m_pBase = REPLAYPACKET_END; + MarkEverythingAsNew(); +} +#endif +WRAPPER void CReplay::StorePedUpdate(CPed *ped, int id) { EAXJMP(0x5935B0); } +WRAPPER void CReplay::StorePedAnimation(CPed *ped, CStoredAnimationState *state) { EAXJMP(0x593670); } +WRAPPER void CReplay::StoreDetailedPedAnimation(CPed *ped, CStoredDetailedAnimationState *state) { EAXJMP(0x593BB0); } +WRAPPER void CReplay::ProcessPedUpdate(CPed *ped, float interpolation, CAddressInReplayBuffer *buffer) { EAXJMP(0x594050); } +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); } +WRAPPER void CReplay::StoreCarUpdate(CVehicle *vehicle, int id) { EAXJMP(0x5947F0); } +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::ProcessReplayCamera(void) { EAXJMP(0x595C40); } WRAPPER void CReplay::Display(void) { EAXJMP(0x595EE0); } +WRAPPER void CReplay::TriggerPlayback(uint8 cam_mode, float cam_x, float cam_y, float cam_z, bool load_scene) { EAXJMP(0x596030); } +WRAPPER void CReplay::StoreStuffInMem(void) { EAXJMP(0x5961F0); } +WRAPPER void CReplay::RestoreStuffFromMem(void) { EAXJMP(0x5966E0); } +WRAPPER void CReplay::EmptyPedsAndVehiclePools(void) { EAXJMP(0x5970E0); } +WRAPPER void CReplay::EmptyAllPools(void) { EAXJMP(0x5971B0); } +WRAPPER void CReplay::MarkEverythingAsNew(void) { EAXJMP(0x597280); } +WRAPPER void CReplay::SaveReplayToHD(void) { EAXJMP(0x597330); } +WRAPPER void PlayReplayFromHD(void) { EAXJMP(0x597420); } +WRAPPER void CReplay::StreamAllNecessaryCarsAndPeds(void) { EAXJMP(0x597560); } +WRAPPER void CReplay::FindFirstFocusCoordinate(CVector *coord) { EAXJMP(0x5975E00); } +WRAPPER bool CReplay::ShouldStandardCameraBeProcessed(void) { EAXJMP(0x597680); } +WRAPPER void CReplay::ProcessLookAroundCam(void) { EAXJMP(0x5976C0); } +WRAPPER size_t CReplay::FindSizeOfPacket(uint8 type) { EAXJMP(0x597CC0); } + +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(0x593170, CReplay::Update, PATCH_JUMP); +ENDPATCHES diff --git a/src/control/Replay.h b/src/control/Replay.h index 70835596..b37bd29f 100644 --- a/src/control/Replay.h +++ b/src/control/Replay.h @@ -1,14 +1,217 @@ #pragma once +#include "Camera.h" +#include "Ped.h" +#include "Pools.h" +#include "Pickup.h" +#include "Radar.h" +#include "References.h" +#include "Vehicle.h" +#include "World.h" +#include "common.h" + +struct CAddressInReplayBuffer +{ + uint32 m_nOffset; + uint8 *m_pBase; + uint8 m_bSlot; +}; + +struct CStoredAnimationState +{ + int8 animId; + int8 time; + int8 speed; + int8 secAnimId; + int8 secTime; + int8 secSpeed; + int8 blendAmount; + int8 partAnimId; + int8 partAnimTime; + int8 partAnimSpeed; + int8 partBlendAmount; +}; + +struct CStoredDetailedAnimationState +{ + int8 m_abAnimId[3]; + int8 m_abCurTime[3]; + int8 m_abSpeed[3]; + int8 m_abBlendAmount[3]; + int8 m_abFunctionCallbackID[3]; + int16 m_awFlags[3]; + int8 m_abAnimId2[6]; + int8 m_abCurTime2[6]; + int8 m_abSpeed2[6]; + int8 m_abBlendAmount2[6]; + int8 m_abFunctionCallbackID2[6]; + int16 m_awFlags2[6]; +}; + class CReplay { -public: enum { - MODE_1 = 1 + MODE_RECORD = 0, + MODE_PLAYBACK = 1 + }; + + enum { + REPLAYCAMMODE_ASSTORED = 0, + REPLAYCAMMODE_TOPDOWN = 1, + REPLAYCAMMODE_FIXED = 2 + }; + + enum { + REPLAYPACKET_END = 0, + REPLAYPACKET_VEHICLE = 1, + REPLAYPACKET_PED_HEADER = 2, + REPLAYPACKET_PED = 3, + REPLAYPACKET_GENERAL = 4, + REPLAYPACKET_CLOCK = 5, + REPLAYPACKET_WEATHER = 6, + REPLAYPACKET_ENDOFFRAME = 7, + REPLAYPACKET_TIMER = 8, + REPLAYPACKET_BULLETTRACES = 9 + }; + + enum { + REPLAYBUFFER_UNUSED = 0, + REPLAYBUFFER_PLAYBACK = 1, + REPLAYBUFFER_RECORD = 2 + }; + + + struct tGeneralPacket + { + uint8 type; + bool in_rcvehicle; + CMatrix camera_pos; + CVector player_pos; + }; + static_assert(sizeof(tGeneralPacket) == 88, "tGeneralPacket: error"); + + struct tClockPacket + { + uint8 type; + uint8 hours; + uint8 minutes; + private: + uint8 __align; + }; + static_assert(sizeof(tClockPacket) == 4, "tClockPacket: error"); + + struct tWeatherPacket + { + uint8 type; + uint8 old_weather; + uint8 new_weather; + float interpolation; + }; + static_assert(sizeof(tWeatherPacket) == 8, "tWeatherPacket: error"); + + struct tTimerPacket + { + uint8 type; + uint32 timer; }; + static_assert(sizeof(tTimerPacket) == 8, "tTimerPacket: error"); + struct tPedHeaderPacket + { + uint8 type; + uint8 index; + uint16 mi; + uint8 pedtype; + private: + uint8 __align[3]; + }; + static_assert(sizeof(tPedHeaderPacket) == 8, "tPedHeaderPacket: error"); + + struct tBulletTracePacket + { + uint8 type; + uint8 frames; + uint8 lifetime; + uint8 index; + CVector inf; + CVector sup; + }; + static_assert(sizeof(tBulletTracePacket) == 28, "tBulletTracePacket: error"); + + struct tEndOfFramePacket + { + uint8 type; + private: + uint8 __align[3]; + }; + static_assert(sizeof(tEndOfFramePacket) == 4, "tEndOfFramePacket: error"); + +private: static uint8 &Mode; + static CAddressInReplayBuffer &Record; + static CAddressInReplayBuffer &Playback; + static uint8 *&pBuf0; + static CAutomobile *&pBuf1; + static uint8 *&pBuf2; + static CPlayerPed *&pBuf3; + static uint8 *&pBuf4; + static CCutsceneHead *&pBuf5; + static uint8 *&pBuf6; + static CPtrNode *&pBuf7; + static uint8 *&pBuf8; + static CEntryInfoNode *&pBuf9; + static uint8 *&pBuf10; + static CDummyPed *&pBuf11; + static CBlip *&pRadarBlips; + static CCamera *&pStoredCam; + static CSector *&pWorld1; + static CReference *&pEmptyReferences; + static CStoredDetailedAnimationState *&pPedAnims; + static CPickup *&pPickups; + static CReference *&pReferences; + static uint8 (&BufferStatus)[8]; + static uint8 (&Buffers)[8][100000]; static bool &bPlayingBackFromFile; + static bool &bReplayEnabled; + static uint32 &SlowMotion; + static uint32 &FramesActiveLookAroundCam; + static bool &bDoLoadSceneWhenDone; +public: + static void Init(void); + static void DisableReplays(void); + static void EnableReplays(void); + static void Update(void); + static void FinishPlayback(void); + static void Shutdown(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); + static bool ShouldStandardCameraBeProcessed(void); + + inline static bool IsPlayingBack() { return Mode == MODE_PLAYBACK; } + inline static bool IsPlayingBackFromFile() { return bPlayingBackFromFile; } + +private: + static void RecordThisFrame(void); + static void StorePedUpdate(CPed *ped, int id); + static void StorePedAnimation(CPed *ped, CStoredAnimationState *state); + static void StoreDetailedPedAnimation(CPed *ped, CStoredDetailedAnimationState *state); + static void ProcessPedUpdate(CPed *ped, float interpolation, CAddressInReplayBuffer *buffer); + static void RetrievePedAnimation(CPed *ped, CStoredAnimationState *state); + static void RetrieveDetailedPedAnimation(CPed *ped, CStoredDetailedAnimationState *state); + static void PlaybackThisFrame(void); + static void StoreCarUpdate(CVehicle *vehicle, int id); + static void ProcessCarUpdate(CVehicle *vehicle, float interpolation, CAddressInReplayBuffer *buffer); + static bool PlayBackThisFrameInterpolation(CAddressInReplayBuffer *buffer, float interpolation, uint32 *pTimer); + static void ProcessReplayCamera(void); + static void StoreStuffInMem(void); + static void RestoreStuffFromMem(void); + static void EmptyPedsAndVehiclePools(void); + static void EmptyAllPools(void); + static void MarkEverythingAsNew(void); + static void SaveReplayToHD(void); + static void FindFirstFocusCoordinate(CVector *coord); + static void ProcessLookAroundCam(void); + static size_t FindSizeOfPacket(uint8); }; diff --git a/src/entities/CutsceneObject.cpp b/src/entities/CutsceneObject.cpp index 1e665dd6..163d0513 100644 --- a/src/entities/CutsceneObject.cpp +++ b/src/entities/CutsceneObject.cpp @@ -74,7 +74,7 @@ CCutsceneObject::SetupLighting(void) }else{ CVector coors = GetPosition(); float lighting = CPointLights::GenerateLightsAffectingObject(&coors); - if(!m_flagB20 && lighting != 1.0f){ + if(!bHasBlip && lighting != 1.0f){ SetAmbientAndDirectionalColours(lighting); return true; } diff --git a/src/entities/Entity.cpp b/src/entities/Entity.cpp index 0ab1488d..d2b2577d 100644 --- a/src/entities/Entity.cpp +++ b/src/entities/Entity.cpp @@ -31,7 +31,7 @@ CEntity::CEntity(void) bIsVisible = true; bHasCollided = false; bRenderScorched = false; - m_flagB20 = false; + bHasBlip = false; bIsBIGBuilding = false; bRenderDamaged = false; diff --git a/src/entities/Entity.h b/src/entities/Entity.h index 95294ed8..0ce47428 100644 --- a/src/entities/Entity.h +++ b/src/entities/Entity.h @@ -5,6 +5,19 @@ struct CReference; +enum eEntityFlags +{ + IS_UNK = 0, + CONTROL_POSTPONED, + IS_EXPLOSIONPROOF, + IS_VISIBLE, + IS_ON_GROUND, + REQUIRES_SCORCHED_LIGHTS, + HAS_BLIP, + IS_BIG_BUILDING, + HAS_BEEN_DAMAGED, +}; + enum eEntityType { ENTITY_TYPE_NOTHING = 0, @@ -59,7 +72,7 @@ public: uint32 bIsVisible : 1; uint32 bHasCollided : 1; // uint32 bRenderScorched : 1; - uint32 m_flagB20 : 1; // bFlashing? + uint32 bHasBlip : 1; uint32 bIsBIGBuilding : 1; // VC inserts one more flag here: if drawdist <= 2000 uint32 bRenderDamaged : 1; diff --git a/src/entities/Ped.h b/src/entities/Ped.h index 660f3462..800c5bb9 100644 --- a/src/entities/Ped.h +++ b/src/entities/Ped.h @@ -166,7 +166,7 @@ public: uint8 m_ped_flagI1 : 1; uint8 m_ped_flagI2 : 1; uint8 m_ped_flagI4 : 1; - uint8 m_ped_flagI8 : 1; + uint8 bRecordedForReplay : 1; uint8 m_ped_flagI10 : 1; uint8 m_ped_flagI20 : 1; uint8 m_ped_flagI40 : 1; diff --git a/src/math/Matrix.h b/src/math/Matrix.h index 10255af1..a93de636 100644 --- a/src/math/Matrix.h +++ b/src/math/Matrix.h @@ -155,6 +155,9 @@ public: r.Normalise(); f = CrossProduct(u, r); } + void CopyOnlyMatrix(CMatrix *other){ + m_matrix = other->m_matrix; + } }; inline CMatrix& diff --git a/src/render/Hud.cpp b/src/render/Hud.cpp index 96e50f06..23a796e6 100644 --- a/src/render/Hud.cpp +++ b/src/render/Hud.cpp @@ -189,7 +189,7 @@ void CHud::Draw() RwRenderStateSet(rwRENDERSTATESHADEMODE, (void*)rwSHADEMODEFLAT); RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void*)rwFILTERLINEAR); - if (CReplay::Mode != 1) { + if (!CReplay::IsPlayingBack()) { if (m_Wants_To_Draw_Hud && !TheCamera.m_WideScreenOn) { bool Mode_RunAround = 0; bool Mode_FirstPerson = 0; @@ -1063,7 +1063,7 @@ WRAPPER void CHud::DrawAfterFade(void) { EAXJMP(0x509030); } #else void CHud::DrawAfterFade() { - if (CTimer::GetIsUserPaused() || CReplay::Mode == 1) + if (CTimer::GetIsUserPaused() || CReplay::IsPlayingBack()) return; if (m_HelpMessage[0]) { diff --git a/src/templates.h b/src/templates.h index 65f92a2a..d1ef99f0 100644 --- a/src/templates.h +++ b/src/templates.h @@ -101,6 +101,27 @@ public: n++; return n; } + void ClearStorage(uint8 **flags, U **entries){ + delete[] flags; + delete[] entries; + *flags = nil; + *entries = nil; + } + void CopyBack(uint8 **flags, U **entries){ + memcpy(m_flags, *flags, sizeof(Flags)*m_size); + memcpy(m_entries, *entries, sizeof(U)*m_size); + debug("Size copied:%d (%d)", sizeof(U)*m_size, sizeof(Flags)*m_size); + m_allocPtr = 0; + ClearStorage(flags, entries); + debug("CopyBack:%d (/%d)", GetNoOfUsedSpaces(), m_size); /* Assumed inlining */ + } + void Store(uint8 **flags, U** entries){ + *flags = (Flags*)malloc(sizeof(Flags)*m_size); + *entries = (U*)malloc(sizeof(U)*m_size); + memcpy(*flags, m_flags, sizeof(Flags)*m_size); + memcpy(*entries, m_entries, sizeof(U)*m_size); + debug("Stored:%d (/%d)", GetNoOfUsedSpaces(), m_size); /* Assumed inlining */ + } }; template<typename T> |