Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include "stdafx.h"
- #include "COpCodeSync.h"
- #include <Commands/CCustomCommandMgr.h>
- enum class eSyncedParamType
- {
- NONE,
- // any `CPed` (aka actor, character), examples: `$ACTOR_SMOKE`
- PED,
- // `$PLAYER_CHAR` (internal playerId for the `CWorld::Players` array)
- // also used as `CPed` in cases where it is necessary to handle
- // a player as a ped rather than a player (very often, e.g. `$PLAYER_ACTOR`)
- PLAYER,
- // any `CVehicle` (aka car)
- VEHICLE,
- // not in use yet
- OBJECT,
- MAX_PARAMS
- };
- struct SSyncedOpCode
- {
- uint16_t m_wOpCode;
- // means the opcode has parameters that are hard to sync,
- // like entities from the `eSyncedParamType`
- bool m_bHasComplexParams = false;
- // yes, only the first 4 parameters contain entity handles,
- // i checked and did not find any opcode where a handle is in
- // the 5th or later parameters
- eSyncedParamType m_aParamTypes[4] = { eSyncedParamType::NONE, eSyncedParamType::NONE, eSyncedParamType::NONE, eSyncedParamType::NONE };
- };
- // Keep sorted!
- const SSyncedOpCode syncedOpcodes[] =
- {
- // Messages
- {0x00BA}, // show_text_styled GXT 'SWEET_5' time 1000 style 2
- //{0x00BC}, // show_text_highpriority GXT 'MTIME3' time 1000 flag 1
- {0x00BE}, // text_clear_all
- //{0x01E3}, // show_text_1number_styled GXT 'M_PASSR' number 3 time 5000 style 1
- {0x0318}, // set_latest_mission_passed 'INTRO_1'
- {0x03E5}, // show_text_box 'HELP101'
- // Population managment
- {0x01EB}, // set_traffic_density_multiplier_to 0.0
- {0x0395}, // clear_area 1 at 2494.91 -1682.17 12.32 radius 50.0
- {0x03DE}, // set_pedestrians_density_multiplier_to 0.2
- {0x09D2}, // set_cops_chase_criminals 0
- {0x06D0}, // enable_emergency_traffic 1
- // Camera
- {0x015F}, // set_camera_position 2498.947 -1690.0 14.4011 rotation 0.0 0.0 0.0
- {0x0160}, // set_camera_point_at 2498.405 -1689.177 14.2309 switchstyle 2
- {0x02EB}, // restore_camera_with_jumpcut
- {0x0373}, // set_camera_directly_behind_player
- {0x0920}, // point_camera 2359.521 -1246.843 28.7047 transverse_to 2359.276 -1247.129 28.7047 time 7000 smooth_transition 1
- {0x0925}, // restore_camera_to_user_defined
- {0x092F}, // lock_camera_target_point 1
- {0x0930}, // lock_camera_position 1
- {0x0936}, // set_camera 2358.656 -1246.348 28.7884 position_to 2358.656 -1246.348 28.7884 time 7000 smooth_transition 1
- {0x0A0B}, // set_rendering_origin_at_3D_coord 2495.59 -1686.96 12.51 angle 32.2
- // Scenes
- {0x016A}, // fade 1 time 1000
- {0x02A3}, // enable_widescreen 1
- {0x02E4}, // load_cutscene_data 'PROLOG1'
- {0x02E7}, // start_cutscene
- {0x02EA}, // end_cutscene
- // World
- // Interiors
- {0x04BB}, // select_interior 0
- {0x07FB}, // set_interior 'CARLS' access 1
- // Weapons
- {0x06AB, true, {eSyncedParamType::PED}}, // set_actor $NETWORK_PLAYER[2] all_weapons_hidden 1
- {0x07A7, true, {eSyncedParamType::PED}}, // put_jetpack_on_actor $PLAYER_ACTOR
- // Tasks
- {0x05C0, true, {eSyncedParamType::PED, eSyncedParamType::VEHICLE}}, // AS_actor 66@ look_at_car 51@ 4000 ms
- {0x05D3, true, {eSyncedParamType::PED}}, //AS_actor $PLAYER_ACTOR goto_point 954.0 -1103.5 22.85 mode 4 time 20000 ms // versionA
- {0x0647, true, {eSyncedParamType::PED}}, // AS_actor 66@ clear_look_task
- {0x0687, true, {eSyncedParamType::PED}}, //clear_actor $PLAYER_ACTOR task
- {0x0792, true, {eSyncedParamType::PED}}, //disembark_instantly_actor $PLAYER_ACTOR
- {0x0673, true, {eSyncedParamType::PED}}, // AS_actor 66@ dive_to_offset 1.0 -3.0 time_on_ground 1000 ms
- {0x0634, true, {eSyncedParamType::PED, eSyncedParamType::PED}}, // AS_actor 67@ attack_using_weapon_actor 50@ flags 4 perform_actions_after_time 2000 chance_of_action 100
- // Actors
- {0x00A1, true, {eSyncedParamType::PED}}, // put_actor $PLAYER_ACTOR at 345.5621 306.2212 998.4484
- {0x0350, true, {eSyncedParamType::PED}}, // set_actor 65@ maintain_position_when_attacked 1
- {0x0173, true, {eSyncedParamType::PED}}, // set_actor $NETWORK_PLAYER[0] Z_angle_to 262.3977
- // Vehicles
- {0x00AB, true, {eSyncedParamType::VEHICLE}}, // put_car 69@ at 1638.712 -1050.319 22.8984
- {0x0175, true, {eSyncedParamType::VEHICLE}}, // set_car 69@ Z_angle_to 252.8
- // Explosions
- {0x070C, true, {eSyncedParamType::VEHICLE}}, // explode_car_without_radius_damage 41@
- // Audio
- {0x097A}, // play_audio_at -1000.0 -1000.0 -1000.0 event 1058
- // Blips
- //{0x0164}, // disable_marker $MARKER_CATALINA
- //{0x018A}, // 1@ = create_checkpoint_at 14@ 15@ 16@
- //{0x02A7}, // $439 = create_icon_marker_and_sphere $ICON_CJ at $X_JOHNSON_HOUSE $Y_JOHNSON_HOUSE $Z_JOHNSON_HOUSE
- };
- struct OpcodeSyncHeader
- {
- uint16_t opcode;
- uint8_t intParamCount : 4;
- uint8_t stringParamCount : 4;
- };
- struct OpcodeParameter
- {
- union
- {
- struct
- {
- eSyncedParamType entityType : 4;
- int entityId : 28;
- };
- int value;
- };
- };
- static OpcodeParameter scriptParamsBuffer[10];
- static uint8_t textLengthBuffer[10];
- static char textParamBuffer[10][256];
- static uint16_t scriptParamCount = 0;
- static uint16_t textParamCount = 0;
- static uint32_t lastOpCodeProcessed;
- static CRunningScript* lastProcessedScript;
- static uint8_t currentStringIdx = 0;
- void __fastcall CRunningScript__CollectParameters_Hook_SwitchParametersContext(CRunningScript* script, int, uint16_t count)
- {
- memcpy(ScriptParams, scriptParamsBuffer, sizeof scriptParamsBuffer);
- }
- void __fastcall CRunningScript__ReadTextLabelFromScript_Hook_SwitchParametersContext(CRunningScript* script, int, char* ptr, uint8_t len)
- {
- memset(ptr, 0, len);
- strncpy(ptr, textParamBuffer[currentStringIdx], textLengthBuffer[currentStringIdx]);
- currentStringIdx++;
- }
- /// <param name="opcodeIdx">syncedOpcodes index</param>
- bool IsOpcodeSyncable(int* opcodeIdx = nullptr)
- {
- if (CLocalPlayer::m_bIsHost
- && COpCodeSync::ms_bSyncingEnabled
- && (lastProcessedScript->m_bIsMission || (uintptr_t)lastProcessedScript->m_pBaseIP < 0xCB0600) // catch opcode calls only from the game memory
- && !lastProcessedScript->m_bIsExternal)
- {
- for (int i = 0; i < ARRAY_SIZE(syncedOpcodes); i++)
- {
- if (syncedOpcodes[i].m_wOpCode == lastOpCodeProcessed)
- {
- if (opcodeIdx)
- {
- *opcodeIdx = i;
- }
- return true;
- }
- }
- }
- return false;
- }
- void BuildAndSendOpcode()
- {
- int idx = 0;
- if (!IsOpcodeSyncable(&idx))
- return;
- int dataSize =
- sizeof(OpcodeSyncHeader)
- + scriptParamCount * sizeof(int)
- + textParamCount * sizeof(uint8_t);
- for (int i = 0; i < textParamCount; i++)
- {
- dataSize += textLengthBuffer[i];
- }
- std::vector<uint8_t> buffer(dataSize);
- uint8_t* current = buffer.data();
- OpcodeSyncHeader header;
- header.opcode = lastOpCodeProcessed;
- header.intParamCount = scriptParamCount;
- header.stringParamCount = textParamCount;
- memcpy(current, &header, sizeof(header));
- current += sizeof(header);
- if (scriptParamCount)
- {
- for (int i = 0; i < scriptParamCount; i++)
- {
- if (syncedOpcodes[idx].m_bHasComplexParams && i < 4)
- {
- //CChat::AddMessage("Parsing complex opcode %04x parameter %d...", header.opcode, i);
- switch (syncedOpcodes[idx].m_aParamTypes[i])
- {
- case eSyncedParamType::PED:
- {
- //CChat::AddMessage("Trying to parse a ped handle %d...", scriptParamsBuffer[i].value);
- if (auto ped = CPools::GetPed(scriptParamsBuffer[i].value))
- {
- if (ped->m_nPedType > 3) // is a regular ped
- {
- if (auto networkPed = CNetworkPedManager::GetPed(ped))
- {
- //CChat::AddMessage("Network id %d...", networkPed->m_nPedId);
- if (networkPed->m_bSyncing)
- {
- scriptParamsBuffer[i].entityId = networkPed->m_nPedId;
- scriptParamsBuffer[i].entityType = eSyncedParamType::PED;
- //CChat::AddMessage("Parsed ped id %d...", networkPed->m_nPedId);
- }
- }
- }
- else // is a player ped
- {
- if (ped == FindPlayerPed(0))
- {
- scriptParamsBuffer[i].entityId = CNetworkPlayerManager::m_nMyId;
- }
- else if (auto networkPlayer = CNetworkPlayerManager::GetPlayer(ped))
- {
- scriptParamsBuffer[i].entityId = networkPlayer->m_iPlayerId;
- }
- scriptParamsBuffer[i].entityType = eSyncedParamType::PLAYER;
- }
- }
- break;
- }
- case eSyncedParamType::PLAYER:
- {
- //CChat::AddMessage("Trying to parse a player...");
- if (!scriptParamsBuffer[i].value)
- {
- scriptParamsBuffer[i].entityType = eSyncedParamType::PLAYER;
- scriptParamsBuffer[i].entityId = CNetworkPlayerManager::m_nMyId;
- //CChat::AddMessage("Parsed player id %d (me)...", CNetworkPlayerManager::m_nMyId);
- break;
- }
- if (auto player = CWorld::Players[scriptParamsBuffer[i].value].m_pPed)
- {
- if (auto networkPlayer = CNetworkPlayerManager::GetPlayer(player))
- {
- scriptParamsBuffer[i].entityType = eSyncedParamType::PLAYER;
- scriptParamsBuffer[i].entityId = networkPlayer->m_iPlayerId;
- //CChat::AddMessage("Parsed player id %d...", networkPlayer->m_iPlayerId);
- }
- }
- break;
- }
- case eSyncedParamType::VEHICLE:
- {
- //CChat::AddMessage("Trying to parse a vehicle...");
- if (auto vehicle = CPools::GetVehicle(scriptParamsBuffer[i].value))
- {
- if (auto networkVehicle = CNetworkVehicleManager::GetVehicle(vehicle))
- {
- scriptParamsBuffer[i].entityId = networkVehicle->m_nVehicleId;
- scriptParamsBuffer[i].entityType = eSyncedParamType::VEHICLE;
- //CChat::AddMessage("Parsed vehicle id %d...", networkVehicle->m_nVehicleId);
- }
- }
- break;
- }
- default:
- break;
- }
- }
- memcpy(current, &scriptParamsBuffer[i], sizeof(int));
- current += sizeof(int);
- }
- }
- if(textParamCount)
- {
- for (int i = 0; i < textParamCount; i++)
- {
- *current = static_cast<uint8_t>(textLengthBuffer[i]);
- current += sizeof(uint8_t);
- memcpy(current, textParamBuffer[i], textLengthBuffer[i]);
- current += textLengthBuffer[i];
- }
- }
- CNetwork::SendPacket(CPacketsID::OPCODE_SYNC, buffer.data(), dataSize, ENET_PACKET_FLAG_RELIABLE);
- memset(textParamBuffer, 0, sizeof textParamBuffer);
- memset(textLengthBuffer, 0, sizeof textLengthBuffer);
- scriptParamCount = 0;
- textParamCount = 0;
- }
- void COpCodeSync::HandlePacket(const uint8_t* buffer, int bufferSize)
- {
- if (!buffer || bufferSize < sizeof(OpcodeSyncHeader))
- {
- return;
- }
- const uint8_t* current = buffer;
- OpcodeSyncHeader header;
- memcpy(&header, current, sizeof(header));
- current += sizeof(header);
- if (bufferSize < sizeof(header) + header.intParamCount * sizeof(int))
- {
- return;
- }
- memset(scriptParamsBuffer, 0, sizeof(scriptParamsBuffer));
- memset(textLengthBuffer, 0, sizeof(textLengthBuffer));
- memset(textParamBuffer, 0, sizeof(textParamBuffer));
- scriptParamCount = 0;
- textParamCount = 0;
- currentStringIdx = 0;
- scriptParamCount = header.intParamCount;
- if (scriptParamCount > 10) scriptParamCount = 10;
- textParamCount = header.stringParamCount;
- if (textParamCount > 10) textParamCount = 10;
- if (scriptParamCount)
- {
- memcpy(scriptParamsBuffer, current, scriptParamCount * sizeof(int));
- current += scriptParamCount * sizeof(int);
- int idx = 0;
- bool found = false;
- for (; idx < ARRAY_SIZE(syncedOpcodes); idx++)
- {
- if (syncedOpcodes[idx].m_wOpCode == header.opcode)
- {
- found = true;
- break;
- }
- }
- if(!found)
- return;
- if (syncedOpcodes[idx].m_bHasComplexParams)
- {
- //CChat::AddMessage("Parsing complex opcode %04x...", header.opcode);
- int max = min(scriptParamCount, 4);
- for (int i = 0; i < max; i++)
- {
- switch (syncedOpcodes[idx].m_aParamTypes[i])
- {
- case eSyncedParamType::PED:
- {
- //CChat::AddMessage("Parsing ped...");
- if (scriptParamsBuffer[i].entityType == eSyncedParamType::PED)
- {
- //CChat::AddMessage("Trying to parse as a regular ped...");
- if (auto networkPed = CNetworkPedManager::GetPed(scriptParamsBuffer[i].entityId))
- {
- //CChat::AddMessage("Network instance found...");
- if (auto ped = networkPed->m_pPed)
- {
- scriptParamsBuffer[i].value = CPools::GetPedRef(ped);
- //CChat::AddMessage("Parsed ped id %d...", networkPed->m_nPedId);
- }
- else return;
- }
- else return;
- }
- else
- {
- if (scriptParamsBuffer[i].entityId == CNetworkPlayerManager::m_nMyId)
- {
- if (auto playerPed = FindPlayerPed(0))
- {
- scriptParamsBuffer[i].value = CPools::GetPedRef(playerPed);
- }
- }
- else
- {
- //CChat::AddMessage("Trying to parse as a player ped... %d", scriptParamsBuffer[i].entityId);
- if (auto networkPlayer = CNetworkPlayerManager::GetPlayer(scriptParamsBuffer[i].entityId))
- {
- //CChat::AddMessage("Network instance found...");
- if (auto ped = networkPlayer->m_pPed)
- {
- scriptParamsBuffer[i].value = CPools::GetPedRef(ped);
- //CChat::AddMessage("Parsed player id as ped %d...", networkPlayer->m_iPlayerId);
- }
- else return;
- }
- else return;
- }
- }
- break;
- }
- case eSyncedParamType::PLAYER:
- {
- if (scriptParamsBuffer[i].entityId == CNetworkPlayerManager::m_nMyId)
- {
- scriptParamsBuffer[i].value = 0;
- //CChat::AddMessage("Parsed player id %d (me)...", CNetworkPlayerManager::m_nMyId);
- break;
- }
- if (auto networkPlayer = CNetworkPlayerManager::GetPlayer(scriptParamsBuffer[i].entityId))
- {
- if (networkPlayer->m_pPed)
- {
- int playerNum = networkPlayer->GetInternalId();
- if (playerNum)
- {
- scriptParamsBuffer[i].value = playerNum;
- //CChat::AddMessage("Parsed player id %d...", networkPlayer->m_iPlayerId);
- }
- else return;
- }
- else return;
- }
- else return;
- break;
- }
- case eSyncedParamType::VEHICLE:
- {
- if (auto networkVehicle = CNetworkVehicleManager::GetVehicle(scriptParamsBuffer[i].entityId))
- {
- if (auto vehicle = networkVehicle->m_pVehicle)
- {
- scriptParamsBuffer[i].value = CPools::GetVehicleRef(vehicle);
- // CChat::AddMessage("Parsed vehicle id %d...", networkVehicle->m_nVehicleId);
- }
- else return;
- }
- else return;
- break;
- }
- default:
- break;
- }
- }
- //CChat::AddMessage("OK");
- }
- }
- if (textParamCount)
- {
- for (int i = 0; i < textParamCount; i++)
- {
- if (current >= buffer + bufferSize)
- {
- return;
- }
- textLengthBuffer[i] = *current;
- current += sizeof(uint8_t);
- if (current + textLengthBuffer[i] > buffer + bufferSize || textLengthBuffer[i] > 255)
- {
- return;
- }
- memcpy(textParamBuffer[i], current, textLengthBuffer[i]);
- textParamBuffer[i][textLengthBuffer[i]] = '\0';
- current += textLengthBuffer[i];
- }
- }
- static CRunningScript script;
- memset(&script, 0, sizeof(CRunningScript));
- script.Init();
- script.m_bIsMission = true;
- script.m_bUseMissionCleanup = false;
- strcpy(script.m_szName, "coopand");
- script.m_pBaseIP = script.m_pCurrentIP = (uint8_t*)&header.opcode;
- lastOpCodeProcessed = header.opcode;
- // TODO: refactor
- if (lastOpCodeProcessed == 0x0701) // end_scene_skip
- {
- CHud::m_BigMessage[1][0] = 0;
- }
- else if (lastOpCodeProcessed == 0x02E7) // start_cutscene
- {
- if(CCutsceneMgr::ms_cutsceneLoadStatus != 2)
- {
- COpCodeSync::ms_bLoadingCutscene = true;
- return; // dont process opcode
- }
- }
- patch::RedirectJump(0x464080, CRunningScript__CollectParameters_Hook_SwitchParametersContext, false);
- patch::RedirectJump(0x463D50, CRunningScript__ReadTextLabelFromScript_Hook_SwitchParametersContext, false);
- if ((header.opcode & 0x7FFF) < CCustomCommandMgr::MIN_CUSTOM_COMMAND)
- {
- CRunningScript::CommandHandlerTable[(header.opcode & 0x7FFF) / 100](&script, header.opcode & 0x7FFF);
- }
- else
- {
- CCustomCommandMgr::ProcessCommand((header.opcode & 0x7FFF), &script);
- }
- patch::SetRaw(0x464080, "\x66\x8B\x44\x24\x04", 5, false);
- patch::SetRaw(0x463D50, "\x8B\x41\x14\x83\xEC\x08", 6, false);
- }
- void __declspec(naked) OpcodeProcessingWellDone_Hook()
- {
- __asm
- {
- mov lastOpCodeProcessed, ecx
- mov lastProcessedScript, esi
- mov ecx, esi
- call edx
- push eax
- call BuildAndSendOpcode
- pop eax
- test al, al
- push 0x469FF9
- ret
- }
- }
- void __declspec(naked) CRunningScript__CollectParameters_Hook_GetSyncingParams()
- {
- __asm
- {
- pop ebx
- mov eax, [esp + 0x4]
- mov scriptParamCount, ax
- pop eax
- add esp, 4
- pushad
- }
- if (lastProcessedScript
- && IsOpcodeSyncable())
- {
- memcpy(scriptParamsBuffer, ScriptParams, scriptParamCount * sizeof(int));
- }
- else
- {
- scriptParamCount = 0;
- }
- __asm
- {
- popad
- jmp eax
- }
- }
- static char* textPointer;
- static uint8_t textLength;
- void CollectTextParameters()
- {
- if (textPointer
- && lastProcessedScript
- && IsOpcodeSyncable())
- {
- textLengthBuffer[textParamCount] = min(textLength, strlen(textPointer));
- strncpy_s(textParamBuffer[textParamCount], textPointer, textLengthBuffer[textParamCount]);
- textParamCount++;
- }
- }
- void __declspec(naked) CRunningScript__ReadTextLabelFromScript_Hook_GetSyncingParams()
- {
- __asm
- {
- add esp, 8
- mov eax, [esp + 0x4]
- mov textPointer, eax
- mov eax, [esp + 0x8]
- mov textLength, al
- call CollectTextParameters
- retn 8
- }
- }
- void COpCodeSync::Init()
- {
- DWORD temp;
- injector::UnprotectMemory(0x464080, 5, temp);
- injector::UnprotectMemory(0x463D50, 6, temp);
- patch::RedirectJump(0x469FF3, OpcodeProcessingWellDone_Hook);
- std::vector<int> hookPositions = { 0x463D92, 0x463DBF, 0x463E1A, 0x463E6B, 0x463EAC, 0x463F2A, 0x463F7F, 0x463FA2, 0x463FDA, 0x463FFB, 0x464034 };
- patch::RedirectJump(hookPositions, CRunningScript__ReadTextLabelFromScript_Hook_GetSyncingParams);
- patch::RedirectJump(0x46421D, CRunningScript__CollectParameters_Hook_GetSyncingParams);
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement