mirror of
https://github.com/roflmuffin/CounterStrikeSharp.git
synced 2025-12-08 08:56:34 -08:00
Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
02d5191e74 | ||
|
|
aec696abc0 | ||
|
|
c01aeec14b | ||
|
|
41e7bee85a | ||
|
|
9834271956 | ||
|
|
fb5967d102 | ||
|
|
928bc3f74d | ||
|
|
6a7d7dba4f | ||
|
|
11e5e9972d | ||
|
|
9a221b4ebb |
12
.github/dependabot.yaml
vendored
Normal file
12
.github/dependabot.yaml
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
version: 2
|
||||
updates:
|
||||
# Update the submodule in libraries/hl2sdk-cs2 every day
|
||||
- package-ecosystem: "gitsubmodule"
|
||||
directory: "/"
|
||||
allow:
|
||||
- dependency-name: "libraries/hl2sdk-cs2"
|
||||
- dependency-name: "libraries/metamod-source"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
commit-message:
|
||||
prefix: "chore(deps)"
|
||||
Submodule libraries/hl2sdk-cs2 updated: aaaaaf040b...36dd2db721
Submodule libraries/metamod-source updated: e857fbe90c...607301adc3
@@ -1,6 +1,5 @@
|
||||
#set(_ITERATOR_DEBUG_LEVEL 2)
|
||||
add_definitions(-D_LINUX -DPOSIX -DLINUX -DGNUC -DCOMPILER_GCC -DPLATFORM_64BITS)
|
||||
|
||||
add_definitions(-D_LINUX -DPOSIX -DLINUX -DGNUC -DCOMPILER_GCC -DPLATFORM_64BITS -D_FILE_OFFSET_BITS=64)
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Dstricmp=strcasecmp -D_stricmp=strcasecmp -D_strnicmp=strncasecmp")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Dstrnicmp=strncasecmp -D_snprintf=snprintf")
|
||||
@@ -16,16 +15,18 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-invalid-offsetof -Wno-reorder")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfpmath=sse -msse -fno-strict-aliasing")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-threadsafe-statics -v -fvisibility=default")
|
||||
|
||||
SET(
|
||||
COUNTER_STRIKE_SHARP_LINK_LIBRARIES
|
||||
${SOURCESDK_LIB}/linux64/libtier0.so
|
||||
${SOURCESDK_LIB}/linux64/tier1.a
|
||||
${SOURCESDK_LIB}/linux64/interfaces.a
|
||||
${SOURCESDK_LIB}/linux64/mathlib.a
|
||||
spdlog
|
||||
dynload_s
|
||||
dyncall_s
|
||||
distorm
|
||||
funchook-static
|
||||
dynohook
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -static-libgcc -static-libstdc++")
|
||||
|
||||
set(
|
||||
COUNTER_STRIKE_SHARP_LINK_LIBRARIES
|
||||
${SOURCESDK_LIB}/linux64/libtier0.so
|
||||
${SOURCESDK_LIB}/linux64/tier1.a
|
||||
${SOURCESDK_LIB}/linux64/interfaces.a
|
||||
${SOURCESDK_LIB}/linux64/mathlib.a
|
||||
spdlog
|
||||
dynload_s
|
||||
dyncall_s
|
||||
distorm
|
||||
funchook-static
|
||||
dynohook
|
||||
)
|
||||
@@ -1,8 +1,8 @@
|
||||
if (UNIX AND NOT APPLE)
|
||||
if(UNIX AND NOT APPLE)
|
||||
set(LINUX TRUE)
|
||||
endif()
|
||||
|
||||
if (WIN32 AND NOT MSVC)
|
||||
if(WIN32 AND NOT MSVC)
|
||||
message(FATAL "MSVC restricted.")
|
||||
endif()
|
||||
|
||||
@@ -11,9 +11,9 @@ set(CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING
|
||||
FORCE
|
||||
)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
if (LINUX)
|
||||
if(LINUX)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
|
||||
endif()
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "core/gameconfig.h"
|
||||
|
||||
#include <fstream>
|
||||
|
||||
#include "log.h"
|
||||
@@ -13,7 +14,8 @@ CGameConfig::~CGameConfig() = default;
|
||||
bool CGameConfig::Init(char* conf_error, int conf_error_size)
|
||||
{
|
||||
std::ifstream ifs(m_sPath);
|
||||
if (!ifs) {
|
||||
if (!ifs)
|
||||
{
|
||||
V_snprintf(conf_error, conf_error_size, "Gamedata file not found.");
|
||||
return false;
|
||||
}
|
||||
@@ -26,44 +28,53 @@ bool CGameConfig::Init(char* conf_error, int conf_error_size)
|
||||
constexpr auto platform = "linux";
|
||||
#endif
|
||||
|
||||
try {
|
||||
for (auto& [k, v] : m_json.items()) {
|
||||
if (v.contains("signatures")) {
|
||||
if (auto library = v["signatures"]["library"]; library.is_string()) {
|
||||
try
|
||||
{
|
||||
for (auto& [k, v] : m_json.items())
|
||||
{
|
||||
if (v.contains("signatures"))
|
||||
{
|
||||
if (auto library = v["signatures"]["library"]; library.is_string())
|
||||
{
|
||||
m_umLibraries[k] = library.get<std::string>();
|
||||
}
|
||||
if (auto signature = v["signatures"][platform]; signature.is_string()) {
|
||||
if (auto signature = v["signatures"][platform]; signature.is_string())
|
||||
{
|
||||
m_umSignatures[k] = signature.get<std::string>();
|
||||
}
|
||||
}
|
||||
if (v.contains("offsets")) {
|
||||
if (auto offset = v["offsets"][platform]; offset.is_number_integer()) {
|
||||
if (v.contains("offsets"))
|
||||
{
|
||||
if (auto offset = v["offsets"][platform]; offset.is_number_integer())
|
||||
{
|
||||
m_umOffsets[k] = offset.get<std::int64_t>();
|
||||
}
|
||||
}
|
||||
if (v.contains("patches")) {
|
||||
if (auto patch = v["patches"][platform]; patch.is_string()) {
|
||||
if (v.contains("patches"))
|
||||
{
|
||||
if (auto patch = v["patches"][platform]; patch.is_string())
|
||||
{
|
||||
m_umPatches[k] = patch.get<std::string>();
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (const std::exception& ex) {
|
||||
}
|
||||
catch (const std::exception& ex)
|
||||
{
|
||||
V_snprintf(conf_error, conf_error_size, "Failed to parse gamedata file: %s", ex.what());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const std::string CGameConfig::GetPath()
|
||||
{
|
||||
return m_sPath;
|
||||
}
|
||||
const std::string CGameConfig::GetPath() { return m_sPath; }
|
||||
|
||||
const char* CGameConfig::GetLibrary(const std::string& name)
|
||||
{
|
||||
// My recommendation is switch to C++20.
|
||||
auto it = m_umLibraries.find(name);
|
||||
if (it == m_umLibraries.end()) {
|
||||
if (it == m_umLibraries.end())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
return it->second.c_str();
|
||||
@@ -72,7 +83,8 @@ const char* CGameConfig::GetLibrary(const std::string& name)
|
||||
const char* CGameConfig::GetSignature(const std::string& name)
|
||||
{
|
||||
auto it = m_umSignatures.find(name);
|
||||
if (it == m_umSignatures.end()) {
|
||||
if (it == m_umSignatures.end())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
return it->second.c_str();
|
||||
@@ -82,7 +94,8 @@ const char* CGameConfig::GetSymbol(const char* name)
|
||||
{
|
||||
const char* symbol = this->GetSignature(name);
|
||||
|
||||
if (!symbol || strlen(symbol) <= 1) {
|
||||
if (!symbol || strlen(symbol) <= 1)
|
||||
{
|
||||
CSSHARP_CORE_ERROR("Missing symbol: {}\n", name);
|
||||
return nullptr;
|
||||
}
|
||||
@@ -92,7 +105,8 @@ const char* CGameConfig::GetSymbol(const char* name)
|
||||
const char* CGameConfig::GetPatch(const std::string& name)
|
||||
{
|
||||
auto it = m_umPatches.find(name);
|
||||
if (it == m_umPatches.end()) {
|
||||
if (it == m_umPatches.end())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
return it->second.c_str();
|
||||
@@ -101,14 +115,14 @@ const char* CGameConfig::GetPatch(const std::string& name)
|
||||
int CGameConfig::GetOffset(const std::string& name)
|
||||
{
|
||||
auto it = m_umOffsets.find(name);
|
||||
if (it == m_umOffsets.end()) {
|
||||
if (it == m_umOffsets.end())
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
void* CGameConfig::GetAddress(const std::string& name, void* engine, void* server, char* error,
|
||||
int maxlen)
|
||||
void* CGameConfig::GetAddress(const std::string& name, void* engine, void* server, char* error, int maxlen)
|
||||
{
|
||||
CSSHARP_CORE_ERROR("Not implemented.");
|
||||
return nullptr;
|
||||
@@ -117,11 +131,9 @@ void* CGameConfig::GetAddress(const std::string& name, void* engine, void* serve
|
||||
modules::CModule** CGameConfig::GetModule(const char* name)
|
||||
{
|
||||
const char* library = this->GetLibrary(name);
|
||||
if (!library)
|
||||
return nullptr;
|
||||
if (!library) return nullptr;
|
||||
|
||||
if (strcmp(library, "engine") == 0)
|
||||
return &modules::engine;
|
||||
if (strcmp(library, "engine") == 0) return &modules::engine;
|
||||
else if (strcmp(library, "server") == 0)
|
||||
return &modules::server;
|
||||
else if (strcmp(library, "vscript") == 0)
|
||||
@@ -135,7 +147,8 @@ modules::CModule** CGameConfig::GetModule(const char* name)
|
||||
bool CGameConfig::IsSymbol(const char* name)
|
||||
{
|
||||
const char* sigOrSymbol = this->GetSignature(name);
|
||||
if (!sigOrSymbol || strlen(sigOrSymbol) <= 0) {
|
||||
if (!sigOrSymbol || strlen(sigOrSymbol) <= 0)
|
||||
{
|
||||
CSSHARP_CORE_ERROR("Missing signature or symbol: {}\n", name);
|
||||
return false;
|
||||
}
|
||||
@@ -145,22 +158,28 @@ bool CGameConfig::IsSymbol(const char* name)
|
||||
void* CGameConfig::ResolveSignature(const char* name)
|
||||
{
|
||||
modules::CModule** module = this->GetModule(name);
|
||||
if (!module || !(*module)) {
|
||||
if (!module || !(*module))
|
||||
{
|
||||
CSSHARP_CORE_ERROR("Invalid Module {}\n", name);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void* address = nullptr;
|
||||
if (this->IsSymbol(name)) {
|
||||
if (this->IsSymbol(name))
|
||||
{
|
||||
const char* symbol = this->GetSymbol(name);
|
||||
if (!symbol) {
|
||||
if (!symbol)
|
||||
{
|
||||
CSSHARP_CORE_ERROR("Invalid symbol for {}\n", name);
|
||||
return nullptr;
|
||||
}
|
||||
address = (*module)->FindSymbol(symbol);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
const char* signature = this->GetSignature(name);
|
||||
if (!signature) {
|
||||
if (!signature)
|
||||
{
|
||||
CSSHARP_CORE_ERROR("Failed to find signature for {}\n", name);
|
||||
return nullptr;
|
||||
}
|
||||
@@ -168,7 +187,8 @@ void* CGameConfig::ResolveSignature(const char* name)
|
||||
address = (*module)->FindSignature(signature);
|
||||
}
|
||||
|
||||
if (!address) {
|
||||
if (!address)
|
||||
{
|
||||
CSSHARP_CORE_ERROR("Failed to find address for {}\n", name);
|
||||
return nullptr;
|
||||
}
|
||||
@@ -180,7 +200,8 @@ std::string CGameConfig::GetDirectoryName(const std::string& directoryPathInput)
|
||||
std::string directoryPath = std::string(directoryPathInput);
|
||||
|
||||
size_t found = std::string(directoryPath).find_last_of("/\\");
|
||||
if (found != std::string::npos) {
|
||||
if (found != std::string::npos)
|
||||
{
|
||||
return std::string(directoryPath, found + 1);
|
||||
}
|
||||
return "";
|
||||
@@ -188,17 +209,15 @@ std::string CGameConfig::GetDirectoryName(const std::string& directoryPathInput)
|
||||
|
||||
std::vector<int16_t> CGameConfig::HexToByte(std::string_view src)
|
||||
{
|
||||
if (src.empty()) {
|
||||
if (src.empty())
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
auto hex_char_to_byte = [](char c) -> int16_t {
|
||||
if (c >= '0' && c <= '9')
|
||||
return c - '0';
|
||||
if (c >= 'A' && c <= 'F')
|
||||
return c - 'A' + 10;
|
||||
if (c >= 'a' && c <= 'f')
|
||||
return c - 'a' + 10;
|
||||
if (c >= '0' && c <= '9') return c - '0';
|
||||
if (c >= 'A' && c <= 'F') return c - 'A' + 10;
|
||||
if (c >= 'a' && c <= 'f') return c - 'a' + 10;
|
||||
|
||||
// a valid hex char can never go up to 0xFF
|
||||
return -1;
|
||||
@@ -211,36 +230,38 @@ std::vector<int16_t> CGameConfig::HexToByte(std::string_view src)
|
||||
const std::string_view pattern = is_code_style ? R"(\x)" : " ";
|
||||
const std::string_view wildcard = is_code_style ? "2A" : "?";
|
||||
|
||||
auto split = std::views::split(src, pattern);
|
||||
std::string::size_type pos = 0;
|
||||
|
||||
for (auto&& str : split) {
|
||||
if (str.empty()) [[unlikely]] {
|
||||
continue;
|
||||
while (pos < src.size())
|
||||
{
|
||||
std::string::size_type found = src.find(pattern, pos);
|
||||
if (found == std::string::npos)
|
||||
{
|
||||
found = src.size();
|
||||
}
|
||||
std::string_view str = src.substr(pos, found - pos);
|
||||
pos = found + pattern.size();
|
||||
|
||||
// std::string_view(std::subrange) constructor only exists in C++23 or above
|
||||
// use this when compiler is GCC >= 12.1 or Clang >= 16
|
||||
// const std::string_view byte(str.begin(), str.end());
|
||||
if (str.empty()) continue;
|
||||
|
||||
// a workaround for GCC < 12.1, it doesn't work with Clang < 16
|
||||
// https://stackoverflow.com/a/48403210
|
||||
std::string_view byte (&*str.begin(), std::ranges::distance(str));
|
||||
std::string byte(str.data(), str.size());
|
||||
|
||||
if (byte.starts_with(wildcard)) {
|
||||
if (byte.substr(0, wildcard.size()) == wildcard)
|
||||
{
|
||||
result.emplace_back(-1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (byte.size() < 2) [[unlikely]] {
|
||||
if (byte.size() < 2)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
const auto high = hex_char_to_byte(byte[0]);
|
||||
const auto low = hex_char_to_byte(byte[1]);
|
||||
|
||||
// if then is malformed, return nothing
|
||||
// maybe print error message here?
|
||||
if (high == 0xFF || low == 0xFF) [[unlikely]] {
|
||||
if (high == 0xFF || low == 0xFF)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
@@ -15,21 +15,19 @@
|
||||
*/
|
||||
|
||||
#include "core/managers/chat_manager.h"
|
||||
#include "core/managers/con_command_manager.h"
|
||||
#include "scripting/callback_manager.h"
|
||||
#include "characterset.h"
|
||||
|
||||
#include <igameevents.h>
|
||||
#include <baseentity.h>
|
||||
#include <public/eiface.h>
|
||||
#include "core/memory.h"
|
||||
#include "core/log.h"
|
||||
#include "core/coreconfig.h"
|
||||
#include "core/gameconfig.h"
|
||||
|
||||
#include <funchook.h>
|
||||
#include <igameevents.h>
|
||||
#include <public/eiface.h>
|
||||
|
||||
#include "characterset.h"
|
||||
#include "core/coreconfig.h"
|
||||
#include "core/gameconfig.h"
|
||||
#include "core/log.h"
|
||||
#include "core/managers/con_command_manager.h"
|
||||
#include "core/memory.h"
|
||||
#include "core/memory_module.h"
|
||||
#include "scripting/callback_manager.h"
|
||||
|
||||
namespace counterstrikesharp {
|
||||
|
||||
@@ -39,10 +37,10 @@ ChatManager::~ChatManager() {}
|
||||
|
||||
void ChatManager::OnAllInitialized()
|
||||
{
|
||||
m_pHostSay = reinterpret_cast<HostSay>(
|
||||
modules::server->FindSignature(globals::gameConfig->GetSignature("Host_Say")));
|
||||
m_pHostSay = reinterpret_cast<HostSay>(modules::server->FindSignature(globals::gameConfig->GetSignature("Host_Say")));
|
||||
|
||||
if (m_pHostSay == nullptr) {
|
||||
if (m_pHostSay == nullptr)
|
||||
{
|
||||
CSSHARP_CORE_ERROR("Failed to find signature for \'Host_Say\'");
|
||||
return;
|
||||
}
|
||||
@@ -54,12 +52,13 @@ void ChatManager::OnAllInitialized()
|
||||
|
||||
void ChatManager::OnShutdown() {}
|
||||
|
||||
void DetourHostSay(CBaseEntity* pController, CCommand& args, bool teamonly, int unk1,
|
||||
const char* unk2)
|
||||
void DetourHostSay(CEntityInstance* pController, CCommand& args, bool teamonly, int unk1, const char* unk2)
|
||||
{
|
||||
if (pController) {
|
||||
if (pController)
|
||||
{
|
||||
auto pEvent = globals::gameEventManager->CreateEvent("player_chat", true);
|
||||
if (pEvent) {
|
||||
if (pEvent)
|
||||
{
|
||||
pEvent->SetBool("teamonly", teamonly);
|
||||
pEvent->SetInt("userid", pController->GetEntityIndex().Get() - 1);
|
||||
pEvent->SetString("text", args[1]);
|
||||
@@ -72,17 +71,17 @@ void DetourHostSay(CBaseEntity* pController, CCommand& args, bool teamonly, int
|
||||
bool bSilent = globals::coreConfig->IsSilentChatTrigger(args[1], prefix);
|
||||
bool bCommand = globals::coreConfig->IsPublicChatTrigger(args[1], prefix) || bSilent;
|
||||
|
||||
if (!bSilent) {
|
||||
if (!bSilent)
|
||||
{
|
||||
m_pHostSay(pController, args, teamonly, unk1, unk2);
|
||||
}
|
||||
|
||||
if (bCommand)
|
||||
{
|
||||
char *pszMessage = (char *)(args.ArgS() + prefix.length() + 1);
|
||||
char* pszMessage = (char*)(args.ArgS() + prefix.length() + 1);
|
||||
|
||||
// Trailing slashes are only removed if Host_Say has been called.
|
||||
if (bSilent)
|
||||
pszMessage[V_strlen(pszMessage) - 1] = 0;
|
||||
if (bSilent) pszMessage[V_strlen(pszMessage) - 1] = 0;
|
||||
|
||||
CCommand args;
|
||||
args.Tokenize(pszMessage);
|
||||
@@ -90,7 +89,8 @@ void DetourHostSay(CBaseEntity* pController, CCommand& args, bool teamonly, int
|
||||
auto prefixedPhrase = std::string("css_") + args.Arg(0);
|
||||
auto bValidWithPrefix = globals::conCommandManager.IsValidValveCommand(prefixedPhrase.c_str());
|
||||
|
||||
if (bValidWithPrefix) {
|
||||
if (bValidWithPrefix)
|
||||
{
|
||||
// Re-tokenize with a `css_` prefix if we have found that its a valid command.
|
||||
args.Tokenize(("css_" + std::string(pszMessage)).c_str());
|
||||
}
|
||||
@@ -99,30 +99,29 @@ void DetourHostSay(CBaseEntity* pController, CCommand& args, bool teamonly, int
|
||||
}
|
||||
}
|
||||
|
||||
bool ChatManager::OnSayCommandPre(CBaseEntity* pController, CCommand& command) { return false; }
|
||||
bool ChatManager::OnSayCommandPre(CEntityInstance* pController, CCommand& command) { return false; }
|
||||
|
||||
void ChatManager::OnSayCommandPost(CBaseEntity* pController, CCommand& command)
|
||||
void ChatManager::OnSayCommandPost(CEntityInstance* pController, CCommand& command)
|
||||
{
|
||||
auto commandStr = command.Arg(0);
|
||||
|
||||
return InternalDispatch(pController, commandStr, command);
|
||||
}
|
||||
|
||||
void ChatManager::InternalDispatch(CBaseEntity* pPlayerController, const char* szTriggerPhase,
|
||||
CCommand& fullCommand)
|
||||
void ChatManager::InternalDispatch(CEntityInstance* pPlayerController, const char* szTriggerPhase, CCommand& fullCommand)
|
||||
{
|
||||
if (pPlayerController == nullptr) {
|
||||
globals::conCommandManager.ExecuteCommandCallbacks(
|
||||
fullCommand.Arg(0), CCommandContext(CommandTarget_t::CT_NO_TARGET, CPlayerSlot(-1)),
|
||||
fullCommand, HookMode::Pre, CommandCallingContext::Chat);
|
||||
if (pPlayerController == nullptr)
|
||||
{
|
||||
globals::conCommandManager.ExecuteCommandCallbacks(fullCommand.Arg(0),
|
||||
CCommandContext(CommandTarget_t::CT_NO_TARGET, CPlayerSlot(-1)), fullCommand,
|
||||
HookMode::Pre, CommandCallingContext::Chat);
|
||||
return;
|
||||
}
|
||||
|
||||
auto index = pPlayerController->GetEntityIndex().Get();
|
||||
auto slot = CPlayerSlot(index - 1);
|
||||
|
||||
globals::conCommandManager.ExecuteCommandCallbacks(
|
||||
fullCommand.Arg(0), CCommandContext(CommandTarget_t::CT_NO_TARGET, slot), fullCommand,
|
||||
HookMode::Pre, CommandCallingContext::Chat);
|
||||
globals::conCommandManager.ExecuteCommandCallbacks(fullCommand.Arg(0), CCommandContext(CommandTarget_t::CT_NO_TARGET, slot),
|
||||
fullCommand, HookMode::Pre, CommandCallingContext::Chat);
|
||||
}
|
||||
} // namespace counterstrikesharp
|
||||
@@ -19,14 +19,14 @@
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include "core/globals.h"
|
||||
#include "core/global_listener.h"
|
||||
#include "core/globals.h"
|
||||
#include "scripting/script_engine.h"
|
||||
|
||||
namespace counterstrikesharp {
|
||||
class ScriptCallback;
|
||||
|
||||
typedef void (*HostSay)(CBaseEntity*, CCommand&, bool, int, const char*);
|
||||
typedef void (*HostSay)(CEntityInstance*, CCommand&, bool, int, const char*);
|
||||
|
||||
class ChatCommandInfo
|
||||
{
|
||||
@@ -52,18 +52,17 @@ class ChatManager : public GlobalClass
|
||||
void OnAllInitialized() override;
|
||||
void OnShutdown() override;
|
||||
|
||||
bool OnSayCommandPre(CBaseEntity* pController, CCommand& args);
|
||||
void OnSayCommandPost(CBaseEntity* pController, CCommand& args);
|
||||
bool OnSayCommandPre(CEntityInstance* pController, CCommand& args);
|
||||
void OnSayCommandPost(CEntityInstance* pController, CCommand& args);
|
||||
|
||||
private:
|
||||
void InternalDispatch(CBaseEntity* pPlayerController, const char* szTriggerPhrase,
|
||||
CCommand& pFullCommand);
|
||||
void InternalDispatch(CEntityInstance* pPlayerController, const char* szTriggerPhrase, CCommand& pFullCommand);
|
||||
|
||||
std::vector<ChatCommandInfo*> m_cmd_list;
|
||||
std::map<std::string, ChatCommandInfo*> m_cmd_lookup;
|
||||
};
|
||||
|
||||
static void DetourHostSay(CBaseEntity* pController, CCommand& args, bool teamonly, int unk1,
|
||||
const char* unk2);
|
||||
static void DetourHostSay(CEntityInstance* pController, CCommand& args, bool teamonly, int unk1, const char* unk2);
|
||||
static HostSay m_pHostSay = nullptr;
|
||||
|
||||
} // namespace counterstrikesharp
|
||||
@@ -31,21 +31,20 @@
|
||||
|
||||
#include "core/managers/con_command_manager.h"
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <public/eiface.h>
|
||||
#include <schemasystem.h>
|
||||
#include <schematypes.h>
|
||||
#include <sourcehook/sourcehook.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "scripting/callback_manager.h"
|
||||
#include "core/log.h"
|
||||
#include "core/utils.h"
|
||||
#include "core/memory.h"
|
||||
#include "core/utils.h"
|
||||
#include "interfaces/cs2_interfaces.h"
|
||||
#include <schematypes.h>
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <schemasystem.h>
|
||||
|
||||
#include "metamod_oslink.h"
|
||||
#include "scripting/callback_manager.h"
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace counterstrikesharp {
|
||||
@@ -55,30 +54,37 @@ json WriteTypeJson(json obj, CSchemaType* current_type)
|
||||
obj["name"] = current_type->m_sTypeName.Get();
|
||||
obj["category"] = current_type->m_eTypeCategory;
|
||||
|
||||
if (current_type->m_eTypeCategory == SCHEMA_TYPE_ATOMIC) {
|
||||
if (current_type->m_eTypeCategory == SCHEMA_TYPE_ATOMIC)
|
||||
{
|
||||
obj["atomic"] = current_type->m_eAtomicCategory;
|
||||
|
||||
if (current_type->m_eAtomicCategory == SCHEMA_ATOMIC_T) {
|
||||
if (current_type->m_eAtomicCategory == SCHEMA_ATOMIC_T)
|
||||
{
|
||||
auto atomicTType = static_cast<CSchemaType_Atomic_T*>(current_type);
|
||||
|
||||
if (atomicTType->m_pAtomicInfo != nullptr) {
|
||||
if (atomicTType->m_pAtomicInfo != nullptr)
|
||||
{
|
||||
obj["outer"] = atomicTType->m_pAtomicInfo->m_pszName1;
|
||||
}
|
||||
}
|
||||
|
||||
if (current_type->m_eAtomicCategory == SCHEMA_ATOMIC_T ||
|
||||
current_type->m_eAtomicCategory == SCHEMA_ATOMIC_COLLECTION_OF_T) {
|
||||
|
||||
if (current_type->m_eAtomicCategory == SCHEMA_ATOMIC_T || current_type->m_eAtomicCategory == SCHEMA_ATOMIC_COLLECTION_OF_T)
|
||||
{
|
||||
auto atomicType = static_cast<CSchemaType_Atomic_T*>(current_type);
|
||||
|
||||
if (atomicType->GetInnerType().Get() != nullptr) {
|
||||
if (atomicType->GetInnerType().Get() != nullptr)
|
||||
{
|
||||
obj["inner"] = WriteTypeJson(json::object(), atomicType->GetInnerType().Get());
|
||||
}
|
||||
}
|
||||
} else if (current_type->m_eTypeCategory == SCHEMA_TYPE_FIXED_ARRAY) {
|
||||
}
|
||||
else if (current_type->m_eTypeCategory == SCHEMA_TYPE_FIXED_ARRAY)
|
||||
{
|
||||
auto fixedArrayType = static_cast<CSchemaType_FixedArray*>(current_type);
|
||||
obj["inner"] = WriteTypeJson(json::object(), fixedArrayType->m_pElementType);
|
||||
} else if (current_type->m_eTypeCategory == SCHEMA_TYPE_PTR) {
|
||||
}
|
||||
else if (current_type->m_eTypeCategory == SCHEMA_TYPE_PTR)
|
||||
{
|
||||
auto ptrType = static_cast<CSchemaType_Ptr*>(current_type);
|
||||
obj["inner"] = WriteTypeJson(json::object(), ptrType->m_pObjectType);
|
||||
}
|
||||
@@ -97,68 +103,73 @@ CON_COMMAND(dump_schema, "dump schema symbols")
|
||||
std::ofstream output(utils::GamedataDirectory() + "/schema.json");
|
||||
std::string line;
|
||||
|
||||
while (std::getline(inputClasses, line)) {
|
||||
if (!line.empty() && line.back() == '\r') {
|
||||
while (std::getline(inputClasses, line))
|
||||
{
|
||||
if (!line.empty() && line.back() == '\r')
|
||||
{
|
||||
line.pop_back();
|
||||
}
|
||||
classNames.push_back(line);
|
||||
}
|
||||
|
||||
while (std::getline(inputEnums, line)) {
|
||||
if (!line.empty() && line.back() == '\r') {
|
||||
while (std::getline(inputEnums, line))
|
||||
{
|
||||
if (!line.empty() && line.back() == '\r')
|
||||
{
|
||||
line.pop_back();
|
||||
}
|
||||
enumNames.push_back(line);
|
||||
}
|
||||
|
||||
CSchemaSystemTypeScope* pType =
|
||||
globals::schemaSystem->FindTypeScopeForModule(MODULE_PREFIX "server" MODULE_EXT);
|
||||
CSchemaSystemTypeScope* pType = globals::schemaSystem->FindTypeScopeForModule(MODULE_PREFIX "server" MODULE_EXT);
|
||||
|
||||
json j;
|
||||
j["classes"] = json::object();
|
||||
j["enums"] = json::object();
|
||||
|
||||
for (const auto& line : classNames) {
|
||||
for (const auto& line : classNames)
|
||||
{
|
||||
auto* pClassInfo = pType->FindDeclaredClass(line.c_str()).Get();
|
||||
if (!pClassInfo)
|
||||
continue;
|
||||
if (!pClassInfo) continue;
|
||||
|
||||
short fieldsSize = pClassInfo->m_nFieldCount;
|
||||
SchemaClassFieldData_t* pFields = pClassInfo->m_pFields;
|
||||
|
||||
j["classes"][pClassInfo->m_pszName] = json::object();
|
||||
if (pClassInfo->m_pBaseClasses) {
|
||||
j["classes"][pClassInfo->m_pszName]["parent"] =
|
||||
pClassInfo->m_pBaseClasses->m_pClass->m_pszName;
|
||||
if (pClassInfo->m_pBaseClasses)
|
||||
{
|
||||
j["classes"][pClassInfo->m_pszName]["parent"] = pClassInfo->m_pBaseClasses->m_pClass->m_pszName;
|
||||
}
|
||||
|
||||
j["classes"][pClassInfo->m_pszName]["fields"] = json::array();
|
||||
|
||||
for (int i = 0; i < fieldsSize; ++i) {
|
||||
for (int i = 0; i < fieldsSize; ++i)
|
||||
{
|
||||
SchemaClassFieldData_t& field = pFields[i];
|
||||
|
||||
j["classes"][pClassInfo->m_pszName]["fields"].push_back({
|
||||
{"name", field.m_pszName},
|
||||
{"type", WriteTypeJson(json::object(), field.m_pType)},
|
||||
{ "name", field.m_pszName },
|
||||
{ "type", WriteTypeJson(json::object(), field.m_pType) },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& line : enumNames) {
|
||||
for (const auto& line : enumNames)
|
||||
{
|
||||
auto* pEnumInfo = pType->FindDeclaredEnum(line.c_str()).Get();
|
||||
if (!pEnumInfo)
|
||||
continue;
|
||||
if (!pEnumInfo) continue;
|
||||
|
||||
j["enums"][pEnumInfo->m_pszName] = json::object();
|
||||
j["enums"][pEnumInfo->m_pszName]["align"] = pEnumInfo->m_nSize;
|
||||
j["enums"][pEnumInfo->m_pszName]["items"] = json::array();
|
||||
|
||||
for (int i = 0; i < pEnumInfo->m_nEnumeratorCount; ++i) {
|
||||
for (int i = 0; i < pEnumInfo->m_nEnumeratorCount; ++i)
|
||||
{
|
||||
auto& field = pEnumInfo->m_pEnumerators[i];
|
||||
|
||||
j["enums"][pEnumInfo->m_pszName]["items"].push_back({
|
||||
{"name", field.m_pszName},
|
||||
{"value", field.m_nValue},
|
||||
{ "name", field.m_pszName },
|
||||
{ "value", field.m_nValue },
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -167,8 +178,7 @@ CON_COMMAND(dump_schema, "dump schema symbols")
|
||||
output << std::setw(2) << j << std::endl;
|
||||
}
|
||||
|
||||
SH_DECL_HOOK3_void(ICvar, DispatchConCommand, SH_NOATTRIB, 0, ConCommandHandle,
|
||||
const CCommandContext&, const CCommand&);
|
||||
SH_DECL_HOOK3_void(ICvar, DispatchConCommand, SH_NOATTRIB, 0, ConCommandHandle, const CCommandContext&, const CCommand&);
|
||||
|
||||
ConCommandInfo::ConCommandInfo()
|
||||
{
|
||||
@@ -180,9 +190,7 @@ ConCommandInfo::~ConCommandInfo()
|
||||
globals::callbackManager.ReleaseCallback(callback_pre);
|
||||
globals::callbackManager.ReleaseCallback(callback_post);
|
||||
}
|
||||
ConCommandInfo::ConCommandInfo(bool bNoCallbacks) {
|
||||
|
||||
}
|
||||
ConCommandInfo::ConCommandInfo(bool bNoCallbacks) {}
|
||||
|
||||
ConCommandManager::ConCommandManager() {}
|
||||
|
||||
@@ -190,22 +198,17 @@ ConCommandManager::~ConCommandManager() {}
|
||||
|
||||
void ConCommandManager::OnAllInitialized()
|
||||
{
|
||||
SH_ADD_HOOK_MEMFUNC(ICvar, DispatchConCommand, globals::cvars, this,
|
||||
&ConCommandManager::Hook_DispatchConCommand, false);
|
||||
SH_ADD_HOOK_MEMFUNC(ICvar, DispatchConCommand, globals::cvars, this,
|
||||
&ConCommandManager::Hook_DispatchConCommand_Post, true);
|
||||
SH_ADD_HOOK_MEMFUNC(ICvar, DispatchConCommand, globals::cvars, this, &ConCommandManager::Hook_DispatchConCommand, false);
|
||||
SH_ADD_HOOK_MEMFUNC(ICvar, DispatchConCommand, globals::cvars, this, &ConCommandManager::Hook_DispatchConCommand_Post, true);
|
||||
|
||||
m_global_cmd.callback_pre = globals::callbackManager.CreateCallback("OnClientCommandGlobalPre");
|
||||
m_global_cmd.callback_post =
|
||||
globals::callbackManager.CreateCallback("OnClientCommandGlobalPost");
|
||||
m_global_cmd.callback_post = globals::callbackManager.CreateCallback("OnClientCommandGlobalPost");
|
||||
}
|
||||
|
||||
void ConCommandManager::OnShutdown()
|
||||
{
|
||||
SH_REMOVE_HOOK_MEMFUNC(ICvar, DispatchConCommand, globals::cvars, this,
|
||||
&ConCommandManager::Hook_DispatchConCommand, false);
|
||||
SH_REMOVE_HOOK_MEMFUNC(ICvar, DispatchConCommand, globals::cvars, this,
|
||||
&ConCommandManager::Hook_DispatchConCommand_Post, true);
|
||||
SH_REMOVE_HOOK_MEMFUNC(ICvar, DispatchConCommand, globals::cvars, this, &ConCommandManager::Hook_DispatchConCommand, false);
|
||||
SH_REMOVE_HOOK_MEMFUNC(ICvar, DispatchConCommand, globals::cvars, this, &ConCommandManager::Hook_DispatchConCommand_Post, true);
|
||||
|
||||
globals::callbackManager.ReleaseCallback(m_global_cmd.callback_pre);
|
||||
globals::callbackManager.ReleaseCallback(m_global_cmd.callback_post);
|
||||
@@ -219,10 +222,14 @@ void CommandCallback(const CCommandContext& context, const CCommand& command)
|
||||
|
||||
void ConCommandManager::AddCommandListener(const char* name, CallbackT callback, HookMode mode)
|
||||
{
|
||||
if (name == nullptr) {
|
||||
if (mode == HookMode::Pre) {
|
||||
if (name == nullptr)
|
||||
{
|
||||
if (mode == HookMode::Pre)
|
||||
{
|
||||
m_global_cmd.callback_pre->AddListener(callback);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
m_global_cmd.callback_post->AddListener(callback);
|
||||
}
|
||||
return;
|
||||
@@ -231,29 +238,38 @@ void ConCommandManager::AddCommandListener(const char* name, CallbackT callback,
|
||||
auto strName = std::string(name);
|
||||
ConCommandInfo* pInfo = m_cmd_lookup[strName];
|
||||
|
||||
if (!pInfo) {
|
||||
if (!pInfo)
|
||||
{
|
||||
pInfo = new ConCommandInfo();
|
||||
m_cmd_lookup[strName] = pInfo;
|
||||
|
||||
ConCommandHandle hExistingCommand = globals::cvars->FindCommand(name);
|
||||
if (hExistingCommand.IsValid()) {
|
||||
if (hExistingCommand.IsValid())
|
||||
{
|
||||
pInfo->command = globals::cvars->GetCommand(hExistingCommand);
|
||||
}
|
||||
}
|
||||
|
||||
if (mode == HookMode::Pre) {
|
||||
if (mode == HookMode::Pre)
|
||||
{
|
||||
pInfo->callback_pre->AddListener(callback);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
pInfo->callback_post->AddListener(callback);
|
||||
}
|
||||
}
|
||||
|
||||
void ConCommandManager::RemoveCommandListener(const char* name, CallbackT callback, HookMode mode)
|
||||
{
|
||||
if (name == nullptr) {
|
||||
if (mode == HookMode::Pre) {
|
||||
if (name == nullptr)
|
||||
{
|
||||
if (mode == HookMode::Pre)
|
||||
{
|
||||
m_global_cmd.callback_pre->RemoveListener(callback);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
m_global_cmd.callback_post->RemoveListener(callback);
|
||||
}
|
||||
return;
|
||||
@@ -262,31 +278,33 @@ void ConCommandManager::RemoveCommandListener(const char* name, CallbackT callba
|
||||
auto strName = std::string(name);
|
||||
ConCommandInfo* pInfo = m_cmd_lookup[strName];
|
||||
|
||||
if (!pInfo) {
|
||||
if (!pInfo)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (mode == HookMode::Pre) {
|
||||
if (mode == HookMode::Pre)
|
||||
{
|
||||
pInfo->callback_pre->RemoveListener(callback);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
pInfo->callback_post->RemoveListener(callback);
|
||||
}
|
||||
}
|
||||
|
||||
bool ConCommandManager::AddValveCommand(const char* name, const char* description, bool server_only,
|
||||
int flags)
|
||||
bool ConCommandManager::AddValveCommand(const char* name, const char* description, bool server_only, int flags)
|
||||
{
|
||||
ConCommandHandle hExistingCommand = globals::cvars->FindCommand(name);
|
||||
if (hExistingCommand.IsValid())
|
||||
return false;
|
||||
if (hExistingCommand.IsValid()) return false;
|
||||
|
||||
ConCommandRefAbstract conCommandRefAbstract;
|
||||
auto conCommand =
|
||||
new ConCommand(&conCommandRefAbstract, strdup(name), CommandCallback, strdup(description), flags);
|
||||
auto conCommand = new ConCommand(&conCommandRefAbstract, strdup(name), CommandCallback, description ? strdup(description) : "", flags);
|
||||
|
||||
ConCommandInfo* pInfo = m_cmd_lookup[std::string(name)];
|
||||
|
||||
if (!pInfo) {
|
||||
if (!pInfo)
|
||||
{
|
||||
pInfo = new ConCommandInfo();
|
||||
m_cmd_lookup[std::string(name)] = pInfo;
|
||||
}
|
||||
@@ -302,14 +320,16 @@ bool ConCommandManager::RemoveValveCommand(const char* name)
|
||||
{
|
||||
auto hFoundCommand = globals::cvars->FindCommand(name);
|
||||
|
||||
if (!hFoundCommand.IsValid()) {
|
||||
if (!hFoundCommand.IsValid())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
globals::cvars->UnregisterConCommand(hFoundCommand);
|
||||
|
||||
auto pInfo = m_cmd_lookup[std::string(name)];
|
||||
if (!pInfo) {
|
||||
if (!pInfo)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -318,11 +338,10 @@ bool ConCommandManager::RemoveValveCommand(const char* name)
|
||||
return true;
|
||||
}
|
||||
|
||||
HookResult ConCommandManager::ExecuteCommandCallbacks(const char* name, const CCommandContext& ctx,
|
||||
const CCommand& args, HookMode mode, CommandCallingContext callingContext)
|
||||
HookResult ConCommandManager::ExecuteCommandCallbacks(
|
||||
const char* name, const CCommandContext& ctx, const CCommand& args, HookMode mode, CommandCallingContext callingContext)
|
||||
{
|
||||
CSSHARP_CORE_TRACE("[ConCommandManager::ExecuteCommandCallbacks][{}]: {}",
|
||||
mode == Pre ? "Pre" : "Post", name);
|
||||
CSSHARP_CORE_TRACE("[ConCommandManager::ExecuteCommandCallbacks][{}]: {}", mode == Pre ? "Pre" : "Post", name);
|
||||
ConCommandInfo* pInfo = m_cmd_lookup[std::string(name)];
|
||||
|
||||
HookResult result = HookResult::Continue;
|
||||
@@ -331,20 +350,23 @@ HookResult ConCommandManager::ExecuteCommandCallbacks(const char* name, const CC
|
||||
|
||||
m_cmd_contexts[&args] = callingContext;
|
||||
|
||||
if (globalCallback->GetFunctionCount() > 0) {
|
||||
if (globalCallback->GetFunctionCount() > 0)
|
||||
{
|
||||
globalCallback->ScriptContext().Reset();
|
||||
globalCallback->ScriptContext().Push(ctx.GetPlayerSlot().Get());
|
||||
globalCallback->ScriptContext().Push(&args);
|
||||
|
||||
for (auto fnMethodToCall : globalCallback->GetFunctions()) {
|
||||
if (!fnMethodToCall)
|
||||
continue;
|
||||
for (auto fnMethodToCall : globalCallback->GetFunctions())
|
||||
{
|
||||
if (!fnMethodToCall) continue;
|
||||
fnMethodToCall(&globalCallback->ScriptContextStruct());
|
||||
|
||||
auto hookResult = globalCallback->ScriptContext().GetResult<HookResult>();
|
||||
|
||||
if (hookResult >= HookResult::Stop) {
|
||||
if (mode == HookMode::Pre) {
|
||||
if (hookResult >= HookResult::Stop)
|
||||
{
|
||||
if (mode == HookMode::Pre)
|
||||
{
|
||||
return HookResult::Stop;
|
||||
}
|
||||
|
||||
@@ -352,13 +374,15 @@ HookResult ConCommandManager::ExecuteCommandCallbacks(const char* name, const CC
|
||||
break;
|
||||
}
|
||||
|
||||
if (hookResult >= HookResult::Handled) {
|
||||
if (hookResult >= HookResult::Handled)
|
||||
{
|
||||
result = hookResult;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!pInfo) {
|
||||
if (!pInfo)
|
||||
{
|
||||
m_cmd_contexts.erase(&args);
|
||||
return result;
|
||||
}
|
||||
@@ -369,17 +393,20 @@ HookResult ConCommandManager::ExecuteCommandCallbacks(const char* name, const CC
|
||||
pCallback->ScriptContext().Push(ctx.GetPlayerSlot().Get());
|
||||
pCallback->ScriptContext().Push(&args);
|
||||
|
||||
for (auto fnMethodToCall : pCallback->GetFunctions()) {
|
||||
if (!fnMethodToCall)
|
||||
continue;
|
||||
for (auto fnMethodToCall : pCallback->GetFunctions())
|
||||
{
|
||||
if (!fnMethodToCall) continue;
|
||||
fnMethodToCall(&pCallback->ScriptContextStruct());
|
||||
|
||||
auto thisResult = pCallback->ScriptContext().GetResult<HookResult>();
|
||||
|
||||
if (thisResult >= HookResult::Handled) {
|
||||
if (thisResult >= HookResult::Handled)
|
||||
{
|
||||
m_cmd_contexts.erase(&args);
|
||||
return thisResult;
|
||||
} else if (thisResult > result) {
|
||||
}
|
||||
else if (thisResult > result)
|
||||
{
|
||||
result = thisResult;
|
||||
}
|
||||
}
|
||||
@@ -389,36 +416,34 @@ HookResult ConCommandManager::ExecuteCommandCallbacks(const char* name, const CC
|
||||
return result;
|
||||
}
|
||||
|
||||
void ConCommandManager::Hook_DispatchConCommand(ConCommandHandle cmd, const CCommandContext& ctx,
|
||||
const CCommand& args)
|
||||
void ConCommandManager::Hook_DispatchConCommand(ConCommandHandle cmd, const CCommandContext& ctx, const CCommand& args)
|
||||
{
|
||||
const char* name = args.Arg(0);
|
||||
|
||||
CSSHARP_CORE_TRACE("[ConCommandManager::Hook_DispatchConCommand]: {}", name);
|
||||
|
||||
auto result = ExecuteCommandCallbacks(name, ctx, args, HookMode::Pre, CommandCallingContext::Console);
|
||||
if (result >= HookResult::Handled) {
|
||||
if (result >= HookResult::Handled)
|
||||
{
|
||||
RETURN_META(MRES_SUPERCEDE);
|
||||
}
|
||||
}
|
||||
void ConCommandManager::Hook_DispatchConCommand_Post(ConCommandHandle cmd,
|
||||
const CCommandContext& ctx,
|
||||
const CCommand& args)
|
||||
void ConCommandManager::Hook_DispatchConCommand_Post(ConCommandHandle cmd, const CCommandContext& ctx, const CCommand& args)
|
||||
{
|
||||
const char* name = args.Arg(0);
|
||||
|
||||
auto result = ExecuteCommandCallbacks(name, ctx, args, HookMode::Post, CommandCallingContext::Console);
|
||||
if (result >= HookResult::Handled) {
|
||||
if (result >= HookResult::Handled)
|
||||
{
|
||||
RETURN_META(MRES_SUPERCEDE);
|
||||
}
|
||||
}
|
||||
bool ConCommandManager::IsValidValveCommand(const char* name) {
|
||||
bool ConCommandManager::IsValidValveCommand(const char* name)
|
||||
{
|
||||
ConCommandHandle pCmd = globals::cvars->FindCommand(name);
|
||||
return pCmd.IsValid();
|
||||
}
|
||||
|
||||
CommandCallingContext ConCommandManager::GetCommandCallingContext(CCommand* args) {
|
||||
return m_cmd_contexts[args];
|
||||
}
|
||||
CommandCallingContext ConCommandManager::GetCommandCallingContext(CCommand* args) { return m_cmd_contexts[args]; }
|
||||
|
||||
} // namespace counterstrikesharp
|
||||
@@ -15,15 +15,15 @@
|
||||
*/
|
||||
|
||||
#include "core/managers/voice_manager.h"
|
||||
#include "core/managers/player_manager.h"
|
||||
|
||||
#include <public/eiface.h>
|
||||
#include "scripting/callback_manager.h"
|
||||
#include <schema.h>
|
||||
#include <entity2/entitysystem.h>
|
||||
#include <public/eiface.h>
|
||||
#include <schema.h>
|
||||
|
||||
SH_DECL_HOOK3(IVEngineServer2, SetClientListening, SH_NOATTRIB, 0, bool, CPlayerSlot, CPlayerSlot,
|
||||
bool);
|
||||
#include "core/managers/player_manager.h"
|
||||
#include "scripting/callback_manager.h"
|
||||
|
||||
SH_DECL_HOOK3(IVEngineServer2, SetClientListening, SH_NOATTRIB, 0, bool, CPlayerSlot, CPlayerSlot, bool);
|
||||
|
||||
namespace counterstrikesharp {
|
||||
|
||||
@@ -33,14 +33,12 @@ VoiceManager::~VoiceManager() {}
|
||||
|
||||
void VoiceManager::OnAllInitialized()
|
||||
{
|
||||
SH_ADD_HOOK(IVEngineServer2, SetClientListening, globals::engine,
|
||||
SH_MEMBER(this, &VoiceManager::SetClientListening), false);
|
||||
SH_ADD_HOOK(IVEngineServer2, SetClientListening, globals::engine, SH_MEMBER(this, &VoiceManager::SetClientListening), false);
|
||||
}
|
||||
|
||||
void VoiceManager::OnShutdown()
|
||||
{
|
||||
SH_REMOVE_HOOK(IVEngineServer2, SetClientListening, globals::engine,
|
||||
SH_MEMBER(this, &VoiceManager::SetClientListening), false);
|
||||
SH_REMOVE_HOOK(IVEngineServer2, SetClientListening, globals::engine, SH_MEMBER(this, &VoiceManager::SetClientListening), false);
|
||||
}
|
||||
|
||||
bool VoiceManager::SetClientListening(CPlayerSlot iReceiver, CPlayerSlot iSender, bool bListen)
|
||||
@@ -56,28 +54,26 @@ bool VoiceManager::SetClientListening(CPlayerSlot iReceiver, CPlayerSlot iSender
|
||||
|
||||
if (pReceiver->m_selfMutes->Get(iSender.Get()))
|
||||
{
|
||||
RETURN_META_VALUE_NEWPARAMS(MRES_IGNORED, bListen, &IVEngineServer2::SetClientListening,
|
||||
(iReceiver, iSender, false));
|
||||
RETURN_META_VALUE_NEWPARAMS(MRES_IGNORED, bListen, &IVEngineServer2::SetClientListening, (iReceiver, iSender, false));
|
||||
}
|
||||
|
||||
if (senderFlags & Speak_Muted)
|
||||
{
|
||||
RETURN_META_VALUE_NEWPARAMS(MRES_IGNORED, bListen, &IVEngineServer2::SetClientListening,
|
||||
(iReceiver, iSender, false));
|
||||
RETURN_META_VALUE_NEWPARAMS(MRES_IGNORED, bListen, &IVEngineServer2::SetClientListening, (iReceiver, iSender, false));
|
||||
}
|
||||
|
||||
if (listenOverride == Listen_Mute)
|
||||
{
|
||||
RETURN_META_VALUE_NEWPARAMS(MRES_IGNORED, bListen, &IVEngineServer2::SetClientListening,
|
||||
(iReceiver, iSender, false));
|
||||
} else if (listenOverride == Listen_Hear) {
|
||||
RETURN_META_VALUE_NEWPARAMS(MRES_IGNORED, bListen, &IVEngineServer2::SetClientListening,
|
||||
(iReceiver, iSender, true));
|
||||
RETURN_META_VALUE_NEWPARAMS(MRES_IGNORED, bListen, &IVEngineServer2::SetClientListening, (iReceiver, iSender, false));
|
||||
}
|
||||
else if (listenOverride == Listen_Hear)
|
||||
{
|
||||
RETURN_META_VALUE_NEWPARAMS(MRES_IGNORED, bListen, &IVEngineServer2::SetClientListening, (iReceiver, iSender, true));
|
||||
}
|
||||
|
||||
if ((senderFlags & Speak_All) || (receiverFlags & Speak_ListenAll)) {
|
||||
RETURN_META_VALUE_NEWPARAMS(MRES_IGNORED, bListen, &IVEngineServer2::SetClientListening,
|
||||
(iReceiver, iSender, true));
|
||||
if ((senderFlags & Speak_All) || (receiverFlags & Speak_ListenAll))
|
||||
{
|
||||
RETURN_META_VALUE_NEWPARAMS(MRES_IGNORED, bListen, &IVEngineServer2::SetClientListening, (iReceiver, iSender, true));
|
||||
}
|
||||
|
||||
if ((senderFlags & Speak_Team) || (receiverFlags & Speak_ListenTeam))
|
||||
@@ -86,19 +82,16 @@ bool VoiceManager::SetClientListening(CPlayerSlot iReceiver, CPlayerSlot iSender
|
||||
static auto memberKey = hash_32_fnv1a_const("m_iTeamNum");
|
||||
const static auto m_key = schema::GetOffset("CBaseEntity", classKey, "m_iTeamNum", memberKey);
|
||||
|
||||
auto receiverController = globals::entitySystem->GetBaseEntity(CEntityIndex(iReceiver.Get() + 1));
|
||||
auto senderController = globals::entitySystem->GetBaseEntity(CEntityIndex(iSender.Get() + 1));
|
||||
auto receiverController = globals::entitySystem->GetEntityInstance(CEntityIndex(iReceiver.Get() + 1));
|
||||
auto senderController = globals::entitySystem->GetEntityInstance(CEntityIndex(iSender.Get() + 1));
|
||||
|
||||
if (receiverController && senderController)
|
||||
{
|
||||
auto receiverTeam = *reinterpret_cast<std::add_pointer_t<unsigned int>>(
|
||||
(uintptr_t)(receiverController) + m_key.offset);
|
||||
auto receiverTeam = *reinterpret_cast<std::add_pointer_t<unsigned int>>((uintptr_t)(receiverController) + m_key.offset);
|
||||
|
||||
auto senderTeam = *reinterpret_cast<std::add_pointer_t<unsigned int>>(
|
||||
(uintptr_t)(senderController) + m_key.offset);
|
||||
auto senderTeam = *reinterpret_cast<std::add_pointer_t<unsigned int>>((uintptr_t)(senderController) + m_key.offset);
|
||||
|
||||
RETURN_META_VALUE_NEWPARAMS(MRES_IGNORED, bListen,
|
||||
&IVEngineServer2::SetClientListening,
|
||||
RETURN_META_VALUE_NEWPARAMS(MRES_IGNORED, bListen, &IVEngineServer2::SetClientListening,
|
||||
(iReceiver, iSender, receiverTeam == senderTeam));
|
||||
}
|
||||
}
|
||||
@@ -111,17 +104,16 @@ void VoiceManager::OnClientCommand(CPlayerSlot slot, const CCommand& args)
|
||||
{
|
||||
auto pPlayer = globals::playerManager.GetPlayerBySlot(slot.Get());
|
||||
|
||||
if (!pPlayer)
|
||||
return;
|
||||
if (!pPlayer) return;
|
||||
|
||||
if (args.ArgC() > 1 && stricmp(args.Arg(0), "vban") == 0)
|
||||
{
|
||||
// clients just refuse to send vban for indexes over 32 and all 4 fields are just the same number, so we only get the first one
|
||||
//for (int i = 1; (i < args.ArgC()) && (i < 3); i++) {
|
||||
unsigned int mask = 0;
|
||||
sscanf(args.Arg(1), "%x", &mask);
|
||||
// for (int i = 1; (i < args.ArgC()) && (i < 3); i++) {
|
||||
unsigned int mask = 0;
|
||||
sscanf(args.Arg(1), "%x", &mask);
|
||||
|
||||
pPlayer->m_selfMutes->SetDWord(0, mask);
|
||||
pPlayer->m_selfMutes->SetDWord(0, mask);
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,97 +1,86 @@
|
||||
#include "core/memory_module.h"
|
||||
#include "core/globals.h"
|
||||
#include "platform.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <filesystem>
|
||||
#include <memory>
|
||||
#include <string_view>
|
||||
#include <algorithm>
|
||||
|
||||
#include "core/globals.h"
|
||||
#include "platform.h"
|
||||
|
||||
#if _WIN32
|
||||
#include <Psapi.h>
|
||||
#include <winternl.h>
|
||||
#else
|
||||
#include <link.h>
|
||||
#include <elf.h>
|
||||
#include <link.h>
|
||||
#endif
|
||||
|
||||
#include "dbg.h"
|
||||
#include "log.h"
|
||||
#include "core/gameconfig.h"
|
||||
#include "core/memory.h"
|
||||
#include "dbg.h"
|
||||
#include "log.h"
|
||||
#include "metamod_oslink.h"
|
||||
|
||||
namespace counterstrikesharp::modules {
|
||||
void Initialize()
|
||||
{
|
||||
if (!moduleList.empty())
|
||||
return;
|
||||
if (!moduleList.empty()) return;
|
||||
|
||||
#ifdef _WIN32
|
||||
// walk through peb to get modules
|
||||
const auto pteb = reinterpret_cast<PTEB>(
|
||||
__readgsqword(reinterpret_cast<DWORD_PTR>(&static_cast<NT_TIB*>(nullptr)->Self)));
|
||||
const auto pteb = reinterpret_cast<PTEB>(__readgsqword(reinterpret_cast<DWORD_PTR>(&static_cast<NT_TIB*>(nullptr)->Self)));
|
||||
const auto peb = pteb->ProcessEnvironmentBlock;
|
||||
|
||||
for (auto entry = peb->Ldr->InMemoryOrderModuleList.Flink;
|
||||
entry != &peb->Ldr->InMemoryOrderModuleList; entry = entry->Flink) {
|
||||
const auto module_entry =
|
||||
CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
|
||||
for (auto entry = peb->Ldr->InMemoryOrderModuleList.Flink; entry != &peb->Ldr->InMemoryOrderModuleList; entry = entry->Flink)
|
||||
{
|
||||
const auto module_entry = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
|
||||
|
||||
std::wstring_view w_name = module_entry->FullDllName.Buffer;
|
||||
|
||||
// a hack way to do so
|
||||
std::string name(w_name.begin(), w_name.end());
|
||||
|
||||
std::ranges::replace(name, '\\', '/');
|
||||
std::replace(name.begin(), name.end(), '\\', '/');
|
||||
|
||||
// check for extension first
|
||||
if (!name.ends_with(MODULE_EXT))
|
||||
continue;
|
||||
if (name.rfind(MODULE_EXT) != name.length() - strlen(MODULE_EXT)) continue;
|
||||
|
||||
// no addons
|
||||
if (name.find(R"(csgo/addons/)") != std::string::npos)
|
||||
continue;
|
||||
if (name.find(R"(csgo/addons/)") != std::string::npos) continue;
|
||||
|
||||
// we need only modules from ROOTBIN and GAMEBIN
|
||||
bool isFromRootBin = name.find(ROOTBIN) != std::string::npos;
|
||||
bool isFromGameBin = name.find(GAMEBIN) != std::string::npos;
|
||||
if (!isFromGameBin && !isFromRootBin)
|
||||
continue;
|
||||
if (!isFromGameBin && !isFromRootBin) continue;
|
||||
|
||||
auto mod = std::make_unique<CModule>(
|
||||
name, reinterpret_cast<std::uintptr_t>(module_entry->DllBase));
|
||||
auto mod = std::make_unique<CModule>(name, reinterpret_cast<std::uintptr_t>(module_entry->DllBase));
|
||||
// it will delete itself after going out of scope
|
||||
if (!mod->IsInitialized())
|
||||
continue;
|
||||
if (!mod->IsInitialized()) continue;
|
||||
|
||||
moduleList.emplace_back(std::move(mod));
|
||||
}
|
||||
#else
|
||||
dl_iterate_phdr(
|
||||
[](struct dl_phdr_info* info, size_t, void*) {
|
||||
std::string name = info->dlpi_name;
|
||||
std::string name = info->dlpi_name;
|
||||
|
||||
if (!name.ends_with(MODULE_EXT))
|
||||
return 0;
|
||||
if (name.rfind(MODULE_EXT) != name.length() - strlen(MODULE_EXT)) return 0;
|
||||
|
||||
if (name.find("csgo/addons") != std::string::npos)
|
||||
return 0;
|
||||
if (name.find("csgo/addons") != std::string::npos) return 0;
|
||||
|
||||
bool isFromRootBin = name.find(ROOTBIN) != std::string::npos;
|
||||
bool isFromGameBin = name.find(GAMEBIN) != std::string::npos;
|
||||
if (!isFromGameBin && !isFromRootBin)
|
||||
return 0;
|
||||
bool isFromRootBin = name.find(ROOTBIN) != std::string::npos;
|
||||
bool isFromGameBin = name.find(GAMEBIN) != std::string::npos;
|
||||
if (!isFromGameBin && !isFromRootBin) return 0;
|
||||
|
||||
auto mod = std::make_unique<CModule>(name, info);
|
||||
if (!mod->IsInitialized())
|
||||
return 0;
|
||||
auto mod = std::make_unique<CModule>(name, info);
|
||||
if (!mod->IsInitialized()) return 0;
|
||||
|
||||
moduleList.emplace_back(std::move(mod));
|
||||
return 0;
|
||||
},
|
||||
moduleList.emplace_back(std::move(mod));
|
||||
return 0;
|
||||
},
|
||||
nullptr);
|
||||
#endif
|
||||
}
|
||||
@@ -100,14 +89,16 @@ CModule* GetModuleByName(std::string name)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
// or add this in GetGameDirectory()?
|
||||
std::ranges::replace(name, '\\', '/');
|
||||
std::replace(name.begin(), name.end(), '\\', '/');
|
||||
#endif
|
||||
|
||||
const auto it = std::ranges::find_if(moduleList, [name](const std::unique_ptr<CModule>& i) {
|
||||
return name.ends_with(i->m_pszModule);
|
||||
const auto it = std::find_if(moduleList.begin(), moduleList.end(), [&name](const std::unique_ptr<CModule>& i) {
|
||||
return !i->m_pszModule.empty() && name.size() >= i->m_pszModule.size() &&
|
||||
name.substr(name.size() - i->m_pszModule.size()) == i->m_pszModule;
|
||||
});
|
||||
|
||||
if (it == moduleList.end()) {
|
||||
if (it == moduleList.end())
|
||||
{
|
||||
CSSHARP_CORE_ERROR("Cannot find module {}", name);
|
||||
|
||||
return nullptr;
|
||||
@@ -125,12 +116,14 @@ constexpr std::array modules_to_read_from_disk = {
|
||||
CModule::CModule(std::string_view path, std::uint64_t base)
|
||||
{
|
||||
const auto dos_header = reinterpret_cast<PIMAGE_DOS_HEADER>(base);
|
||||
if (dos_header->e_magic != IMAGE_DOS_SIGNATURE) {
|
||||
if (dos_header->e_magic != IMAGE_DOS_SIGNATURE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const auto nt_header = reinterpret_cast<PIMAGE_NT_HEADERS>(base + dos_header->e_lfanew);
|
||||
if (nt_header->Signature != IMAGE_NT_SIGNATURE) {
|
||||
if (nt_header->Signature != IMAGE_NT_SIGNATURE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -140,13 +133,16 @@ CModule::CModule(std::string_view path, std::uint64_t base)
|
||||
m_baseAddress = base;
|
||||
m_size = nt_header->OptionalHeader.SizeOfImage;
|
||||
|
||||
const bool should_read_from_disk = std::ranges::any_of(modules_to_read_from_disk,
|
||||
[&](const auto& i) { return m_pszModule == i; });
|
||||
const bool should_read_from_disk = std::any_of(modules_to_read_from_disk.begin(), modules_to_read_from_disk.end(), [&](const auto& i) {
|
||||
return m_pszModule == i;
|
||||
});
|
||||
|
||||
std::vector<std::uint8_t> disk_data{};
|
||||
if (should_read_from_disk) {
|
||||
if (should_read_from_disk)
|
||||
{
|
||||
std::ifstream stream(m_pszPath, std::ios::in | std::ios::binary);
|
||||
if (!stream.good()) {
|
||||
if (!stream.good())
|
||||
{
|
||||
CSSHARP_CORE_ERROR("Cannot open file {}", m_pszPath);
|
||||
return;
|
||||
}
|
||||
@@ -156,11 +152,13 @@ CModule::CModule(std::string_view path, std::uint64_t base)
|
||||
|
||||
auto section = IMAGE_FIRST_SECTION(nt_header);
|
||||
|
||||
for (auto i = 0; i < nt_header->FileHeader.NumberOfSections; i++, section++) {
|
||||
for (auto i = 0; i < nt_header->FileHeader.NumberOfSections; i++, section++)
|
||||
{
|
||||
const auto is_executable = (section->Characteristics & IMAGE_SCN_MEM_EXECUTE) != 0;
|
||||
const auto is_readable = (section->Characteristics & IMAGE_SCN_MEM_READ) != 0;
|
||||
|
||||
if (is_executable && is_readable) {
|
||||
if (is_executable && is_readable)
|
||||
{
|
||||
const auto start = this->m_baseAddress + section->VirtualAddress;
|
||||
const auto size = (std::min)(section->SizeOfRawData, section->Misc.VirtualSize);
|
||||
const auto data = reinterpret_cast<std::uint8_t*>(start);
|
||||
@@ -170,8 +168,10 @@ CModule::CModule(std::string_view path, std::uint64_t base)
|
||||
segment.address = start;
|
||||
segment.bytes.reserve(size);
|
||||
|
||||
if (should_read_from_disk) {
|
||||
if (auto bytes = GetOriginalBytes(disk_data, start - m_baseAddress, size)) {
|
||||
if (should_read_from_disk)
|
||||
{
|
||||
if (auto bytes = GetOriginalBytes(disk_data, start - m_baseAddress, size))
|
||||
{
|
||||
CSSHARP_CORE_INFO("Copying bytes from disk for {}", m_pszPath);
|
||||
segment.bytes = bytes.value();
|
||||
continue;
|
||||
@@ -186,8 +186,7 @@ CModule::CModule(std::string_view path, std::uint64_t base)
|
||||
|
||||
DumpSymbols();
|
||||
|
||||
if (m_fnCreateInterface == nullptr)
|
||||
return;
|
||||
if (m_fnCreateInterface == nullptr) return;
|
||||
|
||||
m_bInitialized = true;
|
||||
}
|
||||
@@ -198,13 +197,16 @@ CModule::CModule(std::string_view path, dl_phdr_info* info)
|
||||
m_pszPath = path.data();
|
||||
m_baseAddress = info->dlpi_addr;
|
||||
|
||||
const bool should_read_from_disk = std::ranges::any_of(modules_to_read_from_disk,
|
||||
[&](const auto& i) { return m_pszModule == i; });
|
||||
const bool should_read_from_disk = std::any_of(modules_to_read_from_disk.begin(), modules_to_read_from_disk.end(), [&](const auto& i) {
|
||||
return m_pszModule == i;
|
||||
});
|
||||
|
||||
std::vector<std::uint8_t> disk_data{};
|
||||
if (should_read_from_disk) {
|
||||
if (should_read_from_disk)
|
||||
{
|
||||
std::ifstream stream(m_pszPath, std::ios::in | std::ios::binary);
|
||||
if (!stream.good()) {
|
||||
if (!stream.good())
|
||||
{
|
||||
CSSHARP_CORE_ERROR("Cannot open file {}", m_pszPath);
|
||||
return;
|
||||
}
|
||||
@@ -212,25 +214,25 @@ CModule::CModule(std::string_view path, dl_phdr_info* info)
|
||||
disk_data.assign((std::istreambuf_iterator(stream)), std::istreambuf_iterator<char>());
|
||||
}
|
||||
|
||||
for (auto i = 0; i < info->dlpi_phnum; i++) {
|
||||
for (auto i = 0; i < info->dlpi_phnum; i++)
|
||||
{
|
||||
auto address = m_baseAddress + info->dlpi_phdr[i].p_paddr;
|
||||
auto type = info->dlpi_phdr[i].p_type;
|
||||
auto is_dynamic_section = type == PT_DYNAMIC;
|
||||
if (is_dynamic_section) {
|
||||
if (is_dynamic_section)
|
||||
{
|
||||
DumpSymbols(reinterpret_cast<ElfW(Dyn)*>(address));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (type != PT_LOAD)
|
||||
continue;
|
||||
if (type != PT_LOAD) continue;
|
||||
|
||||
auto flags = info->dlpi_phdr[i].p_flags;
|
||||
|
||||
auto is_executable = (flags & PF_X) != 0;
|
||||
auto is_readable = (flags & PF_R) != 0;
|
||||
|
||||
if (!is_executable || !is_readable)
|
||||
continue;
|
||||
if (!is_executable || !is_readable) continue;
|
||||
|
||||
auto size = info->dlpi_phdr[i].p_filesz;
|
||||
auto* data = reinterpret_cast<std::uint8_t*>(address);
|
||||
@@ -240,8 +242,10 @@ CModule::CModule(std::string_view path, dl_phdr_info* info)
|
||||
segment.address = address;
|
||||
segment.bytes.reserve(size);
|
||||
|
||||
if (should_read_from_disk) {
|
||||
if (auto bytes = GetOriginalBytes(disk_data, address - m_baseAddress, size)) {
|
||||
if (should_read_from_disk)
|
||||
{
|
||||
if (auto bytes = GetOriginalBytes(disk_data, address - m_baseAddress, size))
|
||||
{
|
||||
CSSHARP_CORE_INFO("Copying bytes from disk for {}", m_pszPath);
|
||||
segment.bytes = bytes.value();
|
||||
continue;
|
||||
@@ -253,8 +257,7 @@ CModule::CModule(std::string_view path, dl_phdr_info* info)
|
||||
segment.bytes.assign(&data[0], &data[size]);
|
||||
}
|
||||
|
||||
if (m_fnCreateInterface == nullptr)
|
||||
return;
|
||||
if (m_fnCreateInterface == nullptr) return;
|
||||
|
||||
m_bInitialized = true;
|
||||
}
|
||||
@@ -265,24 +268,18 @@ void CModule::DumpSymbols()
|
||||
{
|
||||
const auto dos_header = reinterpret_cast<PIMAGE_DOS_HEADER>(m_baseAddress);
|
||||
|
||||
const auto nt_header = reinterpret_cast<PIMAGE_NT_HEADERS>(
|
||||
reinterpret_cast<std::uint8_t*>(m_baseAddress) + dos_header->e_lfanew);
|
||||
const auto nt_header = reinterpret_cast<PIMAGE_NT_HEADERS>(reinterpret_cast<std::uint8_t*>(m_baseAddress) + dos_header->e_lfanew);
|
||||
|
||||
const auto [export_address_rva, export_size] =
|
||||
nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
|
||||
if (export_size == 0 || export_address_rva == 0)
|
||||
return;
|
||||
const auto [export_address_rva, export_size] = nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
|
||||
if (export_size == 0 || export_address_rva == 0) return;
|
||||
|
||||
auto export_directory =
|
||||
reinterpret_cast<IMAGE_EXPORT_DIRECTORY*>(m_baseAddress + export_address_rva);
|
||||
const auto names =
|
||||
reinterpret_cast<uint32_t*>(m_baseAddress + export_directory->AddressOfNames);
|
||||
const auto addresses =
|
||||
reinterpret_cast<uint32_t*>(m_baseAddress + export_directory->AddressOfFunctions);
|
||||
const auto ordinals =
|
||||
reinterpret_cast<std::uint16_t*>(m_baseAddress + export_directory->AddressOfNameOrdinals);
|
||||
auto export_directory = reinterpret_cast<IMAGE_EXPORT_DIRECTORY*>(m_baseAddress + export_address_rva);
|
||||
const auto names = reinterpret_cast<uint32_t*>(m_baseAddress + export_directory->AddressOfNames);
|
||||
const auto addresses = reinterpret_cast<uint32_t*>(m_baseAddress + export_directory->AddressOfFunctions);
|
||||
const auto ordinals = reinterpret_cast<std::uint16_t*>(m_baseAddress + export_directory->AddressOfNameOrdinals);
|
||||
|
||||
for (auto i = 0ull; i < export_directory->NumberOfNames; i++) {
|
||||
for (auto i = 0ull; i < export_directory->NumberOfNames; i++)
|
||||
{
|
||||
const auto export_name = reinterpret_cast<const char*>(m_baseAddress + names[i]);
|
||||
const auto address = m_baseAddress + addresses[ordinals[i]];
|
||||
|
||||
@@ -290,7 +287,8 @@ void CModule::DumpSymbols()
|
||||
address < reinterpret_cast<uintptr_t>(export_directory) + export_size)
|
||||
continue;
|
||||
|
||||
if (std::string_view(export_name) == "CreateInterface") {
|
||||
if (std::string_view(export_name) == "CreateInterface")
|
||||
{
|
||||
m_fnCreateInterface = reinterpret_cast<fnCreateInterface>(address);
|
||||
}
|
||||
|
||||
@@ -313,33 +311,36 @@ void CModule::DumpSymbols(ElfW(Dyn) * dyn)
|
||||
};
|
||||
|
||||
auto header = (Header*)gnuHashAddress;
|
||||
const auto bucketsAddress =
|
||||
gnuHashAddress + sizeof(Header) + (sizeof(std::uintptr_t) * header->bloom_size);
|
||||
const auto bucketsAddress = gnuHashAddress + sizeof(Header) + (sizeof(std::uintptr_t) * header->bloom_size);
|
||||
|
||||
// Locate the chain that handles the largest index bucket.
|
||||
uint32_t lastSymbol = 0;
|
||||
auto bucketAddress = (uint32_t*)bucketsAddress;
|
||||
for (uint32_t i = 0; i < header->nbuckets; ++i) {
|
||||
for (uint32_t i = 0; i < header->nbuckets; ++i)
|
||||
{
|
||||
uint32_t bucket = *bucketAddress;
|
||||
if (lastSymbol < bucket) {
|
||||
if (lastSymbol < bucket)
|
||||
{
|
||||
lastSymbol = bucket;
|
||||
}
|
||||
bucketAddress++;
|
||||
}
|
||||
|
||||
if (lastSymbol < header->symoffset) {
|
||||
if (lastSymbol < header->symoffset)
|
||||
{
|
||||
return header->symoffset;
|
||||
}
|
||||
|
||||
// Walk the bucket's chain to add the chain length to the total.
|
||||
const auto chainBaseAddress = bucketsAddress + (sizeof(uint32_t) * header->nbuckets);
|
||||
for (;;) {
|
||||
auto chainEntry =
|
||||
(uint32_t*)(chainBaseAddress + (lastSymbol - header->symoffset) * sizeof(uint32_t));
|
||||
for (;;)
|
||||
{
|
||||
auto chainEntry = (uint32_t*)(chainBaseAddress + (lastSymbol - header->symoffset) * sizeof(uint32_t));
|
||||
lastSymbol++;
|
||||
|
||||
// If the low bit is set, this entry is the end of the chain.
|
||||
if (*chainEntry & 1) {
|
||||
if (*chainEntry & 1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -353,34 +354,46 @@ void CModule::DumpSymbols(ElfW(Dyn) * dyn)
|
||||
char* string_table{};
|
||||
std::size_t symbol_count{};
|
||||
|
||||
while (dyn->d_tag != DT_NULL) {
|
||||
if (dyn->d_tag == DT_HASH) {
|
||||
while (dyn->d_tag != DT_NULL)
|
||||
{
|
||||
if (dyn->d_tag == DT_HASH)
|
||||
{
|
||||
hash_ptr = reinterpret_cast<ElfW(Word)*>(dyn->d_un.d_ptr);
|
||||
symbol_count = hash_ptr[1];
|
||||
} else if (dyn->d_tag == DT_STRTAB) {
|
||||
}
|
||||
else if (dyn->d_tag == DT_STRTAB)
|
||||
{
|
||||
string_table = reinterpret_cast<char*>(dyn->d_un.d_ptr);
|
||||
} else if (!symbol_count && dyn->d_tag == DT_GNU_HASH) {
|
||||
}
|
||||
else if (!symbol_count && dyn->d_tag == DT_GNU_HASH)
|
||||
{
|
||||
symbol_count = GetNumberOfSymbolsFromGnuHash(dyn->d_un.d_ptr);
|
||||
} else if (dyn->d_tag == DT_SYMTAB) {
|
||||
}
|
||||
else if (dyn->d_tag == DT_SYMTAB)
|
||||
{
|
||||
symbols = reinterpret_cast<ElfW(Sym)*>(dyn->d_un.d_ptr);
|
||||
|
||||
for (auto i = 0; i < symbol_count; i++) {
|
||||
if (!symbols[i].st_name) {
|
||||
for (auto i = 0; i < symbol_count; i++)
|
||||
{
|
||||
if (!symbols[i].st_name)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (symbols[i].st_other != 0) {
|
||||
if (symbols[i].st_other != 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
auto address = symbols[i].st_value + m_baseAddress;
|
||||
std::string_view name = &string_table[symbols[i].st_name];
|
||||
|
||||
if (name == "CreateInterface") {
|
||||
if (name == "CreateInterface")
|
||||
{
|
||||
m_fnCreateInterface = reinterpret_cast<fnCreateInterface>(address);
|
||||
}
|
||||
|
||||
_symbols.insert({name.data(), address});
|
||||
_symbols.insert({ name.data(), address });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -390,11 +403,9 @@ void CModule::DumpSymbols(ElfW(Dyn) * dyn)
|
||||
#endif
|
||||
|
||||
std::optional<std::vector<std::uint8_t>>
|
||||
CModule::GetOriginalBytes(const std::vector<std::uint8_t>& disk_data, std::uintptr_t rva,
|
||||
std::size_t size)
|
||||
CModule::GetOriginalBytes(const std::vector<std::uint8_t>& disk_data, std::uintptr_t rva, std::size_t size)
|
||||
{
|
||||
auto get_file_ptr_from_rva = [](std::uint8_t* data,
|
||||
std::uintptr_t address) -> std::optional<std::uintptr_t> {
|
||||
auto get_file_ptr_from_rva = [](std::uint8_t* data, std::uintptr_t address) -> std::optional<std::uintptr_t> {
|
||||
#ifdef _WIN32
|
||||
// thank you praydog
|
||||
// https://github.com/cursey/kananlib/blob/b0323a0b005fc9e3944e0ea36dcc98eda4b84eea/src/Module.cpp#L176
|
||||
@@ -402,14 +413,16 @@ CModule::GetOriginalBytes(const std::vector<std::uint8_t>& disk_data, std::uintp
|
||||
const auto dos_header = reinterpret_cast<PIMAGE_DOS_HEADER>(data);
|
||||
const auto nt_header = reinterpret_cast<PIMAGE_NT_HEADERS>(&data[dos_header->e_lfanew]);
|
||||
auto section = IMAGE_FIRST_SECTION(nt_header);
|
||||
for (auto i = 0; i < nt_header->FileHeader.NumberOfSections; i++, section++) {
|
||||
for (auto i = 0; i < nt_header->FileHeader.NumberOfSections; i++, section++)
|
||||
{
|
||||
auto section_size = section->Misc.VirtualSize;
|
||||
if (section_size == 0) {
|
||||
if (section_size == 0)
|
||||
{
|
||||
section_size = section->SizeOfRawData;
|
||||
}
|
||||
|
||||
if (address >= section->VirtualAddress &&
|
||||
address < static_cast<uintptr_t>(section->VirtualAddress) + section_size) {
|
||||
if (address >= section->VirtualAddress && address < static_cast<uintptr_t>(section->VirtualAddress) + section_size)
|
||||
{
|
||||
const auto delta = section->VirtualAddress - section->PointerToRawData;
|
||||
|
||||
return reinterpret_cast<std::uintptr_t>(data + (address - delta));
|
||||
@@ -423,23 +436,24 @@ CModule::GetOriginalBytes(const std::vector<std::uint8_t>& disk_data, std::uintp
|
||||
};
|
||||
|
||||
const auto disk_ptr = get_file_ptr_from_rva(const_cast<std::uint8_t*>(disk_data.data()), rva);
|
||||
if (!disk_ptr)
|
||||
return std::nullopt;
|
||||
if (!disk_ptr) return std::nullopt;
|
||||
|
||||
const auto disk_bytes = reinterpret_cast<std::uint8_t*>(*disk_ptr);
|
||||
std::vector<std::uint8_t> result{&disk_bytes[0], &disk_bytes[size]};
|
||||
std::vector<std::uint8_t> result{ &disk_bytes[0], &disk_bytes[size] };
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void* CModule::FindSignature(const char* signature)
|
||||
{
|
||||
if (signature == nullptr || strlen(signature) == 0) {
|
||||
if (signature == nullptr || strlen(signature) == 0)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto pData = CGameConfig::HexToByte(signature);
|
||||
if (pData.empty()) [[unlikely]] {
|
||||
if (pData.empty()) [[unlikely]]
|
||||
{
|
||||
CSSHARP_CORE_ERROR("Cannot convert signture \"{}\" to bytes", signature);
|
||||
return nullptr;
|
||||
}
|
||||
@@ -449,25 +463,27 @@ void* CModule::FindSignature(const char* signature)
|
||||
|
||||
void* CModule::FindSignature(const std::vector<int16_t>& sigBytes)
|
||||
{
|
||||
for (auto&& segment : m_vecSegments) {
|
||||
for (auto&& segment : m_vecSegments)
|
||||
{
|
||||
const auto size = segment.bytes.size();
|
||||
auto* data = segment.bytes.data();
|
||||
|
||||
auto first_byte = sigBytes[0];
|
||||
std::uint8_t* end = data + size - sigBytes.size();
|
||||
|
||||
for (std::uint8_t* current = data; current <= end; ++current) {
|
||||
if (first_byte != -1)
|
||||
current = std::find(current, end, first_byte);
|
||||
for (std::uint8_t* current = data; current <= end; ++current)
|
||||
{
|
||||
if (first_byte != -1) current = std::find(current, end, first_byte);
|
||||
|
||||
if (current == end) {
|
||||
if (current == end)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (std::equal(sigBytes.begin() + 1, sigBytes.end(), current + 1,
|
||||
[](auto opt, auto byte) {
|
||||
return opt == -1 || opt == byte;
|
||||
})) {
|
||||
if (std::equal(sigBytes.begin() + 1, sigBytes.end(), current + 1, [](auto opt, auto byte) {
|
||||
return opt == -1 || opt == byte;
|
||||
}))
|
||||
{
|
||||
return reinterpret_cast<void*>(current - data + segment.address);
|
||||
}
|
||||
}
|
||||
@@ -478,7 +494,8 @@ void* CModule::FindSignature(const std::vector<int16_t>& sigBytes)
|
||||
|
||||
void* CModule::FindInterface(std::string_view name)
|
||||
{
|
||||
if (_interfaces.empty()) {
|
||||
if (_interfaces.empty())
|
||||
{
|
||||
auto RelToAbs = [](std::uintptr_t address, int offset) {
|
||||
const auto displacement = *reinterpret_cast<int32_t*>(address + offset);
|
||||
return address + offset + displacement + sizeof(int32_t);
|
||||
@@ -506,15 +523,16 @@ void* CModule::FindInterface(std::string_view name)
|
||||
void* ret_interface{};
|
||||
|
||||
const auto interface_reg = *reinterpret_cast<CInterfaceRegister**>(RelToAbs(address, 3));
|
||||
for (auto list = interface_reg; list != nullptr; list = list->pNext) {
|
||||
for (auto list = interface_reg; list != nullptr; list = list->pNext)
|
||||
{
|
||||
auto interface_addrss = list->fnCreate();
|
||||
if (const std::string_view interface_name = list->szName; interface_name == name)
|
||||
ret_interface = interface_addrss;
|
||||
if (const std::string_view interface_name = list->szName; interface_name == name) ret_interface = interface_addrss;
|
||||
|
||||
_interfaces.insert({list->szName, reinterpret_cast<uintptr_t>(interface_addrss)});
|
||||
_interfaces.insert({ list->szName, reinterpret_cast<uintptr_t>(interface_addrss) });
|
||||
}
|
||||
|
||||
if (ret_interface == nullptr) {
|
||||
if (ret_interface == nullptr)
|
||||
{
|
||||
// Replace Error() from hl2sdk-cs2, it essentially calls Plat_ExitProcess
|
||||
CSSHARP_CORE_ERROR("Could not find interface {} in {}", name, m_pszModule);
|
||||
Plat_ExitProcess(1);
|
||||
@@ -525,7 +543,8 @@ void* CModule::FindInterface(std::string_view name)
|
||||
|
||||
const auto it = _interfaces.find(name.data());
|
||||
|
||||
if (it == _interfaces.end()) {
|
||||
if (it == _interfaces.end())
|
||||
{
|
||||
CSSHARP_CORE_ERROR("Could not find interface {} in {}", name, m_pszModule);
|
||||
Plat_ExitProcess(1);
|
||||
}
|
||||
@@ -535,7 +554,8 @@ void* CModule::FindInterface(std::string_view name)
|
||||
|
||||
void* CModule::FindSymbol(const std::string& name)
|
||||
{
|
||||
if (const auto it = _symbols.find(name); it != _symbols.end()) {
|
||||
if (const auto it = _symbols.find(name); it != _symbols.end())
|
||||
{
|
||||
return reinterpret_cast<void*>(it->second);
|
||||
}
|
||||
|
||||
|
||||
@@ -14,21 +14,22 @@
|
||||
* along with CounterStrikeSharp. If not, see <https://www.gnu.org/licenses/>. *
|
||||
*/
|
||||
|
||||
#include <public/entity2/entitysystem.h>
|
||||
|
||||
#include <ios>
|
||||
#include <sstream>
|
||||
|
||||
#include "core/log.h"
|
||||
#include "core/managers/entity_manager.h"
|
||||
#include "core/managers/player_manager.h"
|
||||
#include "core/memory.h"
|
||||
#include "scripting/autonative.h"
|
||||
#include "scripting/script_engine.h"
|
||||
#include "core/memory.h"
|
||||
#include "core/log.h"
|
||||
#include "core/managers/player_manager.h"
|
||||
#include "core/managers/entity_manager.h"
|
||||
|
||||
#include <public/entity2/entitysystem.h>
|
||||
|
||||
namespace counterstrikesharp {
|
||||
|
||||
CBaseEntity* GetEntityFromIndex(ScriptContext& script_context) {
|
||||
CEntityInstance* GetEntityFromIndex(ScriptContext& script_context)
|
||||
{
|
||||
if (!globals::entitySystem)
|
||||
{
|
||||
script_context.ThrowNativeError("Entity system is not yet initialized");
|
||||
@@ -37,55 +38,64 @@ CBaseEntity* GetEntityFromIndex(ScriptContext& script_context) {
|
||||
|
||||
auto entityIndex = script_context.GetArgument<int>(0);
|
||||
|
||||
return globals::entitySystem->GetBaseEntity(CEntityIndex(entityIndex));
|
||||
return globals::entitySystem->GetEntityInstance(CEntityIndex(entityIndex));
|
||||
}
|
||||
|
||||
int GetUserIdFromIndex(ScriptContext& scriptContext) {
|
||||
int GetUserIdFromIndex(ScriptContext& scriptContext)
|
||||
{
|
||||
auto entityIndex = scriptContext.GetArgument<int>(0);
|
||||
|
||||
// CPlayerSlot is 1 less than index
|
||||
return globals::engine->GetPlayerUserId(CPlayerSlot(entityIndex - 1)).Get();
|
||||
}
|
||||
|
||||
const char* GetDesignerName(ScriptContext& scriptContext) {
|
||||
auto entity = scriptContext.GetArgument<CBaseEntity*>(0);
|
||||
const char* GetDesignerName(ScriptContext& scriptContext)
|
||||
{
|
||||
auto entity = scriptContext.GetArgument<CEntityInstance*>(0);
|
||||
return entity->GetClassname();
|
||||
}
|
||||
|
||||
void* GetEntityPointerFromHandle(ScriptContext& scriptContext) {
|
||||
if (!globals::entitySystem) {
|
||||
void* GetEntityPointerFromHandle(ScriptContext& scriptContext)
|
||||
{
|
||||
if (!globals::entitySystem)
|
||||
{
|
||||
scriptContext.ThrowNativeError("Entity system is not yet initialized");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto handle = scriptContext.GetArgument<CEntityHandle*>(0);
|
||||
|
||||
if (!handle->IsValid()) {
|
||||
if (!handle->IsValid())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return globals::entitySystem->GetBaseEntity(*handle);
|
||||
return globals::entitySystem->GetEntityInstance(*handle);
|
||||
}
|
||||
|
||||
void* GetEntityPointerFromRef(ScriptContext& scriptContext) {
|
||||
if (!globals::entitySystem) {
|
||||
void* GetEntityPointerFromRef(ScriptContext& scriptContext)
|
||||
{
|
||||
if (!globals::entitySystem)
|
||||
{
|
||||
scriptContext.ThrowNativeError("Entity system yet is not initialized");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto ref = scriptContext.GetArgument<unsigned int>(0);
|
||||
|
||||
if (ref == INVALID_EHANDLE_INDEX) {
|
||||
if (ref == INVALID_EHANDLE_INDEX)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CBaseHandle hndl(ref);
|
||||
|
||||
return globals::entitySystem->GetBaseEntity(hndl);
|
||||
return globals::entitySystem->GetEntityInstance(hndl);
|
||||
}
|
||||
|
||||
unsigned int GetRefFromEntityPointer(ScriptContext& scriptContext) {
|
||||
auto* pEntity = scriptContext.GetArgument<CBaseEntity*>(0);
|
||||
unsigned int GetRefFromEntityPointer(ScriptContext& scriptContext)
|
||||
{
|
||||
auto* pEntity = scriptContext.GetArgument<CEntityInstance*>(0);
|
||||
|
||||
if (pEntity == nullptr)
|
||||
{
|
||||
@@ -102,36 +112,43 @@ unsigned int GetRefFromEntityPointer(ScriptContext& scriptContext) {
|
||||
return hndl.ToInt();
|
||||
}
|
||||
|
||||
bool IsRefValidEntity(ScriptContext& scriptContext) {
|
||||
if (!globals::entitySystem) {
|
||||
bool IsRefValidEntity(ScriptContext& scriptContext)
|
||||
{
|
||||
if (!globals::entitySystem)
|
||||
{
|
||||
scriptContext.ThrowNativeError("Entity system yet is not initialized");
|
||||
return false;
|
||||
}
|
||||
|
||||
auto ref = scriptContext.GetArgument<unsigned int>(0);
|
||||
|
||||
if (ref == INVALID_EHANDLE_INDEX) {
|
||||
if (ref == INVALID_EHANDLE_INDEX)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
CBaseHandle hndl(ref);
|
||||
|
||||
if (!hndl.IsValid()) {
|
||||
if (!hndl.IsValid())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return globals::entitySystem->GetBaseEntity(hndl) != nullptr;
|
||||
return globals::entitySystem->GetEntityInstance(hndl) != nullptr;
|
||||
}
|
||||
|
||||
void PrintToConsole(ScriptContext& scriptContext) {
|
||||
void PrintToConsole(ScriptContext& scriptContext)
|
||||
{
|
||||
auto index = scriptContext.GetArgument<int>(0);
|
||||
auto message = scriptContext.GetArgument<const char*>(1);
|
||||
|
||||
globals::engine->ClientPrintf(CPlayerSlot{index - 1}, message);
|
||||
globals::engine->ClientPrintf(CPlayerSlot{ index - 1 }, message);
|
||||
}
|
||||
|
||||
CEntityIdentity* GetFirstActiveEntity(ScriptContext& script_context) {
|
||||
if (!globals::entitySystem) {
|
||||
CEntityIdentity* GetFirstActiveEntity(ScriptContext& script_context)
|
||||
{
|
||||
if (!globals::entitySystem)
|
||||
{
|
||||
script_context.ThrowNativeError("Entity system yet is not initialized");
|
||||
return nullptr;
|
||||
}
|
||||
@@ -139,8 +156,10 @@ CEntityIdentity* GetFirstActiveEntity(ScriptContext& script_context) {
|
||||
return globals::entitySystem->m_EntityList.m_pFirstActiveEntity;
|
||||
}
|
||||
|
||||
void* GetConcreteEntityListPointer(ScriptContext& script_context) {
|
||||
if (!globals::entitySystem) {
|
||||
void* GetConcreteEntityListPointer(ScriptContext& script_context)
|
||||
{
|
||||
if (!globals::entitySystem)
|
||||
{
|
||||
script_context.ThrowNativeError("Entity system yet is not initialized");
|
||||
return nullptr;
|
||||
}
|
||||
@@ -148,27 +167,32 @@ void* GetConcreteEntityListPointer(ScriptContext& script_context) {
|
||||
return &globals::entitySystem->m_EntityList;
|
||||
}
|
||||
|
||||
unsigned long GetPlayerAuthorizedSteamID(ScriptContext& script_context) {
|
||||
unsigned long GetPlayerAuthorizedSteamID(ScriptContext& script_context)
|
||||
{
|
||||
auto iSlot = script_context.GetArgument<int>(0);
|
||||
|
||||
auto pPlayer = globals::playerManager.GetPlayerBySlot(iSlot);
|
||||
if (pPlayer == nullptr || !pPlayer->m_is_authorized) {
|
||||
if (pPlayer == nullptr || !pPlayer->m_is_authorized)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto pSteamId = pPlayer->GetSteamId();
|
||||
if (pSteamId == nullptr) {
|
||||
if (pSteamId == nullptr)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return pSteamId->ConvertToUint64();
|
||||
}
|
||||
|
||||
const char* GetPlayerIpAddress(ScriptContext& script_context) {
|
||||
const char* GetPlayerIpAddress(ScriptContext& script_context)
|
||||
{
|
||||
auto iSlot = script_context.GetArgument<int>(0);
|
||||
|
||||
auto pPlayer = globals::playerManager.GetPlayerBySlot(iSlot);
|
||||
if (pPlayer == nullptr) {
|
||||
if (pPlayer == nullptr)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -236,8 +260,7 @@ REGISTER_NATIVES(entities, {
|
||||
ScriptEngine::RegisterNativeHandler("GET_ENTITY_FROM_INDEX", GetEntityFromIndex);
|
||||
ScriptEngine::RegisterNativeHandler("GET_USERID_FROM_INDEX", GetUserIdFromIndex);
|
||||
ScriptEngine::RegisterNativeHandler("GET_DESIGNER_NAME", GetDesignerName);
|
||||
ScriptEngine::RegisterNativeHandler("GET_ENTITY_POINTER_FROM_HANDLE",
|
||||
GetEntityPointerFromHandle);
|
||||
ScriptEngine::RegisterNativeHandler("GET_ENTITY_POINTER_FROM_HANDLE", GetEntityPointerFromHandle);
|
||||
ScriptEngine::RegisterNativeHandler("GET_ENTITY_POINTER_FROM_REF", GetEntityPointerFromRef);
|
||||
ScriptEngine::RegisterNativeHandler("GET_REF_FROM_ENTITY_POINTER", GetRefFromEntityPointer);
|
||||
ScriptEngine::RegisterNativeHandler("GET_CONCRETE_ENTITY_LIST_POINTER", GetConcreteEntityListPointer);
|
||||
@@ -251,4 +274,4 @@ REGISTER_NATIVES(entities, {
|
||||
ScriptEngine::RegisterNativeHandler("ACCEPT_INPUT", AcceptInput);
|
||||
ScriptEngine::RegisterNativeHandler("ADD_ENTITY_IO_EVENT", AddEntityIOEvent);
|
||||
})
|
||||
} // namespace counterstrikesharp
|
||||
} // namespace counterstrikesharp
|
||||
|
||||
@@ -14,38 +14,40 @@
|
||||
* along with CounterStrikeSharp. If not, see <https://www.gnu.org/licenses/>. *
|
||||
*/
|
||||
|
||||
#include "scripting/autonative.h"
|
||||
#include "scripting/script_engine.h"
|
||||
#include "core/managers/player_manager.h"
|
||||
#include <public/entity2/entitysystem.h>
|
||||
|
||||
#include "core/managers/player_manager.h"
|
||||
#include "scripting/autonative.h"
|
||||
#include "scripting/script_engine.h"
|
||||
|
||||
namespace counterstrikesharp {
|
||||
|
||||
void SetClientListening(ScriptContext& scriptContext)
|
||||
{
|
||||
auto receiver = scriptContext.GetArgument<CBaseEntity*>(0);
|
||||
auto sender = scriptContext.GetArgument<CBaseEntity*>(1);
|
||||
auto receiver = scriptContext.GetArgument<CEntityInstance*>(0);
|
||||
auto sender = scriptContext.GetArgument<CEntityInstance*>(1);
|
||||
auto listen = scriptContext.GetArgument<ListenOverride>(2);
|
||||
|
||||
if (!receiver) {
|
||||
if (!receiver)
|
||||
{
|
||||
scriptContext.ThrowNativeError("Receiver is a null pointer");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!sender) {
|
||||
if (!sender)
|
||||
{
|
||||
scriptContext.ThrowNativeError("Sender is a null pointer");
|
||||
return;
|
||||
}
|
||||
|
||||
auto iSenderSlot = sender->GetEntityIndex().Get() - 1;
|
||||
|
||||
if (iSenderSlot < 0 || iSenderSlot >= globals::getGlobalVars()->maxClients)
|
||||
scriptContext.ThrowNativeError("Invalid sender");
|
||||
if (iSenderSlot < 0 || iSenderSlot >= globals::getGlobalVars()->maxClients) scriptContext.ThrowNativeError("Invalid sender");
|
||||
|
||||
auto pPlayer = globals::playerManager.GetPlayerBySlot(receiver->GetEntityIndex().Get() - 1);
|
||||
|
||||
if (pPlayer == nullptr) {
|
||||
if (pPlayer == nullptr)
|
||||
{
|
||||
scriptContext.ThrowNativeError("Invalid receiver");
|
||||
return;
|
||||
}
|
||||
@@ -55,27 +57,29 @@ void SetClientListening(ScriptContext& scriptContext)
|
||||
|
||||
ListenOverride GetClientListening(ScriptContext& scriptContext)
|
||||
{
|
||||
auto receiver = scriptContext.GetArgument<CBaseEntity*>(0);
|
||||
auto sender = scriptContext.GetArgument<CBaseEntity*>(1);
|
||||
auto receiver = scriptContext.GetArgument<CEntityInstance*>(0);
|
||||
auto sender = scriptContext.GetArgument<CEntityInstance*>(1);
|
||||
|
||||
if (!receiver) {
|
||||
if (!receiver)
|
||||
{
|
||||
scriptContext.ThrowNativeError("Receiver is a null pointer");
|
||||
return Listen_Default;
|
||||
}
|
||||
|
||||
if (!sender) {
|
||||
if (!sender)
|
||||
{
|
||||
scriptContext.ThrowNativeError("Sender is a null pointer");
|
||||
return Listen_Default;
|
||||
}
|
||||
|
||||
auto iSenderSlot = sender->GetEntityIndex().Get() - 1;
|
||||
|
||||
if (iSenderSlot < 0 || iSenderSlot >= globals::getGlobalVars()->maxClients)
|
||||
scriptContext.ThrowNativeError("Invalid sender");
|
||||
if (iSenderSlot < 0 || iSenderSlot >= globals::getGlobalVars()->maxClients) scriptContext.ThrowNativeError("Invalid sender");
|
||||
|
||||
auto pPlayer = globals::playerManager.GetPlayerBySlot(receiver->GetEntityIndex().Get() - 1);
|
||||
|
||||
if (pPlayer == nullptr) {
|
||||
if (pPlayer == nullptr)
|
||||
{
|
||||
scriptContext.ThrowNativeError("Invalid receiver");
|
||||
return Listen_Default;
|
||||
}
|
||||
@@ -85,16 +89,18 @@ ListenOverride GetClientListening(ScriptContext& scriptContext)
|
||||
|
||||
void SetClientVoiceFlags(ScriptContext& scriptContext)
|
||||
{
|
||||
auto client = scriptContext.GetArgument<CBaseEntity*>(0);
|
||||
auto client = scriptContext.GetArgument<CEntityInstance*>(0);
|
||||
auto flags = scriptContext.GetArgument<VoiceFlag_t>(1);
|
||||
|
||||
if (!client) {
|
||||
if (!client)
|
||||
{
|
||||
scriptContext.ThrowNativeError("Receiver is a null pointer");
|
||||
return;
|
||||
}
|
||||
auto pPlayer = globals::playerManager.GetPlayerBySlot(client->GetEntityIndex().Get() - 1);
|
||||
|
||||
if (pPlayer == nullptr) {
|
||||
if (pPlayer == nullptr)
|
||||
{
|
||||
scriptContext.ThrowNativeError("Invalid receiver");
|
||||
return;
|
||||
}
|
||||
@@ -104,16 +110,18 @@ void SetClientVoiceFlags(ScriptContext& scriptContext)
|
||||
|
||||
VoiceFlag_t GetClientVoiceFlags(ScriptContext& scriptContext)
|
||||
{
|
||||
auto client = scriptContext.GetArgument<CBaseEntity*>(0);
|
||||
auto client = scriptContext.GetArgument<CEntityInstance*>(0);
|
||||
|
||||
if (!client) {
|
||||
if (!client)
|
||||
{
|
||||
scriptContext.ThrowNativeError("Receiver is a null pointer");
|
||||
return VoiceFlag_t{};
|
||||
}
|
||||
|
||||
auto pPlayer = globals::playerManager.GetPlayerBySlot(client->GetEntityIndex().Get() - 1);
|
||||
|
||||
if (pPlayer == nullptr) {
|
||||
if (pPlayer == nullptr)
|
||||
{
|
||||
scriptContext.ThrowNativeError("Invalid receiver");
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user