From 74fde1397e04fe78af0508789fdd1a7bf0e02799 Mon Sep 17 00:00:00 2001 From: Nikolay Korolev Date: Mon, 27 Apr 2020 00:54:43 +0300 Subject: [PATCH 1/4] pools compatibility --- librw | 2 +- src/core/Pools.cpp | 90 ++++++- src/core/Pools.h | 534 ++++++++++++++++++++++++++++++++++++++++++ src/core/config.h | 2 + src/entities/Entity.h | 2 + 5 files changed, 625 insertions(+), 5 deletions(-) diff --git a/librw b/librw index 43190a51..d8d13d44 160000 --- a/librw +++ b/librw @@ -1 +1 @@ -Subproject commit 43190a51f799a3ef315c0b6245b70ee3a09a64ac +Subproject commit d8d13d44293a58b58d51c3a8e91e3ea76c6d6feb diff --git a/src/core/Pools.cpp b/src/core/Pools.cpp index 4f4588da..8c979f6e 100644 --- a/src/core/Pools.cpp +++ b/src/core/Pools.cpp @@ -110,17 +110,31 @@ INITSAVEBUF CStreaming::LoadAllRequestedModels(false); int32 slot = ReadSaveBuf(buf); CVehicle* pVehicle; +#ifdef COMPATIBLE_SAVES + char* vbuf = new char[Max(sizeof(CAutomobile_FS), sizeof(CBoat_FS))]; +#else char* vbuf = new char[Max(sizeof(CAutomobile), sizeof(CBoat))]; +#endif if (type == VEHICLE_TYPE_BOAT) { +#ifdef COMPATIBLE_SAVES + memcpy(vbuf, buf, sizeof(CBoat_FS)); + SkipSaveBuf(buf, sizeof(CBoat_FS)); +#else memcpy(vbuf, buf, sizeof(CBoat)); SkipSaveBuf(buf, sizeof(CBoat)); +#endif CBoat* pBoat = new(slot) CBoat(model, RANDOM_VEHICLE); pVehicle = pBoat; --CCarCtrl::NumRandomCars; // why? } else if (type == VEHICLE_TYPE_CAR) { +#ifdef COMPATIBLE_SAVES + memcpy(vbuf, buf, sizeof(CAutomobile_FS)); + SkipSaveBuf(buf, sizeof(CAutomobile_FS)); +#else memcpy(vbuf, buf, sizeof(CAutomobile)); SkipSaveBuf(buf, sizeof(CAutomobile)); +#endif CStreaming::RequestModel(model, 0); // is it needed? CStreaming::LoadAllRequestedModels(false); CAutomobile* pAutomobile = new(slot) CAutomobile(model, RANDOM_VEHICLE); @@ -131,6 +145,10 @@ INITSAVEBUF } else assert(0); +#ifdef COMPATIBLE_SAVES + CVehicle_FS* pBufferVehicle = (CVehicle_FS*)vbuf; + pBufferVehicle->Restore(pVehicle); +#else CVehicle* pBufferVehicle = (CVehicle*)vbuf; pVehicle->GetMatrix() = pBufferVehicle->GetMatrix(); pVehicle->VehicleCreatedBy = pBufferVehicle->VehicleCreatedBy; @@ -166,6 +184,7 @@ INITSAVEBUF (pVehicle->GetAddressOfEntityProperties())[0] = (pBufferVehicle->GetAddressOfEntityProperties())[0]; (pVehicle->GetAddressOfEntityProperties())[1] = (pBufferVehicle->GetAddressOfEntityProperties())[1]; pVehicle->AutoPilot = pBufferVehicle->AutoPilot; +#endif CWorld::Add(pVehicle); delete[] vbuf; } @@ -184,7 +203,7 @@ INITSAVEBUF continue; bool bHasPassenger = false; for (int j = 0; j < ARRAY_SIZE(pVehicle->pPassengers); j++) { - if (pVehicle->pPassengers[i]) + if (pVehicle->pPassengers[j]) bHasPassenger = true; } if (!pVehicle->pDriver && !bHasPassenger) { @@ -194,8 +213,20 @@ INITSAVEBUF ++nNumBoats; } } - *size = nNumCars * (sizeof(uint32) + sizeof(int16) + sizeof(int32) + sizeof(CAutomobile)) + sizeof(int) + - nNumBoats * (sizeof(uint32) + sizeof(int16) + sizeof(int32) + sizeof(CBoat)) + sizeof(int); + *size = nNumCars * (sizeof(uint32) + sizeof(int16) + sizeof(int32) + +#ifdef COMPATIBLE_SAVES + sizeof(CAutomobile_FS)) + +#else + sizeof(CAutomobile)) + +#endif + sizeof(int) + + nNumBoats * (sizeof(uint32) + sizeof(int16) + sizeof(int32) + +#ifdef COMPATIBLE_SAVES + sizeof(CBoat_FS)) + +#else + sizeof(CBoat)) + +#endif + sizeof(int); WriteSaveBuf(buf, nNumCars); WriteSaveBuf(buf, nNumBoats); for (int i = 0; i < nPoolSize; i++) { @@ -212,8 +243,15 @@ INITSAVEBUF WriteSaveBuf(buf, (uint32)pVehicle->m_vehType); WriteSaveBuf(buf, pVehicle->m_modelIndex); WriteSaveBuf(buf, GetVehicleRef(pVehicle)); +#ifdef COMPATIBLE_SAVES + ((CVehicle_FS*)buf)->Store(pVehicle); + SkipSaveBuf(buf, sizeof(CVehicle_FS)); + WriteSaveBuf(buf, ((CAutomobile*)pVehicle)->Damage); + SkipSaveBuf(buf, sizeof(CAutomobile_FS) - sizeof(CVehicle_FS) - sizeof(CDamageManager)); +#else memcpy(buf, pVehicle, sizeof(CAutomobile)); SkipSaveBuf(buf, sizeof(CAutomobile)); +#endif } if (pVehicle->IsBoat() && pVehicle->VehicleCreatedBy == MISSION_VEHICLE) { WriteSaveBuf(buf, (uint32)pVehicle->m_vehType); @@ -279,8 +317,14 @@ INITSAVEBUF WriteSaveBuf(buf, pObject->m_nCollisionDamageEffect); WriteSaveBuf(buf, pObject->m_nSpecialCollisionResponseCases); WriteSaveBuf(buf, pObject->m_nEndOfLifeTime); +#ifdef COMPATIBLE_SAVES + CEntityProperties properties; + properties.Store(pObject); + WriteSaveBuf(buf, properties); +#else WriteSaveBuf(buf, (pObject->GetAddressOfEntityProperties())[0]); WriteSaveBuf(buf, (pObject->GetAddressOfEntityProperties())[1]); +#endif } } VALIDATESAVEBUF(*size) @@ -315,8 +359,12 @@ INITSAVEBUF pBufferObject->m_nCollisionDamageEffect = ReadSaveBuf(buf); pBufferObject->m_nSpecialCollisionResponseCases = ReadSaveBuf(buf); pBufferObject->m_nEndOfLifeTime = ReadSaveBuf(buf); +#ifdef COMPATIBLE_SAVES + CEntityProperties properties = ReadSaveBuf(buf); +#else (pBufferObject->GetAddressOfEntityProperties())[0] = ReadSaveBuf(buf); (pBufferObject->GetAddressOfEntityProperties())[1] = ReadSaveBuf(buf); +#endif if (GetObjectPool()->GetSlot(ref >> 8)) CPopulation::ConvertToDummyObject(GetObjectPool()->GetSlot(ref >> 8)); CObject* pObject = new(ref) CObject(mi, false); @@ -335,8 +383,12 @@ INITSAVEBUF pObject->m_nCollisionDamageEffect = pBufferObject->m_nCollisionDamageEffect; pObject->m_nSpecialCollisionResponseCases = pBufferObject->m_nSpecialCollisionResponseCases; pObject->m_nEndOfLifeTime = pBufferObject->m_nEndOfLifeTime; +#ifdef COMPATIBLE_SAVES + properties.Restore(pObject); +#else (pObject->GetAddressOfEntityProperties())[0] = (pBufferObject->GetAddressOfEntityProperties())[0]; (pObject->GetAddressOfEntityProperties())[1] = (pBufferObject->GetAddressOfEntityProperties())[1]; +#endif pObject->bHasCollided = false; CWorld::Add(pObject); delete[] obuf; @@ -356,7 +408,12 @@ INITSAVEBUF if (!pPed->bInVehicle && pPed->m_nPedType == PEDTYPE_PLAYER1) nNumPeds++; } - *size = sizeof(int) + nNumPeds * (sizeof(uint32) + sizeof(int16) + sizeof(int) + sizeof(CPlayerPed) + + *size = sizeof(int) + nNumPeds * (sizeof(uint32) + sizeof(int16) + sizeof(int) + +#ifdef COMPATIBLE_SAVES + sizeof(CPlayerPed_FS) + +#else + sizeof(CPlayerPed) + +#endif sizeof(CWanted::MaximumWantedLevel) + sizeof(CWanted::nMaximumWantedLevel) + MAX_MODEL_NAME); WriteSaveBuf(buf, nNumPeds); for (int i = 0; i < nPoolSize; i++) { @@ -367,8 +424,14 @@ INITSAVEBUF WriteSaveBuf(buf, pPed->m_nPedType); WriteSaveBuf(buf, pPed->m_modelIndex); WriteSaveBuf(buf, GetPedRef(pPed)); +#ifdef COMPATIBLE_SAVES + ((CPlayerPed_FS*)buf)->StorePlayerPed((CPlayerPed*)pPed); + ((CPlayerPed_FS*)buf)->StorePed(pPed); + SkipSaveBuf(buf, sizeof(CPlayerPed_FS)); +#else memcpy(buf, pPed, sizeof(CPlayerPed)); SkipSaveBuf(buf, sizeof(CPlayerPed)); +#endif WriteSaveBuf(buf, CWanted::MaximumWantedLevel); WriteSaveBuf(buf, CWanted::nMaximumWantedLevel); memcpy(buf, CModelInfo::GetModelInfo(pPed->GetModelIndex())->GetName(), MAX_MODEL_NAME); @@ -386,14 +449,24 @@ INITSAVEBUF uint32 pedtype = ReadSaveBuf(buf); int16 model = ReadSaveBuf(buf); int ref = ReadSaveBuf(buf); +#ifdef COMPATIBLE_SAVES + char* pbuf = new char[sizeof(CPlayerPed_FS)]; + CPlayerPed_FS* pBufferPlayer = (CPlayerPed_FS*)buf; +#else char* pbuf = new char[sizeof(CPlayerPed)]; CPlayerPed* pBufferPlayer = (CPlayerPed*)pbuf; +#endif CPed* pPed; char name[MAX_MODEL_NAME]; // the code implies that there was idea to load non-player ped if (pedtype == PEDTYPE_PLAYER1) { // always true +#ifdef COMPATIBLE_SAVES + memcpy(pbuf, buf, sizeof(CPlayerPed_FS)); + SkipSaveBuf(buf, sizeof(CPlayerPed_FS)); +#else memcpy(pbuf, buf, sizeof(CPlayerPed)); SkipSaveBuf(buf, sizeof(CPlayerPed)); +#endif CWanted::MaximumWantedLevel = ReadSaveBuf(buf); CWanted::nMaximumWantedLevel = ReadSaveBuf(buf); memcpy(name, buf, MAX_MODEL_NAME); @@ -403,11 +476,19 @@ INITSAVEBUF CStreaming::LoadAllRequestedModels(false); if (pedtype == PEDTYPE_PLAYER1) { CPlayerPed* pPlayerPed = new(ref) CPlayerPed(); +#ifdef COMPATIBLE_SAVES + pBufferPlayer->RestorePlayerPed(pPlayerPed); +#else for (int i = 0; i < ARRAY_SIZE(pPlayerPed->m_nTargettableObjects); i++) pPlayerPed->m_nTargettableObjects[i] = pBufferPlayer->m_nTargettableObjects[i]; pPlayerPed->m_fMaxStamina = pBufferPlayer->m_fMaxStamina; +#endif pPed = pPlayerPed; } +#ifdef COMPATIBLE_SAVES + pBufferPlayer->RestorePed(pPed); + pPed->m_currentWeapon = 0; +#else pPed->GetPosition() = pBufferPlayer->GetPosition(); pPed->m_fHealth = pBufferPlayer->m_fHealth; pPed->m_fArmour = pBufferPlayer->m_fArmour; @@ -416,6 +497,7 @@ INITSAVEBUF pPed->m_maxWeaponTypeAllowed = pBufferPlayer->m_maxWeaponTypeAllowed; for (int i = 0; i < WEAPONTYPE_TOTAL_INVENTORY_WEAPONS; i++) pPed->m_weapons[i] = pBufferPlayer->m_weapons[i]; +#endif if (pedtype == PEDTYPE_PLAYER1) { pPed->m_wepAccuracy = 100; CWorld::Players[0].m_pPed = (CPlayerPed*)pPed; diff --git a/src/core/Pools.h b/src/core/Pools.h index b0ba6598..6e5b0ac1 100644 --- a/src/core/Pools.h +++ b/src/core/Pools.h @@ -59,3 +59,537 @@ public: static void SavePedPool(uint8 *buf, uint32 *size); static void SaveVehiclePool(uint8 *buf, uint32 *size); }; + +#ifdef COMPATIBLE_SAVES + +// Following stuff allows changing structures like CPed, CAutomobile and CBoat without breaking compatibility with original saves. + +// For saving we have to assume that sizeof(void*) == 4, so we use int32 everywhere. +// It will break some pointers, but saving them makes no sense anyway. + +struct CEntityProperties +{ + // these properties are defined exactly as in original game + + uint32 m_type : 3; + uint32 m_status : 5; + + // flagsA + uint32 bUsesCollision : 1; // does entity use collision + uint32 bCollisionProcessed : 1; // has object been processed by a ProcessEntityCollision function + uint32 bIsStatic : 1; // is entity static + uint32 bHasContacted : 1; // has entity processed some contact forces + uint32 bPedPhysics : 1; + uint32 bIsStuck : 1; // is entity stuck + uint32 bIsInSafePosition : 1; // is entity in a collision free safe position + uint32 bUseCollisionRecords : 1; + + // flagsB + uint32 bWasPostponed : 1; // was entity control processing postponed + uint32 bExplosionProof : 1; + uint32 bIsVisible : 1; //is the entity visible + uint32 bHasCollided : 1; + uint32 bRenderScorched : 1; + uint32 bHasBlip : 1; + uint32 bIsBIGBuilding : 1; // Set if this entity is a big building + // VC inserts one more flag here: if drawdist <= 2000 + uint32 bRenderDamaged : 1; // use damaged LOD models for objects with applicable damage + + // flagsC + uint32 bBulletProof : 1; + uint32 bFireProof : 1; + uint32 bCollisionProof : 1; + uint32 bMeleeProof : 1; + uint32 bOnlyDamagedByPlayer : 1; + uint32 bStreamingDontDelete : 1; // Dont let the streaming remove this + uint32 bZoneCulled : 1; + uint32 bZoneCulled2 : 1; // only treadables+10m + + // flagsD + uint32 bRemoveFromWorld : 1; // remove this entity next time it should be processed + uint32 bHasHitWall : 1; // has collided with a building (changes subsequent collisions) + uint32 bImBeingRendered : 1; // don't delete me because I'm being rendered + uint32 bTouchingWater : 1; // used by cBuoyancy::ProcessBuoyancy + uint32 bIsSubway : 1; // set when subway, but maybe different meaning? + uint32 bDrawLast : 1; // draw object last + uint32 bNoBrightHeadLights : 1; + uint32 bDoNotRender : 1; + + // flagsE + uint32 bDistanceFade : 1; // Fade entity because it is far away + uint32 m_flagE2 : 1; + + void Store(CEntity* pEntity) + { + m_type = pEntity->m_type; + m_status = pEntity->m_status; + bUsesCollision = pEntity->bUsesCollision; + bCollisionProcessed = pEntity->bCollisionProcessed; + bIsStatic = pEntity->bIsStatic; + bHasContacted = pEntity->bHasContacted; + bPedPhysics = pEntity->bPedPhysics; + bIsStuck = pEntity->bIsStuck; + bIsInSafePosition = pEntity->bIsInSafePosition; + bUseCollisionRecords = pEntity->bUseCollisionRecords; + bWasPostponed = pEntity->bWasPostponed; + bExplosionProof = pEntity->bExplosionProof; + bIsVisible = pEntity->bIsVisible; + bHasCollided = pEntity->bHasCollided; + bRenderScorched = pEntity->bRenderScorched; + bHasBlip = pEntity->bHasBlip; + bIsBIGBuilding = pEntity->bIsBIGBuilding; + bRenderDamaged = pEntity->bRenderDamaged; + bBulletProof = pEntity->bBulletProof; + bFireProof = pEntity->bFireProof; + bCollisionProof = pEntity->bCollisionProof; + bMeleeProof = pEntity->bMeleeProof; + bOnlyDamagedByPlayer = pEntity->bOnlyDamagedByPlayer; + bStreamingDontDelete = pEntity->bStreamingDontDelete; + bZoneCulled = pEntity->bZoneCulled; + bZoneCulled2 = pEntity->bZoneCulled2; + bRemoveFromWorld = pEntity->bRemoveFromWorld; + bHasHitWall = pEntity->bHasHitWall; + bImBeingRendered = pEntity->bImBeingRendered; + bTouchingWater = pEntity->bTouchingWater; + bIsSubway = pEntity->bIsSubway; + bDrawLast = pEntity->bDrawLast; + bNoBrightHeadLights = pEntity->bNoBrightHeadLights; + bDoNotRender = pEntity->bDoNotRender; + bDistanceFade = pEntity->bDistanceFade; + m_flagE2 = pEntity->m_flagE2; + } + + void Restore(CEntity* pEntity) + { + pEntity->m_type = m_type; + pEntity->m_status = m_status; + pEntity->bUsesCollision = bUsesCollision; + pEntity->bCollisionProcessed = bCollisionProcessed; + pEntity->bIsStatic = bIsStatic; + pEntity->bHasContacted = bHasContacted; + pEntity->bPedPhysics = bPedPhysics; + pEntity->bIsStuck = bIsStuck; + pEntity->bIsInSafePosition = bIsInSafePosition; + pEntity->bUseCollisionRecords = bUseCollisionRecords; + pEntity->bWasPostponed = bWasPostponed; + pEntity->bExplosionProof = bExplosionProof; + pEntity->bIsVisible = bIsVisible; + pEntity->bHasCollided = bHasCollided; + pEntity->bRenderScorched = bRenderScorched; + pEntity->bHasBlip = bHasBlip; + pEntity->bIsBIGBuilding = bIsBIGBuilding; + pEntity->bRenderDamaged = bRenderDamaged; + pEntity->bBulletProof = bBulletProof; + pEntity->bFireProof = bFireProof; + pEntity->bCollisionProof = bCollisionProof; + pEntity->bMeleeProof = bMeleeProof; + pEntity->bOnlyDamagedByPlayer = bOnlyDamagedByPlayer; + pEntity->bStreamingDontDelete = bStreamingDontDelete; + pEntity->bZoneCulled = bZoneCulled; + pEntity->bZoneCulled2 = bZoneCulled2; + pEntity->bRemoveFromWorld = bRemoveFromWorld; + pEntity->bHasHitWall = bHasHitWall; + pEntity->bImBeingRendered = bImBeingRendered; + pEntity->bTouchingWater = bTouchingWater; + pEntity->bIsSubway = bIsSubway; + pEntity->bDrawLast = bDrawLast; + pEntity->bNoBrightHeadLights = bNoBrightHeadLights; + pEntity->bDoNotRender = bDoNotRender; + pEntity->bDistanceFade = bDistanceFade; + pEntity->m_flagE2 = m_flagE2; + } +}; + +VALIDATE_SIZE(CEntityProperties, 8); + +struct CAutoPilot_FS +{ + int32 m_nCurrentRouteNode; + int32 m_nNextRouteNode; + int32 m_nPrevRouteNode; + uint32 m_nTimeEnteredCurve; + uint32 m_nTimeToSpendOnCurrentCurve; + uint32 m_nCurrentPathNodeInfo; + uint32 m_nNextPathNodeInfo; + uint32 m_nPreviousPathNodeInfo; + uint32 m_nAntiReverseTimer; + uint32 m_nTimeToStartMission; + int8 m_nPreviousDirection; + int8 m_nCurrentDirection; + int8 m_nNextDirection; + int8 m_nCurrentLane; + int8 m_nNextLane; + uint8 m_nDrivingStyle; + uint8 m_nCarMission; + uint8 m_nTempAction; + uint32 m_nTimeTempAction; + float m_fMaxTrafficSpeed; + uint8 m_nCruiseSpeed; + uint8 m_bSlowedDownBecauseOfCars : 1; + uint8 m_bSlowedDownBecauseOfPeds : 1; + uint8 m_bStayInCurrentLevel : 1; + uint8 m_bStayInFastLane : 1; + uint8 m_bIgnorePathfinding : 1; + float m_vecDestinationCoors[3]; + int32 m_aPathFindNodesInfo[8]; // CPathNode* [NUM_PATH_NODES_IN_AUTOPILOT] + int16 m_nPathFindNodesCount; + int32 m_pTargetCar; + + void Store(CAutoPilot* pAutoPilot) + { + m_nCurrentRouteNode = pAutoPilot->m_nCurrentRouteNode; + m_nNextRouteNode = pAutoPilot->m_nNextRouteNode; + m_nPrevRouteNode = pAutoPilot->m_nPrevRouteNode; + m_nTimeEnteredCurve = pAutoPilot->m_nTimeEnteredCurve; + m_nTimeToSpendOnCurrentCurve = pAutoPilot->m_nTimeToSpendOnCurrentCurve; + m_nCurrentPathNodeInfo = pAutoPilot->m_nCurrentPathNodeInfo; + m_nNextPathNodeInfo = pAutoPilot->m_nNextPathNodeInfo; + m_nPreviousPathNodeInfo = pAutoPilot->m_nPreviousPathNodeInfo; + m_nAntiReverseTimer = pAutoPilot->m_nAntiReverseTimer; + m_nTimeToStartMission = pAutoPilot->m_nTimeToStartMission; + m_nPreviousDirection = pAutoPilot->m_nPreviousDirection; + m_nCurrentDirection = pAutoPilot->m_nCurrentDirection; + m_nNextDirection = pAutoPilot->m_nNextDirection; + m_nCurrentLane = pAutoPilot->m_nCurrentLane; + m_nNextLane = pAutoPilot->m_nNextLane; + m_nDrivingStyle = pAutoPilot->m_nDrivingStyle; + m_nCarMission = pAutoPilot->m_nCarMission; + m_nTempAction = pAutoPilot->m_nTempAction; + m_nTimeTempAction = pAutoPilot->m_nTimeTempAction; + m_fMaxTrafficSpeed = pAutoPilot->m_fMaxTrafficSpeed; + m_nCruiseSpeed = pAutoPilot->m_nCruiseSpeed; + m_bSlowedDownBecauseOfCars = pAutoPilot->m_bSlowedDownBecauseOfCars; + m_bSlowedDownBecauseOfPeds = pAutoPilot->m_bSlowedDownBecauseOfPeds; + m_bStayInCurrentLevel = pAutoPilot->m_bStayInCurrentLevel; + m_bStayInFastLane = pAutoPilot->m_bStayInFastLane; + m_bIgnorePathfinding = pAutoPilot->m_bIgnorePathfinding; + m_vecDestinationCoors[0] = pAutoPilot->m_vecDestinationCoors.x; + m_vecDestinationCoors[1] = pAutoPilot->m_vecDestinationCoors.y; + m_vecDestinationCoors[2] = pAutoPilot->m_vecDestinationCoors.z; + for (int i = 0; i < 8; i++) + m_aPathFindNodesInfo[i] = 0; + m_nPathFindNodesCount = pAutoPilot->m_nPathFindNodesCount; + m_pTargetCar = 0; + } + + void Restore(CAutoPilot* pAutoPilot) + { + pAutoPilot->m_nCurrentRouteNode = m_nCurrentRouteNode; + pAutoPilot->m_nNextRouteNode = m_nNextRouteNode; + pAutoPilot->m_nPrevRouteNode = m_nPrevRouteNode; + pAutoPilot->m_nTimeEnteredCurve = m_nTimeEnteredCurve; + pAutoPilot->m_nTimeToSpendOnCurrentCurve = m_nTimeToSpendOnCurrentCurve; + pAutoPilot->m_nCurrentPathNodeInfo = m_nCurrentPathNodeInfo; + pAutoPilot->m_nNextPathNodeInfo = m_nNextPathNodeInfo; + pAutoPilot->m_nPreviousPathNodeInfo = m_nPreviousPathNodeInfo; + pAutoPilot->m_nAntiReverseTimer = m_nAntiReverseTimer; + pAutoPilot->m_nTimeToStartMission = m_nTimeToStartMission; + pAutoPilot->m_nPreviousDirection = m_nPreviousDirection; + pAutoPilot->m_nCurrentDirection = m_nCurrentDirection; + pAutoPilot->m_nNextDirection = m_nNextDirection; + pAutoPilot->m_nCurrentLane = m_nCurrentLane; + pAutoPilot->m_nNextLane = m_nNextLane; + pAutoPilot->m_nDrivingStyle = (eCarDrivingStyle)m_nDrivingStyle; + pAutoPilot->m_nCarMission = (eCarMission)m_nCarMission; + pAutoPilot->m_nTempAction = (eCarTempAction)m_nTempAction; + pAutoPilot->m_nTimeTempAction = m_nTimeTempAction; + pAutoPilot->m_fMaxTrafficSpeed = m_fMaxTrafficSpeed; + pAutoPilot->m_nCruiseSpeed = m_nCruiseSpeed; + pAutoPilot->m_bSlowedDownBecauseOfCars = m_bSlowedDownBecauseOfCars; + pAutoPilot->m_bSlowedDownBecauseOfPeds = m_bSlowedDownBecauseOfPeds; + pAutoPilot->m_bStayInCurrentLevel = m_bStayInCurrentLevel; + pAutoPilot->m_bStayInFastLane = m_bStayInFastLane; + pAutoPilot->m_bIgnorePathfinding = m_bIgnorePathfinding; + pAutoPilot->m_vecDestinationCoors.x = m_vecDestinationCoors[0]; + pAutoPilot->m_vecDestinationCoors.y = m_vecDestinationCoors[1]; + pAutoPilot->m_vecDestinationCoors.z = m_vecDestinationCoors[2]; + for (int i = 0; i < NUM_PATH_NODES_IN_AUTOPILOT; i++) + pAutoPilot->m_aPathFindNodesInfo[i] = nil; + pAutoPilot->m_nPathFindNodesCount = m_nPathFindNodesCount; + pAutoPilot->m_pTargetCar = nil; + } +}; + +struct CMatrix_FS +{ + float right[3]; + uint8 gap1[4]; + float forward[3]; + uint8 gap2[4]; + float up[3]; + uint8 gap3[4]; + float pos[3]; + uint8 gap4[12]; + + void Store(CMatrix* pMatrix) + { + right[0] = pMatrix->GetRight().x; + right[1] = pMatrix->GetRight().y; + right[2] = pMatrix->GetRight().z; + forward[0] = pMatrix->GetForward().x; + forward[1] = pMatrix->GetForward().y; + forward[2] = pMatrix->GetForward().z; + up[0] = pMatrix->GetUp().x; + up[1] = pMatrix->GetUp().y; + up[2] = pMatrix->GetUp().z; + pos[0] = pMatrix->GetPosition().x; + pos[1] = pMatrix->GetPosition().y; + pos[2] = pMatrix->GetPosition().z; + } + + void Restore(CMatrix* pMatrix) + { + CMatrix tmp; + tmp.GetRight().x = right[0]; + tmp.GetRight().y = right[1]; + tmp.GetRight().z = right[2]; + tmp.GetForward().x = forward[0]; + tmp.GetForward().y = forward[1]; + tmp.GetForward().z = forward[2]; + tmp.GetUp().x = up[0]; + tmp.GetUp().y = up[1]; + tmp.GetUp().z = up[2]; + tmp.GetPosition().x = pos[0]; + tmp.GetPosition().y = pos[1]; + tmp.GetPosition().z = pos[2]; + *pMatrix = tmp; + } +}; + +VALIDATE_SIZE(CMatrix_FS, 72); + +struct CVehicle_FS +{ + uint32 vtable; + CMatrix_FS matrix; + uint8 gap1[4]; + CEntityProperties properties; + uint8 gap2[212]; + CAutoPilot_FS AutoPilot; + uint8 m_currentColour1; + uint8 m_currentColour2; + uint8 gap3[2]; + int16 m_nAlarmState; + int8 gap4[43]; + uint8 m_nNumMaxPassengers; + float field_1D0[4]; + uint8 gap5[8]; + float m_fSteerAngle; + float m_fGasPedal; + float m_fBrakePedal; + uint8 VehicleCreatedBy; + + // cf. https://github.com/DK22Pac/plugin-sdk/blob/master/plugin_sa/game_sa/CVehicle.h from R* + uint8 bIsLawEnforcer : 1; // Is this guy chasing the player at the moment + uint8 gap_b1 : 1; + uint8 gap_b2 : 1; + uint8 bIsLocked : 1; // Is this guy locked by the script (cannot be removed) + uint8 bEngineOn : 1; // For sound purposes. Parked cars have their engines switched off (so do destroyed cars) + uint8 bIsHandbrakeOn : 1; // How's the handbrake doing ? + uint8 bLightsOn : 1; // Are the lights switched on ? + uint8 bFreebies : 1; // Any freebies left in this vehicle ? + + uint8 gap6[3]; + + uint8 gap7[6]; + float m_fHealth; // 1000.0f = full health. 250.0f = fire. 0 -> explode + uint8 m_nCurrentGear; + float m_fChangeGearTime; + uint8 gap8[4]; + uint32 m_nTimeOfDeath; + uint8 gap9[2]; + int16 m_nBombTimer; + uint8 gap10[12]; + int8 m_nDoorLock; + uint8 gap11[96]; + + void Store(CVehicle* pVehicle) + { + matrix.Store(&pVehicle->GetMatrix()); + VehicleCreatedBy = pVehicle->VehicleCreatedBy; + m_currentColour1 = pVehicle->m_currentColour1; + m_currentColour2 = pVehicle->m_currentColour2; + m_nAlarmState = pVehicle->m_nAlarmState; + m_nNumMaxPassengers = pVehicle->m_nNumMaxPassengers; + field_1D0[0] = pVehicle->field_1D0[0]; + field_1D0[1] = pVehicle->field_1D0[1]; + field_1D0[2] = pVehicle->field_1D0[2]; + field_1D0[3] = pVehicle->field_1D0[3]; + m_fSteerAngle = pVehicle->m_fSteerAngle; + m_fGasPedal = pVehicle->m_fGasPedal; + m_fBrakePedal = pVehicle->m_fBrakePedal; + bIsLawEnforcer = pVehicle->bIsLawEnforcer; + bIsLocked = pVehicle->bIsLocked; + bEngineOn = pVehicle->bEngineOn; + bIsHandbrakeOn = pVehicle->bIsHandbrakeOn; + bLightsOn = pVehicle->bLightsOn; + bFreebies = pVehicle->bFreebies; + m_fHealth = pVehicle->m_fHealth; + m_nCurrentGear = pVehicle->m_nCurrentGear; + m_fChangeGearTime = pVehicle->m_fChangeGearTime; + m_nTimeOfDeath = pVehicle->m_nTimeOfDeath; +#ifdef FIX_BUGS //must be copypaste + m_nBombTimer = pVehicle->m_nBombTimer; +#else + m_nTimeOfDeath = pVehicle->m_nTimeOfDeath; +#endif + m_nDoorLock = pVehicle->m_nDoorLock; + properties.Store(pVehicle); + AutoPilot.Store(&pVehicle->AutoPilot); + } + + void Restore(CVehicle* pVehicle) + { + matrix.Restore(&pVehicle->GetMatrix()); + pVehicle->VehicleCreatedBy = VehicleCreatedBy; + pVehicle->m_currentColour1 = m_currentColour1; + pVehicle->m_currentColour2 = m_currentColour2; + pVehicle->m_nAlarmState = m_nAlarmState; + pVehicle->m_nNumMaxPassengers = m_nNumMaxPassengers; + pVehicle->field_1D0[0] = field_1D0[0]; + pVehicle->field_1D0[1] = field_1D0[1]; + pVehicle->field_1D0[2] = field_1D0[2]; + pVehicle->field_1D0[3] = field_1D0[3]; + pVehicle->m_fSteerAngle = m_fSteerAngle; + pVehicle->m_fGasPedal = m_fGasPedal; + pVehicle->m_fBrakePedal = m_fBrakePedal; + pVehicle->bIsLawEnforcer = bIsLawEnforcer; + pVehicle->bIsLocked = bIsLocked; + pVehicle->bEngineOn = bEngineOn; + pVehicle->bIsHandbrakeOn = bIsHandbrakeOn; + pVehicle->bLightsOn = bLightsOn; + pVehicle->bFreebies = bFreebies; + pVehicle->m_fHealth = m_fHealth; + pVehicle->m_nCurrentGear = m_nCurrentGear; + pVehicle->m_fChangeGearTime = m_fChangeGearTime; + pVehicle->m_nTimeOfDeath = m_nTimeOfDeath; +#ifdef FIX_BUGS //must be copypaste + pVehicle->m_nBombTimer = m_nBombTimer; +#else + pVehicle->m_nTimeOfDeath = m_nTimeOfDeath; +#endif + pVehicle->m_nDoorLock = (eCarLock)m_nDoorLock; + properties.Restore(pVehicle); + AutoPilot.Restore(&pVehicle->AutoPilot); + } +}; + +VALIDATE_SIZE(CVehicle_FS, 648); + +static_assert(sizeof(CDamageManager) < 1448 - sizeof(CVehicle_FS), "CDamageManager size too big to keep saves compatible"); + +struct CAutomobile_FS +{ + CVehicle_FS vehicle; + CDamageManager Damage; + char gap[1448 - sizeof(CVehicle_FS) - sizeof(CDamageManager)]; // even allows increasing size of CDamageManager +}; + +struct CBoat_FS +{ + CVehicle_FS vehicle; + char gap[1156 - sizeof(CVehicle_FS)]; +}; + +VALIDATE_SIZE(CAutomobile_FS, 1448); +VALIDATE_SIZE(CBoat_FS, 1156); + +struct CWeapon_FS +{ + int32 m_eWeaponType; + int32 m_eWeaponState; + uint32 m_nAmmoInClip; + uint32 m_nAmmoTotal; + uint32 m_nTimer; + bool m_bAddRotOffset; + + void Store(CWeapon* pWeapon) + { + m_eWeaponType = pWeapon->m_eWeaponType; + m_eWeaponState = pWeapon->m_eWeaponState; + m_nAmmoInClip = pWeapon->m_nAmmoInClip; + m_nAmmoTotal = pWeapon->m_nAmmoTotal; + m_nTimer = pWeapon->m_nTimer; + m_bAddRotOffset = pWeapon->m_bAddRotOffset; + } + + void Restore(CWeapon* pWeapon) + { + pWeapon->m_eWeaponType = (eWeaponType)m_eWeaponType; + pWeapon->m_eWeaponState = (eWeaponState)m_eWeaponState; + pWeapon->m_nAmmoInClip = m_nAmmoInClip; + pWeapon->m_nAmmoTotal = m_nAmmoTotal; + pWeapon->m_nTimer = m_nTimer; + pWeapon->m_bAddRotOffset = m_bAddRotOffset; + } +}; + +static_assert(WEAPONTYPE_TOTAL_INVENTORY_WEAPONS == 13, + "Saving struct needs to be changed by adding new weapons to existing space; or COMPATIBLE_SAVES needs to be undefined"); + +struct CPlayerPed_FS +{ + int32 vtable; + int8 gap[48]; + float pos[3]; + uint8 gap_2[288]; + uint8 CharCreatedBy; + uint8 gap_3[351]; + float m_fHealth; + float m_fArmour; + uint8 gap_4[148]; + + CWeapon_FS m_weapons[13]; + int32 m_storedWeapon; + uint8 m_currentWeapon; + uint8 m_maxWeaponTypeAllowed; + uint8 gap_5[178]; + float m_fMaxStamina; + uint8 gap_6[28]; + int32 m_nTargettableObjects[4]; + uint8 gap_7[116]; + + void StorePlayerPed(CPlayerPed* pPlayerPed) + { + for (int i = 0; i < 4; i++) + m_nTargettableObjects[i] = pPlayerPed->m_nTargettableObjects[i]; + m_fMaxStamina = pPlayerPed->m_fMaxStamina; + } + + void StorePed(CPed* pPed) + { + pos[0] = pPed->GetPosition().x; + pos[1] = pPed->GetPosition().y; + pos[2] = pPed->GetPosition().z; + m_fHealth = pPed->m_fHealth; + m_fArmour = pPed->m_fArmour; + CharCreatedBy = pPed->CharCreatedBy; + m_maxWeaponTypeAllowed = pPed->m_maxWeaponTypeAllowed; + for (int i = 0; i < 13; i++) + m_weapons[i].Store(&pPed->m_weapons[i]); + } + + void RestorePlayerPed(CPlayerPed* pPlayerPed) + { + for (int i = 0; i < 4; i++) + pPlayerPed->m_nTargettableObjects[i] = m_nTargettableObjects[i]; + pPlayerPed->m_fMaxStamina = m_fMaxStamina; + } + + void RestorePed(CPed* pPed) + { + pPed->GetPosition().x = pos[0]; + pPed->GetPosition().y = pos[1]; + pPed->GetPosition().z = pos[2]; + pPed->m_fHealth = m_fHealth; + pPed->m_fArmour = m_fArmour; + pPed->CharCreatedBy = CharCreatedBy; + pPed->m_maxWeaponTypeAllowed = m_maxWeaponTypeAllowed; + for (int i = 0; i < 13; i++) + m_weapons[i].Restore(&pPed->m_weapons[i]); + } +}; + +VALIDATE_SIZE(CPlayerPed_FS, 1520); + +#endif diff --git a/src/core/config.h b/src/core/config.h index a6876ab0..f1999c71 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -223,6 +223,8 @@ enum Config { #define USE_MEASUREMENTS_IN_METERS // makes game use meters instead of feet in script #define USE_PRECISE_MEASUREMENT_CONVERTION // makes game convert feet to meeters more precisely +#define COMPATIBLE_SAVES // this allows changing structs while keeping saves compatible + // Replay //#define DONT_FIX_REPLAY_BUGS // keeps various bugs in CReplay, some of which are fairly cool! //#define USE_BETA_REPLAY_MODE // adds another replay mode, a few seconds slomo (caution: buggy!) diff --git a/src/entities/Entity.h b/src/entities/Entity.h index ee9e6490..82a78779 100644 --- a/src/entities/Entity.h +++ b/src/entities/Entity.h @@ -91,7 +91,9 @@ public: CReference *m_pFirstReference; CColModel *GetColModel(void) { return CModelInfo::GetModelInfo(m_modelIndex)->GetColModel(); } +#ifndef COMPATIBLE_SAVES uint32* GetAddressOfEntityProperties() { /* AWFUL */ return (uint32*)((char*)&m_rwObject + sizeof(m_rwObject)); } +#endif CEntity(void); ~CEntity(void); From ef5a70b8c0cd9493a8a0ca7b2f8b23167612f07f Mon Sep 17 00:00:00 2001 From: Nikolay Korolev Date: Mon, 27 Apr 2020 00:56:49 +0300 Subject: [PATCH 2/4] librw update --- librw | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/librw b/librw index d8d13d44..4db08e15 160000 --- a/librw +++ b/librw @@ -1 +1 @@ -Subproject commit d8d13d44293a58b58d51c3a8e91e3ea76c6d6feb +Subproject commit 4db08e15e8bdd0286195f48a28d4c8108ea64c6a From 063bf51bf137c26a4315183f798f1dfc55e15bf7 Mon Sep 17 00:00:00 2001 From: Nikolay Korolev Date: Thu, 30 Apr 2020 22:04:07 +0300 Subject: [PATCH 3/4] updated get/set --- src/core/Pools.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/core/Pools.h b/src/core/Pools.h index 6e5b0ac1..67fd29b2 100644 --- a/src/core/Pools.h +++ b/src/core/Pools.h @@ -121,8 +121,8 @@ struct CEntityProperties void Store(CEntity* pEntity) { - m_type = pEntity->m_type; - m_status = pEntity->m_status; + m_type = pEntity->GetType(); + m_status = pEntity->GetStatus(); bUsesCollision = pEntity->bUsesCollision; bCollisionProcessed = pEntity->bCollisionProcessed; bIsStatic = pEntity->bIsStatic; @@ -161,8 +161,8 @@ struct CEntityProperties void Restore(CEntity* pEntity) { - pEntity->m_type = m_type; - pEntity->m_status = m_status; + pEntity->SetType((eEntityType)m_type); + pEntity->SetStatus((eEntityStatus)m_status); pEntity->bUsesCollision = bUsesCollision; pEntity->bCollisionProcessed = bCollisionProcessed; pEntity->bIsStatic = bIsStatic; From f372ce156d76350ef4705ecbf488b43484878ca2 Mon Sep 17 00:00:00 2001 From: Nikolay Korolev Date: Sat, 2 May 2020 18:02:17 +0300 Subject: [PATCH 4/4] changed saving compatibility --- src/control/AutoPilot.cpp | 81 +++++- src/control/AutoPilot.h | 5 + src/core/Pools.cpp | 134 ++++----- src/core/Pools.h | 534 ------------------------------------ src/entities/Entity.cpp | 105 +++++++ src/entities/Entity.h | 5 +- src/peds/Ped.cpp | 42 +++ src/peds/Ped.h | 5 + src/peds/PlayerPed.cpp | 37 +++ src/peds/PlayerPed.h | 7 + src/vehicles/Automobile.cpp | 26 ++ src/vehicles/Automobile.h | 6 + src/vehicles/Boat.cpp | 23 ++ src/vehicles/Boat.h | 7 + src/vehicles/Vehicle.cpp | 125 +++++++++ src/vehicles/Vehicle.h | 4 + src/weapons/Weapon.cpp | 28 +- src/weapons/Weapon.h | 5 + 18 files changed, 567 insertions(+), 612 deletions(-) diff --git a/src/control/AutoPilot.cpp b/src/control/AutoPilot.cpp index 69511bc8..96a1fedf 100644 --- a/src/control/AutoPilot.cpp +++ b/src/control/AutoPilot.cpp @@ -44,4 +44,83 @@ void CAutoPilot::RemoveOnePathNode() --m_nPathFindNodesCount; for (int i = 0; i < m_nPathFindNodesCount; i++) m_aPathFindNodesInfo[i] = m_aPathFindNodesInfo[i + 1]; -} \ No newline at end of file +} + +#ifdef COMPATIBLE_SAVES +void CAutoPilot::Save(uint8*& buf) +{ + WriteSaveBuf(buf, m_nCurrentRouteNode); + WriteSaveBuf(buf, m_nNextRouteNode); + WriteSaveBuf(buf, m_nPrevRouteNode); + WriteSaveBuf(buf, m_nTimeEnteredCurve); + WriteSaveBuf(buf, m_nTimeToSpendOnCurrentCurve); + WriteSaveBuf(buf, m_nCurrentPathNodeInfo); + WriteSaveBuf(buf, m_nNextPathNodeInfo); + WriteSaveBuf(buf, m_nPreviousPathNodeInfo); + WriteSaveBuf(buf, m_nAntiReverseTimer); + WriteSaveBuf(buf, m_nTimeToStartMission); + WriteSaveBuf(buf, m_nPreviousDirection); + WriteSaveBuf(buf, m_nCurrentDirection); + WriteSaveBuf(buf, m_nNextDirection); + WriteSaveBuf(buf, m_nCurrentLane); + WriteSaveBuf(buf, m_nNextLane); + WriteSaveBuf(buf, m_nDrivingStyle); + WriteSaveBuf(buf, m_nCarMission); + WriteSaveBuf(buf, m_nTempAction); + WriteSaveBuf(buf, m_nTimeTempAction); + WriteSaveBuf(buf, m_fMaxTrafficSpeed); + WriteSaveBuf(buf, m_nCruiseSpeed); + uint8 flags = 0; + if (m_bSlowedDownBecauseOfCars) flags |= BIT(0); + if (m_bSlowedDownBecauseOfPeds) flags |= BIT(1); + if (m_bStayInCurrentLevel) flags |= BIT(2); + if (m_bStayInFastLane) flags |= BIT(3); + if (m_bIgnorePathfinding) flags |= BIT(4); + WriteSaveBuf(buf, flags); + SkipSaveBuf(buf, 2); + WriteSaveBuf(buf, m_vecDestinationCoors.x); + WriteSaveBuf(buf, m_vecDestinationCoors.y); + WriteSaveBuf(buf, m_vecDestinationCoors.z); + SkipSaveBuf(buf, 32); + WriteSaveBuf(buf, m_nPathFindNodesCount); + SkipSaveBuf(buf, 6); +} + +void CAutoPilot::Load(uint8*& buf) +{ + m_nCurrentRouteNode = ReadSaveBuf(buf); + m_nNextRouteNode = ReadSaveBuf(buf); + m_nPrevRouteNode = ReadSaveBuf(buf); + m_nTimeEnteredCurve = ReadSaveBuf(buf); + m_nTimeToSpendOnCurrentCurve = ReadSaveBuf(buf); + m_nCurrentPathNodeInfo = ReadSaveBuf(buf); + m_nNextPathNodeInfo = ReadSaveBuf(buf); + m_nPreviousPathNodeInfo = ReadSaveBuf(buf); + m_nAntiReverseTimer = ReadSaveBuf(buf); + m_nTimeToStartMission = ReadSaveBuf(buf); + m_nPreviousDirection = ReadSaveBuf(buf); + m_nCurrentDirection = ReadSaveBuf(buf); + m_nNextDirection = ReadSaveBuf(buf); + m_nCurrentLane = ReadSaveBuf(buf); + m_nNextLane = ReadSaveBuf(buf); + m_nDrivingStyle = (eCarDrivingStyle)ReadSaveBuf(buf); + m_nCarMission = (eCarMission)ReadSaveBuf(buf); + m_nTempAction = (eCarTempAction)ReadSaveBuf(buf); + m_nTimeTempAction = ReadSaveBuf(buf); + m_fMaxTrafficSpeed = ReadSaveBuf(buf); + m_nCruiseSpeed = ReadSaveBuf(buf); + uint8 flags = ReadSaveBuf(buf); + m_bSlowedDownBecauseOfCars = !!(flags & BIT(0)); + m_bSlowedDownBecauseOfPeds = !!(flags & BIT(1)); + m_bStayInCurrentLevel = !!(flags & BIT(2)); + m_bStayInFastLane = !!(flags & BIT(3)); + m_bIgnorePathfinding = !!(flags & BIT(4)); + SkipSaveBuf(buf, 2); + m_vecDestinationCoors.x = ReadSaveBuf(buf); + m_vecDestinationCoors.y = ReadSaveBuf(buf); + m_vecDestinationCoors.z = ReadSaveBuf(buf); + SkipSaveBuf(buf, 32); + m_nPathFindNodesCount = ReadSaveBuf(buf); + SkipSaveBuf(buf, 6); +} +#endif \ No newline at end of file diff --git a/src/control/AutoPilot.h b/src/control/AutoPilot.h index e1066071..4c356f96 100644 --- a/src/control/AutoPilot.h +++ b/src/control/AutoPilot.h @@ -120,5 +120,10 @@ public: void ModifySpeed(float); void RemoveOnePathNode(); +#ifdef COMPATIBLE_SAVES + void Save(uint8*& buf); + void Load(uint8*& buf); +#endif + }; static_assert(sizeof(CAutoPilot) == 0x70, "CAutoPilot: error"); diff --git a/src/core/Pools.cpp b/src/core/Pools.cpp index 011c7af7..4306cf09 100644 --- a/src/core/Pools.cpp +++ b/src/core/Pools.cpp @@ -111,30 +111,27 @@ INITSAVEBUF int32 slot = ReadSaveBuf(buf); CVehicle* pVehicle; #ifdef COMPATIBLE_SAVES - char* vbuf = new char[Max(sizeof(CAutomobile_FS), sizeof(CBoat_FS))]; + if (type == VEHICLE_TYPE_BOAT) + pVehicle = new(slot) CBoat(model, RANDOM_VEHICLE); + else if (type == VEHICLE_TYPE_CAR) + pVehicle = new(slot) CAutomobile(model, RANDOM_VEHICLE); + else + assert(0); + --CCarCtrl::NumRandomCars; + pVehicle->Load(buf); + CWorld::Add(pVehicle); #else - char* vbuf = new char[Max(sizeof(CAutomobile), sizeof(CBoat))]; -#endif + char* vbuf = new char[Max(CAutomobile::nSaveStructSize, CBoat::nSaveStructSize)]; if (type == VEHICLE_TYPE_BOAT) { -#ifdef COMPATIBLE_SAVES - memcpy(vbuf, buf, sizeof(CBoat_FS)); - SkipSaveBuf(buf, sizeof(CBoat_FS)); -#else memcpy(vbuf, buf, sizeof(CBoat)); SkipSaveBuf(buf, sizeof(CBoat)); -#endif CBoat* pBoat = new(slot) CBoat(model, RANDOM_VEHICLE); pVehicle = pBoat; - --CCarCtrl::NumRandomCars; // why? + --CCarCtrl::NumRandomCars; } else if (type == VEHICLE_TYPE_CAR) { -#ifdef COMPATIBLE_SAVES - memcpy(vbuf, buf, sizeof(CAutomobile_FS)); - SkipSaveBuf(buf, sizeof(CAutomobile_FS)); -#else memcpy(vbuf, buf, sizeof(CAutomobile)); SkipSaveBuf(buf, sizeof(CAutomobile)); -#endif CStreaming::RequestModel(model, 0); // is it needed? CStreaming::LoadAllRequestedModels(false); CAutomobile* pAutomobile = new(slot) CAutomobile(model, RANDOM_VEHICLE); @@ -145,10 +142,6 @@ INITSAVEBUF } else assert(0); -#ifdef COMPATIBLE_SAVES - CVehicle_FS* pBufferVehicle = (CVehicle_FS*)vbuf; - pBufferVehicle->Restore(pVehicle); -#else CVehicle* pBufferVehicle = (CVehicle*)vbuf; pVehicle->GetMatrix() = pBufferVehicle->GetMatrix(); pVehicle->VehicleCreatedBy = pBufferVehicle->VehicleCreatedBy; @@ -184,9 +177,9 @@ INITSAVEBUF (pVehicle->GetAddressOfEntityProperties())[0] = (pBufferVehicle->GetAddressOfEntityProperties())[0]; (pVehicle->GetAddressOfEntityProperties())[1] = (pBufferVehicle->GetAddressOfEntityProperties())[1]; pVehicle->AutoPilot = pBufferVehicle->AutoPilot; -#endif CWorld::Add(pVehicle); delete[] vbuf; +#endif } VALIDATESAVEBUF(size) } @@ -213,20 +206,8 @@ INITSAVEBUF ++nNumBoats; } } - *size = nNumCars * (sizeof(uint32) + sizeof(int16) + sizeof(int32) + -#ifdef COMPATIBLE_SAVES - sizeof(CAutomobile_FS)) + -#else - sizeof(CAutomobile)) + -#endif - sizeof(int) + - nNumBoats * (sizeof(uint32) + sizeof(int16) + sizeof(int32) + -#ifdef COMPATIBLE_SAVES - sizeof(CBoat_FS)) + -#else - sizeof(CBoat)) + -#endif - sizeof(int); + *size = nNumCars * (sizeof(uint32) + sizeof(int16) + sizeof(int32) + CAutomobile::nSaveStructSize) + sizeof(int) + + nNumBoats * (sizeof(uint32) + sizeof(int16) + sizeof(int32) + CBoat::nSaveStructSize) + sizeof(int); WriteSaveBuf(buf, nNumCars); WriteSaveBuf(buf, nNumBoats); for (int i = 0; i < nPoolSize; i++) { @@ -239,19 +220,20 @@ INITSAVEBUF bHasPassenger = true; } if (!pVehicle->pDriver && !bHasPassenger) { +#ifdef COMPATIBLE_SAVES + if ((pVehicle->IsCar() || pVehicle->IsBoat()) && pVehicle->VehicleCreatedBy == MISSION_VEHICLE) { + WriteSaveBuf(buf, pVehicle->m_vehType); + WriteSaveBuf(buf, pVehicle->m_modelIndex); + WriteSaveBuf(buf, GetVehicleRef(pVehicle)); + pVehicle->Save(buf); + } +#else if (pVehicle->IsCar() && pVehicle->VehicleCreatedBy == MISSION_VEHICLE) { WriteSaveBuf(buf, (uint32)pVehicle->m_vehType); WriteSaveBuf(buf, pVehicle->m_modelIndex); WriteSaveBuf(buf, GetVehicleRef(pVehicle)); -#ifdef COMPATIBLE_SAVES - ((CVehicle_FS*)buf)->Store(pVehicle); - SkipSaveBuf(buf, sizeof(CVehicle_FS)); - WriteSaveBuf(buf, ((CAutomobile*)pVehicle)->Damage); - SkipSaveBuf(buf, sizeof(CAutomobile_FS) - sizeof(CVehicle_FS) - sizeof(CDamageManager)); -#else memcpy(buf, pVehicle, sizeof(CAutomobile)); SkipSaveBuf(buf, sizeof(CAutomobile)); -#endif } if (pVehicle->IsBoat() && pVehicle->VehicleCreatedBy == MISSION_VEHICLE) { WriteSaveBuf(buf, (uint32)pVehicle->m_vehType); @@ -260,6 +242,7 @@ INITSAVEBUF memcpy(buf, pVehicle, sizeof(CBoat)); SkipSaveBuf(buf, sizeof(CBoat)); } +#endif } } VALIDATESAVEBUF(*size) @@ -318,9 +301,7 @@ INITSAVEBUF WriteSaveBuf(buf, pObject->m_nSpecialCollisionResponseCases); WriteSaveBuf(buf, pObject->m_nEndOfLifeTime); #ifdef COMPATIBLE_SAVES - CEntityProperties properties; - properties.Store(pObject); - WriteSaveBuf(buf, properties); + pObject->SaveEntityFlags(buf); #else WriteSaveBuf(buf, (pObject->GetAddressOfEntityProperties())[0]); WriteSaveBuf(buf, (pObject->GetAddressOfEntityProperties())[1]); @@ -359,9 +340,7 @@ INITSAVEBUF pBufferObject->m_nCollisionDamageEffect = ReadSaveBuf(buf); pBufferObject->m_nSpecialCollisionResponseCases = ReadSaveBuf(buf); pBufferObject->m_nEndOfLifeTime = ReadSaveBuf(buf); -#ifdef COMPATIBLE_SAVES - CEntityProperties properties = ReadSaveBuf(buf); -#else +#ifndef COMPATIBLE_SAVES (pBufferObject->GetAddressOfEntityProperties())[0] = ReadSaveBuf(buf); (pBufferObject->GetAddressOfEntityProperties())[1] = ReadSaveBuf(buf); #endif @@ -369,6 +348,9 @@ INITSAVEBUF CPopulation::ConvertToDummyObject(GetObjectPool()->GetSlot(ref >> 8)); CObject* pObject = new(ref) CObject(mi, false); pObject->GetMatrix() = pBufferObject->GetMatrix(); +#ifdef COMPATIBLE_SAVES + pObject->LoadEntityFlags(buf); +#endif pObject->m_fUprootLimit = pBufferObject->m_fUprootLimit; pObject->m_objectMatrix = pBufferObject->m_objectMatrix; pObject->ObjectCreatedBy = pBufferObject->ObjectCreatedBy; @@ -383,9 +365,7 @@ INITSAVEBUF pObject->m_nCollisionDamageEffect = pBufferObject->m_nCollisionDamageEffect; pObject->m_nSpecialCollisionResponseCases = pBufferObject->m_nSpecialCollisionResponseCases; pObject->m_nEndOfLifeTime = pBufferObject->m_nEndOfLifeTime; -#ifdef COMPATIBLE_SAVES - properties.Restore(pObject); -#else +#ifndef COMPATIBLE_SAVES (pObject->GetAddressOfEntityProperties())[0] = (pBufferObject->GetAddressOfEntityProperties())[0]; (pObject->GetAddressOfEntityProperties())[1] = (pBufferObject->GetAddressOfEntityProperties())[1]; #endif @@ -408,12 +388,7 @@ INITSAVEBUF if (!pPed->bInVehicle && pPed->m_nPedType == PEDTYPE_PLAYER1) nNumPeds++; } - *size = sizeof(int) + nNumPeds * (sizeof(uint32) + sizeof(int16) + sizeof(int) + -#ifdef COMPATIBLE_SAVES - sizeof(CPlayerPed_FS) + -#else - sizeof(CPlayerPed) + -#endif + *size = sizeof(int) + nNumPeds * (sizeof(uint32) + sizeof(int16) + sizeof(int) + CPlayerPed::nSaveStructSize + sizeof(CWanted::MaximumWantedLevel) + sizeof(CWanted::nMaximumWantedLevel) + MAX_MODEL_NAME); WriteSaveBuf(buf, nNumPeds); for (int i = 0; i < nPoolSize; i++) { @@ -425,9 +400,7 @@ INITSAVEBUF WriteSaveBuf(buf, pPed->m_modelIndex); WriteSaveBuf(buf, GetPedRef(pPed)); #ifdef COMPATIBLE_SAVES - ((CPlayerPed_FS*)buf)->StorePlayerPed((CPlayerPed*)pPed); - ((CPlayerPed_FS*)buf)->StorePed(pPed); - SkipSaveBuf(buf, sizeof(CPlayerPed_FS)); + pPed->Save(buf); #else memcpy(buf, pPed, sizeof(CPlayerPed)); SkipSaveBuf(buf, sizeof(CPlayerPed)); @@ -450,23 +423,41 @@ INITSAVEBUF int16 model = ReadSaveBuf(buf); int ref = ReadSaveBuf(buf); #ifdef COMPATIBLE_SAVES - char* pbuf = new char[sizeof(CPlayerPed_FS)]; - CPlayerPed_FS* pBufferPlayer = (CPlayerPed_FS*)buf; + CPed* pPed; + + char name[MAX_MODEL_NAME]; + // Unfortunate hack: player model is stored after ped structure. + // It could be avoided by just using "player" because in practice it is always true. + memcpy(name, buf + CPlayerPed::nSaveStructSize + 2 * sizeof(int32), MAX_MODEL_NAME); + CStreaming::RequestSpecialModel(model, name, STREAMFLAGS_DONT_REMOVE); + CStreaming::LoadAllRequestedModels(false); + + if (pedtype == PEDTYPE_PLAYER1) + pPed = new(ref) CPlayerPed(); + else + assert(0); + + pPed->Load(buf); + if (pedtype == PEDTYPE_PLAYER1) { + CWanted::MaximumWantedLevel = ReadSaveBuf(buf); + CWanted::nMaximumWantedLevel = ReadSaveBuf(buf); + SkipSaveBuf(buf, MAX_MODEL_NAME); + } + + if (pedtype == PEDTYPE_PLAYER1) { + pPed->m_wepAccuracy = 100; + CWorld::Players[0].m_pPed = (CPlayerPed*)pPed; + } + CWorld::Add(pPed); #else char* pbuf = new char[sizeof(CPlayerPed)]; CPlayerPed* pBufferPlayer = (CPlayerPed*)pbuf; -#endif CPed* pPed; char name[MAX_MODEL_NAME]; // the code implies that there was idea to load non-player ped if (pedtype == PEDTYPE_PLAYER1) { // always true -#ifdef COMPATIBLE_SAVES - memcpy(pbuf, buf, sizeof(CPlayerPed_FS)); - SkipSaveBuf(buf, sizeof(CPlayerPed_FS)); -#else memcpy(pbuf, buf, sizeof(CPlayerPed)); SkipSaveBuf(buf, sizeof(CPlayerPed)); -#endif CWanted::MaximumWantedLevel = ReadSaveBuf(buf); CWanted::nMaximumWantedLevel = ReadSaveBuf(buf); memcpy(name, buf, MAX_MODEL_NAME); @@ -476,19 +467,11 @@ INITSAVEBUF CStreaming::LoadAllRequestedModels(false); if (pedtype == PEDTYPE_PLAYER1) { CPlayerPed* pPlayerPed = new(ref) CPlayerPed(); -#ifdef COMPATIBLE_SAVES - pBufferPlayer->RestorePlayerPed(pPlayerPed); -#else for (int i = 0; i < ARRAY_SIZE(pPlayerPed->m_nTargettableObjects); i++) pPlayerPed->m_nTargettableObjects[i] = pBufferPlayer->m_nTargettableObjects[i]; pPlayerPed->m_fMaxStamina = pBufferPlayer->m_fMaxStamina; -#endif pPed = pPlayerPed; } -#ifdef COMPATIBLE_SAVES - pBufferPlayer->RestorePed(pPed); - pPed->m_currentWeapon = 0; -#else pPed->GetPosition() = pBufferPlayer->GetPosition(); pPed->m_fHealth = pBufferPlayer->m_fHealth; pPed->m_fArmour = pBufferPlayer->m_fArmour; @@ -497,13 +480,14 @@ INITSAVEBUF pPed->m_maxWeaponTypeAllowed = pBufferPlayer->m_maxWeaponTypeAllowed; for (int i = 0; i < WEAPONTYPE_TOTAL_INVENTORY_WEAPONS; i++) pPed->m_weapons[i] = pBufferPlayer->m_weapons[i]; -#endif + if (pedtype == PEDTYPE_PLAYER1) { pPed->m_wepAccuracy = 100; CWorld::Players[0].m_pPed = (CPlayerPed*)pPed; } CWorld::Add(pPed); delete[] pbuf; +#endif } VALIDATESAVEBUF(size) } diff --git a/src/core/Pools.h b/src/core/Pools.h index 67fd29b2..b0ba6598 100644 --- a/src/core/Pools.h +++ b/src/core/Pools.h @@ -59,537 +59,3 @@ public: static void SavePedPool(uint8 *buf, uint32 *size); static void SaveVehiclePool(uint8 *buf, uint32 *size); }; - -#ifdef COMPATIBLE_SAVES - -// Following stuff allows changing structures like CPed, CAutomobile and CBoat without breaking compatibility with original saves. - -// For saving we have to assume that sizeof(void*) == 4, so we use int32 everywhere. -// It will break some pointers, but saving them makes no sense anyway. - -struct CEntityProperties -{ - // these properties are defined exactly as in original game - - uint32 m_type : 3; - uint32 m_status : 5; - - // flagsA - uint32 bUsesCollision : 1; // does entity use collision - uint32 bCollisionProcessed : 1; // has object been processed by a ProcessEntityCollision function - uint32 bIsStatic : 1; // is entity static - uint32 bHasContacted : 1; // has entity processed some contact forces - uint32 bPedPhysics : 1; - uint32 bIsStuck : 1; // is entity stuck - uint32 bIsInSafePosition : 1; // is entity in a collision free safe position - uint32 bUseCollisionRecords : 1; - - // flagsB - uint32 bWasPostponed : 1; // was entity control processing postponed - uint32 bExplosionProof : 1; - uint32 bIsVisible : 1; //is the entity visible - uint32 bHasCollided : 1; - uint32 bRenderScorched : 1; - uint32 bHasBlip : 1; - uint32 bIsBIGBuilding : 1; // Set if this entity is a big building - // VC inserts one more flag here: if drawdist <= 2000 - uint32 bRenderDamaged : 1; // use damaged LOD models for objects with applicable damage - - // flagsC - uint32 bBulletProof : 1; - uint32 bFireProof : 1; - uint32 bCollisionProof : 1; - uint32 bMeleeProof : 1; - uint32 bOnlyDamagedByPlayer : 1; - uint32 bStreamingDontDelete : 1; // Dont let the streaming remove this - uint32 bZoneCulled : 1; - uint32 bZoneCulled2 : 1; // only treadables+10m - - // flagsD - uint32 bRemoveFromWorld : 1; // remove this entity next time it should be processed - uint32 bHasHitWall : 1; // has collided with a building (changes subsequent collisions) - uint32 bImBeingRendered : 1; // don't delete me because I'm being rendered - uint32 bTouchingWater : 1; // used by cBuoyancy::ProcessBuoyancy - uint32 bIsSubway : 1; // set when subway, but maybe different meaning? - uint32 bDrawLast : 1; // draw object last - uint32 bNoBrightHeadLights : 1; - uint32 bDoNotRender : 1; - - // flagsE - uint32 bDistanceFade : 1; // Fade entity because it is far away - uint32 m_flagE2 : 1; - - void Store(CEntity* pEntity) - { - m_type = pEntity->GetType(); - m_status = pEntity->GetStatus(); - bUsesCollision = pEntity->bUsesCollision; - bCollisionProcessed = pEntity->bCollisionProcessed; - bIsStatic = pEntity->bIsStatic; - bHasContacted = pEntity->bHasContacted; - bPedPhysics = pEntity->bPedPhysics; - bIsStuck = pEntity->bIsStuck; - bIsInSafePosition = pEntity->bIsInSafePosition; - bUseCollisionRecords = pEntity->bUseCollisionRecords; - bWasPostponed = pEntity->bWasPostponed; - bExplosionProof = pEntity->bExplosionProof; - bIsVisible = pEntity->bIsVisible; - bHasCollided = pEntity->bHasCollided; - bRenderScorched = pEntity->bRenderScorched; - bHasBlip = pEntity->bHasBlip; - bIsBIGBuilding = pEntity->bIsBIGBuilding; - bRenderDamaged = pEntity->bRenderDamaged; - bBulletProof = pEntity->bBulletProof; - bFireProof = pEntity->bFireProof; - bCollisionProof = pEntity->bCollisionProof; - bMeleeProof = pEntity->bMeleeProof; - bOnlyDamagedByPlayer = pEntity->bOnlyDamagedByPlayer; - bStreamingDontDelete = pEntity->bStreamingDontDelete; - bZoneCulled = pEntity->bZoneCulled; - bZoneCulled2 = pEntity->bZoneCulled2; - bRemoveFromWorld = pEntity->bRemoveFromWorld; - bHasHitWall = pEntity->bHasHitWall; - bImBeingRendered = pEntity->bImBeingRendered; - bTouchingWater = pEntity->bTouchingWater; - bIsSubway = pEntity->bIsSubway; - bDrawLast = pEntity->bDrawLast; - bNoBrightHeadLights = pEntity->bNoBrightHeadLights; - bDoNotRender = pEntity->bDoNotRender; - bDistanceFade = pEntity->bDistanceFade; - m_flagE2 = pEntity->m_flagE2; - } - - void Restore(CEntity* pEntity) - { - pEntity->SetType((eEntityType)m_type); - pEntity->SetStatus((eEntityStatus)m_status); - pEntity->bUsesCollision = bUsesCollision; - pEntity->bCollisionProcessed = bCollisionProcessed; - pEntity->bIsStatic = bIsStatic; - pEntity->bHasContacted = bHasContacted; - pEntity->bPedPhysics = bPedPhysics; - pEntity->bIsStuck = bIsStuck; - pEntity->bIsInSafePosition = bIsInSafePosition; - pEntity->bUseCollisionRecords = bUseCollisionRecords; - pEntity->bWasPostponed = bWasPostponed; - pEntity->bExplosionProof = bExplosionProof; - pEntity->bIsVisible = bIsVisible; - pEntity->bHasCollided = bHasCollided; - pEntity->bRenderScorched = bRenderScorched; - pEntity->bHasBlip = bHasBlip; - pEntity->bIsBIGBuilding = bIsBIGBuilding; - pEntity->bRenderDamaged = bRenderDamaged; - pEntity->bBulletProof = bBulletProof; - pEntity->bFireProof = bFireProof; - pEntity->bCollisionProof = bCollisionProof; - pEntity->bMeleeProof = bMeleeProof; - pEntity->bOnlyDamagedByPlayer = bOnlyDamagedByPlayer; - pEntity->bStreamingDontDelete = bStreamingDontDelete; - pEntity->bZoneCulled = bZoneCulled; - pEntity->bZoneCulled2 = bZoneCulled2; - pEntity->bRemoveFromWorld = bRemoveFromWorld; - pEntity->bHasHitWall = bHasHitWall; - pEntity->bImBeingRendered = bImBeingRendered; - pEntity->bTouchingWater = bTouchingWater; - pEntity->bIsSubway = bIsSubway; - pEntity->bDrawLast = bDrawLast; - pEntity->bNoBrightHeadLights = bNoBrightHeadLights; - pEntity->bDoNotRender = bDoNotRender; - pEntity->bDistanceFade = bDistanceFade; - pEntity->m_flagE2 = m_flagE2; - } -}; - -VALIDATE_SIZE(CEntityProperties, 8); - -struct CAutoPilot_FS -{ - int32 m_nCurrentRouteNode; - int32 m_nNextRouteNode; - int32 m_nPrevRouteNode; - uint32 m_nTimeEnteredCurve; - uint32 m_nTimeToSpendOnCurrentCurve; - uint32 m_nCurrentPathNodeInfo; - uint32 m_nNextPathNodeInfo; - uint32 m_nPreviousPathNodeInfo; - uint32 m_nAntiReverseTimer; - uint32 m_nTimeToStartMission; - int8 m_nPreviousDirection; - int8 m_nCurrentDirection; - int8 m_nNextDirection; - int8 m_nCurrentLane; - int8 m_nNextLane; - uint8 m_nDrivingStyle; - uint8 m_nCarMission; - uint8 m_nTempAction; - uint32 m_nTimeTempAction; - float m_fMaxTrafficSpeed; - uint8 m_nCruiseSpeed; - uint8 m_bSlowedDownBecauseOfCars : 1; - uint8 m_bSlowedDownBecauseOfPeds : 1; - uint8 m_bStayInCurrentLevel : 1; - uint8 m_bStayInFastLane : 1; - uint8 m_bIgnorePathfinding : 1; - float m_vecDestinationCoors[3]; - int32 m_aPathFindNodesInfo[8]; // CPathNode* [NUM_PATH_NODES_IN_AUTOPILOT] - int16 m_nPathFindNodesCount; - int32 m_pTargetCar; - - void Store(CAutoPilot* pAutoPilot) - { - m_nCurrentRouteNode = pAutoPilot->m_nCurrentRouteNode; - m_nNextRouteNode = pAutoPilot->m_nNextRouteNode; - m_nPrevRouteNode = pAutoPilot->m_nPrevRouteNode; - m_nTimeEnteredCurve = pAutoPilot->m_nTimeEnteredCurve; - m_nTimeToSpendOnCurrentCurve = pAutoPilot->m_nTimeToSpendOnCurrentCurve; - m_nCurrentPathNodeInfo = pAutoPilot->m_nCurrentPathNodeInfo; - m_nNextPathNodeInfo = pAutoPilot->m_nNextPathNodeInfo; - m_nPreviousPathNodeInfo = pAutoPilot->m_nPreviousPathNodeInfo; - m_nAntiReverseTimer = pAutoPilot->m_nAntiReverseTimer; - m_nTimeToStartMission = pAutoPilot->m_nTimeToStartMission; - m_nPreviousDirection = pAutoPilot->m_nPreviousDirection; - m_nCurrentDirection = pAutoPilot->m_nCurrentDirection; - m_nNextDirection = pAutoPilot->m_nNextDirection; - m_nCurrentLane = pAutoPilot->m_nCurrentLane; - m_nNextLane = pAutoPilot->m_nNextLane; - m_nDrivingStyle = pAutoPilot->m_nDrivingStyle; - m_nCarMission = pAutoPilot->m_nCarMission; - m_nTempAction = pAutoPilot->m_nTempAction; - m_nTimeTempAction = pAutoPilot->m_nTimeTempAction; - m_fMaxTrafficSpeed = pAutoPilot->m_fMaxTrafficSpeed; - m_nCruiseSpeed = pAutoPilot->m_nCruiseSpeed; - m_bSlowedDownBecauseOfCars = pAutoPilot->m_bSlowedDownBecauseOfCars; - m_bSlowedDownBecauseOfPeds = pAutoPilot->m_bSlowedDownBecauseOfPeds; - m_bStayInCurrentLevel = pAutoPilot->m_bStayInCurrentLevel; - m_bStayInFastLane = pAutoPilot->m_bStayInFastLane; - m_bIgnorePathfinding = pAutoPilot->m_bIgnorePathfinding; - m_vecDestinationCoors[0] = pAutoPilot->m_vecDestinationCoors.x; - m_vecDestinationCoors[1] = pAutoPilot->m_vecDestinationCoors.y; - m_vecDestinationCoors[2] = pAutoPilot->m_vecDestinationCoors.z; - for (int i = 0; i < 8; i++) - m_aPathFindNodesInfo[i] = 0; - m_nPathFindNodesCount = pAutoPilot->m_nPathFindNodesCount; - m_pTargetCar = 0; - } - - void Restore(CAutoPilot* pAutoPilot) - { - pAutoPilot->m_nCurrentRouteNode = m_nCurrentRouteNode; - pAutoPilot->m_nNextRouteNode = m_nNextRouteNode; - pAutoPilot->m_nPrevRouteNode = m_nPrevRouteNode; - pAutoPilot->m_nTimeEnteredCurve = m_nTimeEnteredCurve; - pAutoPilot->m_nTimeToSpendOnCurrentCurve = m_nTimeToSpendOnCurrentCurve; - pAutoPilot->m_nCurrentPathNodeInfo = m_nCurrentPathNodeInfo; - pAutoPilot->m_nNextPathNodeInfo = m_nNextPathNodeInfo; - pAutoPilot->m_nPreviousPathNodeInfo = m_nPreviousPathNodeInfo; - pAutoPilot->m_nAntiReverseTimer = m_nAntiReverseTimer; - pAutoPilot->m_nTimeToStartMission = m_nTimeToStartMission; - pAutoPilot->m_nPreviousDirection = m_nPreviousDirection; - pAutoPilot->m_nCurrentDirection = m_nCurrentDirection; - pAutoPilot->m_nNextDirection = m_nNextDirection; - pAutoPilot->m_nCurrentLane = m_nCurrentLane; - pAutoPilot->m_nNextLane = m_nNextLane; - pAutoPilot->m_nDrivingStyle = (eCarDrivingStyle)m_nDrivingStyle; - pAutoPilot->m_nCarMission = (eCarMission)m_nCarMission; - pAutoPilot->m_nTempAction = (eCarTempAction)m_nTempAction; - pAutoPilot->m_nTimeTempAction = m_nTimeTempAction; - pAutoPilot->m_fMaxTrafficSpeed = m_fMaxTrafficSpeed; - pAutoPilot->m_nCruiseSpeed = m_nCruiseSpeed; - pAutoPilot->m_bSlowedDownBecauseOfCars = m_bSlowedDownBecauseOfCars; - pAutoPilot->m_bSlowedDownBecauseOfPeds = m_bSlowedDownBecauseOfPeds; - pAutoPilot->m_bStayInCurrentLevel = m_bStayInCurrentLevel; - pAutoPilot->m_bStayInFastLane = m_bStayInFastLane; - pAutoPilot->m_bIgnorePathfinding = m_bIgnorePathfinding; - pAutoPilot->m_vecDestinationCoors.x = m_vecDestinationCoors[0]; - pAutoPilot->m_vecDestinationCoors.y = m_vecDestinationCoors[1]; - pAutoPilot->m_vecDestinationCoors.z = m_vecDestinationCoors[2]; - for (int i = 0; i < NUM_PATH_NODES_IN_AUTOPILOT; i++) - pAutoPilot->m_aPathFindNodesInfo[i] = nil; - pAutoPilot->m_nPathFindNodesCount = m_nPathFindNodesCount; - pAutoPilot->m_pTargetCar = nil; - } -}; - -struct CMatrix_FS -{ - float right[3]; - uint8 gap1[4]; - float forward[3]; - uint8 gap2[4]; - float up[3]; - uint8 gap3[4]; - float pos[3]; - uint8 gap4[12]; - - void Store(CMatrix* pMatrix) - { - right[0] = pMatrix->GetRight().x; - right[1] = pMatrix->GetRight().y; - right[2] = pMatrix->GetRight().z; - forward[0] = pMatrix->GetForward().x; - forward[1] = pMatrix->GetForward().y; - forward[2] = pMatrix->GetForward().z; - up[0] = pMatrix->GetUp().x; - up[1] = pMatrix->GetUp().y; - up[2] = pMatrix->GetUp().z; - pos[0] = pMatrix->GetPosition().x; - pos[1] = pMatrix->GetPosition().y; - pos[2] = pMatrix->GetPosition().z; - } - - void Restore(CMatrix* pMatrix) - { - CMatrix tmp; - tmp.GetRight().x = right[0]; - tmp.GetRight().y = right[1]; - tmp.GetRight().z = right[2]; - tmp.GetForward().x = forward[0]; - tmp.GetForward().y = forward[1]; - tmp.GetForward().z = forward[2]; - tmp.GetUp().x = up[0]; - tmp.GetUp().y = up[1]; - tmp.GetUp().z = up[2]; - tmp.GetPosition().x = pos[0]; - tmp.GetPosition().y = pos[1]; - tmp.GetPosition().z = pos[2]; - *pMatrix = tmp; - } -}; - -VALIDATE_SIZE(CMatrix_FS, 72); - -struct CVehicle_FS -{ - uint32 vtable; - CMatrix_FS matrix; - uint8 gap1[4]; - CEntityProperties properties; - uint8 gap2[212]; - CAutoPilot_FS AutoPilot; - uint8 m_currentColour1; - uint8 m_currentColour2; - uint8 gap3[2]; - int16 m_nAlarmState; - int8 gap4[43]; - uint8 m_nNumMaxPassengers; - float field_1D0[4]; - uint8 gap5[8]; - float m_fSteerAngle; - float m_fGasPedal; - float m_fBrakePedal; - uint8 VehicleCreatedBy; - - // cf. https://github.com/DK22Pac/plugin-sdk/blob/master/plugin_sa/game_sa/CVehicle.h from R* - uint8 bIsLawEnforcer : 1; // Is this guy chasing the player at the moment - uint8 gap_b1 : 1; - uint8 gap_b2 : 1; - uint8 bIsLocked : 1; // Is this guy locked by the script (cannot be removed) - uint8 bEngineOn : 1; // For sound purposes. Parked cars have their engines switched off (so do destroyed cars) - uint8 bIsHandbrakeOn : 1; // How's the handbrake doing ? - uint8 bLightsOn : 1; // Are the lights switched on ? - uint8 bFreebies : 1; // Any freebies left in this vehicle ? - - uint8 gap6[3]; - - uint8 gap7[6]; - float m_fHealth; // 1000.0f = full health. 250.0f = fire. 0 -> explode - uint8 m_nCurrentGear; - float m_fChangeGearTime; - uint8 gap8[4]; - uint32 m_nTimeOfDeath; - uint8 gap9[2]; - int16 m_nBombTimer; - uint8 gap10[12]; - int8 m_nDoorLock; - uint8 gap11[96]; - - void Store(CVehicle* pVehicle) - { - matrix.Store(&pVehicle->GetMatrix()); - VehicleCreatedBy = pVehicle->VehicleCreatedBy; - m_currentColour1 = pVehicle->m_currentColour1; - m_currentColour2 = pVehicle->m_currentColour2; - m_nAlarmState = pVehicle->m_nAlarmState; - m_nNumMaxPassengers = pVehicle->m_nNumMaxPassengers; - field_1D0[0] = pVehicle->field_1D0[0]; - field_1D0[1] = pVehicle->field_1D0[1]; - field_1D0[2] = pVehicle->field_1D0[2]; - field_1D0[3] = pVehicle->field_1D0[3]; - m_fSteerAngle = pVehicle->m_fSteerAngle; - m_fGasPedal = pVehicle->m_fGasPedal; - m_fBrakePedal = pVehicle->m_fBrakePedal; - bIsLawEnforcer = pVehicle->bIsLawEnforcer; - bIsLocked = pVehicle->bIsLocked; - bEngineOn = pVehicle->bEngineOn; - bIsHandbrakeOn = pVehicle->bIsHandbrakeOn; - bLightsOn = pVehicle->bLightsOn; - bFreebies = pVehicle->bFreebies; - m_fHealth = pVehicle->m_fHealth; - m_nCurrentGear = pVehicle->m_nCurrentGear; - m_fChangeGearTime = pVehicle->m_fChangeGearTime; - m_nTimeOfDeath = pVehicle->m_nTimeOfDeath; -#ifdef FIX_BUGS //must be copypaste - m_nBombTimer = pVehicle->m_nBombTimer; -#else - m_nTimeOfDeath = pVehicle->m_nTimeOfDeath; -#endif - m_nDoorLock = pVehicle->m_nDoorLock; - properties.Store(pVehicle); - AutoPilot.Store(&pVehicle->AutoPilot); - } - - void Restore(CVehicle* pVehicle) - { - matrix.Restore(&pVehicle->GetMatrix()); - pVehicle->VehicleCreatedBy = VehicleCreatedBy; - pVehicle->m_currentColour1 = m_currentColour1; - pVehicle->m_currentColour2 = m_currentColour2; - pVehicle->m_nAlarmState = m_nAlarmState; - pVehicle->m_nNumMaxPassengers = m_nNumMaxPassengers; - pVehicle->field_1D0[0] = field_1D0[0]; - pVehicle->field_1D0[1] = field_1D0[1]; - pVehicle->field_1D0[2] = field_1D0[2]; - pVehicle->field_1D0[3] = field_1D0[3]; - pVehicle->m_fSteerAngle = m_fSteerAngle; - pVehicle->m_fGasPedal = m_fGasPedal; - pVehicle->m_fBrakePedal = m_fBrakePedal; - pVehicle->bIsLawEnforcer = bIsLawEnforcer; - pVehicle->bIsLocked = bIsLocked; - pVehicle->bEngineOn = bEngineOn; - pVehicle->bIsHandbrakeOn = bIsHandbrakeOn; - pVehicle->bLightsOn = bLightsOn; - pVehicle->bFreebies = bFreebies; - pVehicle->m_fHealth = m_fHealth; - pVehicle->m_nCurrentGear = m_nCurrentGear; - pVehicle->m_fChangeGearTime = m_fChangeGearTime; - pVehicle->m_nTimeOfDeath = m_nTimeOfDeath; -#ifdef FIX_BUGS //must be copypaste - pVehicle->m_nBombTimer = m_nBombTimer; -#else - pVehicle->m_nTimeOfDeath = m_nTimeOfDeath; -#endif - pVehicle->m_nDoorLock = (eCarLock)m_nDoorLock; - properties.Restore(pVehicle); - AutoPilot.Restore(&pVehicle->AutoPilot); - } -}; - -VALIDATE_SIZE(CVehicle_FS, 648); - -static_assert(sizeof(CDamageManager) < 1448 - sizeof(CVehicle_FS), "CDamageManager size too big to keep saves compatible"); - -struct CAutomobile_FS -{ - CVehicle_FS vehicle; - CDamageManager Damage; - char gap[1448 - sizeof(CVehicle_FS) - sizeof(CDamageManager)]; // even allows increasing size of CDamageManager -}; - -struct CBoat_FS -{ - CVehicle_FS vehicle; - char gap[1156 - sizeof(CVehicle_FS)]; -}; - -VALIDATE_SIZE(CAutomobile_FS, 1448); -VALIDATE_SIZE(CBoat_FS, 1156); - -struct CWeapon_FS -{ - int32 m_eWeaponType; - int32 m_eWeaponState; - uint32 m_nAmmoInClip; - uint32 m_nAmmoTotal; - uint32 m_nTimer; - bool m_bAddRotOffset; - - void Store(CWeapon* pWeapon) - { - m_eWeaponType = pWeapon->m_eWeaponType; - m_eWeaponState = pWeapon->m_eWeaponState; - m_nAmmoInClip = pWeapon->m_nAmmoInClip; - m_nAmmoTotal = pWeapon->m_nAmmoTotal; - m_nTimer = pWeapon->m_nTimer; - m_bAddRotOffset = pWeapon->m_bAddRotOffset; - } - - void Restore(CWeapon* pWeapon) - { - pWeapon->m_eWeaponType = (eWeaponType)m_eWeaponType; - pWeapon->m_eWeaponState = (eWeaponState)m_eWeaponState; - pWeapon->m_nAmmoInClip = m_nAmmoInClip; - pWeapon->m_nAmmoTotal = m_nAmmoTotal; - pWeapon->m_nTimer = m_nTimer; - pWeapon->m_bAddRotOffset = m_bAddRotOffset; - } -}; - -static_assert(WEAPONTYPE_TOTAL_INVENTORY_WEAPONS == 13, - "Saving struct needs to be changed by adding new weapons to existing space; or COMPATIBLE_SAVES needs to be undefined"); - -struct CPlayerPed_FS -{ - int32 vtable; - int8 gap[48]; - float pos[3]; - uint8 gap_2[288]; - uint8 CharCreatedBy; - uint8 gap_3[351]; - float m_fHealth; - float m_fArmour; - uint8 gap_4[148]; - - CWeapon_FS m_weapons[13]; - int32 m_storedWeapon; - uint8 m_currentWeapon; - uint8 m_maxWeaponTypeAllowed; - uint8 gap_5[178]; - float m_fMaxStamina; - uint8 gap_6[28]; - int32 m_nTargettableObjects[4]; - uint8 gap_7[116]; - - void StorePlayerPed(CPlayerPed* pPlayerPed) - { - for (int i = 0; i < 4; i++) - m_nTargettableObjects[i] = pPlayerPed->m_nTargettableObjects[i]; - m_fMaxStamina = pPlayerPed->m_fMaxStamina; - } - - void StorePed(CPed* pPed) - { - pos[0] = pPed->GetPosition().x; - pos[1] = pPed->GetPosition().y; - pos[2] = pPed->GetPosition().z; - m_fHealth = pPed->m_fHealth; - m_fArmour = pPed->m_fArmour; - CharCreatedBy = pPed->CharCreatedBy; - m_maxWeaponTypeAllowed = pPed->m_maxWeaponTypeAllowed; - for (int i = 0; i < 13; i++) - m_weapons[i].Store(&pPed->m_weapons[i]); - } - - void RestorePlayerPed(CPlayerPed* pPlayerPed) - { - for (int i = 0; i < 4; i++) - pPlayerPed->m_nTargettableObjects[i] = m_nTargettableObjects[i]; - pPlayerPed->m_fMaxStamina = m_fMaxStamina; - } - - void RestorePed(CPed* pPed) - { - pPed->GetPosition().x = pos[0]; - pPed->GetPosition().y = pos[1]; - pPed->GetPosition().z = pos[2]; - pPed->m_fHealth = m_fHealth; - pPed->m_fArmour = m_fArmour; - pPed->CharCreatedBy = CharCreatedBy; - pPed->m_maxWeaponTypeAllowed = m_maxWeaponTypeAllowed; - for (int i = 0; i < 13; i++) - m_weapons[i].Restore(&pPed->m_weapons[i]); - } -}; - -VALIDATE_SIZE(CPlayerPed_FS, 1520); - -#endif diff --git a/src/entities/Entity.cpp b/src/entities/Entity.cpp index ee4faa82..2a6211d6 100644 --- a/src/entities/Entity.cpp +++ b/src/entities/Entity.cpp @@ -920,3 +920,108 @@ CEntity::AddSteamsFromGround(CPtrList& list) pNode = pNode->next; } } + +#ifdef COMPATIBLE_SAVES +void +CEntity::SaveEntityFlags(uint8*& buf) +{ + uint32 tmp = 0; + tmp |= (m_type & (BIT(3) - 1)); + tmp |= (m_status & (BIT(5) - 1)) << 3; + + if (bUsesCollision) tmp |= BIT(8); + if (bCollisionProcessed) tmp |= BIT(9); + if (bIsStatic) tmp |= BIT(10); + if (bHasContacted) tmp |= BIT(11); + if (bPedPhysics) tmp |= BIT(12); + if (bIsStuck) tmp |= BIT(13); + if (bIsInSafePosition) tmp |= BIT(14); + if (bUseCollisionRecords) tmp |= BIT(15); + + if (bWasPostponed) tmp |= BIT(16); + if (bExplosionProof) tmp |= BIT(17); + if (bIsVisible) tmp |= BIT(18); + if (bHasCollided) tmp |= BIT(19); + if (bRenderScorched) tmp |= BIT(20); + if (bHasBlip) tmp |= BIT(21); + if (bIsBIGBuilding) tmp |= BIT(22); + if (bRenderDamaged) tmp |= BIT(23); + + if (bBulletProof) tmp |= BIT(24); + if (bFireProof) tmp |= BIT(25); + if (bCollisionProof) tmp |= BIT(26); + if (bMeleeProof) tmp |= BIT(27); + if (bOnlyDamagedByPlayer) tmp |= BIT(28); + if (bStreamingDontDelete) tmp |= BIT(29); + if (bZoneCulled) tmp |= BIT(30); + if (bZoneCulled2) tmp |= BIT(31); + + WriteSaveBuf(buf, tmp); + + tmp = 0; + + if (bRemoveFromWorld) tmp |= BIT(0); + if (bHasHitWall) tmp |= BIT(1); + if (bImBeingRendered) tmp |= BIT(2); + if (bTouchingWater) tmp |= BIT(3); + if (bIsSubway) tmp |= BIT(4); + if (bDrawLast) tmp |= BIT(5); + if (bNoBrightHeadLights) tmp |= BIT(6); + if (bDoNotRender) tmp |= BIT(7); + + if (bDistanceFade) tmp |= BIT(8); + if (m_flagE2) tmp |= BIT(9); + + WriteSaveBuf(buf, tmp); +} + +void +CEntity::LoadEntityFlags(uint8*& buf) +{ + uint32 tmp = ReadSaveBuf(buf); + m_type = (tmp & ((BIT(3) - 1))); + m_status = ((tmp >> 3) & (BIT(5) - 1)); + + bUsesCollision = !!(tmp & BIT(8)); + bCollisionProcessed = !!(tmp & BIT(9)); + bIsStatic = !!(tmp & BIT(10)); + bHasContacted = !!(tmp & BIT(11)); + bPedPhysics = !!(tmp & BIT(12)); + bIsStuck = !!(tmp & BIT(13)); + bIsInSafePosition = !!(tmp & BIT(14)); + bUseCollisionRecords = !!(tmp & BIT(15)); + + bWasPostponed = !!(tmp & BIT(16)); + bExplosionProof = !!(tmp & BIT(17)); + bIsVisible = !!(tmp & BIT(18)); + bHasCollided = !!(tmp & BIT(19)); + bRenderScorched = !!(tmp & BIT(20)); + bHasBlip = !!(tmp & BIT(21)); + bIsBIGBuilding = !!(tmp & BIT(22)); + bRenderDamaged = !!(tmp & BIT(23)); + + bBulletProof = !!(tmp & BIT(24)); + bFireProof = !!(tmp & BIT(25)); + bCollisionProof = !!(tmp & BIT(26)); + bMeleeProof = !!(tmp & BIT(27)); + bOnlyDamagedByPlayer = !!(tmp & BIT(28)); + bStreamingDontDelete = !!(tmp & BIT(29)); + bZoneCulled = !!(tmp & BIT(30)); + bZoneCulled2 = !!(tmp & BIT(31)); + + tmp = ReadSaveBuf(buf); + + bRemoveFromWorld = !!(tmp & BIT(0)); + bHasHitWall = !!(tmp & BIT(1)); + bImBeingRendered = !!(tmp & BIT(2)); + bTouchingWater = !!(tmp & BIT(3)); + bIsSubway = !!(tmp & BIT(4)); + bDrawLast = !!(tmp & BIT(5)); + bNoBrightHeadLights = !!(tmp & BIT(6)); + bDoNotRender = !!(tmp & BIT(7)); + + bDistanceFade = !!(tmp & BIT(8)); + m_flagE2 = !!(tmp & BIT(9)); +} + +#endif diff --git a/src/entities/Entity.h b/src/entities/Entity.h index 9a0cd5cb..dbe2c08b 100644 --- a/src/entities/Entity.h +++ b/src/entities/Entity.h @@ -98,7 +98,10 @@ public: eEntityStatus GetStatus() const { return (eEntityStatus)m_status; } void SetStatus(eEntityStatus status) { m_status = status; } CColModel *GetColModel(void) { return CModelInfo::GetModelInfo(m_modelIndex)->GetColModel(); } -#ifndef COMPATIBLE_SAVES +#ifdef COMPATIBLE_SAVES + void SaveEntityFlags(uint8*& buf); + void LoadEntityFlags(uint8*& buf); +#else uint32* GetAddressOfEntityProperties() { /* AWFUL */ return (uint32*)((char*)&m_rwObject + sizeof(m_rwObject)); } #endif diff --git a/src/peds/Ped.cpp b/src/peds/Ped.cpp index f81ffb71..d2fa72c3 100644 --- a/src/peds/Ped.cpp +++ b/src/peds/Ped.cpp @@ -17732,3 +17732,45 @@ CPed::SetExitBoat(CVehicle *boat) // Not there in VC. CWaterLevel::FreeBoatWakeArray(); } + +#ifdef COMPATIBLE_SAVES +void +CPed::Save(uint8*& buf) +{ + SkipSaveBuf(buf, 52); + WriteSaveBuf(buf, GetPosition().x); + WriteSaveBuf(buf, GetPosition().y); + WriteSaveBuf(buf, GetPosition().z); + SkipSaveBuf(buf, 288); + WriteSaveBuf(buf, CharCreatedBy); + SkipSaveBuf(buf, 351); + WriteSaveBuf(buf, m_fHealth); + WriteSaveBuf(buf, m_fArmour); + SkipSaveBuf(buf, 148); + for (int i = 0; i < 13; i++) // has to be hardcoded + m_weapons[i].Save(buf); + SkipSaveBuf(buf, 5); + WriteSaveBuf(buf, m_maxWeaponTypeAllowed); + SkipSaveBuf(buf, 162); +} + +void +CPed::Load(uint8*& buf) +{ + SkipSaveBuf(buf, 52); + GetPosition().x = ReadSaveBuf(buf); + GetPosition().y = ReadSaveBuf(buf); + GetPosition().z = ReadSaveBuf(buf); + SkipSaveBuf(buf, 288); + CharCreatedBy = ReadSaveBuf(buf); + SkipSaveBuf(buf, 351); + m_fHealth = ReadSaveBuf(buf); + m_fArmour = ReadSaveBuf(buf); + SkipSaveBuf(buf, 148); + for (int i = 0; i < 13; i++) // has to be hardcoded + m_weapons[i].Load(buf); + SkipSaveBuf(buf, 5); + m_maxWeaponTypeAllowed = ReadSaveBuf(buf); + SkipSaveBuf(buf, 162); +} +#endif diff --git a/src/peds/Ped.h b/src/peds/Ped.h index 91322151..9f105e7a 100644 --- a/src/peds/Ped.h +++ b/src/peds/Ped.h @@ -886,6 +886,11 @@ public: #ifdef PED_SKIN void renderLimb(int node); #endif + +#ifdef COMPATIBLE_SAVES + virtual void Save(uint8*& buf); + virtual void Load(uint8*& buf); +#endif }; void FinishFuckUCB(CAnimBlendAssociation *assoc, void *arg); diff --git a/src/peds/PlayerPed.cpp b/src/peds/PlayerPed.cpp index dc44983d..6d0d394d 100644 --- a/src/peds/PlayerPed.cpp +++ b/src/peds/PlayerPed.cpp @@ -19,6 +19,13 @@ #define PAD_MOVE_TO_GAME_WORLD_MOVE 60.0f +const uint32 CPlayerPed::nSaveStructSize = +#ifdef COMPATIBLE_SAVES + 1520; +#else + sizeof(CPlayerPed); +#endif + CPlayerPed::~CPlayerPed() { delete m_pWanted; @@ -1504,3 +1511,33 @@ CPlayerPed::ProcessControl(void) UpdateRpHAnim(); #endif } + +#ifdef COMPATIBLE_SAVES +void +CPlayerPed::Save(uint8*& buf) +{ + CPed::Save(buf); + SkipSaveBuf(buf, 16); + WriteSaveBuf(buf, m_fMaxStamina); + SkipSaveBuf(buf, 28); + WriteSaveBuf(buf, m_nTargettableObjects[0]); + WriteSaveBuf(buf, m_nTargettableObjects[1]); + WriteSaveBuf(buf, m_nTargettableObjects[2]); + WriteSaveBuf(buf, m_nTargettableObjects[3]); + SkipSaveBuf(buf, 116); +} + +void +CPlayerPed::Load(uint8*& buf) +{ + CPed::Load(buf); + SkipSaveBuf(buf, 16); + m_fMaxStamina = ReadSaveBuf(buf); + SkipSaveBuf(buf, 28); + m_nTargettableObjects[0] = ReadSaveBuf(buf); + m_nTargettableObjects[1] = ReadSaveBuf(buf); + m_nTargettableObjects[2] = ReadSaveBuf(buf); + m_nTargettableObjects[3] = ReadSaveBuf(buf); + SkipSaveBuf(buf, 116); +} +#endif diff --git a/src/peds/PlayerPed.h b/src/peds/PlayerPed.h index b8bd57e4..61b70f89 100644 --- a/src/peds/PlayerPed.h +++ b/src/peds/PlayerPed.h @@ -75,6 +75,13 @@ public: static void SetupPlayerPed(int32); static void DeactivatePlayerPed(int32); static void ReactivatePlayerPed(int32); + +#ifdef COMPATIBLE_SAVES + virtual void Save(uint8*& buf); + virtual void Load(uint8*& buf); +#endif + + static const uint32 nSaveStructSize; }; #ifndef PED_SKIN diff --git a/src/vehicles/Automobile.cpp b/src/vehicles/Automobile.cpp index 4593966f..9d602254 100644 --- a/src/vehicles/Automobile.cpp +++ b/src/vehicles/Automobile.cpp @@ -51,6 +51,13 @@ RwObject *GetCurrentAtomicObjectCB(RwObject *object, void *data); bool CAutomobile::m_sAllTaxiLights; +const uint32 CAutomobile::nSaveStructSize = +#ifdef COMPATIBLE_SAVES + 1448; +#else + sizeof(CAutomobile); +#endif + CAutomobile::CAutomobile(int32 id, uint8 CreatedBy) : CVehicle(CreatedBy) { @@ -4580,3 +4587,22 @@ CAutomobile::SetAllTaxiLights(bool set) { m_sAllTaxiLights = set; } + +#ifdef COMPATIBLE_SAVES +void +CAutomobile::Save(uint8*& buf) +{ + CVehicle::Save(buf); + WriteSaveBuf(buf, Damage); + SkipSaveBuf(buf, 800 - sizeof(CDamageManager)); +} + +void +CAutomobile::Load(uint8*& buf) +{ + CVehicle::Load(buf); + Damage = ReadSaveBuf(buf); + SkipSaveBuf(buf, 800 - sizeof(CDamageManager)); + SetupDamageAfterLoad(); +} +#endif diff --git a/src/vehicles/Automobile.h b/src/vehicles/Automobile.h index 2de85a99..041302bf 100644 --- a/src/vehicles/Automobile.h +++ b/src/vehicles/Automobile.h @@ -188,9 +188,15 @@ public: void HideAllComps(void); void ShowAllComps(void); void ReduceHornCounter(void); +#ifdef COMPATIBLE_SAVES + virtual void Save(uint8*& buf); + virtual void Load(uint8*& buf); +#endif + static const uint32 nSaveStructSize; static void SetAllTaxiLights(bool set); }; + static_assert(sizeof(CAutomobile) == 0x5A8, "CAutomobile: error"); inline uint8 GetCarDoorFlag(int32 carnode) { diff --git a/src/vehicles/Boat.cpp b/src/vehicles/Boat.cpp index 615511bd..8c8cce1c 100644 --- a/src/vehicles/Boat.cpp +++ b/src/vehicles/Boat.cpp @@ -32,6 +32,13 @@ float WAKE_LIFETIME = 400.0f; CBoat *CBoat::apFrameWakeGeneratingBoats[4]; +const uint32 CBoat::nSaveStructSize = +#ifdef COMPATIBLE_SAVES + 1156; +#else + sizeof(CBoat); +#endif + CBoat::CBoat(int mi, uint8 owner) : CVehicle(owner) { CVehicleModelInfo *minfo = (CVehicleModelInfo*)CModelInfo::GetModelInfo(mi); @@ -899,3 +906,19 @@ CBoat::AddWakePoint(CVector point) m_nNumWakePoints = 1; } } + +#ifdef COMPATIBLE_SAVES +void +CBoat::Save(uint8*& buf) +{ + CVehicle::Save(buf); + SkipSaveBuf(buf, 1156 - 648); +} + +void +CBoat::Load(uint8*& buf) +{ + CVehicle::Load(buf); + SkipSaveBuf(buf, 1156 - 648); +} +#endif diff --git a/src/vehicles/Boat.h b/src/vehicles/Boat.h index ba56e355..70407ab9 100644 --- a/src/vehicles/Boat.h +++ b/src/vehicles/Boat.h @@ -64,7 +64,14 @@ public: static float IsVertexAffectedByWake(CVector vecVertex, CBoat *pBoat); static void FillBoatList(void); +#ifdef COMPATIBLE_SAVES + virtual void Save(uint8*& buf); + virtual void Load(uint8*& buf); +#endif + static const uint32 nSaveStructSize; + }; + static_assert(sizeof(CBoat) == 0x484, "CBoat: error"); extern float MAX_WAKE_LENGTH; diff --git a/src/vehicles/Vehicle.cpp b/src/vehicles/Vehicle.cpp index 590e68f2..75f43515 100644 --- a/src/vehicles/Vehicle.cpp +++ b/src/vehicles/Vehicle.cpp @@ -1222,3 +1222,128 @@ DestroyVehicleAndDriverAndPassengers(CVehicle* pVehicle) CWorld::Remove(pVehicle); delete pVehicle; } + +#ifdef COMPATIBLE_SAVES +void +CVehicle::Save(uint8*& buf) +{ + SkipSaveBuf(buf, 4); + WriteSaveBuf(buf, GetRight().x); + WriteSaveBuf(buf, GetRight().y); + WriteSaveBuf(buf, GetRight().z); + SkipSaveBuf(buf, 4); + WriteSaveBuf(buf, GetForward().x); + WriteSaveBuf(buf, GetForward().y); + WriteSaveBuf(buf, GetForward().z); + SkipSaveBuf(buf, 4); + WriteSaveBuf(buf, GetUp().x); + WriteSaveBuf(buf, GetUp().y); + WriteSaveBuf(buf, GetUp().z); + SkipSaveBuf(buf, 4); + WriteSaveBuf(buf, GetPosition().x); + WriteSaveBuf(buf, GetPosition().y); + WriteSaveBuf(buf, GetPosition().z); + SkipSaveBuf(buf, 16); + SaveEntityFlags(buf); + SkipSaveBuf(buf, 212); + AutoPilot.Save(buf); + WriteSaveBuf(buf, m_currentColour1); + WriteSaveBuf(buf, m_currentColour2); + SkipSaveBuf(buf, 2); + WriteSaveBuf(buf, m_nAlarmState); + SkipSaveBuf(buf, 43); + WriteSaveBuf(buf, m_nNumMaxPassengers); + SkipSaveBuf(buf, 2); + WriteSaveBuf(buf, field_1D0[0]); + WriteSaveBuf(buf, field_1D0[1]); + WriteSaveBuf(buf, field_1D0[2]); + WriteSaveBuf(buf, field_1D0[3]); + SkipSaveBuf(buf, 8); + WriteSaveBuf(buf, m_fSteerAngle); + WriteSaveBuf(buf, m_fGasPedal); + WriteSaveBuf(buf, m_fBrakePedal); + WriteSaveBuf(buf, VehicleCreatedBy); + uint8 flags = 0; + if (bIsLawEnforcer) flags |= BIT(0); + if (bIsLocked) flags |= BIT(3); + if (bEngineOn) flags |= BIT(4); + if (bIsHandbrakeOn) flags |= BIT(5); + if (bLightsOn) flags |= BIT(6); + if (bFreebies) flags |= BIT(7); + WriteSaveBuf(buf, flags); + SkipSaveBuf(buf, 10); + WriteSaveBuf(buf, m_fHealth); + WriteSaveBuf(buf, m_nCurrentGear); + SkipSaveBuf(buf, 3); + WriteSaveBuf(buf, m_fChangeGearTime); + SkipSaveBuf(buf, 4); + WriteSaveBuf(buf, m_nTimeOfDeath); + SkipSaveBuf(buf, 2); + WriteSaveBuf(buf, m_nBombTimer); + SkipSaveBuf(buf, 12); + WriteSaveBuf(buf, m_nDoorLock); + SkipSaveBuf(buf, 99); +} + +void +CVehicle::Load(uint8*& buf) +{ + CMatrix tmp; + SkipSaveBuf(buf, 4); + tmp.GetRight().x = ReadSaveBuf(buf); + tmp.GetRight().y = ReadSaveBuf(buf); + tmp.GetRight().z = ReadSaveBuf(buf); + SkipSaveBuf(buf, 4); + tmp.GetForward().x = ReadSaveBuf(buf); + tmp.GetForward().y = ReadSaveBuf(buf); + tmp.GetForward().z = ReadSaveBuf(buf); + SkipSaveBuf(buf, 4); + tmp.GetUp().x = ReadSaveBuf(buf); + tmp.GetUp().y = ReadSaveBuf(buf); + tmp.GetUp().z = ReadSaveBuf(buf); + SkipSaveBuf(buf, 4); + tmp.GetPosition().x = ReadSaveBuf(buf); + tmp.GetPosition().y = ReadSaveBuf(buf); + tmp.GetPosition().z = ReadSaveBuf(buf); + m_matrix = tmp; + SkipSaveBuf(buf, 16); + LoadEntityFlags(buf); + SkipSaveBuf(buf, 212); + AutoPilot.Load(buf); + m_currentColour1 = ReadSaveBuf(buf); + m_currentColour2 = ReadSaveBuf(buf); + SkipSaveBuf(buf, 2); + m_nAlarmState = ReadSaveBuf(buf); + SkipSaveBuf(buf, 43); + m_nNumMaxPassengers = ReadSaveBuf(buf); + SkipSaveBuf(buf, 2); + field_1D0[0] = ReadSaveBuf(buf); + field_1D0[1] = ReadSaveBuf(buf); + field_1D0[2] = ReadSaveBuf(buf); + field_1D0[3] = ReadSaveBuf(buf); + SkipSaveBuf(buf, 8); + m_fSteerAngle = ReadSaveBuf(buf); + m_fGasPedal = ReadSaveBuf(buf); + m_fBrakePedal = ReadSaveBuf(buf); + VehicleCreatedBy = ReadSaveBuf(buf); + uint8 flags = ReadSaveBuf(buf); + bIsLawEnforcer = !!(flags & BIT(0)); + bIsLocked = !!(flags & BIT(3)); + bEngineOn = !!(flags & BIT(4)); + bIsHandbrakeOn = !!(flags & BIT(5)); + bLightsOn = !!(flags & BIT(6)); + bFreebies = !!(flags & BIT(7)); + SkipSaveBuf(buf, 10); + m_fHealth = ReadSaveBuf(buf); + m_nCurrentGear = ReadSaveBuf(buf); + SkipSaveBuf(buf, 3); + m_fChangeGearTime = ReadSaveBuf(buf); + SkipSaveBuf(buf, 4); + m_nTimeOfDeath = ReadSaveBuf(buf); + SkipSaveBuf(buf, 2); + m_nBombTimer = ReadSaveBuf(buf); + SkipSaveBuf(buf, 12); + m_nDoorLock = (eCarLock)ReadSaveBuf(buf); + SkipSaveBuf(buf, 99); +} +#endif diff --git a/src/vehicles/Vehicle.h b/src/vehicles/Vehicle.h index cb4ac2cf..b6b6ea4b 100644 --- a/src/vehicles/Vehicle.h +++ b/src/vehicles/Vehicle.h @@ -231,6 +231,10 @@ public: virtual bool IsRoomForPedToLeaveCar(uint32 component, CVector *forcedDoorPos) { return false;} virtual float GetHeightAboveRoad(void); virtual void PlayCarHorn(void) {} +#ifdef COMPATIBLE_SAVES + virtual void Save(uint8*& buf); + virtual void Load(uint8*& buf); +#endif bool IsCar(void) { return m_vehType == VEHICLE_TYPE_CAR; } bool IsBoat(void) { return m_vehType == VEHICLE_TYPE_BOAT; } diff --git a/src/weapons/Weapon.cpp b/src/weapons/Weapon.cpp index 9897e73f..e9b917de 100644 --- a/src/weapons/Weapon.cpp +++ b/src/weapons/Weapon.cpp @@ -2257,4 +2257,30 @@ bool CWeapon::ProcessLineOfSight(CVector const &point1, CVector const &point2, CColPoint &point, CEntity *&entity, eWeaponType type, CEntity *shooter, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSeeThrough, bool ignoreSomeObjects) { return CWorld::ProcessLineOfSight(point1, point2, point, entity, checkBuildings, checkVehicles, checkPeds, checkObjects, checkDummies, ignoreSeeThrough, ignoreSomeObjects); -} \ No newline at end of file +} + +#ifdef COMPATIBLE_SAVES +void +CWeapon::Save(uint8*& buf) +{ + WriteSaveBuf(buf, m_eWeaponType); + WriteSaveBuf(buf, m_eWeaponState); + WriteSaveBuf(buf, m_nAmmoInClip); + WriteSaveBuf(buf, m_nAmmoTotal); + WriteSaveBuf(buf, m_nTimer); + WriteSaveBuf(buf, m_bAddRotOffset); + SkipSaveBuf(buf, 3); +} + +void +CWeapon::Load(uint8*& buf) +{ + m_eWeaponType = (eWeaponType)ReadSaveBuf(buf); + m_eWeaponState = (eWeaponState)ReadSaveBuf(buf); + m_nAmmoInClip = ReadSaveBuf(buf); + m_nAmmoTotal = ReadSaveBuf(buf); + m_nTimer = ReadSaveBuf(buf); + m_bAddRotOffset = ReadSaveBuf(buf); + SkipSaveBuf(buf, 3); +} +#endif diff --git a/src/weapons/Weapon.h b/src/weapons/Weapon.h index 2c3a9657..1b2c0320 100644 --- a/src/weapons/Weapon.h +++ b/src/weapons/Weapon.h @@ -67,6 +67,11 @@ public: bool HasWeaponAmmoToBeUsed(void); static bool ProcessLineOfSight(CVector const &point1, CVector const &point2, CColPoint &point, CEntity *&entity, eWeaponType type, CEntity *shooter, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSeeThrough, bool ignoreSomeObjects); + +#ifdef COMPATIBLE_SAVES + void Save(uint8*& buf); + void Load(uint8*& buf); +#endif }; VALIDATE_SIZE(CWeapon, 0x18);