CS2-Kit
C++23 library for CS2 Metamod:Source plugin development
Loading...
Searching...
No Matches
Entity.cpp
Go to the documentation of this file.
1#include "Sdk/Schema.hpp"
2
3#include <CS2Kit/Sdk/Entity.hpp>
4#include <CS2Kit/Sdk/GameData.hpp>
5#include <CS2Kit/Sdk/GameInterfaces.hpp>
6#include <CS2Kit/Utils/Log.hpp>
7#include <entity2/concreteentitylist.h>
8#include <entity2/entityidentity.h>
9#include <entity2/entityinstance.h>
10#include <entity2/entitysystem.h>
11
12namespace CS2Kit::Sdk
13{
14using namespace CS2Kit::Utils;
15
16void EntitySystem::ResolveSchemaOffsets()
17{
18 if (_schemaOffsetsResolved)
19 return;
20
21 auto& schema = SchemaService::Instance();
22
23 _offsetPlayerPawn = schema.GetOffset("CBasePlayerController", "m_hPawn");
24 _offsetMovementServices = schema.GetOffset("CBasePlayerPawn", "m_pMovementServices");
25 _offsetButtons = schema.GetOffset("CPlayer_MovementServices", "m_nButtons");
26 _offsetButtonStates = schema.GetOffset("CInButtonState", "m_pButtonStates");
27
28 _schemaOffsetsResolved = true;
29}
30
31bool EntitySystem::Initialize()
32{
33 auto& interfaces = GameInterfaces::Instance();
34
35 if (!interfaces.GameResourceService)
36 {
37 Log::Warn("IGameResourceService not available.");
38 }
39
40 int offsetGameEntitySystem = GameData::Instance().GetOffset("GameEntitySystem");
41
42 if (offsetGameEntitySystem < 0)
43 {
44 Log::Warn("GameEntitySystem offset not found in gamedata.");
45 }
46 else
47 {
48 Log::Info("Gamedata loaded (entity system offset: {}).", offsetGameEntitySystem);
49 }
50
51 if (interfaces.GameResourceService && offsetGameEntitySystem >= 0)
52 {
53 interfaces.EntitySystem = *reinterpret_cast<CGameEntitySystem**>(
54 reinterpret_cast<uintptr_t>(interfaces.GameResourceService) + offsetGameEntitySystem);
55 }
56
57 if (interfaces.EntitySystem)
58 {
59 Log::Info("Entity system initialized.");
60 }
61
62 return true;
63}
64
65CGameEntitySystem* EntitySystem::GetEntitySystem()
66{
67 auto& interfaces = GameInterfaces::Instance();
68
69 if (!interfaces.EntitySystem && interfaces.GameResourceService)
70 {
71 int offsetGameEntitySystem = GameData::Instance().GetOffset("GameEntitySystem");
72 if (offsetGameEntitySystem >= 0)
73 {
74 interfaces.EntitySystem = *reinterpret_cast<CGameEntitySystem**>(
75 reinterpret_cast<uintptr_t>(interfaces.GameResourceService) + offsetGameEntitySystem);
76 }
77 }
78 return interfaces.EntitySystem;
79}
80
81CEntityIdentity* EntitySystem::GetEntityIdentityByIndex(CGameEntitySystem* pSys, int index)
82{
83 if (!pSys || index < 0 || index >= MAX_TOTAL_ENTITIES)
84 return nullptr;
85
86 int chunk = index / MAX_ENTITIES_IN_LIST;
87 int offset = index % MAX_ENTITIES_IN_LIST;
88
89 CEntityIdentity* pChunk = pSys->m_EntityList.m_pIdentityChunks[chunk];
90 if (!pChunk)
91 return nullptr;
92
93 return &pChunk[offset];
94}
95
96CEntityInstance* EntitySystem::ResolveEntityHandle(uint32_t handle)
97{
98 if (handle == 0xFFFFFFFF)
99 return nullptr;
100
101 int entryIndex = handle & 0x7FFF;
102
103 auto* pSys = GetEntitySystem();
104 if (!pSys)
105 return nullptr;
106
107 CEntityIdentity* pIdentity = GetEntityIdentityByIndex(pSys, entryIndex);
108 if (!pIdentity)
109 return nullptr;
110
111 return pIdentity->m_pInstance;
112}
113
114CEntityInstance* EntitySystem::GetPlayerController(int slot)
115{
116 auto* pSys = GetEntitySystem();
117 if (!pSys || slot < 0 || slot >= MaxPlayers)
118 return nullptr;
119
120 CEntityIdentity* pIdentity = GetEntityIdentityByIndex(pSys, slot + 1);
121 if (!pIdentity)
122 return nullptr;
123
124 return pIdentity->m_pInstance;
125}
126
127uint64_t EntitySystem::GetPlayerButtons(int slot)
128{
129 if (!_schemaOffsetsResolved)
130 ResolveSchemaOffsets();
131
132 if (_offsetPlayerPawn < 0 || _offsetMovementServices < 0 || _offsetButtons < 0 || _offsetButtonStates < 0)
133 return 0;
134
135 CEntityInstance* pController = GetPlayerController(slot);
136 if (!pController)
137 return 0;
138
139 auto* pCtrlBase = reinterpret_cast<uint8_t*>(pController);
140
141 uint32_t hPawn = *reinterpret_cast<uint32_t*>(pCtrlBase + _offsetPlayerPawn);
142 CEntityInstance* pPawn = ResolveEntityHandle(hPawn);
143 if (!pPawn)
144 return 0;
145
146 auto* pPawnBase = reinterpret_cast<uint8_t*>(pPawn);
147
148 auto* pMovementServices = *reinterpret_cast<uint8_t**>(pPawnBase + _offsetMovementServices);
149 if (!pMovementServices)
150 return 0;
151
152 auto* pButtonStates = reinterpret_cast<uint64_t*>(pMovementServices + _offsetButtons + _offsetButtonStates);
153
154 return pButtonStates[0];
155}
156
157bool EntitySystem::IsPlayerSlotValid(int slot)
158{
159 return GetPlayerController(slot) != nullptr;
160}
161
162} // namespace CS2Kit::Sdk