mirror of
https://github.com/JezuzLizard/T4SP-Server-Plugin.git
synced 2025-06-26 06:11:52 +00:00
major cleanup
This commit is contained in:
@ -1,575 +0,0 @@
|
||||
#include <stdinc.hpp>
|
||||
#include "loader/component_loader.hpp"
|
||||
|
||||
#include "scheduler.hpp"
|
||||
#include "component/gsc.hpp"
|
||||
|
||||
#include <json.hpp>
|
||||
#include <utils/io.hpp>
|
||||
#include <utils/hook.hpp>
|
||||
#include <utils/string.hpp>
|
||||
|
||||
namespace ai
|
||||
{
|
||||
namespace
|
||||
{
|
||||
int Path_GeneratePath_custom(game::path_t* pPath, game::team_t eTeam, const float* vStartPos, const float* vGoalPos, game::pathnode_t* pNodeFrom, game::pathnode_t* pNodeTo, int bIncludeGoalPos, int bAllowNegotiationLinks)
|
||||
{
|
||||
const char* v9; // eax
|
||||
float v10; // [esp+10h] [ebp-68h]
|
||||
int v12; // [esp+18h] [ebp-60h]
|
||||
game::pathpoint_t* v16; // [esp+30h] [ebp-48h]
|
||||
game::pathpoint_t* v17; // [esp+38h] [ebp-40h]
|
||||
int excess; // [esp+54h] [ebp-24h]
|
||||
game::pathnode_t* pPrevNode; // [esp+58h] [ebp-20h]
|
||||
int iTotal; // [esp+5Ch] [ebp-1Ch]
|
||||
game::pathnode_t* pNode; // [esp+64h] [ebp-14h]
|
||||
game::pathnode_t* pNodea; // [esp+64h] [ebp-14h]
|
||||
int negotiationStartNode; // [esp+68h] [ebp-10h]
|
||||
int i; // [esp+6Ch] [ebp-Ch]
|
||||
int ia; // [esp+6Ch] [ebp-Ch]
|
||||
game::pathnode_t* pPrevPrevNode; // [esp+70h] [ebp-8h]
|
||||
int prevFlags; // [esp+74h] [ebp-4h]
|
||||
|
||||
game::Path_AddTrimmedAmount(vStartPos, pPath);
|
||||
iTotal = 0;
|
||||
pNode = pNodeTo;
|
||||
if (bIncludeGoalPos)
|
||||
{
|
||||
pPath->pts[0].vOrigPoint[0] = *vGoalPos;
|
||||
pPath->pts[0].vOrigPoint[1] = vGoalPos[1];
|
||||
pPath->pts[0].vOrigPoint[2] = vGoalPos[2];
|
||||
if (*vGoalPos == pNodeTo->constant.vOrigin[0] && vGoalPos[1] == pNodeTo->constant.vOrigin[1])
|
||||
{
|
||||
pPath->pts[0].iNodeNum = game::Path_ConvertNodeToIndex(pNodeTo);
|
||||
}
|
||||
else
|
||||
{
|
||||
pPath->pts[0].iNodeNum = -1;
|
||||
iTotal = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pPath->pts[0].vOrigPoint[0] = pNodeTo->constant.vOrigin[0];
|
||||
pPath->pts[0].vOrigPoint[1] = pNodeTo->constant.vOrigin[1];
|
||||
pPath->pts[0].vOrigPoint[2] = pNodeTo->constant.vOrigin[2];
|
||||
pPath->pts[0].iNodeNum = game::Path_ConvertNodeToIndex(pNodeTo);
|
||||
}
|
||||
prevFlags = pPath->flags;
|
||||
pPath->flags = 0;
|
||||
if (!pPath->wPathLen
|
||||
|| (pPath->pts[0].vOrigPoint[0] != pPath->vFinalGoal[0]
|
||||
|| pPath->pts[0].vOrigPoint[1] != pPath->vFinalGoal[1]
|
||||
|| pPath->pts[0].vOrigPoint[2] != pPath->vFinalGoal[2] ? (v12 = 0) : (v12 = 1),
|
||||
!v12))
|
||||
{
|
||||
if (pPath->pts[0].vOrigPoint[0] != pPath->vFinalGoal[0] || pPath->pts[0].vOrigPoint[1] != pPath->vFinalGoal[1])
|
||||
{
|
||||
pPath->iPathEndTime = 0;
|
||||
}
|
||||
pPath->vFinalGoal[0] = pPath->pts[0].vOrigPoint[0];
|
||||
pPath->vFinalGoal[1] = pPath->pts[0].vOrigPoint[1];
|
||||
pPath->vFinalGoal[2] = pPath->pts[0].vOrigPoint[2];
|
||||
}
|
||||
game::Path_Clear(pPath);
|
||||
pPath->wDodgeCount = 0;
|
||||
negotiationStartNode = 0;
|
||||
if (pNodeTo)
|
||||
{
|
||||
for (pPrevNode = pNodeTo->transient.pParent; ; pPrevNode = pPrevPrevNode)
|
||||
{
|
||||
++iTotal;
|
||||
if (pNode == pNodeFrom)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (pPrevNode->constant.type == game::NODE_NEGOTIATION_BEGIN
|
||||
&& pNode->constant.type == game::NODE_NEGOTIATION_END
|
||||
&& pPrevNode->constant.target == pNode->constant.targetname)
|
||||
{
|
||||
/*
|
||||
if (!bAllowNegotiationLinks)
|
||||
return 0;
|
||||
*/
|
||||
negotiationStartNode = iTotal;
|
||||
}
|
||||
pPrevPrevNode = pPrevNode->transient.pParent;
|
||||
pPrevNode->transient.pParent = pNode;
|
||||
pNode = pPrevNode;
|
||||
}
|
||||
}
|
||||
excess = iTotal - 32;
|
||||
if (iTotal - 32 > 0)
|
||||
{
|
||||
iTotal = 32;
|
||||
pPath->flags |= 4u;
|
||||
negotiationStartNode -= excess;
|
||||
if (negotiationStartNode < 0)
|
||||
{
|
||||
*reinterpret_cast<unsigned short*>(&negotiationStartNode) = 0;
|
||||
}
|
||||
}
|
||||
i = iTotal - 1;
|
||||
pNodea = pNodeFrom;
|
||||
while (i > 0)
|
||||
{
|
||||
v17 = &pPath->pts[i];
|
||||
v17->vOrigPoint[0] = pNodea->constant.vOrigin[0];
|
||||
v17->vOrigPoint[1] = pNodea->constant.vOrigin[1];
|
||||
v17->vOrigPoint[2] = pNodea->constant.vOrigin[2];
|
||||
v17->iNodeNum = game::Path_ConvertNodeToIndex(pNodea);
|
||||
--i;
|
||||
pNodea = pNodea->transient.pParent;
|
||||
}
|
||||
if (excess > 0)
|
||||
{
|
||||
pPath->pts[0].vOrigPoint[0] = pNodea->constant.vOrigin[0];
|
||||
pPath->pts[0].vOrigPoint[1] = pNodea->constant.vOrigin[1];
|
||||
pPath->pts[0].vOrigPoint[2] = pNodea->constant.vOrigin[2];
|
||||
pPath->pts[0].iNodeNum = game::Path_ConvertNodeToIndex(pNodea);
|
||||
}
|
||||
pPath->wNegotiationStartNode = negotiationStartNode;
|
||||
if (pPath->wNegotiationStartNode > 0)
|
||||
{
|
||||
game::Path_IncrementNodeUserCount(pPath);
|
||||
}
|
||||
pPath->pts[iTotal - 1].fOrigLength = 0.0;
|
||||
pPath->pts[iTotal - 1].fDir2D[0] = 0.0;
|
||||
pPath->pts[iTotal - 1].fDir2D[1] = 0.0;
|
||||
v16 = &pPath->pts[iTotal - 1];
|
||||
pPath->vCurrPoint[0] = v16->vOrigPoint[0];
|
||||
pPath->vCurrPoint[1] = v16->vOrigPoint[1];
|
||||
pPath->vCurrPoint[2] = v16->vOrigPoint[2];
|
||||
for (ia = 0; ia < iTotal - 1; ++ia)
|
||||
{
|
||||
pPath->pts[ia].fOrigLength = game::Path_GetPathDir(
|
||||
pPath->pts[ia].fDir2D,
|
||||
pPath->pts[ia + 1].vOrigPoint,
|
||||
pPath->pts[ia].vOrigPoint);
|
||||
}
|
||||
if (iTotal <= 1)
|
||||
{
|
||||
v10 = 0.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
v10 = pPath->pts[iTotal - 2].fOrigLength;
|
||||
}
|
||||
pPath->fCurrLength = v10;
|
||||
pPath->wPathLen = iTotal;
|
||||
pPath->wOrigPathLen = pPath->wPathLen;
|
||||
if (bAllowNegotiationLinks)
|
||||
{
|
||||
pPath->flags |= 0x10u;
|
||||
}
|
||||
pPath->eTeam = eTeam;
|
||||
pPath->iPathTime = game::level->time;
|
||||
if (pPath->fLookaheadAmount == 0.0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
if ((prevFlags & 0x180) != 0)
|
||||
{
|
||||
if ((prevFlags & 0x80) != 0)
|
||||
{
|
||||
pPath->fLookaheadAmount = 32768.0;
|
||||
pPath->minLookAheadNodes = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
pPath->fLookaheadAmount = 4096.0;
|
||||
pPath->minLookAheadNodes = 2;
|
||||
}
|
||||
pPath->lookaheadDir[0] = 0.0;
|
||||
pPath->lookaheadDir[1] = 0.0;
|
||||
pPath->lookaheadDir[2] = 0.0;
|
||||
game::Path_UpdateLookahead(pPath, vStartPos, 0, 0, 1);
|
||||
pPath->minLookAheadNodes = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
game::Path_TransferLookahead(pPath, vStartPos);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int __cdecl Path_AStarAlgorithm_CustomSearchInfo_FindPath_custom(game::path_t* pPath, game::team_t eTeam, float* vStartPos, game::pathnode_t* pNodeFrom, float* vGoalPos, int bIncludeGoalInPath, const std::unordered_set<unsigned short>& allowedNegotiationLinks, game::CustomSearchInfo_FindPath* custom, int bIgnoreBadPlaces)
|
||||
{
|
||||
int success; // [esp+28h] [ebp-A0h]
|
||||
game::pathnode_t* pCurrent; // [esp+2Ch] [ebp-9Ch]
|
||||
game::pathnode_t TopParent; // [esp+30h] [ebp-98h] BYREF
|
||||
float fApproxTotalCost; // [esp+B4h] [ebp-14h]
|
||||
game::pathnode_t* pInsert; // [esp+B8h] [ebp-10h]
|
||||
int i; // [esp+BCh] [ebp-Ch]
|
||||
float fCost; // [esp+C0h] [ebp-8h]
|
||||
game::pathnode_t* pSuccessor; // [esp+C4h] [ebp-4h]
|
||||
|
||||
pNodeFrom->transient.iSearchFrame = ++game::level->iSearchFrame;
|
||||
pNodeFrom->transient.pParent = &TopParent;
|
||||
pNodeFrom->transient.pNextOpen = 0;
|
||||
pNodeFrom->transient.pPrevOpen = &TopParent;
|
||||
pNodeFrom->transient.fCost = 0.0;
|
||||
TopParent.transient.pNextOpen = pNodeFrom;
|
||||
while (true)
|
||||
{
|
||||
if (!TopParent.transient.pNextOpen)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
pCurrent = TopParent.transient.pNextOpen;
|
||||
|
||||
if (TopParent.transient.pNextOpen == custom->m_pNodeTo)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
TopParent.transient.pNextOpen = TopParent.transient.pNextOpen->transient.pNextOpen;
|
||||
if (TopParent.transient.pNextOpen)
|
||||
{
|
||||
TopParent.transient.pNextOpen->transient.pPrevOpen = &TopParent;
|
||||
}
|
||||
|
||||
for (i = 0; i < pCurrent->dynamic.wLinkCount; ++i)
|
||||
{
|
||||
if (bIgnoreBadPlaces || !pCurrent->constant.Links[i].ubBadPlaceCount[eTeam])
|
||||
{
|
||||
pSuccessor = game::Path_ConvertIndexToNode(pCurrent->constant.Links[i].nodeNum);
|
||||
if (pCurrent->constant.type == game::NODE_NEGOTIATION_BEGIN && pSuccessor->constant.type == game::NODE_NEGOTIATION_END)
|
||||
{
|
||||
if (std::find(allowedNegotiationLinks.begin(), allowedNegotiationLinks.end(), pCurrent->constant.animscript) == allowedNegotiationLinks.end())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (pCurrent->constant.type != game::NODE_NEGOTIATION_BEGIN
|
||||
|| pSuccessor->constant.type != game::NODE_NEGOTIATION_END
|
||||
|| (pCurrent->dynamic.wOverlapCount == 0 && pSuccessor->dynamic.wOverlapCount == 0))
|
||||
{
|
||||
if (pSuccessor->transient.iSearchFrame == game::level->iSearchFrame)
|
||||
{
|
||||
fCost = (pCurrent->constant.Links[i].fDist * 1.0) + pCurrent->transient.fCost;
|
||||
if (fCost >= pSuccessor->transient.fCost)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (pSuccessor->transient.pPrevOpen)
|
||||
{
|
||||
pSuccessor->transient.pPrevOpen->transient.pNextOpen = pSuccessor->transient.pNextOpen;
|
||||
if (pSuccessor->transient.pNextOpen)
|
||||
{
|
||||
pSuccessor->transient.pNextOpen->transient.pPrevOpen = pSuccessor->transient.pPrevOpen;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pSuccessor->transient.iSearchFrame = game::level->iSearchFrame;
|
||||
pSuccessor->transient.fHeuristic = game::EvaluateHeuristic(custom, pSuccessor, vGoalPos);
|
||||
fCost = (pCurrent->constant.Links[i].fDist * 1.0) + pCurrent->transient.fCost;
|
||||
}
|
||||
|
||||
pSuccessor->transient.pParent = pCurrent;
|
||||
pSuccessor->transient.fCost = fCost;
|
||||
fApproxTotalCost = pSuccessor->transient.fCost + pSuccessor->transient.fHeuristic;
|
||||
|
||||
for (pInsert = &TopParent;
|
||||
pInsert->transient.pNextOpen
|
||||
&& (pInsert->transient.pNextOpen->transient.fCost
|
||||
+ pInsert->transient.pNextOpen->transient.fHeuristic) < fApproxTotalCost;
|
||||
pInsert = pInsert->transient.pNextOpen)
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
pSuccessor->transient.pPrevOpen = pInsert;
|
||||
pSuccessor->transient.pNextOpen = pInsert->transient.pNextOpen;
|
||||
pInsert->transient.pNextOpen = pSuccessor;
|
||||
|
||||
if (pSuccessor->transient.pNextOpen)
|
||||
{
|
||||
pSuccessor->transient.pNextOpen->transient.pPrevOpen = pSuccessor;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
pCurrent->transient.pPrevOpen = 0;
|
||||
}
|
||||
if (!pPath)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
success = Path_GeneratePath_custom(
|
||||
pPath,
|
||||
eTeam,
|
||||
vStartPos,
|
||||
vGoalPos,
|
||||
pNodeFrom,
|
||||
TopParent.transient.pNextOpen,
|
||||
bIncludeGoalInPath,
|
||||
true);
|
||||
return success;
|
||||
}
|
||||
|
||||
/*
|
||||
//Original
|
||||
int __userpurge Path_FindPathFromTo@<eax>(float *startPos@<eax>, pathnode_t *pNodeTo@<edx>, 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, const std::unordered_set<unsigned short>& allowedNegotiationLinks, int bIgnoreBadplaces)
|
||||
{
|
||||
game::CustomSearchInfo_FindPath info = {}; // [esp+0h] [ebp-14h] BYREF
|
||||
|
||||
info.m_pNodeTo = pNodeTo;
|
||||
info.negotiationOverlapCost = (*game::ai_pathNegotiationOverlapCost)->current.integer;
|
||||
info.startPos[0] = startPos[0];
|
||||
info.startPos[1] = startPos[1];
|
||||
info.startPos[2] = startPos[2];
|
||||
return Path_AStarAlgorithm_CustomSearchInfo_FindPath_custom(pPath, eTeam, startPos, pNodeFrom, vGoalPos, true, allowedNegotiationLinks, &info, bIgnoreBadplaces);;
|
||||
}
|
||||
|
||||
/*
|
||||
//Original
|
||||
int __userpurge Path_FindPath@<eax>(path_t* pPath@<ecx>, team_t eTeam@<edx>, 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, const std::unordered_set<unsigned short>& allowedNegotiationLinks)
|
||||
{
|
||||
int result; // eax
|
||||
int returnCount = 0; // [esp+2Ch] [ebp-304h] BYREF
|
||||
const int maxNodes = 64;
|
||||
auto nodes = std::make_unique<game::pathsort_t[]>(maxNodes);
|
||||
|
||||
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, allowedNegotiationLinks, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = 0;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int actor_spawned_callback_handle = 0;
|
||||
|
||||
void actor_spawned_callback(game::actor_s* actor)
|
||||
{
|
||||
static const auto call_addr = SELECT(0x0, 0x4B5550);
|
||||
|
||||
__asm
|
||||
{
|
||||
mov esi, actor;
|
||||
call call_addr;
|
||||
}
|
||||
|
||||
if (!actor_spawned_callback_handle)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto id = game::Scr_ExecEntThread(game::SCRIPTINSTANCE_SERVER, actor->ent->s.number, actor_spawned_callback_handle, 0, game::CLASS_NUM_ENTITY);
|
||||
game::RemoveRefToObject(game::SCRIPTINSTANCE_SERVER, id);
|
||||
}
|
||||
|
||||
void __declspec(naked) actor_spawned_callback_stub()
|
||||
{
|
||||
__asm
|
||||
{
|
||||
push esi;
|
||||
call actor_spawned_callback;
|
||||
add esp, 0x4;
|
||||
retn;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class component final : public component_interface
|
||||
{
|
||||
public:
|
||||
void post_unpack() override
|
||||
{
|
||||
//Add support for codecallback_actorspawned GSC callback
|
||||
utils::hook::call(0x4E06EB, actor_spawned_callback_stub);
|
||||
//Initialize handle for codecallback_actorspawned
|
||||
scheduler::on_postloadscripts([]()
|
||||
{
|
||||
int found_script = game::Scr_LoadScript("scripts/sp/callbacks_ext", game::SCRIPTINSTANCE_SERVER);
|
||||
if (found_script)
|
||||
{
|
||||
actor_spawned_callback_handle = game::Scr_GetFunctionHandle(game::SCRIPTINSTANCE_SERVER, "scripts/sp/callbacks_ext", "codecallback_actorspawned");
|
||||
printf("Adding actor_spawned_callback_handle\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Could not find callbacks_ext.gsc\n");
|
||||
}
|
||||
});
|
||||
|
||||
//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<game::path_t>();
|
||||
float start_pos[3] = {};
|
||||
float goal_pos[3] = {};
|
||||
auto team = "neutral"s;
|
||||
std::unordered_set<unsigned short> allowed_animscripts;
|
||||
|
||||
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)
|
||||
{
|
||||
auto parent_id = game::Scr_GetObject(3, game::SCRIPTINSTANCE_SERVER).pointerValue;
|
||||
auto script_array_size = GetArraySize(game::SCRIPTINSTANCE_SERVER, parent_id);
|
||||
|
||||
for (auto i = 0u; i < script_array_size; ++i)
|
||||
{
|
||||
auto id = game::GetArrayVariable(game::SCRIPTINSTANCE_SERVER, parent_id, i);
|
||||
auto entry_value = &game::gScrVarGlob[0].childVariables[id];
|
||||
|
||||
if ((entry_value->w.type & 0x1F) != game::VAR_STRING)
|
||||
{
|
||||
game::Scr_Error(utils::string::va("index %d in array is not a string", i), game::SCRIPTINSTANCE_SERVER, false);
|
||||
}
|
||||
|
||||
allowed_animscripts.insert(entry_value->u.u.stringValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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, allowed_animscripts);
|
||||
|
||||
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 - 1; i >= 0; i--)
|
||||
{
|
||||
if (path->pts[i].iNodeNum < 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
game::Scr_AddPathnode(game::SCRIPTINSTANCE_SERVER, &(*game::gameWorldCurrent)->path.nodes[path->pts[i].iNodeNum]);
|
||||
game::Scr_AddArray(game::SCRIPTINSTANCE_SERVER);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
};
|
||||
}
|
||||
|
||||
REGISTER_COMPONENT(ai::component)
|
@ -1 +0,0 @@
|
||||
#include <stdinc.hpp>
|
@ -31,7 +31,7 @@ namespace gsc
|
||||
return itr->second;
|
||||
}
|
||||
|
||||
game::BuiltinFunction __declspec(naked) scr_getfunction_stub()
|
||||
game::BuiltinFunction NAKED scr_getfunction_stub()
|
||||
{
|
||||
__asm
|
||||
{
|
||||
@ -87,7 +87,7 @@ namespace gsc
|
||||
return itr->second;
|
||||
}
|
||||
|
||||
game::BuiltinMethod __declspec(naked) scr_getmethod_stub()
|
||||
game::BuiltinMethod NAKED scr_getmethod_stub()
|
||||
{
|
||||
__asm
|
||||
{
|
||||
@ -99,30 +99,6 @@ namespace gsc
|
||||
ret;
|
||||
}
|
||||
}
|
||||
|
||||
int hudelem_spawned_callback_handle = 0;
|
||||
|
||||
game::game_hudelem_s* hudelem_alloc_codecallback(game::game_hudelem_s* hud)
|
||||
{
|
||||
static const auto call_addr = SELECT(0x0, 0x4FA310);
|
||||
|
||||
game::game_hudelem_s* answer;
|
||||
|
||||
__asm
|
||||
{
|
||||
mov eax, hud;
|
||||
call call_addr;
|
||||
mov answer, eax;
|
||||
}
|
||||
|
||||
if (hudelem_spawned_callback_handle)
|
||||
{
|
||||
auto id = game::Scr_ExecEntThread(game::SCRIPTINSTANCE_SERVER, hud - game::g_hudelems, hudelem_spawned_callback_handle, 0, game::CLASS_NUM_HUDELEM);
|
||||
game::RemoveRefToObject(game::SCRIPTINSTANCE_SERVER, id);
|
||||
}
|
||||
|
||||
return answer;
|
||||
}
|
||||
}
|
||||
|
||||
namespace function
|
||||
@ -152,155 +128,6 @@ namespace gsc
|
||||
// custom gsc funcs
|
||||
scr_getfunction_stub_ret_loc = utils::hook::get_displacement_addr(SELECT(0x0, 0x682D99));
|
||||
utils::hook::jump(SELECT(0x0, 0x682D99), scr_getfunction_stub);
|
||||
|
||||
|
||||
//Add support for codecallback_hudelemspawned GSC callback
|
||||
//utils::hook::call(0x4FA40B, hudelem_alloc_stub);
|
||||
//HudElem_Alloc_hook.create(0x4FA3E0, hudelem_alloc_stub2);
|
||||
//Handle for codecallback_hudelemspawned
|
||||
scheduler::on_postloadscripts([]()
|
||||
{
|
||||
auto found_script = game::Scr_LoadScript("scripts/sp/callbacks_ext", game::SCRIPTINSTANCE_SERVER);
|
||||
if (found_script)
|
||||
{
|
||||
hudelem_spawned_callback_handle = game::Scr_GetFunctionHandle(game::SCRIPTINSTANCE_SERVER, "scripts/sp/callbacks_ext", "codecallback_hudelemspawned");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Couldn't load script scripts/sp/callbacks_ext.gsc\n");
|
||||
}
|
||||
});
|
||||
|
||||
function::add("funny_func", []()
|
||||
{
|
||||
printf("How funny\n");
|
||||
printf("You found the funny monkey funkey\n");
|
||||
});
|
||||
|
||||
method::add("is_monkey", [](game::scr_entref_s ent)
|
||||
{
|
||||
printf("Monkey number %d\n", ent.entnum);
|
||||
|
||||
});
|
||||
|
||||
function::add("inttest", []()
|
||||
{
|
||||
int answer = game::Scr_GetInt(game::SCRIPTINSTANCE_SERVER, 0);
|
||||
answer += 69;
|
||||
game::Scr_AddInt(game::SCRIPTINSTANCE_SERVER, answer);
|
||||
});
|
||||
function::add("floattest", []()
|
||||
{
|
||||
float answer = game::Scr_GetFloat(game::SCRIPTINSTANCE_SERVER, 0);
|
||||
answer *= 69.0f;
|
||||
game::Scr_AddFloat(game::SCRIPTINSTANCE_SERVER, answer);
|
||||
});
|
||||
function::add("stringtest", []()
|
||||
{
|
||||
char* answer = game::Scr_GetString(game::SCRIPTINSTANCE_SERVER, 0);
|
||||
|
||||
std::string string(answer);
|
||||
|
||||
string += " haha funny"s;
|
||||
game::Scr_AddString(game::SCRIPTINSTANCE_SERVER, string.data());
|
||||
});
|
||||
function::add("istringtest", []()
|
||||
{
|
||||
const char* answer = game::Scr_GetIString(game::SCRIPTINSTANCE_SERVER, 0);
|
||||
|
||||
std::string string(answer);
|
||||
|
||||
string += " haha funny"s;
|
||||
game::Scr_AddIString(game::SCRIPTINSTANCE_SERVER, string.data());
|
||||
});
|
||||
|
||||
function::add("vectortest", []()
|
||||
{
|
||||
float answer[3] = {};
|
||||
game::Scr_GetVector(game::SCRIPTINSTANCE_SERVER, 0, answer);
|
||||
|
||||
answer[0] += 69.0f;
|
||||
game::Scr_AddVector(game::SCRIPTINSTANCE_SERVER, answer);
|
||||
});
|
||||
|
||||
function::add("undefinedtest", []()
|
||||
{
|
||||
game::Scr_AddUndefined(game::SCRIPTINSTANCE_SERVER);
|
||||
});
|
||||
|
||||
function::add("pathnodetest", []()
|
||||
{
|
||||
game::pathnode_t* node = game::Scr_GetPathnode(game::SCRIPTINSTANCE_SERVER);
|
||||
|
||||
game::Scr_AddPathnode(game::SCRIPTINSTANCE_SERVER, node);
|
||||
});
|
||||
|
||||
function::add("numberindexedarraytest", []()
|
||||
{
|
||||
game::Scr_MakeArray(game::SCRIPTINSTANCE_SERVER);
|
||||
|
||||
game::Scr_AddFloat(game::SCRIPTINSTANCE_SERVER, 69.0f);
|
||||
game::Scr_AddArray(game::SCRIPTINSTANCE_SERVER);
|
||||
|
||||
game::Scr_AddInt(game::SCRIPTINSTANCE_SERVER, 420);
|
||||
game::Scr_AddArray(game::SCRIPTINSTANCE_SERVER);
|
||||
|
||||
game::Scr_AddString(game::SCRIPTINSTANCE_SERVER, "ree");
|
||||
game::Scr_AddArray(game::SCRIPTINSTANCE_SERVER);
|
||||
});
|
||||
|
||||
function::add("stringindexedarraytest", []()
|
||||
{
|
||||
game::Scr_MakeArray(game::SCRIPTINSTANCE_SERVER);
|
||||
|
||||
std::string key1("key1");
|
||||
|
||||
game::Scr_AddFloat(game::SCRIPTINSTANCE_SERVER, 69.0f);
|
||||
game::Scr_AddArrayStringIndexed(game::SCRIPTINSTANCE_SERVER, game::SL_GetStringOfSize(game::SCRIPTINSTANCE_SERVER, key1.data(), 0, key1.length() + 1));
|
||||
|
||||
std::string key2("key2");
|
||||
|
||||
game::Scr_AddInt(game::SCRIPTINSTANCE_SERVER, 420);
|
||||
game::Scr_AddArrayStringIndexed(game::SCRIPTINSTANCE_SERVER, game::SL_GetStringOfSize(game::SCRIPTINSTANCE_SERVER, key2.data(), 0, key2.length() + 1));
|
||||
|
||||
std::string key3("key3");
|
||||
|
||||
game::Scr_AddString(game::SCRIPTINSTANCE_SERVER, "ree");
|
||||
game::Scr_AddArrayStringIndexed(game::SCRIPTINSTANCE_SERVER, game::SL_GetStringOfSize(game::SCRIPTINSTANCE_SERVER, key3.data(), 0, key3.length() + 1));
|
||||
});
|
||||
|
||||
method::add("entitytest", [](game::scr_entref_s ent)
|
||||
{
|
||||
if (ent.classnum != game::CLASS_NUM_ENTITY)
|
||||
{
|
||||
game::Scr_Error("Not an entity", game::SCRIPTINSTANCE_SERVER, false);
|
||||
return;
|
||||
}
|
||||
|
||||
game::gentity_s* ent2 = &game::g_entities[ent.entnum];
|
||||
|
||||
game::Scr_AddEntity(game::SCRIPTINSTANCE_SERVER, ent2);
|
||||
});
|
||||
|
||||
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));
|
||||
});
|
||||
|
||||
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:
|
||||
|
@ -1,14 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdinc.hpp>
|
||||
|
||||
namespace gsc
|
||||
{
|
||||
namespace
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
namespace function
|
||||
{
|
||||
void add(const std::string& name, const game::BuiltinFunction function);
|
||||
|
@ -1,110 +0,0 @@
|
||||
#include <stdinc.hpp>
|
||||
#include "loader/component_loader.hpp"
|
||||
|
||||
#include <utils/hook.hpp>
|
||||
#include <utils/io.hpp>
|
||||
#include <utils/string.hpp>
|
||||
#include <utils/thread.hpp>
|
||||
#include <utils/compression.hpp>
|
||||
|
||||
#include <exception/minidump.hpp>
|
||||
|
||||
namespace player
|
||||
{
|
||||
namespace
|
||||
{
|
||||
utils::hook::detour g_clientdoperframenotifies_hook;
|
||||
|
||||
void G_ClientDoPerFrameNotifies_custom(game::gentity_s* ent)
|
||||
{
|
||||
game::gclient_s* client; // esi
|
||||
unsigned int weapon; // eax
|
||||
bool clientIsFiring; // bl
|
||||
|
||||
client = ent->client;
|
||||
weapon = client->ps.weapon;
|
||||
if (weapon != client->lastWeapon)
|
||||
{
|
||||
game::Scr_AddString(game::SCRIPTINSTANCE_SERVER, game::BG_WeaponNames[weapon]->szInternalName);
|
||||
game::Scr_NotifyNum(game::SCRIPTINSTANCE_SERVER, ent->s.number, 0, game::scr_const->weapon_change, 1);
|
||||
weapon = client->ps.weapon;
|
||||
client->lastWeapon = weapon;
|
||||
}
|
||||
if (!client->previouslyChangingWeapon || client->ps.weaponstate == game::WEAPON_RAISING || client->ps.weaponstate == game::WEAPON_RAISING_ALTSWITCH)
|
||||
{
|
||||
if (client->ps.weaponstate == game::WEAPON_RAISING || client->ps.weaponstate == game::WEAPON_RAISING_ALTSWITCH)
|
||||
client->previouslyChangingWeapon = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
game::Scr_AddString(game::SCRIPTINSTANCE_SERVER, game::BG_WeaponNames[weapon]->szInternalName);
|
||||
game::Scr_NotifyNum(game::SCRIPTINSTANCE_SERVER, ent->s.number, 0, game::scr_const->weapon_change_complete, 1);
|
||||
client->previouslyChangingWeapon = 0;
|
||||
}
|
||||
clientIsFiring = client->ps.weaponstate == game::WEAPON_FIRING && client->ps.pm_type < game::PM_LASTSTAND_TRANSITION;
|
||||
if (clientIsFiring != client->previouslyFiring)
|
||||
{
|
||||
if (clientIsFiring)
|
||||
game::Scr_NotifyNum(game::SCRIPTINSTANCE_SERVER, ent->s.number, 0, game::scr_const->begin_firing, 0);
|
||||
else
|
||||
game::Scr_NotifyNum(game::SCRIPTINSTANCE_SERVER, ent->s.number, 0, game::scr_const->end_firing, 0);
|
||||
client->previouslyFiring = clientIsFiring;
|
||||
}
|
||||
if ((client->ps.weapFlags & 0x40) != 0)
|
||||
{
|
||||
if (!client->previouslyUsingNightVision)
|
||||
{
|
||||
client->previouslyUsingNightVision = 1;
|
||||
game::Scr_NotifyNum(game::SCRIPTINSTANCE_SERVER, ent->s.number, 0, game::scr_const->night_vision_on, 0);
|
||||
}
|
||||
}
|
||||
else if (client->previouslyUsingNightVision)
|
||||
{
|
||||
client->previouslyUsingNightVision = 0;
|
||||
game::Scr_NotifyNum(game::SCRIPTINSTANCE_SERVER, ent->s.number, 0, game::scr_const->night_vision_off, 0);
|
||||
}
|
||||
|
||||
//New addition
|
||||
if (game::PM_IsSprinting(&client->ps))
|
||||
{
|
||||
if (!client->previouslySprinting)
|
||||
{
|
||||
client->previouslySprinting = true;
|
||||
std::string sprintBeginNotifyStr("sprint_begin");
|
||||
game::Scr_NotifyNum(game::SCRIPTINSTANCE_SERVER, ent->s.number, 0, game::SL_GetStringOfSize(game::SCRIPTINSTANCE_SERVER, sprintBeginNotifyStr.data(), 0, sprintBeginNotifyStr.length()), 0);
|
||||
}
|
||||
}
|
||||
else if (client->previouslySprinting)
|
||||
{
|
||||
client->previouslySprinting = false;
|
||||
std::string sprintBeginNotifyStr("sprint_end");
|
||||
game::Scr_NotifyNum(game::SCRIPTINSTANCE_SERVER, ent->s.number, 0, game::SL_GetStringOfSize(game::SCRIPTINSTANCE_SERVER, sprintBeginNotifyStr.data(), 0, sprintBeginNotifyStr.length()), 0);
|
||||
}
|
||||
}
|
||||
|
||||
void __declspec(naked) G_ClientDoPerFrameNotifies_stub()
|
||||
{
|
||||
__asm
|
||||
{
|
||||
push edi;
|
||||
|
||||
call G_ClientDoPerFrameNotifies_custom;
|
||||
add esp, 0x4;
|
||||
ret;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class component final : public component_interface
|
||||
{
|
||||
public:
|
||||
void post_unpack() override
|
||||
{
|
||||
// test usercall detour!
|
||||
g_clientdoperframenotifies_hook.create(game::G_ClientDoPerFrameNotifies(), G_ClientDoPerFrameNotifies_stub);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
REGISTER_COMPONENT(player::component)
|
@ -99,8 +99,6 @@ namespace scheduler
|
||||
|
||||
std::vector<std::function<void()>> post_init_funcs;
|
||||
bool com_inited = false;
|
||||
std::vector<std::function<void()>> post_loadscripts_funcs;
|
||||
bool postloadscripts_inited = false;
|
||||
|
||||
void on_post_init_hook()
|
||||
{
|
||||
@ -120,26 +118,6 @@ namespace scheduler
|
||||
com_init_hook.invoke<void>();
|
||||
on_post_init_hook();
|
||||
}
|
||||
|
||||
void on_post_postloadscripts_hook()
|
||||
{
|
||||
if (postloadscripts_inited)
|
||||
{
|
||||
return;
|
||||
}
|
||||
for (const auto& func : post_loadscripts_funcs)
|
||||
{
|
||||
func();
|
||||
}
|
||||
}
|
||||
|
||||
void postloadscripts_stub()
|
||||
{
|
||||
postloadscripts_inited = false;
|
||||
gscr_postloadscripts_hook.invoke<void>();
|
||||
on_post_postloadscripts_hook();
|
||||
postloadscripts_inited = true;
|
||||
}
|
||||
}
|
||||
|
||||
void schedule(const std::function<bool()>& callback, const pipeline type,
|
||||
@ -187,11 +165,6 @@ namespace scheduler
|
||||
}
|
||||
}
|
||||
|
||||
void on_postloadscripts(const std::function<void()>& callback)
|
||||
{
|
||||
post_loadscripts_funcs.push_back(callback);
|
||||
}
|
||||
|
||||
class component final : public component_interface
|
||||
{
|
||||
public:
|
||||
@ -207,9 +180,6 @@ namespace scheduler
|
||||
});
|
||||
|
||||
com_init_hook.create(SELECT(0x0, 0x59D710), com_init_stub);
|
||||
|
||||
gscr_postloadscripts_hook.create(SELECT(0x0, 0x5150E0), postloadscripts_stub);
|
||||
|
||||
utils::hook::call(SELECT(0x0, 0x503B5D), execute_server);
|
||||
}
|
||||
};
|
||||
|
@ -20,6 +20,4 @@ namespace scheduler
|
||||
std::chrono::milliseconds delay = 0ms);
|
||||
|
||||
void on_init(const std::function<void()>& callback);
|
||||
|
||||
void on_postloadscripts(const std::function<void()>& callback);
|
||||
}
|
||||
|
@ -7,154 +7,13 @@
|
||||
#include <utils/io.hpp>
|
||||
#include <utils/hook.hpp>
|
||||
#include <utils/string.hpp>
|
||||
#include <utils/http.hpp>
|
||||
#include <json.hpp>
|
||||
|
||||
namespace test
|
||||
{
|
||||
utils::hook::detour gscr_spawn_hook;
|
||||
|
||||
// a __usercall detour! :o
|
||||
utils::hook::detour scr_getentityid_hook;
|
||||
|
||||
utils::hook::detour sv_clientthink_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<void>();
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void __declspec(naked) our_funny_hook()
|
||||
{
|
||||
__asm
|
||||
{
|
||||
pushad;
|
||||
mov eax, [esp + 0x20 + 0x98 + 0x1C];
|
||||
push eax;
|
||||
push esi; // end
|
||||
push edi; // begin
|
||||
call our_funny_call;
|
||||
add esp, 0xC;
|
||||
test al, al;
|
||||
popad;
|
||||
|
||||
jnz og;
|
||||
|
||||
push 0x4D3400;
|
||||
retn;
|
||||
|
||||
og:
|
||||
mov ecx, 0x18F78D4;
|
||||
mov ecx, dword ptr [ecx]; // level.iSearchFrame
|
||||
push 0x4D329C;
|
||||
retn;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int scr_getentityid_call(unsigned int entnum, [[maybe_unused]] void* caller_addr, game::scriptInstance_t inst, game::classNum_e classnum, unsigned int clientnum)
|
||||
{
|
||||
// minhook allocated space for the original asm, we want to execute that instead because the original gamecode has the jump from the detour
|
||||
return game::Scr_GetEntityId(inst, entnum, classnum, clientnum, scr_getentityid_hook.get_original());
|
||||
}
|
||||
|
||||
unsigned int __declspec(naked) scr_getentityid_stub()
|
||||
{
|
||||
// 00692520 unsigned int __usercall Scr_GetEntityId@<eax>(unsigned int entnum@<eax>, scriptInstance_t inst, classNum_e classnum, unsigned int clientnum)
|
||||
__asm
|
||||
{
|
||||
// eax is a param, lets push it!
|
||||
push eax;
|
||||
|
||||
// ok so scr_getentityid_call intentionally has more params than it should, so we can access everything on the stack
|
||||
call scr_getentityid_call;
|
||||
|
||||
// clean up and return
|
||||
add esp, 4;
|
||||
ret;
|
||||
}
|
||||
}
|
||||
|
||||
void sv_clientthink_call(game::client_s* client, [[maybe_unused]] void* caller_addr, game::usercmd_s* cmd)
|
||||
{
|
||||
const auto og_addr = sv_clientthink_hook.get_original();
|
||||
|
||||
if (client->bIsTestClient && client->gentity && client->gentity->client)
|
||||
{
|
||||
auto gclient = client->gentity->client;
|
||||
|
||||
cmd->wiimoteGunPitch = static_cast<unsigned short>((gclient->ps.viewangles[0]) * (65536 / 360.f)) & 0xFFFF;
|
||||
cmd->wiimoteGunYaw = static_cast<unsigned short>((gclient->ps.viewangles[1]) * (65536 / 360.f)) & 0xFFFF;
|
||||
}
|
||||
|
||||
__asm
|
||||
{
|
||||
push cmd;
|
||||
mov eax, client;
|
||||
call og_addr;
|
||||
add esp, 0x4;
|
||||
}
|
||||
}
|
||||
|
||||
void __declspec(naked) sv_clientthink_stub()
|
||||
{
|
||||
__asm
|
||||
{
|
||||
push eax;
|
||||
|
||||
call sv_clientthink_call;
|
||||
|
||||
add esp, 0x4;
|
||||
|
||||
ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class component final : public component_interface
|
||||
@ -162,50 +21,6 @@ namespace test
|
||||
public:
|
||||
void post_unpack() override
|
||||
{
|
||||
game::Cmd_AddCommand("testcmd", []()
|
||||
{
|
||||
if (game::Cmd_Argc() == 2)
|
||||
{
|
||||
printf("test %s\n", game::Cmd_Argv(1));
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("test\n");
|
||||
}
|
||||
});
|
||||
|
||||
custom_dvar = game::Dvar_RegisterInt("testdvar1", 69, -69, 420, game::DVAR_FLAG_NONE, "This dvar is a dvar");
|
||||
|
||||
scheduler::on_init([]()
|
||||
{
|
||||
custom_string_dvar = game::Dvar_RegisterString("testdvar2", "This might be a dvar value", game::DVAR_FLAG_NONE, "This dvar is a dvar");
|
||||
printf("We initeded bois\n");
|
||||
});
|
||||
|
||||
scheduler::loop([]()
|
||||
{
|
||||
//printf("Biggie Spam McCheese\n");
|
||||
});
|
||||
|
||||
gsc::function::add("getarraytest", []()
|
||||
{
|
||||
auto parent_id = game::Scr_GetObject(0, game::SCRIPTINSTANCE_SERVER).pointerValue;
|
||||
|
||||
auto script_array_size = GetArraySize(game::SCRIPTINSTANCE_SERVER, parent_id);
|
||||
for (auto i = 0u; i < script_array_size; ++i)
|
||||
{
|
||||
auto id = game::GetArrayVariable(game::SCRIPTINSTANCE_SERVER, parent_id, i);
|
||||
auto entry_value = &game::gScrVarGlob[0].childVariables[id];
|
||||
if ((entry_value->w.type & 0x1F) != game::VAR_STRING)
|
||||
{
|
||||
game::Scr_Error(utils::string::va("index %d in array is not a string", i), game::SCRIPTINSTANCE_SERVER, false);
|
||||
}
|
||||
printf("%s\n", game::SL_ConvertToString(game::SCRIPTINSTANCE_SERVER, entry_value->u.u.stringValue));
|
||||
}
|
||||
});
|
||||
|
||||
gscr_spawn_hook.create(0x517630, gscr_spawn_stub);
|
||||
|
||||
//Disable AI print spam
|
||||
utils::hook::nop(0x4BAB7D, 5);
|
||||
utils::hook::nop(0x4BAAFA, 5);
|
||||
@ -215,15 +30,6 @@ namespace test
|
||||
|
||||
//Disable unknown dvar spam
|
||||
utils::hook::nop(0x5F04AF, 5);
|
||||
|
||||
// fix NEGOTIATION links
|
||||
//utils::hook::jump(0x4D3296, our_funny_hook);
|
||||
|
||||
// test usercall detour!
|
||||
scr_getentityid_hook.create(game::Scr_GetEntityId(), scr_getentityid_stub);
|
||||
// scr_getentityid_hook.create(game::SL_GetStringOfSize.get(), sl_getstringofsize_stub);
|
||||
|
||||
sv_clientthink_hook.create(0x630BF0, sv_clientthink_stub);
|
||||
}
|
||||
|
||||
private:
|
||||
|
Reference in New Issue
Block a user