mirror of
https://github.com/alliedmodders/sourcemod.git
synced 2025-12-06 18:08:36 +00:00
Compare commits
28 Commits
b1bdfcada0
...
0b9de10651
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0b9de10651 | ||
|
|
1819f491b5 | ||
|
|
c4d5235217 | ||
|
|
6439769d50 | ||
|
|
0c900be7fc | ||
|
|
bc8d02c998 | ||
|
|
1fc841713e | ||
|
|
84f67fcd2d | ||
|
|
eb3b4d9822 | ||
|
|
a401d97b09 | ||
|
|
74e9cdd709 | ||
|
|
2ae0d05a23 | ||
|
|
22cc68808c | ||
|
|
9952f62a33 | ||
|
|
f382c3fb5b | ||
|
|
4374cb2168 | ||
|
|
98831a8667 | ||
|
|
66d3f5e60e | ||
|
|
0ccf21ecb6 | ||
|
|
c9ee066a1d | ||
|
|
42c5444a10 | ||
|
|
e4fda1bd78 | ||
|
|
e55747a9e4 | ||
|
|
351917be35 | ||
|
|
063734607f | ||
|
|
19dce02a9c | ||
|
|
f6b8278fd8 | ||
|
|
d44669ef34 |
6
.github/workflows/ci.yml
vendored
6
.github/workflows/ci.yml
vendored
@ -36,7 +36,7 @@ jobs:
|
||||
MYSQL_VERSION: '5.7'
|
||||
MMSOURCE_VERSION: '1.12'
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
path: sourcemod
|
||||
@ -54,9 +54,9 @@ jobs:
|
||||
|
||||
# Setup Python for AMBuild
|
||||
- uses: actions/setup-python@v6
|
||||
name: Setup Python 3.8
|
||||
name: Setup Python 3.12
|
||||
with:
|
||||
python-version: 3.8
|
||||
python-version: 3.12
|
||||
- name: Install Python dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip setuptools wheel
|
||||
|
||||
6
.github/workflows/mocktest.yml
vendored
6
.github/workflows/mocktest.yml
vendored
@ -12,20 +12,20 @@ jobs:
|
||||
mock:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v6
|
||||
name: Clone sourcemod
|
||||
with:
|
||||
submodules: recursive
|
||||
path: sourcemod
|
||||
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v6
|
||||
name: Clone metamod-source
|
||||
with:
|
||||
repository: alliedmodders/metamod-source
|
||||
submodules: recursive
|
||||
path: metamod-source
|
||||
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v6
|
||||
name: Clone hl2sdk-mock
|
||||
with:
|
||||
repository: alliedmodders/hl2sdk-mock
|
||||
|
||||
8
.github/workflows/scripting.yml
vendored
8
.github/workflows/scripting.yml
vendored
@ -25,15 +25,15 @@ jobs:
|
||||
env:
|
||||
ARCH: x86,x86_64
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
# Setup Python for AMBuild
|
||||
- uses: actions/setup-python@v6
|
||||
name: Setup Python 3.8
|
||||
name: Setup Python 3.12
|
||||
with:
|
||||
python-version: 3.8
|
||||
python-version: 3.12
|
||||
- name: Install AMBuild
|
||||
run: |
|
||||
python -m pip install --upgrade pip setuptools wheel
|
||||
@ -67,7 +67,7 @@ jobs:
|
||||
echo "SM_VERSION=$(cat ../product.version)" >> $GITHUB_ENV
|
||||
|
||||
- name: Archive tooling
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: sourcemod-tooling-${{ env.SM_VERSION }}-${{ matrix.os_short }}
|
||||
path: build/package
|
||||
|
||||
2
.github/workflows/translations.yml
vendored
2
.github/workflows/translations.yml
vendored
@ -10,7 +10,7 @@ jobs:
|
||||
update_translations:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
|
||||
@ -15,7 +15,7 @@ jobs:
|
||||
check_translations:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- uses: actions/setup-python@v6
|
||||
name: Setup Python 3.10
|
||||
|
||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -12,3 +12,6 @@
|
||||
[submodule "public/safetyhook"]
|
||||
path = public/safetyhook
|
||||
url = https://github.com/alliedmodders/safetyhook
|
||||
[submodule "core/logic/libaddrz"]
|
||||
path = core/logic/libaddrz
|
||||
url = https://github.com/dvander/libaddrz.git
|
||||
|
||||
@ -58,6 +58,7 @@ public:
|
||||
virtual bool IsDirectory(const char *pFileName, const char *pathID = 0) = 0;
|
||||
virtual void CreateDirHierarchy(const char *path, const char *pathID = 0) = 0;
|
||||
virtual int GetSearchPath(const char* pathID, bool bGetPackFiles, char* pPath, int nMaxLen) = 0;
|
||||
virtual const char * GetGameBinArchSubdirectory() = 0;
|
||||
};
|
||||
|
||||
} // namespace SourceMod
|
||||
|
||||
@ -21,6 +21,15 @@
|
||||
*/
|
||||
"LogMode" "daily"
|
||||
|
||||
/**
|
||||
* This option determines the time format SourceMod logging should use.
|
||||
*
|
||||
* "default" - Uses SourceMod's default time format. (%m/%d/%Y - %H:%M:%S)
|
||||
* You can specify any time format you want. See https://cplusplus.com/reference/ctime/strftime/ for a list of format parameters.
|
||||
* Example: "%d/%m/%Y - %H:%M:%S"
|
||||
*/
|
||||
"LogTimeFormat" "default"
|
||||
|
||||
/**
|
||||
* Language that multilingual enabled plugins and extensions will use to print messages.
|
||||
* Only languages listed in languages.cfg are valid.
|
||||
|
||||
@ -16,7 +16,7 @@ CREATE TABLE IF NOT EXISTS sm_cookie_cache
|
||||
PRIMARY KEY (player, cookie_id)
|
||||
);
|
||||
|
||||
CREATE LANGUAGE plpgsql;
|
||||
CREATE OR REPLACE LANGUAGE plpgsql;
|
||||
|
||||
CREATE OR REPLACE FUNCTION add_or_update_cookie(in_player VARCHAR(65), in_cookie INT, in_value VARCHAR(100), in_time INT) RETURNS VOID AS
|
||||
$$
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
CREATE TABLE sm_admins (
|
||||
CREATE TABLE IF NOT EXISTS sm_admins (
|
||||
id serial,
|
||||
authtype varchar(6) NOT NULL,
|
||||
CHECK (authtype in ('steam', 'name', 'ip')),
|
||||
@ -10,7 +10,7 @@ CREATE TABLE sm_admins (
|
||||
PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
CREATE TABLE sm_groups (
|
||||
CREATE TABLE IF NOT EXISTS sm_groups (
|
||||
id serial,
|
||||
flags varchar(30) NOT NULL,
|
||||
name varchar(120) NOT NULL,
|
||||
@ -18,7 +18,7 @@ CREATE TABLE sm_groups (
|
||||
PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
CREATE TABLE sm_group_immunity (
|
||||
CREATE TABLE IF NOT EXISTS sm_group_immunity (
|
||||
group_id int NOT NULL,
|
||||
other_id int NOT NULL,
|
||||
FOREIGN KEY (group_id) REFERENCES sm_groups(id) ON DELETE CASCADE,
|
||||
@ -26,7 +26,7 @@ CREATE TABLE sm_group_immunity (
|
||||
PRIMARY KEY (group_id, other_id)
|
||||
);
|
||||
|
||||
CREATE TABLE sm_group_overrides (
|
||||
CREATE TABLE IF NOT EXISTS sm_group_overrides (
|
||||
group_id int NOT NULL,
|
||||
FOREIGN KEY (group_id) REFERENCES sm_groups(id) ON DELETE CASCADE,
|
||||
type varchar(10) NOT NULL,
|
||||
@ -37,7 +37,7 @@ CREATE TABLE sm_group_overrides (
|
||||
PRIMARY KEY (group_id, type, name)
|
||||
);
|
||||
|
||||
CREATE TABLE sm_overrides (
|
||||
CREATE TABLE IF NOT EXISTS sm_overrides (
|
||||
type varchar(10) NOT NULL,
|
||||
CHECK (type in ('command', 'group')),
|
||||
name varchar(32) NOT NULL,
|
||||
@ -45,7 +45,7 @@ CREATE TABLE sm_overrides (
|
||||
PRIMARY KEY (type,name)
|
||||
);
|
||||
|
||||
CREATE TABLE sm_admins_groups (
|
||||
CREATE TABLE IF NOT EXISTS sm_admins_groups (
|
||||
admin_id int NOT NULL,
|
||||
group_id int NOT NULL,
|
||||
FOREIGN KEY (admin_id) REFERENCES sm_admins(id) ON DELETE CASCADE,
|
||||
@ -56,10 +56,10 @@ CREATE TABLE sm_admins_groups (
|
||||
|
||||
-- side note, this is pgsql module, sm_config will not exist if the above stuff exists... and it's being left to the admin
|
||||
-- to figure out if it exists.
|
||||
CREATE TABLE sm_config (
|
||||
CREATE TABLE IF NOT EXISTS sm_config (
|
||||
cfg_key varchar(32) NOT NULL,
|
||||
cfg_value varchar(255) NOT NULL,
|
||||
PRIMARY KEY (cfg_key)
|
||||
);
|
||||
|
||||
INSERT INTO sm_config (cfg_key, cfg_value) VALUES ('admin_version', '1.0.0.1409');
|
||||
INSERT INTO sm_config (cfg_key, cfg_value) VALUES ('admin_version', '1.0.0.1409') ON CONFLICT (cfg_key) DO UPDATE SET cfg_value = EXCLUDED.cfg_value;
|
||||
|
||||
@ -86,9 +86,15 @@ for cxx in builder.targets:
|
||||
'DatabaseConfBuilder.cpp',
|
||||
'LumpManager.cpp',
|
||||
'smn_entitylump.cpp',
|
||||
'libaddrz/addrz.cpp',
|
||||
'libaddrz/mapping.cpp',
|
||||
'libaddrz/platform.cpp',
|
||||
'libaddrz/proc_maps.cpp',
|
||||
'PseudoAddrManager.cpp',
|
||||
]
|
||||
|
||||
if binary.compiler.target.arch == 'x86_64':
|
||||
binary.sources += ['PseudoAddrManager.cpp']
|
||||
if binary.compiler.target.platform == 'linux':
|
||||
binary.sources += ['libaddrz/platform_linux.cpp']
|
||||
elif binary.compiler.target.platform == 'windows':
|
||||
binary.sources += ['libaddrz/platform_windows.cpp']
|
||||
|
||||
SM.binaries += [builder.Add(binary)]
|
||||
|
||||
@ -1094,13 +1094,18 @@ void GameBinPathManager::Init()
|
||||
std::istringstream iss(search_path);
|
||||
for (std::string path; std::getline(iss, path, ';');)
|
||||
{
|
||||
if (path.length() > 0
|
||||
&& path.find(addons_folder) == std::string::npos
|
||||
&& m_lookup.find(path) == m_lookup.cend()
|
||||
)
|
||||
if (path.length() > 0)
|
||||
{
|
||||
m_lookup.insert(path);
|
||||
m_ordered.push_back(path);
|
||||
const char* arch_subdir = bridge->filesystem->GetGameBinArchSubdirectory();
|
||||
std::string full_path = path + arch_subdir;
|
||||
if (full_path.find(addons_folder) == std::string::npos
|
||||
&& m_lookup.find(full_path) == m_lookup.cend()
|
||||
)
|
||||
{
|
||||
m_lookup.insert(full_path);
|
||||
m_ordered.push_back(full_path);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -29,6 +29,7 @@
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#include <string_view>
|
||||
#include <time.h>
|
||||
#include <cstdarg>
|
||||
#include "Logger.h"
|
||||
@ -81,6 +82,19 @@ ConfigResult Logger::OnSourceModConfigChanged(const char *key,
|
||||
return ConfigResult_Reject;
|
||||
}
|
||||
|
||||
return ConfigResult_Accept;
|
||||
} else if (strcasecmp(key, "LogTimeFormat") == 0) {
|
||||
if (strcasecmp(value, "default") == 0)
|
||||
{
|
||||
m_isUsingDefaultTimeFormat = true;
|
||||
m_UserTimeFormat.clear();
|
||||
}
|
||||
else {
|
||||
// value is the time format string
|
||||
m_isUsingDefaultTimeFormat = false;
|
||||
m_UserTimeFormat.assign(value);
|
||||
}
|
||||
|
||||
return ConfigResult_Accept;
|
||||
}
|
||||
|
||||
@ -152,11 +166,7 @@ void Logger::LogToOpenFileEx(FILE *fp, const char *msg, va_list ap)
|
||||
char buffer[3072];
|
||||
ke::SafeVsprintf(buffer, sizeof(buffer), msg, ap);
|
||||
|
||||
char date[32];
|
||||
time_t t = g_pSM->GetAdjustedTime();
|
||||
tm *curtime = localtime(&t);
|
||||
strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime);
|
||||
|
||||
const char* date = GetFormattedDate();
|
||||
fprintf(fp, "L %s: %s\n", date, buffer);
|
||||
|
||||
if (!sv_logecho || bridge->GetCvarBool(sv_logecho))
|
||||
@ -174,10 +184,7 @@ void Logger::LogToFileOnlyEx(FILE *fp, const char *msg, va_list ap)
|
||||
char buffer[3072];
|
||||
ke::SafeVsprintf(buffer, sizeof(buffer), msg, ap);
|
||||
|
||||
char date[32];
|
||||
time_t t = g_pSM->GetAdjustedTime();
|
||||
tm *curtime = localtime(&t);
|
||||
strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime);
|
||||
const char* date = GetFormattedDate();
|
||||
fprintf(fp, "L %s: %s\n", date, buffer);
|
||||
|
||||
fflush(fp);
|
||||
@ -378,11 +385,7 @@ FILE *Logger::_OpenNormal()
|
||||
|
||||
if (!m_DamagedNormalFile)
|
||||
{
|
||||
time_t t = g_pSM->GetAdjustedTime();
|
||||
tm *curtime = localtime(&t);
|
||||
char date[32];
|
||||
|
||||
strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime);
|
||||
const char* date = GetFormattedDate();
|
||||
fprintf(pFile, "L %s: SourceMod log file session started (file \"%s\") (Version \"%s\")\n", date, m_NormalFileName.c_str(), SOURCEMOD_VERSION);
|
||||
m_DamagedNormalFile = true;
|
||||
}
|
||||
@ -403,11 +406,7 @@ FILE *Logger::_OpenError()
|
||||
|
||||
if (!m_DamagedErrorFile)
|
||||
{
|
||||
time_t t = g_pSM->GetAdjustedTime();
|
||||
tm *curtime = localtime(&t);
|
||||
|
||||
char date[32];
|
||||
strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime);
|
||||
const char* date = GetFormattedDate();
|
||||
fprintf(pFile, "L %s: SourceMod error session started\n", date);
|
||||
fprintf(pFile, "L %s: Info (map \"%s\") (file \"%s\")\n", date, m_CurrentMapName.c_str(), m_ErrorFileName.c_str());
|
||||
m_DamagedErrorFile = true;
|
||||
@ -452,3 +451,25 @@ void Logger::_CloseError()
|
||||
void Logger::_CloseFatal()
|
||||
{
|
||||
}
|
||||
|
||||
const char* Logger::GetFormattedDate() const
|
||||
{
|
||||
static char date[256];
|
||||
constexpr std::string_view DEFAULT_TIME_FORMAT{ "%m/%d/%Y - %H:%M:%S" };
|
||||
|
||||
time_t t = g_pSM->GetAdjustedTime();
|
||||
tm *curtime = localtime(&t);
|
||||
|
||||
if (m_isUsingDefaultTimeFormat)
|
||||
{
|
||||
strftime(date, sizeof(date), DEFAULT_TIME_FORMAT.data(), curtime);
|
||||
}
|
||||
else
|
||||
{
|
||||
strftime(date, sizeof(date), m_UserTimeFormat.c_str(), curtime);
|
||||
}
|
||||
|
||||
return date;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -53,7 +53,7 @@ enum LoggingMode
|
||||
class Logger : public SMGlobalClass, public ILogger
|
||||
{
|
||||
public:
|
||||
Logger() : m_Day(-1), m_Mode(LoggingMode_Daily), m_Active(true), m_DamagedNormalFile(false), m_DamagedErrorFile(false)
|
||||
Logger() : m_Day(-1), m_Mode(LoggingMode_Daily), m_Active(true), m_DamagedNormalFile(false), m_DamagedErrorFile(false), m_isUsingDefaultTimeFormat(true)
|
||||
{
|
||||
}
|
||||
public: //SMGlobalClass
|
||||
@ -95,10 +95,12 @@ private:
|
||||
void _LogFatalOpen(std::string &str);
|
||||
void _PrintToGameLog(const char *fmt, va_list ap);
|
||||
void _UpdateFiles(bool bLevelChange = false);
|
||||
const char* GetFormattedDate() const;
|
||||
private:
|
||||
std::string m_NormalFileName;
|
||||
std::string m_ErrorFileName;
|
||||
std::string m_CurrentMapName;
|
||||
std::string m_UserTimeFormat;
|
||||
|
||||
int m_Day;
|
||||
|
||||
@ -106,6 +108,7 @@ private:
|
||||
bool m_Active;
|
||||
bool m_DamagedNormalFile;
|
||||
bool m_DamagedErrorFile;
|
||||
bool m_isUsingDefaultTimeFormat;
|
||||
};
|
||||
|
||||
extern Logger g_Logger;
|
||||
|
||||
@ -330,6 +330,13 @@ bool CPlugin::ReadInfo()
|
||||
else
|
||||
m_MaxClientsVar = nullptr;
|
||||
|
||||
if (base->FindPubvarByName("PointerSize", &idx) == SP_ERROR_NONE) {
|
||||
sp_pubvar_t* var = nullptr;
|
||||
if (base->GetPubvarByIndex(idx, &var) == SP_ERROR_NONE && var) {
|
||||
*var->offs = sizeof(void*);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -28,6 +28,7 @@
|
||||
*/
|
||||
|
||||
#include "PseudoAddrManager.h"
|
||||
#include <bridge/include/CoreProvider.h>
|
||||
#ifdef PLATFORM_APPLE
|
||||
#include <mach/mach.h>
|
||||
#include <mach/vm_region.h>
|
||||
@ -35,135 +36,88 @@
|
||||
#ifdef PLATFORM_LINUX
|
||||
#include <inttypes.h>
|
||||
#endif
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
#include <Psapi.h>
|
||||
#endif
|
||||
|
||||
PseudoAddressManager::PseudoAddressManager() : m_NumEntries(0)
|
||||
PseudoAddressManager::PseudoAddressManager() : m_dictionary(am::IPlatform::GetDefault())
|
||||
{
|
||||
}
|
||||
|
||||
// A pseudo address consists of a table index in the upper 6 bits and an offset in the
|
||||
// lower 26 bits. The table consists of memory allocation base addresses.
|
||||
void PseudoAddressManager::Initialize() {
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
auto process = GetCurrentProcess();
|
||||
auto get_module_details = [process](const char* name, void*& baseAddress, size_t& moduleSize) {
|
||||
if (process == NULL) {
|
||||
return false;
|
||||
}
|
||||
auto hndl = GetModuleHandle(name);
|
||||
if (hndl == NULL) {
|
||||
return false;
|
||||
}
|
||||
MODULEINFO info;
|
||||
if (!GetModuleInformation(process, hndl, &info, sizeof(info))) {
|
||||
return false;
|
||||
}
|
||||
moduleSize = info.SizeOfImage;
|
||||
baseAddress = info.lpBaseOfDll;
|
||||
return true;
|
||||
};
|
||||
#endif
|
||||
#ifdef PLATFORM_LINUX
|
||||
auto get_module_details = [](const char* name, void* baseAddress, size_t& moduleSize) {
|
||||
auto hndl = dlopen(name, RTLD_NOLOAD);
|
||||
if (hndl == NULL) {
|
||||
return false;
|
||||
}
|
||||
void* addr = dlsym(hndl, "CreateInterface");
|
||||
dlclose(hndl);
|
||||
|
||||
if (!addr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Dl_info info;
|
||||
if (dladdr(addr, &info) == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
baseAddress = info.dli_fbase;
|
||||
// It doesn't matter much if we figure out the module size
|
||||
// libaddrz coalesce maps on linux
|
||||
moduleSize = 0;
|
||||
return true;
|
||||
};
|
||||
#endif
|
||||
|
||||
// Early map commonly used modules, it's okay if not all of them are here
|
||||
// Everything else will be caught by "ToPseudoAddress" but you risk running out of ranges by then
|
||||
const char* libs[] = { "engine", "server", "tier0", "vstdlib" };
|
||||
|
||||
char formattedName[64];
|
||||
for (int i = 0; i < sizeof(libs) / sizeof(const char*); i++) {
|
||||
bridge->FormatSourceBinaryName(libs[i], formattedName, sizeof(formattedName));
|
||||
void* base_addr = nullptr;
|
||||
size_t module_size = 0;
|
||||
if (get_module_details(formattedName, base_addr, module_size)) {
|
||||
// Create the mapping (hopefully)
|
||||
m_dictionary.Make32bitAddress(base_addr, module_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void *PseudoAddressManager::FromPseudoAddress(uint32_t paddr)
|
||||
{
|
||||
#ifdef KE_ARCH_X64
|
||||
uint8_t index = paddr >> PSEUDO_OFFSET_BITS;
|
||||
uint32_t offset = paddr & ((1 << PSEUDO_OFFSET_BITS) - 1);
|
||||
|
||||
if (index >= m_NumEntries)
|
||||
if (paddr == 0) {
|
||||
return nullptr;
|
||||
|
||||
return reinterpret_cast<void *>(uintptr_t(m_AllocBases[index]) + offset);
|
||||
#else
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
return m_dictionary.RecoverAddress(paddr).value_or(nullptr);
|
||||
}
|
||||
|
||||
uint32_t PseudoAddressManager::ToPseudoAddress(void *addr)
|
||||
{
|
||||
#ifdef KE_ARCH_X64
|
||||
uint8_t index = 0;
|
||||
uint32_t offset = 0;
|
||||
bool hasEntry = false;
|
||||
void *base = GetAllocationBase(addr);
|
||||
|
||||
if (base) {
|
||||
for (int i = 0; i < m_NumEntries; i++) {
|
||||
if (m_AllocBases[i] == base) {
|
||||
index = i;
|
||||
hasEntry = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (addr == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!hasEntry) {
|
||||
index = m_NumEntries;
|
||||
if (m_NumEntries < SM_ARRAYSIZE(m_AllocBases))
|
||||
m_AllocBases[m_NumEntries++] = base;
|
||||
else
|
||||
return 0; // Table is full
|
||||
}
|
||||
|
||||
ptrdiff_t diff = uintptr_t(addr) - uintptr_t(base);
|
||||
|
||||
// Ensure difference fits in 26 bits
|
||||
if (diff > (UINT32_MAX >> PSEUDO_INDEX_BITS))
|
||||
return 0;
|
||||
|
||||
return (index << PSEUDO_OFFSET_BITS) | diff;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void *PseudoAddressManager::GetAllocationBase(void *ptr)
|
||||
{
|
||||
#if defined PLATFORM_WINDOWS
|
||||
|
||||
MEMORY_BASIC_INFORMATION info;
|
||||
if (!VirtualQuery(ptr, &info, sizeof(MEMORY_BASIC_INFORMATION)))
|
||||
return nullptr;
|
||||
return info.AllocationBase;
|
||||
|
||||
#elif defined PLATFORM_APPLE
|
||||
|
||||
#ifdef KE_ARCH_X86
|
||||
typedef vm_region_info_t mach_vm_region_info_t;
|
||||
typedef vm_region_basic_info_data_t mach_vm_region_basic_info_data_t;
|
||||
const vm_region_flavor_t MACH_VM_REGION_BASIC_INFO = VM_REGION_BASIC_INFO;
|
||||
const mach_msg_type_number_t MACH_VM_REGION_BASIC_INFO_COUNT = VM_REGION_BASIC_INFO_COUNT;
|
||||
#define mach_vm_region vm_region
|
||||
#elif defined KE_ARCH_X64
|
||||
typedef vm_region_info_64_t mach_vm_region_info_t ;
|
||||
typedef vm_region_basic_info_data_64_t mach_vm_region_basic_info_data_t;
|
||||
const vm_region_flavor_t MACH_VM_REGION_BASIC_INFO = VM_REGION_BASIC_INFO_64;
|
||||
const mach_msg_type_number_t MACH_VM_REGION_BASIC_INFO_COUNT = VM_REGION_BASIC_INFO_COUNT_64;
|
||||
#define mach_vm_region vm_region_64
|
||||
#endif
|
||||
vm_size_t size;
|
||||
vm_address_t vmaddr = reinterpret_cast<vm_address_t>(ptr);
|
||||
mach_vm_region_basic_info_data_t info;
|
||||
memory_object_name_t obj;
|
||||
vm_region_flavor_t flavor = MACH_VM_REGION_BASIC_INFO;
|
||||
mach_msg_type_number_t count = MACH_VM_REGION_BASIC_INFO_COUNT;
|
||||
|
||||
kern_return_t kr = mach_vm_region(mach_task_self(), &vmaddr, &size, flavor,
|
||||
reinterpret_cast<mach_vm_region_info_t>(&info),
|
||||
&count, &obj);
|
||||
|
||||
if (kr != KERN_SUCCESS)
|
||||
return nullptr;
|
||||
|
||||
return reinterpret_cast<void *>(vmaddr);
|
||||
|
||||
#elif defined PLATFORM_LINUX
|
||||
|
||||
uintptr_t addr = reinterpret_cast<uintptr_t>(ptr);
|
||||
|
||||
// Format:
|
||||
// lower upper prot stuff path
|
||||
// 08048000-0804c000 r-xp 00000000 03:03 1010107 /bin/cat
|
||||
FILE *fp = fopen("/proc/self/maps", "r");
|
||||
if (fp) {
|
||||
uintptr_t lower, upper;
|
||||
while (fscanf(fp, "%" PRIxPTR "-%" PRIxPTR, &lower, &upper) != EOF) {
|
||||
if (addr >= lower && addr <= upper) {
|
||||
fclose(fp);
|
||||
return reinterpret_cast<void *>(lower);
|
||||
}
|
||||
|
||||
// Read to end of line
|
||||
int c;
|
||||
while ((c = fgetc(fp)) != '\n') {
|
||||
if (c == EOF)
|
||||
break;
|
||||
}
|
||||
if (c == EOF)
|
||||
break;
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
return nullptr;
|
||||
#endif
|
||||
return m_dictionary.Make32bitAddress(addr).value_or(0);
|
||||
}
|
||||
|
||||
@ -31,6 +31,7 @@
|
||||
#define _INCLUDE_SOURCEMOD_PSEUDOADDRESSMANAGER_H_
|
||||
|
||||
#include "common_logic.h"
|
||||
#include "libaddrz/addrz.h"
|
||||
|
||||
class PseudoAddressManager
|
||||
{
|
||||
@ -39,13 +40,9 @@ public:
|
||||
public:
|
||||
void *FromPseudoAddress(uint32_t paddr);
|
||||
uint32_t ToPseudoAddress(void *addr);
|
||||
void Initialize();
|
||||
private:
|
||||
void *GetAllocationBase(void *ptr);
|
||||
private:
|
||||
static constexpr uint8_t PSEUDO_OFFSET_BITS = 26;
|
||||
static constexpr uint8_t PSEUDO_INDEX_BITS = sizeof(uint32_t) * 8 - PSEUDO_OFFSET_BITS;
|
||||
void *m_AllocBases[1 << PSEUDO_INDEX_BITS];
|
||||
uint8_t m_NumEntries;
|
||||
am::AddressDict m_dictionary;
|
||||
};
|
||||
|
||||
#endif // _INCLUDE_SOURCEMOD_PSEUDOADDRESSMANAGER_H_
|
||||
|
||||
@ -57,6 +57,7 @@
|
||||
#include "RootConsoleMenu.h"
|
||||
#include "CellArray.h"
|
||||
#include "smn_entitylump.h"
|
||||
#include "PseudoAddrManager.h"
|
||||
#include <bridge/include/BridgeAPI.h>
|
||||
#include <bridge/include/IProviderCallbacks.h>
|
||||
|
||||
@ -86,9 +87,7 @@ IScriptManager *scripts = &g_PluginSys;
|
||||
IExtensionSys *extsys = &g_Extensions;
|
||||
ILogger *logger = &g_Logger;
|
||||
CNativeOwner g_CoreNatives;
|
||||
#ifdef KE_ARCH_X64
|
||||
PseudoAddressManager pseudoAddr;
|
||||
#endif
|
||||
|
||||
EntityLumpParseResult lastParseResult;
|
||||
|
||||
@ -122,20 +121,12 @@ static void RegisterProfiler(IProfilingTool *tool)
|
||||
|
||||
static void *FromPseudoAddress(uint32_t paddr)
|
||||
{
|
||||
#ifdef KE_ARCH_X64
|
||||
return pseudoAddr.FromPseudoAddress(paddr);
|
||||
#else
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
static uint32_t ToPseudoAddress(void *addr)
|
||||
{
|
||||
#ifdef KE_ARCH_X64
|
||||
return pseudoAddr.ToPseudoAddress(addr);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void SetEntityLumpWritable(bool writable)
|
||||
@ -236,6 +227,7 @@ static void logic_init(CoreProvider* core, sm_logic_t* _logic)
|
||||
g_pSourcePawn2 = *core->spe2;
|
||||
SMGlobalClass::head = core->listeners;
|
||||
|
||||
pseudoAddr.Initialize();
|
||||
g_ShareSys.Initialize();
|
||||
g_pCoreIdent = g_ShareSys.CreateCoreIdentity();
|
||||
|
||||
|
||||
1
core/logic/libaddrz
Submodule
1
core/logic/libaddrz
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 661cd316e6ff8e8560efa20db1794f3fa479647c
|
||||
@ -587,27 +587,68 @@ static cell_t FindStringInArray(IPluginContext *pContext, const cell_t *params)
|
||||
return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
|
||||
}
|
||||
|
||||
// the blocknumber is not guaranteed to always be passed
|
||||
// The parameters above 2 are optional
|
||||
|
||||
size_t blocknumber = 0;
|
||||
if (params[0] >= 3)
|
||||
{
|
||||
blocknumber = (size_t)params[3];
|
||||
if (blocknumber >= array->blocksize())
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid block %d (blocksize: %d)", blocknumber, array->blocksize());
|
||||
}
|
||||
}
|
||||
|
||||
if (blocknumber >= array->blocksize())
|
||||
int startidx = -1;
|
||||
if (params[0] >= 4)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid block %d (blocksize: %d)", blocknumber, array->blocksize());
|
||||
startidx = params[4];
|
||||
if (startidx > 0 && startidx > array->size())
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid start index %d (max: %d)", startidx, array->size());
|
||||
}
|
||||
}
|
||||
|
||||
bool reverse = false;
|
||||
if (params[0] >= 5)
|
||||
{
|
||||
reverse = params[5];
|
||||
}
|
||||
|
||||
typedef int (*STRCOMPARE)(const char *, const char *);
|
||||
STRCOMPARE comparefn = (params[0] < 6 || params[6]) ? strcmp : strcasecmp;
|
||||
|
||||
char *str;
|
||||
pContext->LocalToString(params[2], &str);
|
||||
|
||||
for (unsigned int i = 0; i < array->size(); i++)
|
||||
if (reverse)
|
||||
{
|
||||
const char *array_str = (const char *)&array->base()[i * array->blocksize() + blocknumber];
|
||||
if (strcmp(str, array_str) == 0)
|
||||
if (startidx < 0)
|
||||
{
|
||||
return (cell_t) i;
|
||||
startidx = array->size();
|
||||
}
|
||||
for (int i = (startidx - 1); i >= 0; i--)
|
||||
{
|
||||
const char *array_str = (const char *)&array->base()[i * array->blocksize() + blocknumber];
|
||||
if (comparefn(str, array_str) == 0)
|
||||
{
|
||||
return (cell_t) i;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (startidx < -1)
|
||||
{
|
||||
startidx = -1;
|
||||
}
|
||||
for (unsigned int i = (startidx + 1); i < array->size(); i++)
|
||||
{
|
||||
const char *array_str = (const char *)&array->base()[i * array->blocksize() + blocknumber];
|
||||
if (comparefn(str, array_str) == 0)
|
||||
{
|
||||
return (cell_t) i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -626,24 +667,62 @@ static cell_t FindValueInArray(IPluginContext *pContext, const cell_t *params)
|
||||
return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
|
||||
}
|
||||
|
||||
// the blocknumber is not guaranteed to always be passed
|
||||
// The parameters above 2 are optional
|
||||
|
||||
size_t blocknumber = 0;
|
||||
if (params[0] >= 3)
|
||||
{
|
||||
blocknumber = (size_t) params[3];
|
||||
}
|
||||
|
||||
if (blocknumber >= array->blocksize())
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid block %d (blocksize: %d)", blocknumber, array->blocksize());
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < array->size(); i++)
|
||||
{
|
||||
cell_t *blk = array->at(i);
|
||||
if (params[2] == blk[blocknumber])
|
||||
blocknumber = (size_t)params[3];
|
||||
if (blocknumber >= array->blocksize())
|
||||
{
|
||||
return (cell_t) i;
|
||||
return pContext->ThrowNativeError("Invalid block %d (blocksize: %d)", blocknumber, array->blocksize());
|
||||
}
|
||||
}
|
||||
|
||||
int startidx = -1;
|
||||
if (params[0] >= 4)
|
||||
{
|
||||
startidx = params[4];
|
||||
if (startidx > 0 && startidx > array->size())
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid start index %d (max: %d)", startidx, array->size());
|
||||
}
|
||||
}
|
||||
|
||||
bool reverse = false;
|
||||
if (params[0] >= 5)
|
||||
{
|
||||
reverse = params[5];
|
||||
}
|
||||
|
||||
if (reverse)
|
||||
{
|
||||
if (startidx < 0)
|
||||
{
|
||||
startidx = array->size();
|
||||
}
|
||||
for (int i = (startidx - 1); i >= 0; i--)
|
||||
{
|
||||
cell_t *blk = array->at(i);
|
||||
if (params[2] == blk[blocknumber])
|
||||
{
|
||||
return (cell_t) i;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (startidx < -1)
|
||||
{
|
||||
startidx = -1;
|
||||
}
|
||||
for (unsigned int i = (startidx + 1); i < array->size(); i++)
|
||||
{
|
||||
cell_t *blk = array->at(i);
|
||||
if (params[2] == blk[blocknumber])
|
||||
{
|
||||
return (cell_t) i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -59,6 +59,7 @@
|
||||
#include <bridge/include/CoreProvider.h>
|
||||
#include <bridge/include/IScriptManager.h>
|
||||
#include <bridge/include/IExtensionBridge.h>
|
||||
#include "PseudoAddrManager.h"
|
||||
#include <sh_vector.h>
|
||||
|
||||
using namespace SourceMod;
|
||||
@ -863,11 +864,10 @@ enum NumberType
|
||||
|
||||
static cell_t LoadFromAddress(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
#ifdef KE_ARCH_X86
|
||||
void *addr = reinterpret_cast<void*>(params[1]);
|
||||
#else
|
||||
void *addr = pseudoAddr.FromPseudoAddress(params[1]);
|
||||
#endif
|
||||
if (pContext->GetRuntime()->FindPubvarByName("__Virtual_Address__", nullptr) == SP_ERROR_NONE) {
|
||||
addr = pseudoAddr.FromPseudoAddress(params[1]);
|
||||
}
|
||||
|
||||
if (addr == NULL)
|
||||
{
|
||||
@ -892,14 +892,12 @@ static cell_t LoadFromAddress(IPluginContext *pContext, const cell_t *params)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static cell_t StoreToAddress(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
#ifdef KE_ARCH_X86
|
||||
void *addr = reinterpret_cast<void*>(params[1]);
|
||||
#else
|
||||
void *addr = pseudoAddr.FromPseudoAddress(params[1]);
|
||||
#endif
|
||||
if (pContext->GetRuntime()->FindPubvarByName("__Virtual_Address__", nullptr) == SP_ERROR_NONE) {
|
||||
addr = pseudoAddr.FromPseudoAddress(params[1]);
|
||||
}
|
||||
|
||||
if (addr == NULL)
|
||||
{
|
||||
@ -950,6 +948,60 @@ static cell_t StoreToAddress(IPluginContext *pContext, const cell_t *params)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static cell_t LoadAddressFromAddress(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
void *addr = reinterpret_cast<void*>(params[1]);
|
||||
if (pContext->GetRuntime()->FindPubvarByName("__Virtual_Address__", nullptr) == SP_ERROR_NONE) {
|
||||
addr = pseudoAddr.FromPseudoAddress(params[1]);
|
||||
}
|
||||
|
||||
if (addr == NULL)
|
||||
{
|
||||
return pContext->ThrowNativeError("Address cannot be null");
|
||||
}
|
||||
else if (reinterpret_cast<uintptr_t>(addr) < VALID_MINIMUM_MEMORY_ADDRESS)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid address 0x%x is pointing to reserved memory.", addr);
|
||||
}
|
||||
|
||||
void* data = *reinterpret_cast<void**>(addr);
|
||||
if (pContext->GetRuntime()->FindPubvarByName("__Virtual_Address__", nullptr) == SP_ERROR_NONE) {
|
||||
return pseudoAddr.ToPseudoAddress(data);
|
||||
}
|
||||
return reinterpret_cast<uintptr_t>(data);
|
||||
}
|
||||
|
||||
static cell_t StoreAddressToAddress(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
void *addr = reinterpret_cast<void*>(params[1]);
|
||||
if (pContext->GetRuntime()->FindPubvarByName("__Virtual_Address__", nullptr) == SP_ERROR_NONE) {
|
||||
addr = pseudoAddr.FromPseudoAddress(params[1]);
|
||||
}
|
||||
|
||||
if (addr == NULL)
|
||||
{
|
||||
return pContext->ThrowNativeError("Address cannot be null");
|
||||
}
|
||||
else if (reinterpret_cast<uintptr_t>(addr) < VALID_MINIMUM_MEMORY_ADDRESS)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid address 0x%x is pointing to reserved memory.", addr);
|
||||
}
|
||||
|
||||
void *data = reinterpret_cast<void*>(params[2]);
|
||||
if (pContext->GetRuntime()->FindPubvarByName("__Virtual_Address__", nullptr) == SP_ERROR_NONE) {
|
||||
data = pseudoAddr.FromPseudoAddress(params[2]);
|
||||
}
|
||||
|
||||
bool updateMemAccess = params[3];
|
||||
|
||||
if (updateMemAccess) {
|
||||
SourceHook::SetMemAccess(addr, sizeof(void*), SH_MEM_READ|SH_MEM_WRITE|SH_MEM_EXEC);
|
||||
}
|
||||
*reinterpret_cast<void**>(addr) = data;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static cell_t IsNullVector(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
cell_t *pNullVec = pContext->GetNullRef(SP_NULL_VECTOR);
|
||||
@ -1157,6 +1209,8 @@ REGISTER_NATIVES(coreNatives)
|
||||
{"RequireFeature", RequireFeature},
|
||||
{"LoadFromAddress", LoadFromAddress},
|
||||
{"StoreToAddress", StoreToAddress},
|
||||
{"LoadAddressFromAddress", LoadAddressFromAddress},
|
||||
{"StoreAddressToAddress", StoreAddressToAddress},
|
||||
{"IsNullVector", IsNullVector},
|
||||
{"IsNullString", IsNullString},
|
||||
{"LogStackTrace", LogStackTrace},
|
||||
|
||||
@ -32,6 +32,7 @@
|
||||
#include "common_logic.h"
|
||||
#include <IHandleSys.h>
|
||||
#include "GameConfigs.h"
|
||||
#include "PseudoAddrManager.h"
|
||||
|
||||
HandleType_t g_GameConfigsType;
|
||||
|
||||
@ -155,11 +156,10 @@ static cell_t smn_GameConfGetAddress(IPluginContext *pCtx, const cell_t *params)
|
||||
if (!gc->GetAddress(key, &val))
|
||||
return 0;
|
||||
|
||||
#ifdef KE_ARCH_X86
|
||||
return (cell_t)val;
|
||||
#else
|
||||
return pseudoAddr.ToPseudoAddress(val);
|
||||
#endif
|
||||
if (pCtx->GetRuntime()->FindPubvarByName("__Virtual_Address__", nullptr) == SP_ERROR_NONE) {
|
||||
return pseudoAddr.ToPseudoAddress(val);
|
||||
}
|
||||
return reinterpret_cast<uintptr_t>(val);
|
||||
}
|
||||
|
||||
static cell_t smn_GameConfGetMemSig(IPluginContext *pCtx, const cell_t *params)
|
||||
@ -187,11 +187,10 @@ static cell_t smn_GameConfGetMemSig(IPluginContext *pCtx, const cell_t *params)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef KE_ARCH_X86
|
||||
return (cell_t)val;
|
||||
#else
|
||||
return pseudoAddr.ToPseudoAddress(val);
|
||||
#endif
|
||||
if (pCtx->GetRuntime()->FindPubvarByName("__Virtual_Address__", nullptr) == SP_ERROR_NONE) {
|
||||
return pseudoAddr.ToPseudoAddress(val);
|
||||
}
|
||||
return reinterpret_cast<uintptr_t>(val);
|
||||
}
|
||||
|
||||
static GameConfigsNatives s_GameConfigsNatives;
|
||||
|
||||
@ -31,6 +31,7 @@
|
||||
#include <am-float.h>
|
||||
#include <am-string.h>
|
||||
#include <IDBDriver.h>
|
||||
#include <IGameHelpers.h>
|
||||
#include <ITranslator.h>
|
||||
#include <bridge/include/IScriptManager.h>
|
||||
#include <bridge/include/CoreProvider.h>
|
||||
@ -188,6 +189,15 @@ bool AddString(char **buf_p, size_t &maxlen, const char *string, int width, int
|
||||
|
||||
width -= size;
|
||||
|
||||
if (!(flags & LADJUST))
|
||||
{
|
||||
while ((width-- > 0) && maxlen)
|
||||
{
|
||||
*buf++ = ' ';
|
||||
maxlen--;
|
||||
}
|
||||
}
|
||||
|
||||
if (g_FormatEscapeDatabase && (flags & NOESCAPE) == 0)
|
||||
{
|
||||
char *tempBuffer = NULL;
|
||||
@ -226,10 +236,13 @@ bool AddString(char **buf_p, size_t &maxlen, const char *string, int width, int
|
||||
}
|
||||
}
|
||||
|
||||
while ((width-- > 0) && maxlen)
|
||||
if (flags & LADJUST)
|
||||
{
|
||||
*buf++ = ' ';
|
||||
maxlen--;
|
||||
while ((width-- > 0) && maxlen)
|
||||
{
|
||||
*buf++ = ' ';
|
||||
maxlen--;
|
||||
}
|
||||
}
|
||||
|
||||
*buf_p = buf;
|
||||
@ -254,6 +267,12 @@ void AddFloat(char **buf_p, size_t &maxlen, double fval, int width, int prec, in
|
||||
return;
|
||||
}
|
||||
|
||||
if (ke::IsInfinite(static_cast<float>(fval)))
|
||||
{
|
||||
AddString(buf_p, maxlen, "Inf", width, prec, flags | NOESCAPE);
|
||||
return;
|
||||
}
|
||||
|
||||
// default precision
|
||||
if (prec < 0)
|
||||
{
|
||||
@ -485,13 +504,15 @@ void AddInt(char **buf_p, size_t &maxlen, int val, int width, int flags)
|
||||
unsignedVal /= 10;
|
||||
} while (unsignedVal);
|
||||
|
||||
if (signedVal < 0)
|
||||
{
|
||||
text[digits++] = '-';
|
||||
}
|
||||
|
||||
buf = *buf_p;
|
||||
|
||||
// minus sign BEFORE left padding if padding with zeros
|
||||
if (signedVal < 0 && maxlen && (flags & ZEROPAD))
|
||||
{
|
||||
*buf++ = '-';
|
||||
maxlen--;
|
||||
}
|
||||
|
||||
if (!(flags & LADJUST))
|
||||
{
|
||||
while ((digits < width) && maxlen)
|
||||
@ -502,6 +523,13 @@ void AddInt(char **buf_p, size_t &maxlen, int val, int width, int flags)
|
||||
}
|
||||
}
|
||||
|
||||
// minus sign AFTER left padding if padding with spaces
|
||||
if (signedVal < 0 && maxlen && !(flags & ZEROPAD))
|
||||
{
|
||||
*buf++ = '-';
|
||||
maxlen--;
|
||||
}
|
||||
|
||||
while (digits-- && maxlen)
|
||||
{
|
||||
*buf++ = text[digits];
|
||||
@ -1199,6 +1227,22 @@ reswitch:
|
||||
arg++;
|
||||
break;
|
||||
}
|
||||
case 'E':
|
||||
{
|
||||
CHECK_ARGS(0);
|
||||
cell_t *value;
|
||||
pCtx->LocalToPhysAddr(params[arg], &value);
|
||||
|
||||
CBaseEntity *entity = gamehelpers->ReferenceToEntity(*value);
|
||||
if (!entity)
|
||||
return pCtx->ThrowNativeError("Entity index %d is invalid (arg %d)", *value, arg);
|
||||
|
||||
const char *classname = gamehelpers->GetEntityClassname(entity);
|
||||
if (!AddString(&buf_p, llen, classname, width, prec, flags))
|
||||
return pCtx->ThrowNativeError("Escaped string would be truncated (arg %d)", arg);
|
||||
arg++;
|
||||
break;
|
||||
}
|
||||
case 's':
|
||||
{
|
||||
CHECK_ARGS(0);
|
||||
|
||||
@ -194,6 +194,25 @@ public:
|
||||
{
|
||||
return filesystem->GetSearchPath(pathID, bGetPackFiles, pPath, nMaxLen);
|
||||
}
|
||||
const char* GetGameBinArchSubdirectory() override
|
||||
{
|
||||
#if defined( KE_ARCH_X64 ) && SOURCE_ENGINE >= SE_BLADE
|
||||
#if defined( PLATFORM_WINDOWS )
|
||||
#if SOURCE_ENGINE == SE_MCV
|
||||
return "win64" PLATFORM_SEP;
|
||||
#else
|
||||
return "x64" PLATFORM_SEP;
|
||||
#endif // SOURCE_ENGINE == SE_MCV
|
||||
#elif defined( PLATFORM_LINUX )
|
||||
return "linux64" PLATFORM_SEP;
|
||||
#else
|
||||
#error "Unsupported platform"
|
||||
#endif // PLATFORM
|
||||
#else
|
||||
// Already included in the GameBin path(s), if required
|
||||
return "";
|
||||
#endif // defined( KE_ARCH_X64 ) && SOURCE_ENGINE >= SE_BLADE
|
||||
}
|
||||
} fs_wrapper;
|
||||
|
||||
class VPlayerInfo_Logic : public IPlayerInfoBridge
|
||||
|
||||
@ -724,11 +724,10 @@ static cell_t GetEntDataEnt2(IPluginContext *pContext, const cell_t *params)
|
||||
|
||||
static cell_t LoadEntityFromHandleAddress(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
#ifdef KE_ARCH_X86
|
||||
void *addr = reinterpret_cast<void*>(params[1]);
|
||||
#else
|
||||
void *addr = g_SourceMod.FromPseudoAddress(params[1]);
|
||||
#endif
|
||||
if (pContext->GetRuntime()->FindPubvarByName("__Virtual_Address__", nullptr) == SP_ERROR_NONE) {
|
||||
addr = g_SourceMod.FromPseudoAddress(params[1]);
|
||||
}
|
||||
|
||||
if (addr == NULL)
|
||||
{
|
||||
@ -835,11 +834,10 @@ static cell_t SetEntDataEnt2(IPluginContext *pContext, const cell_t *params)
|
||||
|
||||
static cell_t StoreEntityToHandleAddress(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
#ifdef KE_ARCH_X86
|
||||
void *addr = reinterpret_cast<void*>(params[1]);
|
||||
#else
|
||||
void *addr = g_SourceMod.FromPseudoAddress(params[1]);
|
||||
#endif
|
||||
if (pContext->GetRuntime()->FindPubvarByName("__Virtual_Address__", nullptr) == SP_ERROR_NONE) {
|
||||
addr = g_SourceMod.FromPseudoAddress(params[1]);
|
||||
}
|
||||
|
||||
if (addr == NULL)
|
||||
{
|
||||
@ -2772,11 +2770,10 @@ static cell_t GetEntityAddress(IPluginContext *pContext, const cell_t *params)
|
||||
return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
|
||||
}
|
||||
|
||||
#ifdef KE_ARCH_X86
|
||||
return reinterpret_cast<cell_t>(pEntity);
|
||||
#else
|
||||
return g_SourceMod.ToPseudoAddress(pEntity);
|
||||
#endif
|
||||
if (pContext->GetRuntime()->FindPubvarByName("__Virtual_Address__", nullptr) == SP_ERROR_NONE) {
|
||||
return g_SourceMod.ToPseudoAddress(pEntity);
|
||||
}
|
||||
return reinterpret_cast<uintptr_t>(pEntity);
|
||||
}
|
||||
|
||||
REGISTER_NATIVES(entityNatives)
|
||||
|
||||
@ -30,8 +30,12 @@
|
||||
#include "sourcemod.h"
|
||||
#include "sourcemm_api.h"
|
||||
|
||||
#ifndef VPROF_ENABLED
|
||||
#define VPROF_ENABLED
|
||||
#endif
|
||||
#ifndef RAD_TELEMETRY_DISABLED
|
||||
#define RAD_TELEMETRY_DISABLED
|
||||
#endif
|
||||
#include <tier0/vprof.h>
|
||||
|
||||
VProfTool sVProfTool;
|
||||
|
||||
@ -376,7 +376,7 @@ ReturnAction_t HandleDetour(HookType_t hookType, CHook* pDetour)
|
||||
{
|
||||
// The this pointer is implicitly always the first argument.
|
||||
void *thisPtr = pDetour->GetArgument<void *>(0);
|
||||
cell_t thisAddr = GetThisPtr(thisPtr, pWrapper->thisType);
|
||||
cell_t thisAddr = GetThisPtr(pCallback->GetParentContext(), thisPtr, pWrapper->thisType);
|
||||
pCallback->PushCell(thisAddr);
|
||||
}
|
||||
|
||||
@ -532,6 +532,7 @@ CDynamicHooksSourcePawn::CDynamicHooksSourcePawn(HookSetup *setup, CHook *pDetou
|
||||
this->hookType = setup->hookType;
|
||||
this->m_pDetour = pDetour;
|
||||
this->callConv = setup->callConv;
|
||||
this->thisFuncCallConv = setup->callConv;
|
||||
}
|
||||
|
||||
HookReturnStruct *CDynamicHooksSourcePawn::GetReturnStruct()
|
||||
|
||||
@ -42,6 +42,8 @@ enum SDKFuncConfSource
|
||||
SDKConf_Address
|
||||
};
|
||||
|
||||
using ParamVector = SourceHook::CVector<ParamInfo>;
|
||||
|
||||
bool GetHandleIfValidOrError(HandleType_t type, void **object, IPluginContext *pContext, cell_t param)
|
||||
{
|
||||
if(param == BAD_HANDLE)
|
||||
@ -81,6 +83,56 @@ bool GetCallbackArgHandleIfValidOrError(HandleType_t type, HandleType_t otherTyp
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GetObjectAddrOrThis(IPluginContext *pContext, const cell_t *params, void *&retAddr)
|
||||
{
|
||||
HookParamsStruct *paramStruct = NULL;
|
||||
retAddr = NULL;
|
||||
|
||||
if(!GetCallbackArgHandleIfValidOrError(g_HookParamsHandle, g_HookReturnHandle, (void **)¶mStruct, pContext, params[1]))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if(params[2] != 0)
|
||||
{
|
||||
const ParamVector ¶msVec = paramStruct->dg->params;
|
||||
|
||||
if(params[2] < 0 || params[2] > static_cast<int>(paramsVec.size()))
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid param number %i max params is %i", params[2], paramsVec.size());
|
||||
}
|
||||
|
||||
int index = params[2] - 1;
|
||||
const ParamInfo ¶m = paramsVec.at(index);
|
||||
|
||||
if(param.type != HookParamType_ObjectPtr && param.type != HookParamType_Object)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid object value type %i", param.type);
|
||||
}
|
||||
|
||||
size_t offset = GetParamOffset(paramStruct, index);
|
||||
retAddr = GetObjectAddr(param.type, param.flags, paramStruct->orgParams, offset);
|
||||
return true;
|
||||
}
|
||||
|
||||
const DHooksInfo* dgInfo = paramStruct->dg;
|
||||
|
||||
if(dgInfo->thisFuncCallConv != CallConv_THISCALL)
|
||||
{
|
||||
return pContext->ThrowNativeError("Parameter 'this' is only available in member functions");
|
||||
}
|
||||
|
||||
if(dgInfo->thisType != ThisPointer_Address
|
||||
&& dgInfo->thisType != ThisPointer_CBaseEntity
|
||||
&& dgInfo->hookType != HookType_GameRules)
|
||||
{
|
||||
return pContext->ThrowNativeError("Parameter 'this' is not specified as an address, it is not available");
|
||||
}
|
||||
|
||||
retAddr = g_SHPtr->GetIfacePtr();
|
||||
return true;
|
||||
}
|
||||
|
||||
IPluginFunction *GetCallback(IPluginContext *pContext, HookSetup * setup, const cell_t *params, cell_t callback_index)
|
||||
{
|
||||
IPluginFunction *ret = NULL;
|
||||
@ -122,7 +174,12 @@ cell_t Native_CreateHook(IPluginContext *pContext, const cell_t *params)
|
||||
//native Handle:DHookCreateDetour(Address:funcaddr, CallingConvention:callConv, ReturnType:returntype, ThisPointerType:thistype);
|
||||
cell_t Native_CreateDetour(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
HookSetup *setup = new HookSetup((ReturnType)params[3], PASSFLAG_BYVAL, (CallingConvention)params[2], (ThisPointerType)params[4], (void *)params[1]);
|
||||
void* addr = reinterpret_cast<void*>(params[1]);
|
||||
if (pContext->GetRuntime()->FindPubvarByName("__Virtual_Address__", nullptr) == SP_ERROR_NONE) {
|
||||
addr = g_pSM->FromPseudoAddress(params[1]);
|
||||
}
|
||||
|
||||
HookSetup *setup = new HookSetup((ReturnType)params[3], PASSFLAG_BYVAL, (CallingConvention)params[2], (ThisPointerType)params[4], addr);
|
||||
|
||||
Handle_t hndl = handlesys->CreateHandle(g_HookSetupHandle, setup, pContext->GetIdentity(), myself->GetIdentity(), NULL);
|
||||
|
||||
@ -589,7 +646,10 @@ cell_t HookRawImpl(IPluginContext *pContext, const cell_t *params, int callbackI
|
||||
if (removalcbIndex > 0)
|
||||
removalcb = pContext->GetFunctionById(params[removalcbIndex]);
|
||||
|
||||
void *iface = (void *)(params[3]);
|
||||
void* iface = reinterpret_cast<void*>(params[3]);
|
||||
if (pContext->GetRuntime()->FindPubvarByName("__Virtual_Address__", nullptr) == SP_ERROR_NONE) {
|
||||
iface = g_pSM->FromPseudoAddress(params[3]);
|
||||
}
|
||||
|
||||
for(int i = g_pHooks.size() -1; i >= 0; i--)
|
||||
{
|
||||
@ -1089,28 +1149,12 @@ cell_t Native_RemoveEntityListener(IPluginContext *pContext, const cell_t *param
|
||||
//native any:DHookGetParamObjectPtrVar(Handle:hParams, num, offset, ObjectValueType:type);
|
||||
cell_t Native_GetParamObjectPtrVar(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
HookParamsStruct *paramStruct;
|
||||
|
||||
if(!GetCallbackArgHandleIfValidOrError(g_HookParamsHandle, g_HookReturnHandle, (void **)¶mStruct, pContext, params[1]))
|
||||
void *addr = NULL;
|
||||
if(!GetObjectAddrOrThis(pContext, params, addr))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(params[2] <= 0 || params[2] > (int)paramStruct->dg->params.size())
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid param number %i max params is %i", params[2], paramStruct->dg->params.size());
|
||||
}
|
||||
|
||||
int index = params[2] - 1;
|
||||
|
||||
if(paramStruct->dg->params.at(index).type != HookParamType_ObjectPtr && paramStruct->dg->params.at(index).type != HookParamType_Object)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid object value type %i", paramStruct->dg->params.at(index).type);
|
||||
}
|
||||
|
||||
size_t offset = GetParamOffset(paramStruct, index);
|
||||
void *addr = GetObjectAddr(paramStruct->dg->params.at(index).type, paramStruct->dg->params.at(index).flags, paramStruct->orgParams, offset);
|
||||
|
||||
switch((ObjectValueType)params[4])
|
||||
{
|
||||
case ObjectValueType_Int:
|
||||
@ -1160,28 +1204,12 @@ cell_t Native_GetParamObjectPtrVar(IPluginContext *pContext, const cell_t *param
|
||||
//native DHookSetParamObjectPtrVar(Handle:hParams, num, offset, ObjectValueType:type, value)
|
||||
cell_t Native_SetParamObjectPtrVar(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
HookParamsStruct *paramStruct;
|
||||
|
||||
if(!GetCallbackArgHandleIfValidOrError(g_HookParamsHandle, g_HookReturnHandle, (void **)¶mStruct, pContext, params[1]))
|
||||
void *addr = NULL;
|
||||
if(!GetObjectAddrOrThis(pContext, params, addr))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(params[2] <= 0 || params[2] > (int)paramStruct->dg->params.size())
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid param number %i max params is %i", params[2], paramStruct->dg->params.size());
|
||||
}
|
||||
|
||||
int index = params[2] - 1;
|
||||
|
||||
if(paramStruct->dg->params.at(index).type != HookParamType_ObjectPtr && paramStruct->dg->params.at(index).type != HookParamType_Object)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid object value type %i", paramStruct->dg->params.at(index).type);
|
||||
}
|
||||
|
||||
size_t offset = GetParamOffset(paramStruct, index);
|
||||
void *addr = GetObjectAddr(paramStruct->dg->params.at(index).type, paramStruct->dg->params.at(index).flags, paramStruct->orgParams, offset);
|
||||
|
||||
switch((ObjectValueType)params[4])
|
||||
{
|
||||
case ObjectValueType_Int:
|
||||
@ -1245,28 +1273,12 @@ cell_t Native_SetParamObjectPtrVar(IPluginContext *pContext, const cell_t *param
|
||||
//native DHookGetParamObjectPtrVarVector(Handle:hParams, num, offset, ObjectValueType:type, Float:buffer[3]);
|
||||
cell_t Native_GetParamObjectPtrVarVector(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
HookParamsStruct *paramStruct;
|
||||
|
||||
if(!GetCallbackArgHandleIfValidOrError(g_HookParamsHandle, g_HookReturnHandle, (void **)¶mStruct, pContext, params[1]))
|
||||
void *addr = NULL;
|
||||
if(!GetObjectAddrOrThis(pContext, params, addr))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(params[2] <= 0 || params[2] > (int)paramStruct->dg->params.size())
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid param number %i max params is %i", params[2], paramStruct->dg->params.size());
|
||||
}
|
||||
|
||||
int index = params[2] - 1;
|
||||
|
||||
if(paramStruct->dg->params.at(index).type != HookParamType_ObjectPtr && paramStruct->dg->params.at(index).type != HookParamType_Object)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid object value type %i", paramStruct->dg->params.at(index).type);
|
||||
}
|
||||
|
||||
size_t offset = GetParamOffset(paramStruct, index);
|
||||
void *addr = GetObjectAddr(paramStruct->dg->params.at(index).type, paramStruct->dg->params.at(index).flags, paramStruct->orgParams, offset);
|
||||
|
||||
cell_t *buffer;
|
||||
pContext->LocalToPhysAddr(params[5], &buffer);
|
||||
|
||||
@ -1299,28 +1311,12 @@ cell_t Native_GetParamObjectPtrVarVector(IPluginContext *pContext, const cell_t
|
||||
//native DHookSetParamObjectPtrVarVector(Handle:hParams, num, offset, ObjectValueType:type, Float:value[3]);
|
||||
cell_t Native_SetParamObjectPtrVarVector(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
HookParamsStruct *paramStruct;
|
||||
|
||||
if(!GetCallbackArgHandleIfValidOrError(g_HookParamsHandle, g_HookReturnHandle, (void **)¶mStruct, pContext, params[1]))
|
||||
void *addr = NULL;
|
||||
if(!GetObjectAddrOrThis(pContext, params, addr))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(params[2] <= 0 || params[2] > (int)paramStruct->dg->params.size())
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid param number %i max params is %i", params[2], paramStruct->dg->params.size());
|
||||
}
|
||||
|
||||
int index = params[2] - 1;
|
||||
|
||||
if(paramStruct->dg->params.at(index).type != HookParamType_ObjectPtr && paramStruct->dg->params.at(index).type != HookParamType_Object)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid object value type %i", paramStruct->dg->params.at(index).type);
|
||||
}
|
||||
|
||||
size_t offset = GetParamOffset(paramStruct, index);
|
||||
void *addr = GetObjectAddr(paramStruct->dg->params.at(index).type, paramStruct->dg->params.at(index).flags, paramStruct->orgParams, offset);
|
||||
|
||||
cell_t *buffer;
|
||||
pContext->LocalToPhysAddr(params[5], &buffer);
|
||||
|
||||
@ -1352,28 +1348,12 @@ cell_t Native_SetParamObjectPtrVarVector(IPluginContext *pContext, const cell_t
|
||||
//native DHookGetParamObjectPtrString(Handle:hParams, num, offset, ObjectValueType:type, String:buffer[], size)
|
||||
cell_t Native_GetParamObjectPtrString(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
HookParamsStruct *paramStruct;
|
||||
|
||||
if(!GetCallbackArgHandleIfValidOrError(g_HookParamsHandle, g_HookReturnHandle, (void **)¶mStruct, pContext, params[1]))
|
||||
void *addr = NULL;
|
||||
if (!GetObjectAddrOrThis(pContext, params, addr))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(params[2] <= 0 || params[2] > (int)paramStruct->dg->params.size())
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid param number %i max params is %i", params[2], paramStruct->dg->params.size());
|
||||
}
|
||||
|
||||
int index = params[2] - 1;
|
||||
|
||||
if(paramStruct->dg->params.at(index).type != HookParamType_ObjectPtr && paramStruct->dg->params.at(index).type != HookParamType_Object)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid object value type %i", paramStruct->dg->params.at(index).type);
|
||||
}
|
||||
|
||||
size_t offset = GetParamOffset(paramStruct, index);
|
||||
void *addr = GetObjectAddr(paramStruct->dg->params.at(index).type, paramStruct->dg->params.at(index).flags, paramStruct->orgParams, offset);
|
||||
|
||||
switch((ObjectValueType)params[4])
|
||||
{
|
||||
case ObjectValueType_CharPtr:
|
||||
@ -1510,6 +1490,10 @@ cell_t Native_GetParamAddress(IPluginContext *pContext, const cell_t *params)
|
||||
}
|
||||
|
||||
size_t offset = GetParamOffset(paramStruct, index);
|
||||
|
||||
if (pContext->GetRuntime()->FindPubvarByName("__Virtual_Address__", nullptr) == SP_ERROR_NONE) {
|
||||
return g_pSM->ToPseudoAddress(*(void**)((intptr_t)paramStruct->orgParams + offset));
|
||||
}
|
||||
return *(cell_t *)((intptr_t)paramStruct->orgParams + offset);
|
||||
}
|
||||
|
||||
|
||||
@ -465,19 +465,18 @@ HookReturnStruct *GetReturnStruct(DHooksCallback *dg)
|
||||
return res;
|
||||
}
|
||||
|
||||
cell_t GetThisPtr(void *iface, ThisPointerType type)
|
||||
cell_t GetThisPtr(IPluginContext* pContext, void *iface, ThisPointerType type)
|
||||
{
|
||||
if(type == ThisPointer_CBaseEntity)
|
||||
if (type == ThisPointer_CBaseEntity)
|
||||
{
|
||||
if (!iface)
|
||||
return -1;
|
||||
return gamehelpers->EntityToBCompatRef((CBaseEntity *)iface);
|
||||
}
|
||||
#ifdef KE_ARCH_X64
|
||||
return g_pSM->ToPseudoAddress(iface);
|
||||
#else
|
||||
if (pContext->GetRuntime()->FindPubvarByName("__Virtual_Address__", nullptr) == SP_ERROR_NONE) {
|
||||
return g_pSM->ToPseudoAddress(iface);
|
||||
}
|
||||
return (cell_t)iface;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined( WIN32 ) && !defined( KE_ARCH_X64 )
|
||||
@ -500,7 +499,7 @@ void *Callback(DHooksCallback *dg, void **argStack)
|
||||
|
||||
if(dg->thisType == ThisPointer_CBaseEntity || dg->thisType == ThisPointer_Address)
|
||||
{
|
||||
dg->plugin_callback->PushCell(GetThisPtr(g_SHPtr->GetIfacePtr(), dg->thisType));
|
||||
dg->plugin_callback->PushCell(GetThisPtr(dg->plugin_callback->GetParentContext(), g_SHPtr->GetIfacePtr(), dg->thisType));
|
||||
}
|
||||
if(dg->returnType != ReturnType_Void)
|
||||
{
|
||||
@ -684,7 +683,7 @@ float Callback_float(DHooksCallback *dg, void **argStack)
|
||||
|
||||
if(dg->thisType == ThisPointer_CBaseEntity || dg->thisType == ThisPointer_Address)
|
||||
{
|
||||
dg->plugin_callback->PushCell(GetThisPtr(g_SHPtr->GetIfacePtr(), dg->thisType));
|
||||
dg->plugin_callback->PushCell(GetThisPtr(dg->plugin_callback->GetParentContext(), g_SHPtr->GetIfacePtr(), dg->thisType));
|
||||
}
|
||||
|
||||
returnStruct = GetReturnStruct(dg);
|
||||
@ -841,7 +840,7 @@ SDKVector *Callback_vector(DHooksCallback *dg, void **argStack)
|
||||
|
||||
if(dg->thisType == ThisPointer_CBaseEntity || dg->thisType == ThisPointer_Address)
|
||||
{
|
||||
dg->plugin_callback->PushCell(GetThisPtr(g_SHPtr->GetIfacePtr(), dg->thisType));
|
||||
dg->plugin_callback->PushCell(GetThisPtr(dg->plugin_callback->GetParentContext(), g_SHPtr->GetIfacePtr(), dg->thisType));
|
||||
}
|
||||
|
||||
returnStruct = GetReturnStruct(dg);
|
||||
@ -995,7 +994,7 @@ string_t *Callback_stringt(DHooksCallback *dg, void **argStack)
|
||||
|
||||
if(dg->thisType == ThisPointer_CBaseEntity || dg->thisType == ThisPointer_Address)
|
||||
{
|
||||
dg->plugin_callback->PushCell(GetThisPtr(g_SHPtr->GetIfacePtr(), dg->thisType));
|
||||
dg->plugin_callback->PushCell(GetThisPtr(dg->plugin_callback->GetParentContext(), g_SHPtr->GetIfacePtr(), dg->thisType));
|
||||
}
|
||||
|
||||
returnStruct = GetReturnStruct(dg);
|
||||
|
||||
@ -162,6 +162,7 @@ public:
|
||||
int entity;
|
||||
ThisPointerType thisType;
|
||||
HookType hookType;
|
||||
CallingConvention thisFuncCallConv;
|
||||
};
|
||||
|
||||
class DHooksCallback : public SourceHook::ISHDelegate, public DHooksInfo
|
||||
@ -338,7 +339,7 @@ public:
|
||||
};
|
||||
|
||||
size_t GetStackArgsSize(DHooksCallback *dg);
|
||||
cell_t GetThisPtr(void *iface, ThisPointerType type);
|
||||
cell_t GetThisPtr(IPluginContext* pContext, void *iface, ThisPointerType type);
|
||||
|
||||
extern IBinTools *g_pBinTools;
|
||||
extern HandleType_t g_HookParamsHandle;
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
#ifndef _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_
|
||||
#define _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_
|
||||
|
||||
#include "takedamageinfohack.h"
|
||||
|
||||
#include "smsdk_ext.h"
|
||||
#include <ISDKHooks.h>
|
||||
#include <convar.h>
|
||||
@ -15,8 +17,6 @@
|
||||
#include <itoolentity.h>
|
||||
#endif
|
||||
|
||||
#include "takedamageinfohack.h"
|
||||
|
||||
#if SOURCE_ENGINE >= SE_CSS && SOURCE_ENGINE != SE_LEFT4DEAD
|
||||
#define GETMAXHEALTH_IS_VIRTUAL
|
||||
#endif
|
||||
|
||||
@ -34,7 +34,7 @@
|
||||
#include <datamap.h>
|
||||
|
||||
variant_t g_Variant_t;
|
||||
char g_Variant_str_Value[128];
|
||||
char g_Variant_str_Value[1024];
|
||||
|
||||
// copy this definition as the original file includes cbase.h which explodes in a shower of compile errors
|
||||
void variant_t::SetEntity( CBaseEntity *val )
|
||||
|
||||
@ -63,7 +63,8 @@ inline void DecodePassMethod(ValveType vtype, SDKPassMethod method, PassType &ty
|
||||
type = PassType_Basic;
|
||||
if (vtype == Valve_POD
|
||||
|| vtype == Valve_Float
|
||||
|| vtype == Valve_Bool)
|
||||
|| vtype == Valve_Bool
|
||||
|| vtype == Valve_VirtualAddress)
|
||||
{
|
||||
flags = PASSFLAG_BYVAL | PASSFLAG_ASPOINTER;
|
||||
} else {
|
||||
@ -86,6 +87,13 @@ inline void DecodePassMethod(ValveType vtype, SDKPassMethod method, PassType &ty
|
||||
|
||||
static cell_t StartPrepSDKCall(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
auto call_type = (ValveCallType)params[1];
|
||||
if (call_type == ValveCall_Raw && pContext->GetRuntime()->FindPubvarByName("__Virtual_Address__", nullptr) == SP_ERROR_NONE) {
|
||||
return pContext->ThrowNativeError("SDKCall_Raw is unavailable for plugins that have enabled virtual address.");
|
||||
}
|
||||
if (call_type == ValveCall_VirtualAddress && pContext->GetRuntime()->FindPubvarByName("__Virtual_Address__", nullptr) != SP_ERROR_NONE) {
|
||||
return pContext->ThrowNativeError("SDKCall_VirtualAddress is unavailable for plugins that haven't enabled virtual address.");
|
||||
}
|
||||
s_numparams = 0;
|
||||
s_vtbl_index = -1;
|
||||
s_call_addr = NULL;
|
||||
@ -172,11 +180,10 @@ static cell_t PrepSDKCall_SetSignature(IPluginContext *pContext, const cell_t *p
|
||||
|
||||
static cell_t PrepSDKCall_SetAddress(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
#ifdef KE_ARCH_X86
|
||||
s_call_addr = reinterpret_cast<void *>(params[1]);
|
||||
#else
|
||||
s_call_addr = g_pSM->FromPseudoAddress(params[1]);
|
||||
#endif
|
||||
s_call_addr = reinterpret_cast<void*>(params[1]);
|
||||
if (pContext->GetRuntime()->FindPubvarByName("__Virtual_Address__", nullptr) == SP_ERROR_NONE) {
|
||||
s_call_addr = g_pSM->FromPseudoAddress(params[1]);
|
||||
}
|
||||
|
||||
return (s_call_addr != NULL) ? 1 : 0;
|
||||
}
|
||||
@ -413,6 +420,36 @@ static cell_t SDKCall(IPluginContext *pContext, const cell_t *params)
|
||||
startparam++;
|
||||
}
|
||||
break;
|
||||
case ValveCall_VirtualAddress:
|
||||
{
|
||||
//params[startparam] is an address to a pointer to THIS
|
||||
//params following this are params to the method we will invoke later
|
||||
if (startparam > numparams)
|
||||
{
|
||||
vc->stk_put(ptr);
|
||||
return pContext->ThrowNativeError("Expected a ThisPtr address, it wasn't found");
|
||||
}
|
||||
|
||||
//note: varargs pawn args are passed by-ref
|
||||
cell_t *cell;
|
||||
pContext->LocalToPhysAddr(params[startparam], &cell);
|
||||
void* thisptr = reinterpret_cast<void*>(g_pSM->FromPseudoAddress(*cell));
|
||||
|
||||
if (thisptr == nullptr)
|
||||
{
|
||||
vc->stk_put(ptr);
|
||||
return pContext->ThrowNativeError("ThisPtr address cannot be null");
|
||||
}
|
||||
else if (reinterpret_cast<uintptr_t>(thisptr) < VALID_MINIMUM_MEMORY_ADDRESS)
|
||||
{
|
||||
vc->stk_put(ptr);
|
||||
return pContext->ThrowNativeError("Invalid ThisPtr address %p is pointing to reserved memory.", thisptr);
|
||||
}
|
||||
|
||||
*(void **)ptr = thisptr;
|
||||
startparam++;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
vc->stk_put(ptr);
|
||||
@ -536,6 +573,13 @@ static cell_t SDKCall(IPluginContext *pContext, const cell_t *params)
|
||||
addr = *(bool **)addr;
|
||||
}
|
||||
return *addr ? 1 : 0;
|
||||
} else if (vc->retinfo->vtype == Valve_VirtualAddress) {
|
||||
void *addr = *(void **)vc->retbuf;
|
||||
if (vc->retinfo->flags & PASSFLAG_ASPOINTER)
|
||||
{
|
||||
addr = *(void **)addr;
|
||||
}
|
||||
return g_pSM->ToPseudoAddress(addr);
|
||||
} else {
|
||||
cell_t *addr = (cell_t *)vc->retbuf;
|
||||
if (vc->retinfo->flags & PASSFLAG_ASPOINTER)
|
||||
|
||||
@ -164,6 +164,21 @@ size_t ValveParamToBinParam(ValveType type,
|
||||
return sizeof(float);
|
||||
}
|
||||
}
|
||||
case Valve_VirtualAddress:
|
||||
{
|
||||
info->flags = flags;
|
||||
if (flags & PASSFLAG_ASPOINTER)
|
||||
{
|
||||
needs_extra = true;
|
||||
info->type = PassType_Basic;
|
||||
info->size = sizeof(void**);
|
||||
return sizeof(void**) + sizeof(void*);
|
||||
} else {
|
||||
info->type = PassType_Basic;
|
||||
info->size = sizeof(void*);
|
||||
return sizeof(void*);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -276,6 +291,19 @@ DataStatus EncodeValveParam(IPluginContext *pContext,
|
||||
|
||||
*addr = *(bool *)buffer ? 1 : 0;
|
||||
|
||||
return Data_Okay;
|
||||
}
|
||||
case Valve_VirtualAddress:
|
||||
{
|
||||
cell_t *addr;
|
||||
pContext->LocalToPhysAddr(param, &addr);
|
||||
|
||||
if (data->flags & PASSFLAG_ASPOINTER)
|
||||
{
|
||||
buffer = *(void **)buffer;
|
||||
}
|
||||
*addr = g_pSM->ToPseudoAddress(*(void**)buffer);
|
||||
|
||||
return Data_Okay;
|
||||
}
|
||||
}
|
||||
@ -585,6 +613,29 @@ DataStatus DecodeValveParam(IPluginContext *pContext,
|
||||
*(char **)buffer = addr;
|
||||
return Data_Okay;
|
||||
}
|
||||
case Valve_VirtualAddress:
|
||||
{
|
||||
if (data->decflags & VDECODE_FLAG_BYREF)
|
||||
{
|
||||
cell_t *addr;
|
||||
pContext->LocalToPhysAddr(param, &addr);
|
||||
param = *addr;
|
||||
}
|
||||
if (data->flags & PASSFLAG_ASPOINTER)
|
||||
{
|
||||
*(void **)buffer = (unsigned char *)_buffer + pCall->stackEnd + data->obj_offset;
|
||||
buffer = *(void **)buffer;
|
||||
}
|
||||
void* addr = g_pSM->FromPseudoAddress(param);
|
||||
if (addr == nullptr && (data->decflags & VDECODE_FLAG_ALLOWNULL) == 0)
|
||||
{
|
||||
pContext->ThrowNativeError("NULL Address not allowed");
|
||||
return Data_Fail;
|
||||
}
|
||||
|
||||
*(void **)buffer = addr;
|
||||
return Data_Okay;
|
||||
}
|
||||
}
|
||||
|
||||
return Data_Fail;
|
||||
|
||||
@ -53,6 +53,7 @@ enum ValveType
|
||||
Valve_Edict, /**< Edict */
|
||||
Valve_String, /**< String */
|
||||
Valve_Bool, /**< Boolean */
|
||||
Valve_VirtualAddress, /**< SM Virtual Address */
|
||||
Valve_Object, /**< Object, not matching one of the above types */
|
||||
};
|
||||
|
||||
@ -84,6 +85,7 @@ enum ValveCallType
|
||||
ValveCall_Raw, /**< Thiscall (address explicit first parameter) */
|
||||
ValveCall_Server, /**< Thiscall (CBaseServer implicit first parameter) */
|
||||
ValveCall_Engine, /**< Thiscall (CVEngineServer implicit first parameter) */
|
||||
ValveCall_VirtualAddress /**< Thiscall (address explicit first parameter) */
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -57,25 +57,9 @@ void PlayerConditionsMgr::ProcessCondChange(CondChangeData_t *pCondData)
|
||||
return;
|
||||
|
||||
int client = pCondData->hPlayer.GetEntryIndex();
|
||||
int newConds = 0;
|
||||
int prevConds = 0;
|
||||
CondVar var = pCondData->var;
|
||||
|
||||
if (var == m_nPlayerCond)
|
||||
{
|
||||
prevConds = m_OldConds[client][_condition_bits] | m_OldConds[client][var];
|
||||
newConds = m_OldConds[client][_condition_bits] | pCondData->newConds;
|
||||
}
|
||||
else if (var == _condition_bits)
|
||||
{
|
||||
prevConds = m_OldConds[client][m_nPlayerCond] | m_OldConds[client][var];
|
||||
newConds = m_OldConds[client][m_nPlayerCond] | pCondData->newConds;
|
||||
}
|
||||
else
|
||||
{
|
||||
prevConds = m_OldConds[client][var];
|
||||
newConds = pCondData->newConds;
|
||||
}
|
||||
int newConds = pCondData->newConds;
|
||||
int prevConds = m_OldConds[client][var];
|
||||
|
||||
if (prevConds != newConds)
|
||||
{
|
||||
|
||||
@ -16,131 +16,125 @@
|
||||
{
|
||||
"Offsets"
|
||||
{
|
||||
"CanBeAutobalanced"
|
||||
{
|
||||
"windows" "464"
|
||||
"linux" "465"
|
||||
}
|
||||
"EndTouch"
|
||||
{
|
||||
"windows" "101"
|
||||
"linux" "102"
|
||||
"mac" "102"
|
||||
}
|
||||
"FireBullets"
|
||||
{
|
||||
"windows" "113"
|
||||
"linux" "114"
|
||||
"mac" "114"
|
||||
}
|
||||
"GetMaxHealth"
|
||||
{
|
||||
"windows" "118"
|
||||
"linux" "119"
|
||||
}
|
||||
"GroundEntChanged"
|
||||
{
|
||||
"windows" "178"
|
||||
"linux" "179"
|
||||
"mac" "179"
|
||||
}
|
||||
"OnTakeDamage"
|
||||
{
|
||||
"windows" "62"
|
||||
"linux" "63"
|
||||
"mac" "63"
|
||||
}
|
||||
"OnTakeDamage_Alive"
|
||||
{
|
||||
"windows" "273"
|
||||
"linux" "274"
|
||||
}
|
||||
"PreThink"
|
||||
{
|
||||
"windows" "336"
|
||||
"linux" "337"
|
||||
"mac" "337"
|
||||
}
|
||||
"PostThink"
|
||||
{
|
||||
"windows" "337"
|
||||
"linux" "338"
|
||||
"mac" "338"
|
||||
}
|
||||
"Reload"
|
||||
{
|
||||
"windows" "271"
|
||||
"linux" "272"
|
||||
"mac" "272"
|
||||
}
|
||||
"SetTransmit"
|
||||
{
|
||||
"windows" "20"
|
||||
"linux" "21"
|
||||
"mac" "21"
|
||||
}
|
||||
"ShouldCollide"
|
||||
{
|
||||
"windows" "16"
|
||||
"linux" "17"
|
||||
"mac" "17"
|
||||
}
|
||||
"Spawn"
|
||||
{
|
||||
"windows" "22"
|
||||
"linux" "23"
|
||||
"mac" "23"
|
||||
}
|
||||
"StartTouch"
|
||||
{
|
||||
"windows" "99"
|
||||
"linux" "100"
|
||||
"mac" "100"
|
||||
}
|
||||
"Think"
|
||||
{
|
||||
"windows" "47"
|
||||
"linux" "48"
|
||||
"mac" "48"
|
||||
}
|
||||
"Touch"
|
||||
{
|
||||
"windows" "100"
|
||||
"linux" "101"
|
||||
"mac" "101"
|
||||
}
|
||||
"TraceAttack"
|
||||
{
|
||||
"windows" "60"
|
||||
"linux" "61"
|
||||
"mac" "61"
|
||||
}
|
||||
"Use"
|
||||
{
|
||||
"windows" "98"
|
||||
"linux" "99"
|
||||
"mac" "99"
|
||||
}
|
||||
"VPhysicsUpdate"
|
||||
{
|
||||
"windows" "158"
|
||||
"linux" "159"
|
||||
"mac" "159"
|
||||
}
|
||||
"Weapon_CanSwitchTo"
|
||||
{
|
||||
"windows" "267"
|
||||
"linux" "268"
|
||||
"mac" "268"
|
||||
}
|
||||
"Weapon_CanUse"
|
||||
{
|
||||
"windows" "261"
|
||||
"linux" "262"
|
||||
"mac" "262"
|
||||
}
|
||||
"Weapon_Drop"
|
||||
{
|
||||
"windows" "264"
|
||||
"linux" "265"
|
||||
"mac" "265"
|
||||
}
|
||||
"Weapon_Equip"
|
||||
{
|
||||
"windows" "262"
|
||||
"linux" "263"
|
||||
"mac" "263"
|
||||
}
|
||||
"Weapon_Switch"
|
||||
{
|
||||
"windows" "265"
|
||||
"linux" "266"
|
||||
"mac" "266"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,26 +4,32 @@
|
||||
{
|
||||
"Offsets"
|
||||
{
|
||||
"CanBeAutobalanced"
|
||||
{
|
||||
"windows" "465"
|
||||
"linux" "466"
|
||||
}
|
||||
"GroundEntChanged"
|
||||
{
|
||||
"windows" "188"
|
||||
"linux" "190"
|
||||
"windows" "178"
|
||||
"linux" "180"
|
||||
}
|
||||
"OnTakeDamage_Alive"
|
||||
{
|
||||
"windows" "287"
|
||||
"linux" "288"
|
||||
"windows" "283"
|
||||
"linux" "284"
|
||||
}
|
||||
"GetMaxHealth"
|
||||
{
|
||||
"windows" "126"
|
||||
"linux" "127"
|
||||
"windows" "118"
|
||||
"linux" "119"
|
||||
}
|
||||
"Blocked"
|
||||
{
|
||||
"windows" "109"
|
||||
"linux" "110"
|
||||
"windows" "101"
|
||||
"linux" "102"
|
||||
}
|
||||
/* CBaseCombatWeapon::Reload */
|
||||
"Reload"
|
||||
{
|
||||
"windows" "287"
|
||||
@ -31,18 +37,19 @@
|
||||
}
|
||||
"EndTouch"
|
||||
{
|
||||
"windows" "107"
|
||||
"linux" "108"
|
||||
"windows" "99"
|
||||
"linux" "100"
|
||||
}
|
||||
/* CBaseEntity::FireBullets(FireBulletsInfo_t const&) */
|
||||
"FireBullets"
|
||||
{
|
||||
"windows" "121"
|
||||
"linux" "121"
|
||||
"windows" "113"
|
||||
"linux" "113"
|
||||
}
|
||||
"OnTakeDamage"
|
||||
{
|
||||
"windows" "69"
|
||||
"linux" "70"
|
||||
"windows" "61"
|
||||
"linux" "62"
|
||||
}
|
||||
"PreThink"
|
||||
{
|
||||
@ -56,8 +63,8 @@
|
||||
}
|
||||
"SetTransmit"
|
||||
{
|
||||
"windows" "28"
|
||||
"linux" "29"
|
||||
"windows" "20"
|
||||
"linux" "21"
|
||||
}
|
||||
"ShouldCollide"
|
||||
{
|
||||
@ -66,64 +73,64 @@
|
||||
}
|
||||
"Spawn"
|
||||
{
|
||||
"windows" "30"
|
||||
"linux" "31"
|
||||
"windows" "22"
|
||||
"linux" "23"
|
||||
}
|
||||
"StartTouch"
|
||||
{
|
||||
"windows" "105"
|
||||
"linux" "106"
|
||||
"windows" "97"
|
||||
"linux" "98"
|
||||
}
|
||||
"Think"
|
||||
{
|
||||
"windows" "57"
|
||||
"linux" "58"
|
||||
"windows" "49"
|
||||
"linux" "50"
|
||||
}
|
||||
"Touch"
|
||||
{
|
||||
"windows" "106"
|
||||
"linux" "107"
|
||||
"windows" "98"
|
||||
"linux" "99"
|
||||
}
|
||||
"TraceAttack"
|
||||
{
|
||||
"windows" "67"
|
||||
"linux" "68"
|
||||
"windows" "59"
|
||||
"linux" "60"
|
||||
}
|
||||
"Use"
|
||||
{
|
||||
"windows" "104"
|
||||
"linux" "105"
|
||||
"windows" "96"
|
||||
"linux" "97"
|
||||
}
|
||||
"VPhysicsUpdate"
|
||||
{
|
||||
"windows" "168"
|
||||
"linux" "169"
|
||||
"windows" "158"
|
||||
"linux" "159"
|
||||
}
|
||||
"Weapon_CanSwitchTo"
|
||||
{
|
||||
"windows" "278"
|
||||
"linux" "279"
|
||||
"windows" "277"
|
||||
"linux" "278"
|
||||
}
|
||||
"Weapon_CanUse"
|
||||
{
|
||||
"windows" "271"
|
||||
"linux" "272"
|
||||
}
|
||||
"Weapon_Drop"
|
||||
{
|
||||
"windows" "274"
|
||||
"linux" "275"
|
||||
}
|
||||
"Weapon_Equip"
|
||||
{
|
||||
"windows" "272"
|
||||
"linux" "273"
|
||||
}
|
||||
"Weapon_Drop"
|
||||
"Weapon_Switch"
|
||||
{
|
||||
"windows" "275"
|
||||
"linux" "276"
|
||||
}
|
||||
"Weapon_Equip"
|
||||
{
|
||||
"windows" "273"
|
||||
"linux" "274"
|
||||
}
|
||||
"Weapon_Switch"
|
||||
{
|
||||
"windows" "276"
|
||||
"linux" "277"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -121,6 +121,13 @@
|
||||
"linux" "259"
|
||||
"linux64" "259"
|
||||
}
|
||||
"GetAttachment"
|
||||
{
|
||||
"windows" "211"
|
||||
"windows64" "211"
|
||||
"linux" "212"
|
||||
"linux64" "212"
|
||||
}
|
||||
}
|
||||
|
||||
"Keys"
|
||||
|
||||
@ -81,10 +81,10 @@
|
||||
}
|
||||
"Teleport"
|
||||
{
|
||||
"windows" "111"
|
||||
"windows64" "111"
|
||||
"linux" "110"
|
||||
"linux64" "110"
|
||||
"windows" "110"
|
||||
"windows64" "110"
|
||||
"linux" "111"
|
||||
"linux64" "111"
|
||||
}
|
||||
"CommitSuicide"
|
||||
{
|
||||
@ -151,10 +151,10 @@
|
||||
}
|
||||
"GetAttachment"
|
||||
{
|
||||
"windows" "258"
|
||||
"windows64" "258"
|
||||
"linux" "259"
|
||||
"linux64" "259"
|
||||
"windows" "211"
|
||||
"windows64" "211"
|
||||
"linux" "212"
|
||||
"linux64" "212"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -26,19 +26,16 @@
|
||||
{
|
||||
"windows" "4"
|
||||
"linux" "4"
|
||||
"mac" "4"
|
||||
}
|
||||
"GetTENext"
|
||||
{
|
||||
"windows" "8"
|
||||
"linux" "8"
|
||||
"mac" "8"
|
||||
}
|
||||
"TE_GetServerClass"
|
||||
{
|
||||
"windows" "0"
|
||||
"linux" "0"
|
||||
"mac" "0"
|
||||
}
|
||||
}
|
||||
|
||||
@ -53,7 +50,7 @@
|
||||
"s_pTempEntities"
|
||||
{
|
||||
"library" "server"
|
||||
"mac" "@_ZN15CBaseTempEntity15s_pTempEntitiesE"
|
||||
"linux" "@_ZN15CBaseTempEntity15s_pTempEntitiesE"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -64,12 +61,12 @@
|
||||
"Signatures"
|
||||
{
|
||||
/* Functions in CGlobalEntityList */
|
||||
/* Search any functions with the "CAI_StandoffBehavior::PrescheduleThink" string, FindEntityByClassname is called with "ai_battle_line" string as a parameter */
|
||||
"FindEntityByClassname"
|
||||
{
|
||||
"library" "server"
|
||||
"windows" "\x55\x89\xE5\x53\x57\x56\x83\xEC\x08\x8B\x45\x08\x85\xC0\x0F\x85\x2A\x2A\x2A\x2A"
|
||||
"windows" "\x55\x89\xE5\x53\x57\x56\x83\xEC\x08\x8B\x45\x2A\x85\xC0\x0F\x85"
|
||||
"linux" "@_ZN17CGlobalEntityList21FindEntityByClassnameEP11CBaseEntityPKc"
|
||||
"mac" "@_ZN17CGlobalEntityList21FindEntityByClassnameEP11CBaseEntityPKc"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -82,9 +79,19 @@
|
||||
"FireOutput"
|
||||
{
|
||||
"library" "server"
|
||||
"windows" "\x55\x89\xE5\x53\x57\x56\x81\xEC\x10\x01\x00\x00\x8B\x71\x14"
|
||||
"windows" "\x55\x89\xE5\x53\x57\x56\x81\xEC\x10\x01\x00\x00\x8B\x71"
|
||||
"linux" "@_ZN17CBaseEntityOutput10FireOutputE9variant_tP11CBaseEntityS2_f"
|
||||
"mac" "@_ZN17CBaseEntityOutput10FireOutputE9variant_tP11CBaseEntityS2_f"
|
||||
}
|
||||
"LookupAttachment"
|
||||
{
|
||||
/* CBaseAnimating::LookupAttachment */
|
||||
/* Called in a function that has the "zipline" and "cable/cable.vmt" strings.
|
||||
* Inside this function, search for a function call that passes the "zipline" string as the only parameter.
|
||||
* That function is CBaseAnimating::LookupAttachment.
|
||||
*/
|
||||
"library" "server"
|
||||
"windows" "\x31\xC0\x80\xB9\x2A\x2A\x2A\x2A\x00\x0F\x85"
|
||||
"linux" "@_ZN14CBaseAnimating16LookupAttachmentEPKc"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -93,96 +100,96 @@
|
||||
{
|
||||
"Offsets"
|
||||
{
|
||||
"SetOwnerEntity"
|
||||
{
|
||||
"windows" "17"
|
||||
"linux" "18"
|
||||
}
|
||||
/* CBasePlayer */
|
||||
"GiveNamedItem"
|
||||
{
|
||||
"windows" "408"
|
||||
"linux" "409"
|
||||
"mac" "409"
|
||||
}
|
||||
"RemovePlayerItem"
|
||||
{
|
||||
"windows" "271"
|
||||
"linux" "272"
|
||||
"mac" "272"
|
||||
}
|
||||
"Weapon_GetSlot"
|
||||
{
|
||||
"windows" "269"
|
||||
"linux" "270"
|
||||
"mac" "270"
|
||||
}
|
||||
"Ignite"
|
||||
{
|
||||
"windows" "210"
|
||||
"linux" "211"
|
||||
"mac" "211"
|
||||
}
|
||||
"Extinguish"
|
||||
{
|
||||
"windows" "214"
|
||||
"linux" "215"
|
||||
"mac" "215"
|
||||
}
|
||||
"Teleport"
|
||||
{
|
||||
"windows" "109"
|
||||
"linux" "110"
|
||||
"mac" "110"
|
||||
}
|
||||
"CommitSuicide"
|
||||
{
|
||||
"windows" "446"
|
||||
"linux" "447"
|
||||
"mac" "447"
|
||||
}
|
||||
"GetVelocity"
|
||||
{
|
||||
"windows" "141"
|
||||
"linux" "142"
|
||||
"mac" "142"
|
||||
}
|
||||
"EyeAngles"
|
||||
{
|
||||
"windows" "132"
|
||||
"linux" "133"
|
||||
"mac" "133"
|
||||
}
|
||||
"AcceptInput"
|
||||
{
|
||||
"windows" "36"
|
||||
"linux" "37"
|
||||
"mac" "37"
|
||||
}
|
||||
"SetEntityModel"
|
||||
{
|
||||
"windows" "24"
|
||||
"linux" "25"
|
||||
"mac" "25"
|
||||
}
|
||||
"WeaponEquip"
|
||||
{
|
||||
"windows" "262"
|
||||
"linux" "263"
|
||||
"mac" "263"
|
||||
}
|
||||
"Activate"
|
||||
{
|
||||
"windows" "33"
|
||||
"linux" "34"
|
||||
"mac" "34"
|
||||
}
|
||||
"RemoveAllItems"
|
||||
{
|
||||
"windows" "349"
|
||||
"linux" "350"
|
||||
"mac" "350"
|
||||
}
|
||||
"PlayerRunCmd"
|
||||
{
|
||||
"windows" "426"
|
||||
"linux" "427"
|
||||
"mac" "427"
|
||||
}
|
||||
"GiveAmmo"
|
||||
{
|
||||
"windows" "253"
|
||||
"linux" "254"
|
||||
}
|
||||
"GetAttachment"
|
||||
{
|
||||
"windows" "206"
|
||||
"linux" "207"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -23,13 +23,13 @@
|
||||
}
|
||||
"RemovePlayerItem"
|
||||
{
|
||||
"windows" "285"
|
||||
"linux" "286"
|
||||
"windows" "281"
|
||||
"linux" "282"
|
||||
}
|
||||
"Weapon_GetSlot"
|
||||
{
|
||||
"windows" "280"
|
||||
"linux" "281"
|
||||
"windows" "279"
|
||||
"linux" "280"
|
||||
}
|
||||
"Ignite"
|
||||
{
|
||||
@ -43,8 +43,8 @@
|
||||
}
|
||||
"Teleport"
|
||||
{
|
||||
"windows" "115"
|
||||
"linux" "116"
|
||||
"windows" "107"
|
||||
"linux" "108"
|
||||
}
|
||||
"CommitSuicide"
|
||||
{
|
||||
@ -53,33 +53,33 @@
|
||||
}
|
||||
"GetVelocity"
|
||||
{
|
||||
"windows" "151"
|
||||
"linux" "152"
|
||||
"windows" "141"
|
||||
"linux" "142"
|
||||
}
|
||||
"EyeAngles"
|
||||
{
|
||||
"windows" "142"
|
||||
"linux" "143"
|
||||
"windows" "132"
|
||||
"linux" "133"
|
||||
}
|
||||
"AcceptInput"
|
||||
{
|
||||
"windows" "44"
|
||||
"linux" "45"
|
||||
"windows" "36"
|
||||
"linux" "37"
|
||||
}
|
||||
"SetEntityModel"
|
||||
{
|
||||
"windows" "32"
|
||||
"linux" "33"
|
||||
"windows" "24"
|
||||
"linux" "25"
|
||||
}
|
||||
"WeaponEquip"
|
||||
{
|
||||
"windows" "273"
|
||||
"linux" "274"
|
||||
"windows" "272"
|
||||
"linux" "273"
|
||||
}
|
||||
"Activate"
|
||||
{
|
||||
"windows" "41"
|
||||
"linux" "42"
|
||||
"windows" "33"
|
||||
"linux" "34"
|
||||
}
|
||||
"PlayerRunCmd"
|
||||
{
|
||||
@ -93,13 +93,13 @@
|
||||
}
|
||||
"SetOwnerEntity"
|
||||
{
|
||||
"windows" "25"
|
||||
"linux" "26"
|
||||
"windows" "17"
|
||||
"linux" "18"
|
||||
}
|
||||
"GiveAmmo"
|
||||
{
|
||||
"windows" "264"
|
||||
"linux" "265"
|
||||
"windows" "263"
|
||||
"linux" "264"
|
||||
}
|
||||
}
|
||||
"Signatures"
|
||||
|
||||
@ -1 +1 @@
|
||||
Subproject commit 38b4f3670826bbfe7c536ef33ec53f5971d419e2
|
||||
Subproject commit c018a994478d6c31f70ded7adec7aa9e2c40bb1a
|
||||
@ -207,19 +207,28 @@ methodmap ArrayList < Handle {
|
||||
// Returns the index for the first occurrence of the provided string. If
|
||||
// the string cannot be located, -1 will be returned.
|
||||
//
|
||||
// @param item String to search for
|
||||
// @param block Optionally which block to search in
|
||||
// @param item String to search for.
|
||||
// @param block Optionally which block to search in.
|
||||
// @param start Index to start searching from (exclusive), or -1 for direction default.
|
||||
// Valid numbers are in the interval [-1..Length].
|
||||
// @param reverse Whether the search direction should be reversed.
|
||||
// @param caseSensitive If true (default), comparison is case sensitive.
|
||||
// If false, comparison is case insensitive.
|
||||
// @return Array index, or -1 on failure
|
||||
public native int FindString(const char[] item, int block=0);
|
||||
// @error Invalid block, or invalid start index.
|
||||
public native int FindString(const char[] item, int block=0, int start=-1, bool reverse=false, bool caseSensitive=true);
|
||||
|
||||
// Returns the index for the first occurrence of the provided value. If the
|
||||
// value cannot be located, -1 will be returned.
|
||||
//
|
||||
// @param item Value to search for
|
||||
// @param block Optionally which block to search in
|
||||
// @return Array index, or -1 on failure
|
||||
// @error Invalid block index
|
||||
public native int FindValue(any item, int block=0);
|
||||
// @param item Value to search for.
|
||||
// @param block Optionally which block to search in.
|
||||
// @param start Index to start searching from (exclusive), or -1 for direction default.
|
||||
// Valid numbers are in the interval [-1..Length].
|
||||
// @param reverse Whether the search direction should be reversed.
|
||||
// @return Array index, or -1 on failure.
|
||||
// @error Invalid block, or invalid start index.
|
||||
public native int FindValue(any item, int block=0, int start=-1, bool reverse=false);
|
||||
|
||||
// Sort an ADT Array. Specify the type as Integer, Float, or String.
|
||||
//
|
||||
|
||||
@ -310,7 +310,7 @@ methodmap DHookParam < Handle
|
||||
|
||||
// Gets an object's variable value.
|
||||
//
|
||||
// @param num Parameter number to get, starting at 1.
|
||||
// @param num Parameter number to get, 0 for param "this", other parameters start from 1
|
||||
// @param offset Byte offset within the object to the var to get.
|
||||
// @param type Type of var it is.
|
||||
//
|
||||
@ -320,7 +320,7 @@ methodmap DHookParam < Handle
|
||||
|
||||
// Gets an object's vector variable value.
|
||||
//
|
||||
// @param num Parameter number to get, starting at 1.
|
||||
// @param num Parameter number to get, 0 for param "this", other parameters start from 1.
|
||||
// @param offset Byte offset within the object to the var to get.
|
||||
// @param type Type of var it is.
|
||||
// @param vec Buffer to store the result vector.
|
||||
@ -330,7 +330,7 @@ methodmap DHookParam < Handle
|
||||
|
||||
// Gets an object's string variable value.
|
||||
//
|
||||
// @param num Parameter number to get, starting at 1.
|
||||
// @param num Parameter number to get, 0 for param "this", other parameters start from 1.
|
||||
// @param offset Byte offset within the object to the var to get.
|
||||
// @param type Type of var it is.
|
||||
// @param buffer Buffer to store the result string.
|
||||
@ -344,7 +344,7 @@ methodmap DHookParam < Handle
|
||||
// The changes are only applied when MRES_ChangedHandled or MRES_ChangedOverride
|
||||
// is returned in the callback.
|
||||
//
|
||||
// @param num Parameter number to set, starting at 1.
|
||||
// @param num Parameter number to set, 0 for param "this", other parameters start from 1.
|
||||
// @param offset Byte offset within the object to the var to set.
|
||||
// @param type Type of var it is.
|
||||
// @param value The value to set the var to.
|
||||
@ -357,7 +357,7 @@ methodmap DHookParam < Handle
|
||||
// The changes are only applied when MRES_ChangedHandled or MRES_ChangedOverride
|
||||
// is returned in the callback.
|
||||
//
|
||||
// @param num Parameter number to set, starting at 1.
|
||||
// @param num Parameter number to set, 0 for param "this", other parameters start from 1.
|
||||
// @param offset Byte offset within the object to the var to set.
|
||||
// @param type Type of var it is.
|
||||
// @param vec The value to set the vector var to.
|
||||
@ -928,7 +928,7 @@ native void DHookSetReturnString(Handle hReturn, char[] value);
|
||||
* Gets an objects variable value
|
||||
*
|
||||
* @param hParams Handle to params structure
|
||||
* @param num Param number to get.
|
||||
* @param num Param number to get, 0 for param "this".
|
||||
* @param offset Offset within the object to the var to get.
|
||||
* @param type Type of var it is
|
||||
*
|
||||
@ -941,7 +941,7 @@ native any DHookGetParamObjectPtrVar(Handle hParams, int num, int offset, Object
|
||||
* Sets an objects variable value
|
||||
*
|
||||
* @param hParams Handle to params structure
|
||||
* @param num Param number to set.
|
||||
* @param num Param number to set, 0 for param "this".
|
||||
* @param offset Offset within the object to the var to set.
|
||||
* @param type Type of var it is
|
||||
* @param value The value to set the var to.
|
||||
@ -954,7 +954,7 @@ native void DHookSetParamObjectPtrVar(Handle hParams, int num, int offset, Objec
|
||||
* Gets an objects vector variable value
|
||||
*
|
||||
* @param hParams Handle to params structure
|
||||
* @param num Param number to get.
|
||||
* @param num Param number to get, 0 for param "this".
|
||||
* @param offset Offset within the object to the var to get.
|
||||
* @param type Type of var it is
|
||||
* @param buffer Buffer to store the result vector
|
||||
@ -967,7 +967,7 @@ native void DHookGetParamObjectPtrVarVector(Handle hParams, int num, int offset,
|
||||
* Sets an objects vector variable value
|
||||
*
|
||||
* @param hParams Handle to params structure
|
||||
* @param num Param number to set.
|
||||
* @param num Param number to set, 0 for param "this".
|
||||
* @param offset Offset within the object to the var to set.
|
||||
* @param type Type of var it is
|
||||
* @param value The value to set the vector var to.
|
||||
@ -980,7 +980,7 @@ native void DHookSetParamObjectPtrVarVector(Handle hParams, int num, int offset,
|
||||
* Gets an objects string variable value
|
||||
*
|
||||
* @param hParams Handle to params structure
|
||||
* @param num Param number to get.
|
||||
* @param num Param number to get, 0 for param "this".
|
||||
* @param offset Offset within the object to the var to get.
|
||||
* @param type Type of var it is
|
||||
* @param buffer Buffer to store the result vector
|
||||
|
||||
@ -60,9 +60,10 @@ enum SDKCallType
|
||||
SDKCall_Player, /**< CBasePlayer call */
|
||||
SDKCall_GameRules, /**< CGameRules call */
|
||||
SDKCall_EntityList, /**< CGlobalEntityList call */
|
||||
SDKCall_Raw, /**< |this| pointer with an arbitrary address */
|
||||
SDKCall_Raw, /**< |this| pointer with an arbitrary address. This is not available if SM's virtual addresses are enabled */
|
||||
SDKCall_Server, /**< CBaseServer call */
|
||||
SDKCall_Engine /**< CVEngineServer call */
|
||||
SDKCall_Engine, /**< CVEngineServer call */
|
||||
SDKCall_VirtualAddress /**< |this| pointer with an arbitrary SM virtual address */
|
||||
};
|
||||
|
||||
enum SDKLibrary
|
||||
@ -88,7 +89,8 @@ enum SDKType
|
||||
SDKType_Float, /**< Float (any) */
|
||||
SDKType_Edict, /**< edict_t (always as pointer) */
|
||||
SDKType_String, /**< NULL-terminated string (always as pointer) */
|
||||
SDKType_Bool /**< Boolean (any) */
|
||||
SDKType_Bool, /**< Boolean (any) */
|
||||
SDKType_VirtualAddress, /**< SM Virtual Address */
|
||||
};
|
||||
|
||||
enum SDKPassMethod
|
||||
|
||||
@ -754,6 +754,26 @@ native any LoadFromAddress(Address addr, NumberType size);
|
||||
*/
|
||||
native void StoreToAddress(Address addr, any data, NumberType size, bool updateMemAccess = true);
|
||||
|
||||
/**
|
||||
* Load sizeof(void*) from a memory address.
|
||||
*
|
||||
* @param addr Address to a memory location.
|
||||
* @return The address that is stored at that address.
|
||||
* @error Address is null or pointing to reserved memory.
|
||||
*/
|
||||
native Address LoadAddressFromAddress(Address addr);
|
||||
|
||||
/**
|
||||
* Store sizeof(void*) bytes to a memory address.
|
||||
*
|
||||
* @param addr Address to a memory location.
|
||||
* @param data Address to store at that location.
|
||||
* @param updateMemAccess If true, SourceMod will set read / write / exec permissions
|
||||
* on the memory page being written to.
|
||||
* @error Address is null or pointing to reserved memory.
|
||||
*/
|
||||
native void StoreAddressToAddress(Address addr, Address data, bool updateMemAccess = true);
|
||||
|
||||
methodmap FrameIterator < Handle {
|
||||
// Creates a stack frame iterator to build your own stack traces.
|
||||
// @return New handle to a FrameIterator.
|
||||
|
||||
@ -166,7 +166,10 @@ enum {
|
||||
TF_CUSTOM_SLAP_KILL,
|
||||
TF_CUSTOM_CROC,
|
||||
TF_CUSTOM_TAUNTATK_GASBLAST,
|
||||
TF_CUSTOM_AXTINGUISHER_BOOSTED
|
||||
TF_CUSTOM_AXTINGUISHER_BOOSTED,
|
||||
TF_CUSTOM_KRAMPUS_MELEE,
|
||||
TF_CUSTOM_KRAMPUS_RANGED,
|
||||
TF_CUSTOM_TAUNTATK_TRICKSHOT
|
||||
};
|
||||
|
||||
// Weapon codes as used in some events, such as player_death
|
||||
|
||||
39
plugins/include/virtual_address.inc
Normal file
39
plugins/include/virtual_address.inc
Normal file
@ -0,0 +1,39 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod (C)2004-2025 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This file is part of the SourceMod/SourcePawn SDK.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#if defined _virtual_address_included
|
||||
#endinput
|
||||
#endif
|
||||
#define _virtual_address_included
|
||||
|
||||
public const Address __Virtual_Address__ = view_as<Address>(0);
|
||||
public const Address PointerSize = view_as<Address>(0); /**< Size of a pointer in bytes (same as `sizeof(void*)`) */
|
||||
@ -62,7 +62,8 @@ ConVar g_Cvar_ExtendTimeStep;
|
||||
ConVar g_Cvar_ExtendRoundStep;
|
||||
ConVar g_Cvar_ExtendFragStep;
|
||||
ConVar g_Cvar_ExcludeMaps;
|
||||
ConVar g_Cvar_IncludeMaps;
|
||||
ConVar g_Cvar_IncludeMinMaps;
|
||||
ConVar g_Cvar_IncludeMaxMaps;
|
||||
ConVar g_Cvar_PersistentMaps;
|
||||
ConVar g_Cvar_NoVoteMode;
|
||||
ConVar g_Cvar_Extend;
|
||||
@ -127,7 +128,8 @@ public void OnPluginStart()
|
||||
g_Cvar_ExtendRoundStep = CreateConVar("sm_extendmap_roundstep", "5", "Specifies how many more rounds each extension makes", _, true, 1.0);
|
||||
g_Cvar_ExtendFragStep = CreateConVar("sm_extendmap_fragstep", "10", "Specifies how many more frags are allowed when map is extended.", _, true, 5.0);
|
||||
g_Cvar_ExcludeMaps = CreateConVar("sm_mapvote_exclude", "5", "Specifies how many past maps to exclude from the vote.", _, true, 0.0);
|
||||
g_Cvar_IncludeMaps = CreateConVar("sm_mapvote_include", "5", "Specifies how many maps to include in the vote.", _, true, 2.0, true, 6.0);
|
||||
g_Cvar_IncludeMinMaps = CreateConVar("sm_mapvote_include_min", "4", "Specifies the minimum number of maps to include in the vote.", _, true, 2.0, true, 6.0);
|
||||
g_Cvar_IncludeMaxMaps = CreateConVar("sm_mapvote_include_max", "6", "Specifies the maximum number of maps to include in the vote.", _, true, 2.0, true, 6.0);
|
||||
g_Cvar_PersistentMaps = CreateConVar("sm_mapvote_persistentmaps", "0", "Specifies if previous maps should be stored persistently.", _, true, 0.0, true, 1.0);
|
||||
g_Cvar_NoVoteMode = CreateConVar("sm_mapvote_novote", "1", "Specifies whether or not MapChooser should pick a map if no votes are received.", _, true, 0.0, true, 1.0);
|
||||
g_Cvar_Extend = CreateConVar("sm_mapvote_extend", "0", "Number of extensions allowed each map.", _, true, 0.0);
|
||||
@ -609,7 +611,7 @@ void InitiateVote(MapChange when, ArrayList inputlist=null)
|
||||
if (inputlist == null)
|
||||
{
|
||||
int nominateCount = g_NominateList.Length;
|
||||
int voteSize = g_Cvar_IncludeMaps.IntValue;
|
||||
int voteSize = g_Cvar_IncludeMaxMaps.IntValue;
|
||||
|
||||
/* Smaller of the two - It should be impossible for nominations to exceed the size though (cvar changed mid-map?) */
|
||||
int nominationsToAdd = nominateCount >= voteSize ? voteSize : nominateCount;
|
||||
@ -993,16 +995,20 @@ void CreateNextVote()
|
||||
GetCurrentMap(map, sizeof(map));
|
||||
RemoveStringFromArray(tempMaps, map);
|
||||
|
||||
if (g_Cvar_ExcludeMaps.IntValue && tempMaps.Length > g_Cvar_ExcludeMaps.IntValue)
|
||||
// Start excluding the most recently played maps first
|
||||
for (int i = g_OldMapList.Length-1; i >= 0; i--)
|
||||
{
|
||||
for (int i = 0; i < g_OldMapList.Length; i++)
|
||||
if (tempMaps.Length <= g_Cvar_IncludeMinMaps.IntValue)
|
||||
{
|
||||
g_OldMapList.GetString(i, map, sizeof(map));
|
||||
RemoveStringFromArray(tempMaps, map);
|
||||
// Exit if we hit the minimum option count
|
||||
break;
|
||||
}
|
||||
|
||||
g_OldMapList.GetString(i, map, sizeof(map));
|
||||
RemoveStringFromArray(tempMaps, map);
|
||||
}
|
||||
|
||||
int limit = (g_Cvar_IncludeMaps.IntValue < tempMaps.Length ? g_Cvar_IncludeMaps.IntValue : tempMaps.Length);
|
||||
int limit = (g_Cvar_IncludeMaxMaps.IntValue < tempMaps.Length ? g_Cvar_IncludeMaxMaps.IntValue : tempMaps.Length);
|
||||
for (int i = 0; i < limit; i++)
|
||||
{
|
||||
int b = GetRandomInt(0, tempMaps.Length - 1);
|
||||
@ -1054,7 +1060,7 @@ NominateResult InternalNominateMap(char[] map, bool force, int owner)
|
||||
}
|
||||
|
||||
/* Too many nominated maps. */
|
||||
if (g_NominateList.Length >= g_Cvar_IncludeMaps.IntValue && !force)
|
||||
if (g_NominateList.Length >= g_Cvar_IncludeMaxMaps.IntValue && !force)
|
||||
{
|
||||
return Nominate_VoteFull;
|
||||
}
|
||||
@ -1062,7 +1068,7 @@ NominateResult InternalNominateMap(char[] map, bool force, int owner)
|
||||
g_NominateList.PushString(map);
|
||||
g_NominateOwners.Push(owner);
|
||||
|
||||
while (g_NominateList.Length > g_Cvar_IncludeMaps.IntValue)
|
||||
while (g_NominateList.Length > g_Cvar_IncludeMaxMaps.IntValue)
|
||||
{
|
||||
char oldmap[PLATFORM_MAX_PATH];
|
||||
g_NominateList.GetString(0, oldmap, sizeof(oldmap));
|
||||
|
||||
141
plugins/testsuite/mock/test_arraylist_find.sp
Normal file
141
plugins/testsuite/mock/test_arraylist_find.sp
Normal file
@ -0,0 +1,141 @@
|
||||
#pragma semicolon 1
|
||||
#pragma newdecls required
|
||||
#include <testing>
|
||||
|
||||
enum struct TestStruct
|
||||
{
|
||||
int intval;
|
||||
char strval[32];
|
||||
}
|
||||
|
||||
public void OnPluginStart()
|
||||
{
|
||||
ArrayList list = new ArrayList(sizeof(TestStruct));
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
|
||||
SetTestContext("EmptyArrayTest");
|
||||
|
||||
AssertEq("test_forward", list.FindString("index3", TestStruct::strval, -1, false), -1);
|
||||
AssertEq("test_reverse", list.FindString("index3", TestStruct::strval, -1, true), -1);
|
||||
AssertEq("test_forward", list.FindValue(3, TestStruct::intval, -1, false), -1);
|
||||
AssertEq("test_reverse", list.FindValue(3, TestStruct::intval, -1, true), -1);
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
|
||||
// Fill
|
||||
TestStruct ts;
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
ts.intval = i;
|
||||
Format(ts.strval, sizeof(ts.strval), "index%d", i);
|
||||
list.PushArray(ts);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
|
||||
SetTestContext("FindString");
|
||||
|
||||
AssertEq("test_defaults", list.FindString("index3", TestStruct::strval), 3);
|
||||
|
||||
AssertEq("test_forward", list.FindString("index3", TestStruct::strval, -1, false), 3);
|
||||
AssertEq("test_forward", list.FindString("index3", TestStruct::strval, 0, false), 3);
|
||||
AssertEq("test_forward", list.FindString("index3", TestStruct::strval, 2, false), 3);
|
||||
AssertEq("test_forward", list.FindString("index3", TestStruct::strval, 3, false), -1);
|
||||
AssertEq("test_forward", list.FindString("index3", TestStruct::strval, 10, false), -1);
|
||||
|
||||
AssertEq("test_reverse", list.FindString("index3", TestStruct::strval, -1, true), 3);
|
||||
AssertEq("test_reverse", list.FindString("index3", TestStruct::strval, 0, true), -1);
|
||||
AssertEq("test_reverse", list.FindString("index3", TestStruct::strval, 3, true), -1);
|
||||
AssertEq("test_reverse", list.FindString("index3", TestStruct::strval, 4, true), 3);
|
||||
AssertEq("test_reverse", list.FindString("index3", TestStruct::strval, 10, true), 3);
|
||||
|
||||
AssertEq("test_bottom", list.FindString("index0", TestStruct::strval, -1, false), 0);
|
||||
AssertEq("test_bottom", list.FindString("index0", TestStruct::strval, -1, true), 0);
|
||||
AssertEq("test_bottom", list.FindString("index0", TestStruct::strval, 1, true), 0);
|
||||
AssertEq("test_bottom", list.FindString("index0", TestStruct::strval, 10, false), -1);
|
||||
AssertEq("test_bottom", list.FindString("index0", TestStruct::strval, 10, true), 0);
|
||||
|
||||
AssertEq("test_top", list.FindString("index9", TestStruct::strval, -1, false), 9);
|
||||
AssertEq("test_top", list.FindString("index9", TestStruct::strval, -1, true), 9);
|
||||
AssertEq("test_top", list.FindString("index9", TestStruct::strval, 8, false), 9);
|
||||
AssertEq("test_top", list.FindString("index9", TestStruct::strval, 10, false), -1);
|
||||
AssertEq("test_top", list.FindString("index9", TestStruct::strval, 10, true), 9);
|
||||
|
||||
AssertEq("test_case_sensitive", list.FindString("INDEX0", TestStruct::strval, .caseSensitive = true), -1);
|
||||
AssertEq("test_case_sensitive", list.FindString("INDEX0", TestStruct::strval, .caseSensitive = false), 0);
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
|
||||
SetTestContext("FindValue");
|
||||
|
||||
AssertEq("test_defaults", list.FindValue(3, TestStruct::intval), 3);
|
||||
|
||||
AssertEq("test_forward", list.FindValue(3, TestStruct::intval, -1, false), 3);
|
||||
AssertEq("test_forward", list.FindValue(3, TestStruct::intval, 0, false), 3);
|
||||
AssertEq("test_forward", list.FindValue(3, TestStruct::intval, 2, false), 3);
|
||||
AssertEq("test_forward", list.FindValue(3, TestStruct::intval, 3, false), -1);
|
||||
AssertEq("test_forward", list.FindValue(3, TestStruct::intval, 10, false), -1);
|
||||
|
||||
AssertEq("test_reverse", list.FindValue(3, TestStruct::intval, -1, true), 3);
|
||||
AssertEq("test_reverse", list.FindValue(3, TestStruct::intval, 0, true), -1);
|
||||
AssertEq("test_reverse", list.FindValue(3, TestStruct::intval, 3, true), -1);
|
||||
AssertEq("test_reverse", list.FindValue(3, TestStruct::intval, 4, true), 3);
|
||||
AssertEq("test_reverse", list.FindValue(3, TestStruct::intval, 10, true), 3);
|
||||
|
||||
AssertEq("test_bottom", list.FindValue(0, TestStruct::intval, -1, false), 0);
|
||||
AssertEq("test_bottom", list.FindValue(0, TestStruct::intval, -1, true), 0);
|
||||
AssertEq("test_bottom", list.FindValue(0, TestStruct::intval, 1, true), 0);
|
||||
AssertEq("test_bottom", list.FindValue(0, TestStruct::intval, 10, false), -1);
|
||||
AssertEq("test_bottom", list.FindValue(0, TestStruct::intval, 10, true), 0);
|
||||
|
||||
AssertEq("test_top", list.FindValue(9, TestStruct::intval, -1, false), 9);
|
||||
AssertEq("test_top", list.FindValue(9, TestStruct::intval, -1, true), 9);
|
||||
AssertEq("test_top", list.FindValue(9, TestStruct::intval, 8, false), 9);
|
||||
AssertEq("test_top", list.FindValue(9, TestStruct::intval, 10, false), -1);
|
||||
AssertEq("test_top", list.FindValue(9, TestStruct::intval, 10, true), 9);
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
|
||||
SetTestContext("IterateOverFindString");
|
||||
int found, index;
|
||||
|
||||
// Duplicate last entry
|
||||
list.PushArray(ts);
|
||||
|
||||
found = 0; index = -1;
|
||||
while ((index = list.FindString("index9", TestStruct::strval, index, false)) != -1)
|
||||
{
|
||||
found++;
|
||||
}
|
||||
AssertEq("test_find_all_strings_forward", found, 2);
|
||||
|
||||
found = 0; index = -1;
|
||||
while ((index = list.FindString("index9", TestStruct::strval, index, true)) != -1)
|
||||
{
|
||||
found++;
|
||||
}
|
||||
AssertEq("test_find_all_strings_reverse", found, 2);
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
|
||||
SetTestContext("IterateOverFindValue");
|
||||
|
||||
found = 0, index = -1;
|
||||
while ((index = list.FindValue(9, TestStruct::intval, index, false)) != -1)
|
||||
{
|
||||
found++;
|
||||
}
|
||||
AssertEq("test_find_all_values_forward", found, 2);
|
||||
|
||||
found = 0; index = -1;
|
||||
while ((index = list.FindValue(9, TestStruct::intval, index, true)) != -1)
|
||||
{
|
||||
found++;
|
||||
}
|
||||
AssertEq("test_find_all_values_reverse", found, 2);
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
|
||||
PrintToServer("OK");
|
||||
}
|
||||
@ -1 +1 @@
|
||||
Subproject commit ab76f94ee4ef28187cc08030599577996fcba3be
|
||||
Subproject commit 8c6692c85a6c41f5d89f744da57b5ba43515b4ec
|
||||
Loading…
Reference in New Issue
Block a user