diff --git a/src/component/ai.cpp b/src/component/ai.cpp new file mode 100644 index 0000000..e5ba497 --- /dev/null +++ b/src/component/ai.cpp @@ -0,0 +1,522 @@ +#include +#include "loader/component_loader.hpp" + +#include "scheduler.hpp" +#include "component/gsc.hpp" + +#include +#include +#include +#include + +namespace ai +{ + namespace + { + /* + int __cdecl Path_AStarAlgorithm_CustomSearchInfo_FindPath_(path_t *pPath, team_t eTeam, const float *vStartPos, pathnode_t *pNodeFrom, const float *vGoalPos, int bAllowNegotiationLinks, CustomSearchInfo_FindPath *searchInfo, int bIgnoreBadplaces, pathnode_t *nodeTo) + { + float *returnVGoaPosl; // edx + int nodeLinkIndex; // ebx + pathnode_t *returnStartNode; // ecx + pathnode_t *returnEndNode; // edi + pathlink_s *endNodeLinks; // eax + int nodeNum; // esi + float *endNodeLinkDist; // eax + pathnode_t *pSuccessor; // esi + float v17; // xmm0_4 + pathnode_t *v18; // eax + pathnode_t *v19; // eax + float v20; // xmm1_4 + long double v21; // st7 + float v22; // xmm3_4 + float v23; // xmm0_4 + float v24; // xmm1_4 + float v25; // xmm2_4 + float v26; // xmm0_4 + float v27; // xmm1_4 + float v28; // xmm1_4 + pathnode_t *pInsert; // eax + pathnode_t *v30; // ecx + pathnode_t *v31; // eax + int success; // eax + float v33; // [esp+10h] [ebp-8Ch] + int linkCount; // [esp+14h] [ebp-88h] + float negotiationOverlapCost; // [esp+18h] [ebp-84h] + pathnode_t topParent; // [esp+1Ch] [ebp-80h] BYREF + + returnVGoaPosl = (float *)vGoalPos; + nodeLinkIndex = 0; + if ( vGoalPos ) + { + g_pathAttemptGoalPos[0] = *vGoalPos; + g_pathAttemptGoalPos[1] = vGoalPos[1]; + g_pathAttemptGoalPos[2] = vGoalPos[2]; + } + else + { + g_pathAttemptGoalPos[0] = 0.0; + g_pathAttemptGoalPos[1] = 0.0; + g_pathAttemptGoalPos[2] = 0.0; + } + returnStartNode = pNodeFrom; + pNodeFrom->transient.iSearchFrame = ++level.iSearchFrame; + returnEndNode = pNodeFrom; + pNodeFrom->transient.pParent = &topParent; + pNodeFrom->transient.pNextOpen = 0; + pNodeFrom->transient.pPrevOpen = &topParent; + pNodeFrom->transient.fCost = 0.0; + topParent.transient.pNextOpen = pNodeFrom; + while ( returnEndNode != searchInfo->m_pNodeTo ) + { + topParent.transient.pNextOpen = returnEndNode->transient.pNextOpen; + if ( topParent.transient.pNextOpen ) + topParent.transient.pNextOpen->transient.pPrevOpen = &topParent; + linkCount = 0; + if ( returnEndNode->dynamic.wLinkCount > 0 ) + { + while ( 1 ) + { + if ( bIgnoreBadplaces || !returnEndNode->constant.Links[nodeLinkIndex].ubBadPlaceCount[eTeam] ) + { + endNodeLinks = returnEndNode->constant.Links; + nodeNum = endNodeLinks[nodeLinkIndex].nodeNum; + endNodeLinkDist = &endNodeLinks[nodeLinkIndex].fDist; + pSuccessor = &gameWorldCurrent->path.nodes[nodeNum]; + if ( returnEndNode->constant.type != NODE_NEGOTIATION_BEGIN || pSuccessor->constant.type != NODE_NEGOTIATION_END || !returnEndNode->dynamic.wOverlapCount && !pSuccessor->dynamic.wOverlapCount ) + { + if ( pSuccessor->transient.iSearchFrame != level.iSearchFrame ) + { + pSuccessor->transient.iSearchFrame = level.iSearchFrame; + negotiationOverlapCost = searchInfo->negotiationOverlapCost; + v20 = vGoalPos[1] - pSuccessor->constant.vOrigin[1]; + v21 = sqrtf((float)((float)(*vGoalPos - pSuccessor->constant.vOrigin[0]) * (float)(*vGoalPos - pSuccessor->constant.vOrigin[0])) + (float)(v20 * v20)); + v22 = pSuccessor->constant.minUseDistSq; + if ( v22 <= 1.0 || (v23 = searchInfo->startPos[0] - pSuccessor->constant.vOrigin[0], v24 = searchInfo->startPos[1] - pSuccessor->constant.vOrigin[1], v25 = searchInfo->startPos[2] - pSuccessor->constant.vOrigin[2], v22 <= (float)((float)((float)(v23 * v23) + (float)(v24 * v24)) + (float)(v25 * v25))) ) + { + v26 = v21 + (double)pSuccessor->dynamic.userCount * negotiationOverlapCost; + } + else + { + v33 = v21 + (double)pSuccessor->dynamic.userCount * negotiationOverlapCost; + v26 = negotiationOverlapCost + v33; + } + pSuccessor->transient.fHeuristic = v26; + v17 = returnEndNode->constant.Links[nodeLinkIndex].fDist + returnEndNode->transient.fCost; + LABEL_25: + v27 = pSuccessor->transient.fHeuristic; + pSuccessor->transient.pParent = returnEndNode; + pSuccessor->transient.fCost = v17; + v28 = v27 + v17; + pInsert = &topParent; + if ( topParent.transient.pNextOpen ) + { + do + { + v30 = pInsert->transient.pNextOpen; + if ( (float)(v30->transient.fHeuristic + v30->transient.fCost) >= v28 ) + break; + pInsert = pInsert->transient.pNextOpen; + } + while ( v30->transient.pNextOpen ); + } + pSuccessor->transient.pPrevOpen = pInsert; + pSuccessor->transient.pNextOpen = pInsert->transient.pNextOpen; + pInsert->transient.pNextOpen = pSuccessor; + v31 = pSuccessor->transient.pNextOpen; + if ( v31 ) + v31->transient.pPrevOpen = pSuccessor; + goto LABEL_30; + } + v17 = returnEndNode->transient.fCost + *endNodeLinkDist; + if ( v17 < pSuccessor->transient.fCost ) + { + v18 = pSuccessor->transient.pPrevOpen; + if ( v18 ) + { + v18->transient.pNextOpen = pSuccessor->transient.pNextOpen; + v19 = pSuccessor->transient.pNextOpen; + if ( v19 ) + v19->transient.pPrevOpen = pSuccessor->transient.pPrevOpen; + } + goto LABEL_25; + } + } + } + LABEL_30: + ++nodeLinkIndex; + if ( ++linkCount >= returnEndNode->dynamic.wLinkCount ) + { + returnVGoaPosl = (float *)vGoalPos; + returnStartNode = pNodeFrom; + break; + } + } + } + nodeLinkIndex = 0; + returnEndNode->transient.pPrevOpen = 0; + returnEndNode = topParent.transient.pNextOpen; + if ( !topParent.transient.pNextOpen ) + return 0; + } + if ( pPath ) + success = Path_GeneratePath(pPath, eTeam, vStartPos, returnVGoaPosl, returnStartNode, returnEndNode, 1, bAllowNegotiationLinks); + else + success = 1; + return success; + } + */ + + int Path_AStarAlgorithm_CustomSearchInfo_FindPath_custom(game::path_t* pPath, game::team_t eTeam, const float* vStartPos, game::pathnode_t* pNodeFrom, const float* vGoalPos, int bAllowNegotiationLinks, game::CustomSearchInfo_FindPath* searchInfo, int bIgnoreBadplaces, game::pathnode_t* nodeTo) + { + float* returnVGoaPosl; // edx + int nodeLinkIndex; // ebx + game::pathnode_t* returnStartNode; // ecx + game::pathnode_t* returnEndNode; // edi + game::pathlink_s* endNodeLinks; // eax + int nodeNum; // esi + float* endNodeLinkDist; // eax + game::pathnode_t* pSuccessor; // esi + float v17; // xmm0_4 + game::pathnode_t* v18; // eax + game::pathnode_t* v19; // eax + float v20; // xmm1_4 + long double v21; // st7 + float v22; // xmm3_4 + float v23; // xmm0_4 + float v24; // xmm1_4 + float v25; // xmm2_4 + float v26; // xmm0_4 + float v27; // xmm1_4 + float v28; // xmm1_4 + game::pathnode_t* pInsert; // eax + game::pathnode_t* v30; // ecx + game::pathnode_t* v31; // eax + int success; // eax + float v33; // [esp+10h] [ebp-8Ch] + int linkCount; // [esp+14h] [ebp-88h] + float negotiationOverlapCost; // [esp+18h] [ebp-84h] + game::pathnode_t topParent; // [esp+1Ch] [ebp-80h] BYREF + + returnVGoaPosl = (float*)vGoalPos; + nodeLinkIndex = 0; + if (vGoalPos) + { + *game::g_pathAttemptGoalPos[0] = vGoalPos[0]; + *game::g_pathAttemptGoalPos[1] = vGoalPos[1]; + *game::g_pathAttemptGoalPos[2] = vGoalPos[2]; + } + else + { + *game::g_pathAttemptGoalPos[0] = 0.0f; + *game::g_pathAttemptGoalPos[1] = 0.0f; + *game::g_pathAttemptGoalPos[2] = 0.0f; + } + returnStartNode = pNodeFrom; + pNodeFrom->transient.iSearchFrame = ++game::level->iSearchFrame; + returnEndNode = pNodeFrom; + pNodeFrom->transient.pParent = &topParent; + pNodeFrom->transient.pNextOpen = 0; + pNodeFrom->transient.pPrevOpen = &topParent; + pNodeFrom->transient.fCost = 0.0; + topParent.transient.pNextOpen = pNodeFrom; + while (returnEndNode != searchInfo->m_pNodeTo) + { + topParent.transient.pNextOpen = returnEndNode->transient.pNextOpen; + if (topParent.transient.pNextOpen) + topParent.transient.pNextOpen->transient.pPrevOpen = &topParent; + linkCount = 0; + if (returnEndNode->dynamic.wLinkCount > 0) + { + while (1) + { + if (bIgnoreBadplaces || !returnEndNode->constant.Links[nodeLinkIndex].ubBadPlaceCount[eTeam]) + { + endNodeLinks = returnEndNode->constant.Links; + nodeNum = endNodeLinks[nodeLinkIndex].nodeNum; + endNodeLinkDist = &endNodeLinks[nodeLinkIndex].fDist; + pSuccessor = &(*game::gameWorldCurrent)->path.nodes[nodeNum]; + if (returnEndNode->constant.type != game::NODE_NEGOTIATION_BEGIN || pSuccessor->constant.type != game::NODE_NEGOTIATION_END || !returnEndNode->dynamic.wOverlapCount && !pSuccessor->dynamic.wOverlapCount) + { + if (pSuccessor->transient.iSearchFrame != game::level->iSearchFrame) + { + pSuccessor->transient.iSearchFrame = game::level->iSearchFrame; + negotiationOverlapCost = searchInfo->negotiationOverlapCost; + v20 = vGoalPos[1] - pSuccessor->constant.vOrigin[1]; + v21 = sqrtf((float)((float)(*vGoalPos - pSuccessor->constant.vOrigin[0]) * (float)(*vGoalPos - pSuccessor->constant.vOrigin[0])) + (float)(v20 * v20)); + v22 = pSuccessor->constant.minUseDistSq; + if (v22 <= 1.0 || (v23 = searchInfo->startPos[0] - pSuccessor->constant.vOrigin[0], v24 = searchInfo->startPos[1] - pSuccessor->constant.vOrigin[1], v25 = searchInfo->startPos[2] - pSuccessor->constant.vOrigin[2], v22 <= (float)((float)((float)(v23 * v23) + (float)(v24 * v24)) + (float)(v25 * v25)))) + { + v26 = v21 + (double)pSuccessor->dynamic.userCount * negotiationOverlapCost; + } + else + { + v33 = v21 + (double)pSuccessor->dynamic.userCount * negotiationOverlapCost; + v26 = negotiationOverlapCost + v33; + } + pSuccessor->transient.fHeuristic = v26; + v17 = returnEndNode->constant.Links[nodeLinkIndex].fDist + returnEndNode->transient.fCost; + LABEL_25: + v27 = pSuccessor->transient.fHeuristic; + pSuccessor->transient.pParent = returnEndNode; + pSuccessor->transient.fCost = v17; + v28 = v27 + v17; + pInsert = &topParent; + if (topParent.transient.pNextOpen) + { + do + { + v30 = pInsert->transient.pNextOpen; + if ((float)(v30->transient.fHeuristic + v30->transient.fCost) >= v28) + break; + pInsert = pInsert->transient.pNextOpen; + } while (v30->transient.pNextOpen); + } + pSuccessor->transient.pPrevOpen = pInsert; + pSuccessor->transient.pNextOpen = pInsert->transient.pNextOpen; + pInsert->transient.pNextOpen = pSuccessor; + v31 = pSuccessor->transient.pNextOpen; + if (v31) + v31->transient.pPrevOpen = pSuccessor; + goto LABEL_30; + } + v17 = returnEndNode->transient.fCost + *endNodeLinkDist; + if (v17 < pSuccessor->transient.fCost) + { + v18 = pSuccessor->transient.pPrevOpen; + if (v18) + { + v18->transient.pNextOpen = pSuccessor->transient.pNextOpen; + v19 = pSuccessor->transient.pNextOpen; + if (v19) + v19->transient.pPrevOpen = pSuccessor->transient.pPrevOpen; + } + goto LABEL_25; + } + } + } + LABEL_30: + ++nodeLinkIndex; + if (++linkCount >= returnEndNode->dynamic.wLinkCount) + { + returnVGoaPosl = (float*)vGoalPos; + returnStartNode = pNodeFrom; + break; + } + } + } + nodeLinkIndex = 0; + returnEndNode->transient.pPrevOpen = 0; + returnEndNode = topParent.transient.pNextOpen; + if (!topParent.transient.pNextOpen) + return 0; + } + if (pPath) + success = game::Path_GeneratePath(pPath, eTeam, vStartPos, returnVGoaPosl, returnStartNode, returnEndNode, 1, bAllowNegotiationLinks); + else + success = 1; + return success; + } + + /* + //Original + int __userpurge Path_FindPathFromTo@(float *startPos@, pathnode_t *pNodeTo@, path_t *pPath, team_t eTeam, pathnode_t *pNodeFrom, float *vGoalPos, int bAllowNegotiationLinks, int bIgnoreBadplaces) + { + int v8; // xmm0_4 + CustomSearchInfo_FindPath info; // [esp+0h] [ebp-14h] BYREF + + v8 = ai_pathNegotiationOverlapCost->current.integer; + info.m_pNodeTo = pNodeTo; + LODWORD(info.negotiationOverlapCost) = v8; + info.startPos[0] = *startPos; + info.startPos[1] = startPos[1]; + info.startPos[2] = startPos[2]; + return Path_AStarAlgorithm_CustomSearchInfo_FindPath_(pPath, eTeam, startPos, pNodeFrom, vGoalPos, bAllowNegotiationLinks, &info, bIgnoreBadplaces, pNodeTo); + } + */ + + int Path_FindPathFromTo_custom(float* startPos, game::pathnode_t* pNodeTo, game::path_t* pPath, game::team_t eTeam, game::pathnode_t* pNodeFrom, float* vGoalPos, int bAllowNegotiationLinks, int bIgnoreBadplaces) + { + int overlapCost; // xmm0_4 + game::CustomSearchInfo_FindPath info = {}; // [esp+0h] [ebp-14h] BYREF + int result; + + overlapCost = (*game::ai_pathNegotiationOverlapCost)->current.integer; + info.m_pNodeTo = pNodeTo; + info.negotiationOverlapCost = overlapCost; + info.startPos[0] = startPos[0]; + info.startPos[1] = startPos[1]; + info.startPos[2] = startPos[2]; + result = Path_AStarAlgorithm_CustomSearchInfo_FindPath_custom(pPath, eTeam, startPos, pNodeFrom, vGoalPos, bAllowNegotiationLinks, &info, bIgnoreBadplaces, pNodeTo); + return result; + } + + /* + //Original + int __userpurge Path_FindPath@(path_t* pPath@, team_t eTeam@, float* vStartPos, float* vGoalPos, int bAllowNegotiationLinks) + { + pathnode_t* pNodeTo; // esi + int result; // eax + pathnode_t* pNodeFrom; // eax + int a9; // [esp+2Ch] [ebp-304h] BYREF + int a4[192]; // [esp+30h] [ebp-300h] BYREF + + pNodeTo = Path_NearestNodeNotCrossPlanes(NAN, COERCE_FLOAT(64), (int)vGoalPos, (int)a4, 192.0, 0, 0, 0, (int)&a9, 0); + if (pNodeTo && (pNodeFrom = Path_NearestNodeNotCrossPlanes(NAN, COERCE_FLOAT(64), (int)vStartPos, (int)a4, 192.0, 0, 0, 0, (int)&a9, 0)) != 0) + result = Path_FindPathFromTo(vStartPos, pNodeTo, pPath, eTeam, pNodeFrom, vGoalPos, bAllowNegotiationLinks, 0); + else + result = 0; + return result; + } + */ + + int Path_FindPath_custom(game::path_t* pPath, game::team_t eTeam, float* vStartPos, float* vGoalPos, int bAllowNegotiationLinks) + { + int result; // eax + int returnCount = 0; // [esp+2Ch] [ebp-304h] BYREF + std::unique_ptr nodes(new game::pathsort_t[64], [](game::pathsort_t* ptr) { delete[] ptr; }); + const int maxNodes = 64; + + game::pathnode_t* pNodeTo = game::Path_NearestNodeNotCrossPlanes(-2, maxNodes, vGoalPos, nodes.get(), 192.0f, 0.0f, 0.0f, 0.0f, &returnCount, game::NEAREST_NODE_DO_HEIGHT_CHECK); + if (!pNodeTo) + { + printf("Couldn't find the node to\n"); + } + game::pathnode_t* pNodeFrom = game::Path_NearestNodeNotCrossPlanes(-2, maxNodes, vStartPos, nodes.get(), 192.0f, 0.0f, 0.0f, 0.0f, &returnCount, game::NEAREST_NODE_DO_HEIGHT_CHECK); + if (pNodeTo && pNodeFrom) + { + result = Path_FindPathFromTo_custom(vStartPos, pNodeTo, pPath, eTeam, pNodeFrom, vGoalPos, bAllowNegotiationLinks, 0); + } + else + { + result = 0; + } + return result; + } + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + //utils::hook::jump(0x4CF280, Path_FindPath_stub); + + gsc::method::add("getlinkednodes", [](game::scr_entref_s ent) + { + if (ent.classnum != game::CLASS_NUM_PATHNODE) + { + game::Scr_Error("Not a pathnode", game::SCRIPTINSTANCE_SERVER, false); + return; + } + + auto primary_node = &(*game::gameWorldCurrent)->path.nodes[ent.entnum]; + + game::Scr_MakeArray(game::SCRIPTINSTANCE_SERVER); + + for (auto i = 0; i < primary_node->constant.totalLinkCount; i++) + { + auto linked_node = &(*game::gameWorldCurrent)->path.nodes[primary_node->constant.Links[i].nodeNum]; + + game::Scr_AddPathnode(game::SCRIPTINSTANCE_SERVER, linked_node); + game::Scr_AddArray(game::SCRIPTINSTANCE_SERVER); + } + }); + + gsc::method::add("getnodenumber", [](game::scr_entref_s ent) + { + if (ent.classnum != game::CLASS_NUM_PATHNODE) + { + game::Scr_Error("Not a pathnode", game::SCRIPTINSTANCE_SERVER, false); + return; + } + + auto node = &(*game::gameWorldCurrent)->path.nodes[ent.entnum]; + + auto entnum = node - (*game::gameWorldCurrent)->path.nodes; + + game::Scr_AddInt(game::SCRIPTINSTANCE_SERVER, entnum); + }); + + gsc::function::add("getnodebynumber", []() + { + auto node_num = game::Scr_GetInt(game::SCRIPTINSTANCE_SERVER, 0); + + if (node_num == game::g_path->actualNodeCount) + { + game::Scr_AddUndefined(game::SCRIPTINSTANCE_SERVER); + return; + } + + if (node_num < 0 || node_num > game::g_path->actualNodeCount) + { + game::Scr_Error(utils::string::va("Number %d is not valid for a node", node_num), game::SCRIPTINSTANCE_SERVER, false); + return; + } + + auto node = &(*game::gameWorldCurrent)->path.nodes[node_num]; + + game::Scr_AddPathnode(game::SCRIPTINSTANCE_SERVER, node); + }); + + gsc::function::add("generatepath", []() + { + auto path = std::make_unique(); + + float start_pos[3] = {}; + + float goal_pos[3] = {}; + + auto team = "neutral"s; + + auto allow_negotiation_links = false; + + game::Scr_GetVector(game::SCRIPTINSTANCE_SERVER, 0, start_pos); + game::Scr_GetVector(game::SCRIPTINSTANCE_SERVER, 1, goal_pos); + + if (game::Scr_GetNumParam(game::SCRIPTINSTANCE_SERVER) >= 3) + { + if (game::Scr_GetType(game::SCRIPTINSTANCE_SERVER, 2) != game::VAR_UNDEFINED) + { + team = game::Scr_GetString(game::SCRIPTINSTANCE_SERVER, 2); + } + + if (game::Scr_GetNumParam(game::SCRIPTINSTANCE_SERVER) >= 4) + { + allow_negotiation_links = game::Scr_GetInt(game::SCRIPTINSTANCE_SERVER, 3); + } + } + + if (!game::team_map.contains(team)) + { + game::Scr_Error(utils::string::va("Team %s is not valid", team.data()), game::SCRIPTINSTANCE_SERVER, false); + return; + } + + auto eTeam = game::team_map.at(team); + + auto success = Path_FindPath_custom(path.get(), eTeam, start_pos, goal_pos, allow_negotiation_links); + + if (!success) + { + game::Scr_AddUndefined(game::SCRIPTINSTANCE_SERVER); + return; + } + + game::Scr_MakeArray(game::SCRIPTINSTANCE_SERVER); + + //Reverse the order of the array so index 0 is from the starting point instead of the end + for (auto i = path->wPathLen; i >= 0; i--) + { + //Return the number of the node instead of the node itself because of spooky GSC VM corruption + game::Scr_AddInt(game::SCRIPTINSTANCE_SERVER, path->pts[i].iNodeNum); + game::Scr_AddArray(game::SCRIPTINSTANCE_SERVER); + } + }); + } + + private: + }; +} + +REGISTER_COMPONENT(ai::component) \ No newline at end of file diff --git a/src/component/debug.cpp b/src/component/debug.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/component/gsc.cpp b/src/component/gsc.cpp index c62ab51..1187178 100644 --- a/src/component/gsc.cpp +++ b/src/component/gsc.cpp @@ -259,118 +259,26 @@ namespace gsc game::Scr_AddEntity(game::SCRIPTINSTANCE_SERVER, ent2); }); - - method::add("getlinkednodes", [](game::scr_entref_s ent) - { - if (ent.classnum != game::CLASS_NUM_PATHNODE) - { - game::Scr_Error("Not a pathnode", game::SCRIPTINSTANCE_SERVER, false); - return; - } - - auto primary_node = &(*game::gameWorldCurrent)->path.nodes[ent.entnum]; - - game::Scr_MakeArray(game::SCRIPTINSTANCE_SERVER); - - for (auto i = 0; i < primary_node->constant.totalLinkCount; i++) - { - auto linked_node = &(*game::gameWorldCurrent)->path.nodes[primary_node->constant.Links[i].nodeNum]; - - game::Scr_AddPathnode(game::SCRIPTINSTANCE_SERVER, linked_node); - game::Scr_AddArray(game::SCRIPTINSTANCE_SERVER); - } - }); - - method::add("getnodenumber", [](game::scr_entref_s ent) - { - if (ent.classnum != game::CLASS_NUM_PATHNODE) - { - game::Scr_Error("Not a pathnode", game::SCRIPTINSTANCE_SERVER, false); - return; - } - - auto node = &(*game::gameWorldCurrent)->path.nodes[ent.entnum]; - - auto entnum = node - (*game::gameWorldCurrent)->path.nodes; - - game::Scr_AddInt(game::SCRIPTINSTANCE_SERVER, entnum); - }); - - function::add("getnodebynumber", []() - { - auto node_num = game::Scr_GetInt(game::SCRIPTINSTANCE_SERVER, 0); - - if (node_num == game::g_path->actualNodeCount) - { - game::Scr_AddUndefined(game::SCRIPTINSTANCE_SERVER); - return; - } - - if (node_num < 0 || node_num > game::g_path->actualNodeCount) - { - game::Scr_Error(utils::string::va("Number %d is not valid for a node", node_num), game::SCRIPTINSTANCE_SERVER, false); - return; - } - - auto node = &(*game::gameWorldCurrent)->path.nodes[node_num]; - - game::Scr_AddPathnode(game::SCRIPTINSTANCE_SERVER, node); - }); - - function::add("generatepath", []() - { - auto path = std::make_unique(); - - float start_pos[3] = {}; - - float goal_pos[3] = {}; - - auto team = "neutral"s; - - auto allow_negotiation_links = false; - - game::Scr_GetVector(game::SCRIPTINSTANCE_SERVER, 0, start_pos); - game::Scr_GetVector(game::SCRIPTINSTANCE_SERVER, 1, goal_pos); - - if (game::Scr_GetNumParam(game::SCRIPTINSTANCE_SERVER) >= 3) - { - if (game::Scr_GetType(game::SCRIPTINSTANCE_SERVER, 2) != game::VAR_UNDEFINED) - { - team = game::Scr_GetString(game::SCRIPTINSTANCE_SERVER, 2); - } - - if (game::Scr_GetNumParam(game::SCRIPTINSTANCE_SERVER) >= 4) - { - allow_negotiation_links = game::Scr_GetInt(game::SCRIPTINSTANCE_SERVER, 3); - } - } - - if (!game::team_map.contains(team)) - { - game::Scr_Error(utils::string::va("Team %s is not valid", team.data()), game::SCRIPTINSTANCE_SERVER, false); - return; - } - - auto eTeam = game::team_map.at(team); - - auto success = game::Path_FindPath(path.get(), eTeam, start_pos, goal_pos, allow_negotiation_links); - - if (!success) - { - game::Scr_AddUndefined(game::SCRIPTINSTANCE_SERVER); - return; - } - - game::Scr_MakeArray(game::SCRIPTINSTANCE_SERVER); - - for (auto i = 0; i < path->wPathLen; i++) - { - //Return the number of the node instead of the node itself because of spooky GSC VM corruption - game::Scr_AddInt(game::SCRIPTINSTANCE_SERVER, path->pts[i].iNodeNum); - game::Scr_AddArray(game::SCRIPTINSTANCE_SERVER); - } - }); + function::add("writefile", []() + { + const auto path = game::Scr_GetString(game::SCRIPTINSTANCE_SERVER, 0); + const auto data = game::Scr_GetString(game::SCRIPTINSTANCE_SERVER, 1); + + auto append = false; + if (game::Scr_GetNumParam(game::SCRIPTINSTANCE_SERVER) > 2) + { + append = game::Scr_GetInt(game::SCRIPTINSTANCE_SERVER, 2); + } + + game::Scr_AddInt(game::SCRIPTINSTANCE_SERVER, utils::io::write_file(path, data, append)); + }); + + gsc::function::add("readfile", []() + { + const auto path = game::Scr_GetString(game::SCRIPTINSTANCE_SERVER, 0); + game::Scr_AddString(game::SCRIPTINSTANCE_SERVER, utils::io::read_file(path).c_str()); + }); } private: diff --git a/src/component/gsc.hpp b/src/component/gsc.hpp new file mode 100644 index 0000000..6f080ed --- /dev/null +++ b/src/component/gsc.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include + +namespace gsc +{ + namespace + { + + } + + namespace function + { + void add(const std::string& name, const game::BuiltinFunction function); + } + + namespace method + { + void add(const std::string& name, const game::BuiltinMethod method); + } +} \ No newline at end of file diff --git a/src/component/test.cpp b/src/component/test.cpp index 9868374..4ea5140 100644 --- a/src/component/test.cpp +++ b/src/component/test.cpp @@ -5,14 +5,57 @@ #include #include +#include namespace test { + utils::hook::detour gscr_spawn_hook; + namespace { game::dvar_s* custom_dvar; game::dvar_s* custom_string_dvar; + void print_script_callstack(const char* msg, game::scriptInstance_t inst) + { + int i; // [esp+4h] [ebp-4h] + printf("******* Callstack for %s *******\n", msg); + game::Scr_PrintPrevCodePos(game::function_stack[inst].pos, inst, game::CON_CHANNEL_DONT_FILTER, 0); + auto function_count = game::gScrVmPub[inst].function_count; + if (function_count) + { + for (i = function_count - 1; i >= 1; --i) + { + printf("Info: called from:\n"); + game::Scr_PrintPrevCodePos( + game::gScrVmPub[inst].function_frame_start[i].fs.pos, + inst, + game::CON_CHANNEL_DONT_FILTER, + game::gScrVmPub[inst].function_frame_start[i].fs.localId == 0); + } + printf("started from:\n"); + game::Scr_PrintPrevCodePos(game::gScrVmPub[inst].function_frame_start[0].fs.pos, inst, game::CON_CHANNEL_DONT_FILTER, 1u); + } + printf("************************************\n"); + } + + void gscr_spawn_stub() + { + auto classname = game::Scr_GetConstString(game::SCRIPTINSTANCE_SERVER, 0); + + float origin[3] = {}; + + game::Scr_GetVector(game::SCRIPTINSTANCE_SERVER, 1, origin); + + if (classname == game::scr_const->script_origin) + { + print_script_callstack(utils::string::va("GScr_Spawn() classname: script_origin at: (%f, %f, %f)", origin[0], origin[1], origin[2]), game::SCRIPTINSTANCE_SERVER); + } + + gscr_spawn_hook.invoke(); + } + } + bool our_funny_call(game::pathnode_t* begin_node, game::pathnode_t* end_node, bool allowNeg) { if (!allowNeg && begin_node->constant.type == game::NODE_NEGOTIATION_BEGIN && end_node->constant.type == game::NODE_NEGOTIATION_END) @@ -81,6 +124,17 @@ namespace test //printf("Biggie Spam McCheese\n"); }); + gscr_spawn_hook.create(0x517630, gscr_spawn_stub); + + //Disable AI print spam + utils::hook::nop(0x4BAB7D, 5); + utils::hook::nop(0x4BAAFA, 5); + + //Disable asset loading print spam + utils::hook::nop(0x48D9D9, 5); + + //Disable unknown dvar spam + utils::hook::nop(0x5F04AF, 5); // fix NEGOTIATION links utils::hook::jump(0x4D3296, our_funny_hook); diff --git a/src/game/game.cpp b/src/game/game.cpp index 4692b1b..906c2f0 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -32,6 +32,20 @@ namespace game { "dead", TEAM_DEAD } }; + void Scr_PrintPrevCodePos(const char* codepos, int scriptInstance, con_channel_e channel, int index) + { + static const auto call_addr = SELECT(0x0, 0x68B340); + + __asm + { + push index; + push channel; + push scriptInstance; + mov eax, codepos; + call call_addr; + } + } + int Scr_GetInt(game::scriptInstance_t inst, unsigned int arg_index) { static const auto call_addr = SELECT(0x0, 0x699C50); @@ -321,7 +335,7 @@ namespace game unsigned int Scr_GetNumParam(scriptInstance_t inst) { - return scrVmPub[inst].outparamcount; + return gScrVmPub[inst].outparamcount; } VariableType Scr_GetType(scriptInstance_t inst, unsigned int index) @@ -441,6 +455,80 @@ namespace game return answer; } + pathnode_t* Path_NearestNodeNotCrossPlanes(int typeFlags, int maxNodes, float* vOrigin, pathsort_t* nodes, float fMaxDist, float a6, float a7, int iPlaneCount, int* returnCount, nearestNodeHeightCheck heightCheck) + { + static const auto call_addr = SELECT(0x0, 0x55C210); + + pathnode_t* answer; + + __asm + { + push heightCheck; + push returnCount; + push iPlaneCount; + push a7; + push a6; + push fMaxDist; + push nodes; + push vOrigin; + mov ecx, maxNodes; + mov edx, typeFlags; + call call_addr; + add esp, 0x20; + mov answer, eax; + } + + return answer; + } + + //This is a __userpurge, which automatically cleans up the stack by itself so do not do add esp + int Path_FindPathFromTo(float* startPos, pathnode_t* pNodeTo, path_t* pPath, team_t eTeam, pathnode_t* pNodeFrom, float* vGoalPos, int bAllowNegotiationLinks, int bIgnoreBadplaces) + { + static const auto call_addr = SELECT(0x0, 0x4CF3F0); + + int answer; + + __asm + { + push bIgnoreBadplaces; + push bAllowNegotiationLinks; + push vGoalPos; + push pNodeFrom; + push eTeam; + push pPath; + mov edx, pNodeTo; + mov eax, startPos; + call call_addr; + mov answer, eax; + } + + return answer; + } + + //This is a __userpurge, which automatically cleans up the stack by itself so do not do add esp + int Path_GeneratePath(path_t* pPath, team_t eTeam, const float* vStartPos, float* vGoalPos, pathnode_t* pNodeFrom, pathnode_t* pNodeTo, int bIncludeGoalPos, int bAllowNegotiationLinks) + { + static const auto call_addr = SELECT(0x0, 0x4CED90); + + int answer; + + __asm + { + push bAllowNegotiationLinks; + push bIncludeGoalPos; + push pNodeTo; + push pNodeFrom; + push vGoalPos; + push vStartPos; + push eTeam; + mov eax, pPath; + call call_addr; + mov answer, eax; + } + + return answer; + } + namespace plutonium { } diff --git a/src/game/game.hpp b/src/game/game.hpp index f8a0599..556c581 100644 --- a/src/game/game.hpp +++ b/src/game/game.hpp @@ -23,6 +23,8 @@ namespace game extern std::map team_map; + void Scr_PrintPrevCodePos(const char* codepos, int scriptInstance, con_channel_e channel, int index); + const char* Cmd_Argv(int index); unsigned int Cmd_Argc(); void Cmd_AddCommand(const char* name, void(__cdecl* function)()); @@ -57,6 +59,9 @@ namespace game const char* SL_ConvertToString(scriptInstance_t inst, int id); int Path_FindPath(path_t* pPath, team_t eTeam, float* vStartPos, float* vGoalPos, int bAllowNegotiationLinks); + pathnode_t* Path_NearestNodeNotCrossPlanes(int typeFlags, int maxNodes, float* vOrigin, pathsort_t* nodes, float fMaxDist, float a6, float a7, int iPlaneCount, int* returnCount, nearestNodeHeightCheck heightCheck); + int Path_FindPathFromTo(float* startPos, pathnode_t* pNodeTo, path_t* pPath, team_t eTeam, pathnode_t* pNodeFrom, float* vGoalPos, int bAllowNegotiationLinks, int bIgnoreBadplaces); + int Path_GeneratePath(path_t* pPath, team_t eTeam, const float* vStartPos, float* vGoalPos, pathnode_t* pNodeFrom, pathnode_t* pNodeTo, int bIncludeGoalPos, int bAllowNegotiationLinks); template class symbol diff --git a/src/game/structs.hpp b/src/game/structs.hpp index aecb7cb..bab1481 100644 --- a/src/game/structs.hpp +++ b/src/game/structs.hpp @@ -1419,6 +1419,134 @@ namespace game float fOrientLerp; }; + struct animCmdState_s + { + int field_0; + int field_4; + int field_8; + int field_C; + int field_10; + int field_14; + int field_18; + int field_1C; + int field_20; + int field_24; + int field_28; + }; + + struct SpawnVar + { + bool spawnVarsValid; + int numSpawnVars; + char* spawnVars[64][2]; + int numSpawnVarChars; + char spawnVarChars[2048]; + }; + + enum loading_t : __int32 + { + LOADING_DONE = 0x0, + LOADING_LEVEL = 0x1, + LOADING_SAVEGAME = 0x2, + }; + + struct cached_tag_mat_t + { + int time; + int entnum; + unsigned __int16 name; + float tagMat[4][3]; + }; + + struct trigger_info_t + { + unsigned __int16 entnum; + unsigned __int16 otherEntnum; + int useCount; + int otherUseCount; + }; + + struct __declspec(align(4)) level_locals_s + { + gclient_s* clients; + gentity_s* gentities; + int unk1; + int num_entities; + gentity_s* firstFreeEnt; + gentity_s* lastFreeEnt; + sentient_s* sentients; + actor_s* actors; + scr_vehicle_s* vehicles; + TurretInfo* turrets; + animCmdState_s* animCmds; + char gap_2C[4096]; + int logFile; + int initializing; + int clientIsSpawning; + int maxclients; + int framenum; + int time; + int previousTime; + int startTime; + int newSession; + int actorCorpseCount; + SpawnVar spawnVar; + int reloadDelayTime; + int absoluteReloadDelayTime; + EntHandle droppedWeaponCue[32]; + int changelevel; + int bMissionSuccess; + int bMissionFailed; + int exitTime; + int savepersist; + char cinematic[64]; + float fFogOpaqueDist; + float fFogOpaqueDistSqrd; + unsigned int grenadeHintCount; + int remapCount; + int iSearchFrame; + loading_t loading; + int actorPredictDepth; + int bDrawCompassFriendlies; + int bPlayerIgnoreRadiusDamage; + int bPlayerIgnoreRadiusDamageLatched; + int triggerIndex; + int padd; + int currentEntityThink; + int currentIndex; + bool checkAnimChange; + int registerWeapons; + int bRegisterItems; + int framePos; + cached_tag_mat_t cachedTagMat; + cached_tag_mat_t cachedEntTargetTagMat; + __int16 soundAliasFirst; + __int16 soundAliasLast; + trigger_info_t pendingTriggerList[256]; + trigger_info_t currentTriggerList[256]; + int pendingTriggerListSize; + int currentTriggerListSize; + int entTriggerIndex[1024]; + unsigned __int8 specialIndex[1024]; + char gap4808[2628]; + int scriptPrintChannel; + float compassMapUpperLeft[2]; + float compassMapWorldSize[2]; + float compassNorth[2]; + float mapSunColor[3]; + float mapSunDirection[3]; + int script_ai_limit; + int disable_grenade_suicide; + int huh; + int manualNameChange; + objective_t objectives[16]; + int frameTime; + int finished; + int pad; + }; + + static_assert(sizeof(level_locals_s) == 0x549C); + enum nodeType { NODE_BADNODE = 0x0, @@ -1572,12 +1700,12 @@ namespace game float origin[3]; float maxDist; float maxDistSq; - float maxHeight; float maxHeightSq; int typeFlags; pathsort_t* nodes; int maxNodes; int nodeCount; + float maxHeight; }; struct __declspec(align(128)) pathlocal_t @@ -1585,9 +1713,22 @@ namespace game PathLinkInfo pathLinkInfoArray[2048]; int pathLinkInfoArrayInited; unsigned int actualNodeCount; + pathlocal_t_circle circle; unsigned int extraNodes; unsigned int originErrors; - pathlocal_t_circle circle; + }; + + struct CustomSearchInfo_FindPath + { + pathnode_t* m_pNodeTo; + float startPos[3]; + float negotiationOverlapCost; + }; + + enum nearestNodeHeightCheck + { + NEAREST_NODE_DO_HEIGHT_CHECK = 0x0, + NEAREST_NODE_DONT_DO_HEIGHT_CHECK = 0x1, }; enum VariableType @@ -1674,4 +1815,358 @@ namespace game function_frame_t function_frame_start[32]; VariableValue stack[2048]; }; + + struct __declspec(align(2)) scr_const_t + { + unsigned __int16 _; + __int16 active2; + __int16 j_spine4; + __int16 j_helmet; + __int16 j_head; + __int16 all; + __int16 allies; + __int16 axis; + __int16 bad_path; + __int16 begin_firing; + __int16 unknown_location; + __int16 cancel_location; + __int16 confirm_location; + __int16 regroup_location; + __int16 defend_location; + __int16 clear_squadcommand; + __int16 squadleader_changed; + __int16 squad_disbanded; + __int16 deployed_turret; + __int16 crouch; + __int16 current; + __int16 damage; + __int16 dead; + __int16 death; + __int16 disconnect; + __int16 death_or_disconnect; + __int16 detonate; + __int16 direct; + __int16 dlight; + __int16 done; + __int16 empty; + __int16 end_firing; + __int16 enter_vehicle; + __int16 entity; + __int16 exit_vehicle; + __int16 change_seat; + __int16 vehicle_death; + __int16 explode; + __int16 failed; + __int16 free; + __int16 fraction; + __int16 goal; + __int16 goal_changed; + __int16 goal_yaw; + __int16 grenade; + __int16 grenade_danger; + __int16 grenade_fire; + __int16 grenade_launcher_fire; + __int16 grenade_pullback; + __int16 info_notnull; + __int16 invisible; + __int16 key1; + __int16 key2; + __int16 killanimscript; + __int16 left; + __int16 left_tread; + __int16 light; + __int16 movedone; + __int16 noclass; + __int16 none; + __int16 normal; + __int16 player; + __int16 position; + __int16 projectile_impact; + __int16 prone; + __int16 right; + __int16 right_tread; + __int16 tank_armor; + __int16 reload; + __int16 reload_start; + __int16 rocket; + __int16 rotatedone; + __int16 script_brushmodel; + __int16 script_model; + __int16 script_origin; + __int16 snd_enveffectsprio_level; + __int16 snd_enveffectsprio_shellshock; + __int16 snd_busvolprio_holdbreath; + __int16 snd_busvolprio_pain; + __int16 snd_busvolprio_shellshock; + __int16 stand; + __int16 suppression; + __int16 suppression_end; + __int16 surfacetype; + __int16 tag_aim; + __int16 tag_aim_animated; + __int16 tag_brass; + __int16 tag_butt; + __int16 tag_clip; + __int16 tag_flash; + __int16 tag_flash_11; + __int16 tag_flash_2; + __int16 tag_flash_22; + __int16 tag_flash_3; + __int16 tag_fx; + __int16 tag_inhand2; + __int16 tag_knife_attach; + __int16 tag_knife_fx; + __int16 tag_bayonet; + __int16 tag_laser; + __int16 tag_origin; + __int16 tag_weapon; + __int16 tag_player2; + __int16 tag_camera; + __int16 tag_weapon_right; + __int16 tag_gasmask; + __int16 tag_gasmask2; + __int16 tag_sync; + __int16 tag_wake; + __int16 target_script_trigger; + __int16 tempEntity; + __int16 top; + __int16 touch; + __int16 trigger; + __int16 trigger_use; + __int16 trigger_use_touch; + __int16 trigger_damage; + __int16 trigger_lookat; + __int16 trigger_radius; + __int16 truck_cam; + __int16 weapon_change_on_turret; + __int16 weapon_change; + __int16 weapon_change_complete; + __int16 weapon_fired; + __int16 weapon_pvp_attack; + __int16 worldspawn; + __int16 flashbang; + __int16 flash; + __int16 smoke; + __int16 night_vision_on; + __int16 night_vision_off; + __int16 back_low; + __int16 back_mid; + __int16 back_up; + __int16 head; + __int16 j_mainroot; + __int16 neck; + __int16 pelvis; + __int16 j_head2; + __int16 MOD_UNKNOWN; + __int16 MOD_PISTOL_BULLET; + __int16 MOD_RIFLE_BULLET; + __int16 MOD_GRENADE; + __int16 MOD_GRENADE_SPLASH; + __int16 MOD_PROJECTILE; + __int16 MOD_PROJECTILE_SPLASH; + __int16 MOD_MELEE; + __int16 MOD_BAYONET; + __int16 MOD_HEAD_SHOT; + __int16 MOD_CRUSH; + __int16 MOD_TELEFRAG; + __int16 MOD_FALLING; + __int16 MOD_SUICIDE; + __int16 MOD_TRIGGER_HURT; + __int16 MOD_EXPLOSIVE; + __int16 MOD_IMPACT; + __int16 MOD_BURNED; + __int16 MOD_HIT_BY_OBJECT; + __int16 MOD_DROWN; + __int16 script_vehicle; + __int16 script_vehicle_collision; + __int16 script_vehicle_collmap; + __int16 script_vehicle_corpse; + __int16 turret_fire; + __int16 turret_on_target; + __int16 turret_not_on_target; + __int16 turret_on_vistarget; + __int16 turret_no_vis; + __int16 turret_rotate_stopped; + __int16 turret_deactivate; + __int16 turretstatechange; + __int16 turretownerchange; + __int16 reached_end_node; + __int16 reached_wait_node; + __int16 reached_wait_speed; + __int16 near_goal; + __int16 veh_collision; + __int16 veh_predictedcollision; + __int16 script_camera; + __int16 begin; + __int16 curve_nodehit; + __int16 curve_start; + __int16 curve_end; + __int16 tag_enter_driver; + __int16 tag_enter_gunner1; + __int16 tag_enter_gunner2; + __int16 tag_enter_gunner3; + __int16 tag_enter_gunner4; + __int16 tag_enter_passenger; + __int16 tag_enter_passenger2; + __int16 tag_enter_passenger3; + __int16 tag_enter_passenger4; + __int16 tag_player; + __int16 tag_passenger1; + __int16 tag_passenger2; + __int16 tag_passenger3; + __int16 tag_passenger4; + __int16 tag_gunner1; + __int16 tag_gunner2; + __int16 tag_gunner3; + __int16 tag_gunner4; + __int16 tag_gunner_barrel1; + __int16 tag_gunner_barrel2; + __int16 tag_gunner_barrel3; + __int16 tag_gunner_barrel4; + __int16 tag_gunner_turret1; + __int16 tag_gunner_turret2; + __int16 tag_gunner_turret3; + __int16 tag_gunner_turret4; + __int16 tag_flash_gunner1; + __int16 tag_flash_gunner2; + __int16 tag_flash_gunner3; + __int16 tag_flash_gunner4; + __int16 tag_flash_gunner1a; + __int16 tag_flash_gunner2a; + __int16 tag_flash_gunner3a; + __int16 tag_flash_gunner4a; + __int16 tag_gunner_brass1; + __int16 tag_gunner_hands1; + __int16 tag_wheel_front_left; + __int16 tag_wheel_front_right; + __int16 tag_wheel_back_left; + __int16 tag_wheel_back_right; + __int16 tag_wheel_middle_left; + __int16 tag_wheel_middle_right; + __int16 vampire_health_regen; + __int16 vampire_kill; + __int16 morphine_shot; + __int16 morphine_revive; + __int16 freelook; + __int16 intermission; + __int16 playing; + __int16 spectator; + __int16 action_notify_attack; + __int16 action_notify_melee; + __int16 action_notify_use_reload; + __int16 always; + __int16 auto_ai; + __int16 auto_nonai; + __int16 back_left; + __int16 back_right; + __int16 begin_custom_anim; + __int16 bullethit; + __int16 count; + __int16 corner_approach; + __int16 damage_notdone; + __int16 deathplant; + __int16 front_left; + __int16 front_right; + __int16 tag_inhand; + __int16 high_priority; + __int16 info_player_deathmatch; + __int16 infinite_energy; + __int16 low_priority; + __int16 manual; + __int16 manual_ai; + __int16 max_time; + __int16 menuresponse; + __int16 middle_left; + __int16 middle_right; + __int16 min_energy; + __int16 min_time; + __int16 neutral; + __int16 never; + __int16 pickup; + __int16 receiver; + __int16 sound_blend; + __int16 tag_wingtipl; + __int16 tag_wingtipr; + __int16 tag_wingmidl; + __int16 tag_wingmidr; + __int16 tag_prop; + __int16 tag_end; + __int16 tag_tailtop; + __int16 tag_tailbottom; + __int16 tag_detach; + __int16 tag_passenger; + __int16 tag_enter_back; + __int16 tag_detach2; + __int16 tag_popout; + __int16 tag_body; + __int16 tag_turret; + __int16 tag_turret_base; + __int16 tag_barrel; + __int16 tag_weapon_left; + __int16 human; + __int16 custom; + __int16 angle_deltas; + __int16 bulletwhizby; + __int16 dog; + __int16 enemy; + __int16 enemy_visible; + __int16 face_angle; + __int16 face_current; + __int16 face_default; + __int16 face_direction; + __int16 face_enemy; + __int16 face_enemy_or_motion; + __int16 face_goal; + __int16 face_motion; + __int16 face_point; + __int16 gravity; + __int16 groundEntChanged; + __int16 gunshot; + __int16 obstacle; + __int16 movemode; + __int16 node_out_of_range; + __int16 node_relinquished; + __int16 node_taken; + __int16 node_not_safe; + __int16 noclip; + __int16 nogravity; + __int16 nophysics; + __int16 pain; + __int16 run; + __int16 runto_arrived; + __int16 silenced_shot; + __int16 spawned; + __int16 start_move; + __int16 stop; + __int16 stop_soon; + __int16 tag_eye; + __int16 walk; + __int16 world; + __int16 zonly_physics; + __int16 j_ankle_le; + __int16 j_ankle_ri; + __int16 j_ball_le; + __int16 j_ball_ri; + __int16 j_palm_le; + __int16 j_palm_ri; + __int16 broken; + __int16 destructible; + __int16 snapacknowledged; + __int16 disconnected; + __int16 cinematic; + __int16 uicinematic; + __int16 logo; + __int16 connecting; + __int16 challenging; + __int16 connected; + __int16 sendingstats; + __int16 loading; + __int16 primed; + __int16 active; + __int16 map_restart; + __int16 orientdone; + __int16 field_2B6; + }; + + } \ No newline at end of file diff --git a/src/game/symbols.hpp b/src/game/symbols.hpp index 0333f7d..5fc494e 100644 --- a/src/game/symbols.hpp +++ b/src/game/symbols.hpp @@ -12,18 +12,37 @@ namespace game WEAK symbol Scr_AddArray { 0x0, 0x69AA50 }; WEAK symbol SL_GetStringOfSize { 0x0, 0x68DE50 }; + WEAK symbol Path_AStarAlgorithm_CustomSearchInfo_FindPath_{ 0x0, 0x4D3190 }; + // Variables WEAK symbol cmd_functions{ 0x0, 0x1F416F4 }; WEAK symbol cmd_args{ 0x0, 0x1F41670 }; - WEAK symbol gameWorldCurrent{ 0x0, 0x8E1D80 }; - WEAK symbol g_path{ 0x0, 0x1F2F700 }; - WEAK symbol g_entities{ 0x0, 0x176C6F0 }; + //WEAK symbol scrVarPub{ 0x0, 0x3882B70 }; + WEAK symbol gScrVmPub{ 0x0, 0x3BD4700 }; + WEAK symbol level{ 0x0, 0x18F5D88 }; + WEAK symbol g_pathAttemptGoalPos{ 0x0, 0x16CFD6C }; + //WEAK symbol scrParserPub{ 0x0, 0x3882B00 }; + //WEAK symbol gScrVarGlob{ 0x0, 0x3914700 }; - WEAK symbol scrVmPub{ 0x0, 0x3BD4700 }; + WEAK symbol function_stack{ 0x0, 0x3BDDDD0 }; + WEAK symbol scr_const{0x0, 0x1F33B90}; + + // Dvars + + WEAK symbol com_developer{ 0x0, 0x1F55288 }; + WEAK symbol com_logfile{ 0x0, 0x1F552BC }; + WEAK symbol com_developer_script{ 0x0, 0x1F9646C }; + WEAK symbol ai_pathNegotiationOverlapCost{ 0x0, 0x18FB224 }; + WEAK symbol fs_homepath{ 0x0, 0x2123C1C }; + WEAK symbol fs_game{ 0x0, 0x2122B00 }; + WEAK symbol useFastFile{ 0x0, 0x1F552FC }; + WEAK symbol sv_running{ 0x0, 0x1F552DC }; + WEAK symbol g_connectpaths{ 0x0, 0x18ECF8C }; + WEAK symbol r_reflectionProbeGenerate{ 0x0, 0x3BFD478 }; namespace plutonium {