mirror of
https://github.com/roflmuffin/CounterStrikeSharp.git
synced 2025-12-06 08:03:12 -08:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dfc9859806 | ||
|
|
f99f58402a | ||
|
|
6317559bd2 |
@@ -1,21 +1,72 @@
|
||||
BasedOnStyle: LLVM
|
||||
|
||||
# Spacing
|
||||
IndentWidth: 4
|
||||
ColumnLimit: 100
|
||||
UseTab: Never
|
||||
ColumnLimit: 140
|
||||
|
||||
# Line Endings
|
||||
LineEnding: LF
|
||||
InsertNewlineAtEOF: true
|
||||
DerivePointerAlignment: false
|
||||
PointerAlignment: Left
|
||||
|
||||
AlignAfterOpenBracket: Align
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
SortIncludes: false
|
||||
SpaceBeforeParens: ControlStatements
|
||||
AllowAllArgumentsOnNextLine: true
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
IndentCaseLabels: false
|
||||
IndentCaseLabels: true
|
||||
|
||||
# Line Breaks
|
||||
BreakBeforeBraces: Custom
|
||||
BraceWrapping:
|
||||
AfterCaseLabel: true
|
||||
AfterClass: true
|
||||
AfterStruct: true
|
||||
AfterControlStatement: Always
|
||||
AfterEnum: true
|
||||
AfterUnion: true
|
||||
AfterNamespace: false
|
||||
AfterFunction: true
|
||||
AfterNamespace: false
|
||||
AfterStruct: true
|
||||
AfterUnion: true
|
||||
AfterExternBlock: true
|
||||
BeforeCatch: true
|
||||
BeforeElse: true
|
||||
BeforeLambdaBody: false
|
||||
BeforeWhile: false
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: true
|
||||
SplitEmptyRecord: true
|
||||
SplitEmptyNamespace: true
|
||||
|
||||
PointerAlignment: Left
|
||||
SortIncludes: CaseSensitive
|
||||
IncludeBlocks: Regroup
|
||||
IncludeCategories:
|
||||
# External headers in <> with extension or /
|
||||
- Regex: '<[-\w\/-_]+[\.\/][-\w\/-_]+>'
|
||||
Priority: 2
|
||||
# Standard headers in <>
|
||||
- Regex: '<[-\w\/-_]+>'
|
||||
Priority: 3
|
||||
# Local headers in ""
|
||||
- Regex: '"[-\w\/-_]*"'
|
||||
Priority: 4
|
||||
|
||||
ReflowComments: true
|
||||
CompactNamespaces: false
|
||||
Cpp11BracedListStyle: false
|
||||
|
||||
AlignConsecutiveMacros:
|
||||
Enabled: true
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
|
||||
AlignEscapedNewlines: Left
|
||||
AlignTrailingComments: Never
|
||||
|
||||
AllowShortBlocksOnASingleLine: Empty
|
||||
AllowShortIfStatementsOnASingleLine: OnlyFirstIf
|
||||
AllowShortLambdasOnASingleLine: Empty
|
||||
BinPackArguments: true
|
||||
BinPackParameters: false
|
||||
|
||||
LambdaBodyIndentation: OuterScope
|
||||
|
||||
14
.editorconfig
Normal file
14
.editorconfig
Normal file
@@ -0,0 +1,14 @@
|
||||
# top-most EditorConfig file
|
||||
root = true
|
||||
|
||||
# Unix-style newlines with a newline ending every file
|
||||
[*]
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
max_line_length = 140
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.json]
|
||||
indent_size = 2
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -2,7 +2,6 @@
|
||||
.cmake/
|
||||
cmake-build-*/
|
||||
.kdev4/
|
||||
.vscode/
|
||||
generated/
|
||||
|
||||
# configure_file auto generated.
|
||||
|
||||
4
.vscode/settings.json
vendored
Normal file
4
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"editor.defaultFormatter": null,
|
||||
"editor.formatOnSave": true
|
||||
}
|
||||
37
eng/formatting/download-tools.ps1
Normal file
37
eng/formatting/download-tools.ps1
Normal file
@@ -0,0 +1,37 @@
|
||||
# Tool taken from dotnet/runtime
|
||||
# https://github.com/dotnet/runtime/blob/a8158c170b694f8c1dbae114c63c346b38244901/eng/formatting/download-tools.ps1
|
||||
|
||||
function DownloadClangTool {
|
||||
param (
|
||||
[string]
|
||||
$toolName,
|
||||
[string]
|
||||
$downloadOutputPath
|
||||
)
|
||||
|
||||
$clangVersion = "17.0.6"
|
||||
$clangToolsRootUrl = "https://clrjit2.blob.core.windows.net/clang-tools"
|
||||
$clangPlatform = "windows-x64"
|
||||
|
||||
$toolUrl = "$clangToolsRootUrl/$clangVersion/$clangPlatform/$toolName.exe"
|
||||
$targetPath = "$downloadOutputPath\$toolName.exe"
|
||||
|
||||
if (-not $(ls $downloadOutputPath | Where-Object { $_.Name -eq "$toolName.exe" })) {
|
||||
Write-Output "Downloading '$toolUrl' to '$targetPath'"
|
||||
# Pass -PassThru as otherwise Invoke-WebRequest leaves a corrupted file if the download fails. With -PassThru the download is buffered first.
|
||||
# -UseBasicParsing is necessary for older PowerShells when Internet Explorer might not be installed/configured
|
||||
$null = Invoke-WebRequest -Uri "$toolUrl" -OutFile $(Join-Path $downloadOutputPath -ChildPath "$toolName.exe") -PassThru -UseBasicParsing
|
||||
}
|
||||
else {
|
||||
Write-Output "Found '$targetPath'"
|
||||
}
|
||||
}
|
||||
|
||||
$downloadPathFolder = Split-Path $PSScriptRoot -Parent | Split-Path -Parent | Join-Path -ChildPath "artifacts" | Join-Path -ChildPath "tools"
|
||||
|
||||
mkdir $downloadPathFolder -ErrorAction SilentlyContinue
|
||||
|
||||
DownloadClangTool "clang-format" "$downloadPathFolder"
|
||||
|
||||
# Add to path to enable scripts to skip additional downloading steps since the tools will already be on the path.
|
||||
$env:PATH = "$downloadPathFolder;$env:PATH"
|
||||
60
eng/formatting/download-tools.sh
Normal file
60
eng/formatting/download-tools.sh
Normal file
@@ -0,0 +1,60 @@
|
||||
# Tool taken from dotnet/runtime
|
||||
# https://github.com/dotnet/runtime/blob/a8158c170b694f8c1dbae114c63c346b38244901/eng/formatting/download-tools.sh
|
||||
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -ue
|
||||
|
||||
source="${BASH_SOURCE[0]}"
|
||||
|
||||
# resolve $source until the file is no longer a symlink
|
||||
while [[ -h "$source" ]]; do
|
||||
scriptroot="$( cd -P "$( dirname "$source" )" && pwd )"
|
||||
source="$(readlink "$source")"
|
||||
# if $source was a relative symlink, we need to resolve it relative to the path where the
|
||||
# symlink file was located
|
||||
[[ $source != /* ]] && source="$scriptroot/$source"
|
||||
done
|
||||
scriptroot="$( cd -P "$( dirname "$source" )" && pwd )"
|
||||
|
||||
function DownloadClangTool {
|
||||
|
||||
clangVersion="17.0.6"
|
||||
clangToolsRootUrl="https://clrjit2.blob.core.windows.net/clang-tools"
|
||||
|
||||
clangPlatform="$(dotnet --info | grep 'RID:')"
|
||||
clangPlatform="${clangPlatform##*RID:* }"
|
||||
echo "dotnet RID: ${clangPlatform}"
|
||||
|
||||
# override common RIDs with compatible version so we don't need to upload binaries for each RID
|
||||
case $clangPlatform in
|
||||
ubuntu.*-x64)
|
||||
clangPlatform=linux-x64
|
||||
;;
|
||||
esac
|
||||
|
||||
toolUrl="${clangToolsRootUrl}/${clangVersion}/${clangPlatform}/$1"
|
||||
toolOutput=$2/$1
|
||||
|
||||
echo "Downloading $1 from ${toolUrl} to ${toolOutput}"
|
||||
|
||||
if [[ ! -x "$toolOutput" ]]; then
|
||||
curl --silent --retry 5 --fail -o "${toolOutput}" "$toolUrl"
|
||||
chmod 751 $toolOutput
|
||||
fi
|
||||
|
||||
if [[ ! -x "$toolOutput" ]]; then
|
||||
echo "Failed to download $1"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
engFolder="$(cd -P "$( dirname "$scriptroot" )" && pwd )"
|
||||
downloadPathFolder="$(cd -P "$( dirname "$engFolder" )" && pwd )/artifacts/tools"
|
||||
|
||||
mkdir -p "$downloadPathFolder"
|
||||
|
||||
DownloadClangTool "clang-format" "$downloadPathFolder"
|
||||
|
||||
export PATH=$downloadPathFolder:$PATH
|
||||
29
eng/formatting/format.sh
Normal file
29
eng/formatting/format.sh
Normal file
@@ -0,0 +1,29 @@
|
||||
# Tool taken from dotnet/runtime
|
||||
# https://github.com/dotnet/runtime/blob/a8158c170b694f8c1dbae114c63c346b38244901/eng/formatting/format.sh
|
||||
|
||||
#!/bin/sh
|
||||
|
||||
LC_ALL=C
|
||||
# Select files to format
|
||||
NATIVE_FILES=$(git diff --cached --name-only --diff-filter=ACM "*.h" "*.hpp" "*.c" "*.cpp" "*.inl" | sed 's| |\\ |g')
|
||||
MANAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM "*.cs" "*.vb" | sed 's| |\\ |g')
|
||||
|
||||
exec 1>&2
|
||||
|
||||
if [ -n "$NATIVE_FILES" ]; then
|
||||
# Format all selected files
|
||||
echo "$NATIVE_FILES" | cat | xargs | sed -e 's/ /,/g' | xargs "./artifacts/tools/clang-format" -style=file -i
|
||||
|
||||
# Add back the modified files to staging
|
||||
echo "$NATIVE_FILES" | xargs git add
|
||||
fi
|
||||
|
||||
if [ -n "$MANAGED_FILES" ]; then
|
||||
# Format all selected files
|
||||
echo "$MANAGED_FILES" | cat | xargs | sed -e 's/ /,/g' | dotnet format whitespace --include - --folder
|
||||
|
||||
# Add back the modified files to staging
|
||||
echo "$MANAGED_FILES" | xargs git add
|
||||
fi
|
||||
|
||||
exit 0
|
||||
@@ -12,7 +12,7 @@ set(CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING
|
||||
)
|
||||
|
||||
# TODO: Use C++20 instead.
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
|
||||
if (LINUX)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
|
||||
|
||||
@@ -89,7 +89,7 @@ public static class VirtualFunctions
|
||||
new(GameData.GetSignature("StateChanged"));
|
||||
public static Action<IntPtr, IntPtr, int, short, short> StateChanged = StateChangedFunc.Invoke;
|
||||
|
||||
public static MemoryFunctionVoid<IntPtr, int, long> NetworkStateChangedFunc = new("NetworkStateChanged");
|
||||
public static MemoryFunctionVoid<IntPtr, int, long> NetworkStateChangedFunc = new(GameData.GetSignature("NetworkStateChanged"));
|
||||
public static Action<IntPtr, int, long> NetworkStateChanged = NetworkStateChangedFunc.Invoke;
|
||||
|
||||
}
|
||||
@@ -165,11 +165,11 @@ void* CGameConfig::ResolveSignature(const char* name)
|
||||
return nullptr;
|
||||
}
|
||||
size_t iLength = 0;
|
||||
byte* pSignature = HexToByte(signature, iLength);
|
||||
if (!pSignature) {
|
||||
auto pSignature = HexToByte(signature);
|
||||
if (pSignature.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
address = (*module)->FindSignature(pSignature, iLength);
|
||||
address = (*module)->FindSignature(pSignature);
|
||||
}
|
||||
|
||||
if (!address) {
|
||||
@@ -190,47 +190,63 @@ std::string CGameConfig::GetDirectoryName(const std::string& directoryPathInput)
|
||||
return "";
|
||||
}
|
||||
|
||||
int CGameConfig::HexStringToUint8Array(const char* hexString, uint8_t* byteArray, size_t maxBytes)
|
||||
std::vector<int16_t> CGameConfig::HexToByte(std::string_view src)
|
||||
{
|
||||
if (!hexString) {
|
||||
printf("Invalid hex string.\n");
|
||||
if (src.empty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
auto hex_char_to_byte = [](char c) -> int16_t {
|
||||
if (c >= '0' && c <= '9')
|
||||
return c - '0';
|
||||
if (c >= 'A' && c <= 'F')
|
||||
return c - 'A' + 10;
|
||||
if (c >= 'a' && c <= 'f')
|
||||
return c - 'a' + 10;
|
||||
|
||||
// a valid hex char can never go up to 0xFF
|
||||
return -1;
|
||||
}
|
||||
};
|
||||
|
||||
size_t hexStringLength = strlen(hexString);
|
||||
size_t byteCount = hexStringLength / 4; // Each "\\x" represents one byte.
|
||||
std::vector<int16_t> result{};
|
||||
|
||||
if (hexStringLength % 4 != 0 || byteCount == 0 || byteCount > maxBytes) {
|
||||
printf("Invalid hex string format or byte count.\n");
|
||||
return -1; // Return an error code.
|
||||
}
|
||||
const bool is_code_style = src[0] == '\\';
|
||||
|
||||
for (size_t i = 0; i < hexStringLength; i += 4) {
|
||||
if (sscanf(hexString + i, "\\x%2hhX", &byteArray[i / 4]) != 1) {
|
||||
printf("Failed to parse hex string at position %zu.\n", i);
|
||||
return -1; // Return an error code.
|
||||
const std::string_view pattern = is_code_style ? R"(\x)" : " ";
|
||||
const std::string_view wildcard = is_code_style ? "2A" : "?";
|
||||
|
||||
auto split = std::views::split(src, pattern);
|
||||
|
||||
for (auto&& str : split) {
|
||||
if (str.empty()) [[unlikely]] {
|
||||
continue;
|
||||
}
|
||||
|
||||
// std::string_view(std::subrange) constructor only exists in C++23 or above
|
||||
// use this when compiler is GCC >= 12.1 or Clang >= 16
|
||||
// const std::string_view byte(str.begin(), str.end());
|
||||
|
||||
// a workaround for GCC < 12.1, it doesn't work with Clang < 16
|
||||
// https://stackoverflow.com/a/48403210
|
||||
std::string_view byte (&*str.begin(), std::ranges::distance(str));
|
||||
|
||||
if (byte.starts_with(wildcard)) {
|
||||
result.emplace_back(-1);
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto high = hex_char_to_byte(byte[0]);
|
||||
const auto low = hex_char_to_byte(byte[1]);
|
||||
|
||||
// if then is malformed, return nothing
|
||||
// maybe print error message here?
|
||||
if (high == 0xFF || low == 0xFF) [[unlikely]] {
|
||||
return {};
|
||||
}
|
||||
|
||||
result.emplace_back((high << 4) | low);
|
||||
}
|
||||
|
||||
byteArray[byteCount] = '\0'; // Add a null-terminating character.
|
||||
|
||||
return byteCount; // Return the number of bytes successfully converted.
|
||||
return result;
|
||||
}
|
||||
|
||||
byte* CGameConfig::HexToByte(const char* src, size_t& length)
|
||||
{
|
||||
if (!src || strlen(src) <= 0) {
|
||||
CSSHARP_CORE_INFO("Invalid hex string\n");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
length = strlen(src) / 4;
|
||||
uint8_t* dest = new uint8_t[length];
|
||||
int byteCount = HexStringToUint8Array(src, dest, length);
|
||||
if (byteCount <= 0) {
|
||||
CSSHARP_CORE_INFO("Invalid hex format %s\n", src);
|
||||
return nullptr;
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
} // namespace counterstrikesharp
|
||||
} // namespace counterstrikesharp
|
||||
|
||||
@@ -33,8 +33,7 @@ class CGameConfig
|
||||
void* ResolveSignature(const char* name);
|
||||
|
||||
static std::string GetDirectoryName(const std::string& directoryPathInput);
|
||||
static int HexStringToUint8Array(const char* hexString, uint8_t* byteArray, size_t maxBytes);
|
||||
static byte* HexToByte(const char* src, size_t& length);
|
||||
static std::vector<int16_t> HexToByte(std::string_view src);
|
||||
|
||||
private:
|
||||
std::string m_sPath;
|
||||
|
||||
@@ -30,12 +30,15 @@
|
||||
#include <Psapi.h>
|
||||
#endif
|
||||
|
||||
#include <cstdio>
|
||||
#include "gameconfig.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include "memory_module.h"
|
||||
#include "metamod_oslink.h"
|
||||
#include "wchartypes.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#if __linux__
|
||||
struct ModuleInfo {
|
||||
const char *path; // in
|
||||
@@ -118,29 +121,13 @@ int GetModuleInformation(void *hModule, void **base, size_t *length) {
|
||||
}
|
||||
#endif
|
||||
|
||||
byte *ConvertToByteArray(const char *str, size_t *outLength) {
|
||||
size_t len = strlen(str) / 4; // Every byte is represented as \xHH
|
||||
byte *result = (byte *)malloc(len);
|
||||
|
||||
for (size_t i = 0, j = 0; i < len; ++i, j += 4) {
|
||||
sscanf(str + j, "\\x%2hhx", &result[i]);
|
||||
}
|
||||
|
||||
*outLength = len;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void* FindSignature(const char* moduleName, const char* bytesStr) {
|
||||
size_t iSigLength;
|
||||
auto sigBytes = ConvertToByteArray(bytesStr, &iSigLength);
|
||||
|
||||
auto module = dlmount(moduleName);
|
||||
if (module == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void *moduleBase;
|
||||
void* moduleBase;
|
||||
size_t moduleSize;
|
||||
#if __linux__
|
||||
if (GetModuleInformation(module, &moduleBase, &moduleSize) != 0) {
|
||||
@@ -154,18 +141,30 @@ void* FindSignature(const char* moduleName, const char* bytesStr) {
|
||||
moduleSize = m_hModuleInfo.SizeOfImage;
|
||||
#endif
|
||||
|
||||
unsigned char *pMemory;
|
||||
void *returnAddr = nullptr;
|
||||
auto sigBytes = counterstrikesharp::CGameConfig::HexToByte(bytesStr);
|
||||
|
||||
pMemory = (byte *)moduleBase;
|
||||
if (sigBytes.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < moduleSize; i++) {
|
||||
size_t matches = 0;
|
||||
while (*(pMemory + i + matches) == sigBytes[matches] || sigBytes[matches] == '\x2A') {
|
||||
matches++;
|
||||
if (matches == iSigLength) {
|
||||
returnAddr = (void *)(pMemory + i);
|
||||
}
|
||||
void* returnAddr = nullptr;
|
||||
|
||||
const auto first_byte = sigBytes[0];
|
||||
|
||||
auto pMemory = (byte*)moduleBase;
|
||||
std::uint8_t* end = pMemory + moduleSize - sigBytes.size();
|
||||
|
||||
for (std::uint8_t* current = pMemory; current <= end; ++current) {
|
||||
if (first_byte != -1)
|
||||
current = std::find(current, end, first_byte);
|
||||
|
||||
if (current == end) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (std::equal(sigBytes.begin() + 1, sigBytes.end(), current + 1,
|
||||
[](auto opt, auto byte) { return opt == -1 || opt == byte; })) {
|
||||
return current;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,4 +173,4 @@ void* FindSignature(const char* moduleName, const char* bytesStr) {
|
||||
}
|
||||
|
||||
return returnAddr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,29 +41,35 @@ void* CModule::FindSignature(const char* signature)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
size_t iSigLength = 0;
|
||||
byte* pData = CGameConfig::HexToByte(signature, iSigLength);
|
||||
auto pData = CGameConfig::HexToByte(signature);
|
||||
if (pData.empty()) [[unlikely]]
|
||||
return nullptr;
|
||||
|
||||
return this->FindSignature(pData, iSigLength);
|
||||
return this->FindSignature(pData);
|
||||
}
|
||||
|
||||
void* CModule::FindSignature(const byte* pData, size_t iSigLength)
|
||||
void* CModule::FindSignature(const std::vector<int16_t>& sigBytes)
|
||||
{
|
||||
unsigned char* pMemory;
|
||||
void* return_addr = nullptr;
|
||||
const auto first_byte = sigBytes[0];
|
||||
|
||||
pMemory = (byte*)m_base;
|
||||
auto pMemory = (std::uint8_t*)m_base;
|
||||
std::uint8_t* end = pMemory + m_size - sigBytes.size();
|
||||
|
||||
for (size_t i = 0; i < m_size; i++) {
|
||||
size_t Matches = 0;
|
||||
while (*(pMemory + i + Matches) == pData[Matches] || pData[Matches] == '\x2A') {
|
||||
Matches++;
|
||||
if (Matches == iSigLength)
|
||||
return_addr = (void*)(pMemory + i);
|
||||
for (std::uint8_t* current = pMemory; current <= end; ++current) {
|
||||
if (first_byte != -1)
|
||||
current = std::find(current, end, first_byte);
|
||||
|
||||
if (current == end) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (std::equal(sigBytes.begin() + 1, sigBytes.end(), current + 1,
|
||||
[](auto opt, auto byte) { return opt == -1 || opt == byte; })) {
|
||||
return current;
|
||||
}
|
||||
}
|
||||
|
||||
return return_addr;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void* CModule::FindInterface(const char* name)
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
#include "interface.h"
|
||||
#include "strtools.h"
|
||||
#include "metamod_oslink.h"
|
||||
|
||||
#include <vector>
|
||||
#undef snprintf
|
||||
|
||||
namespace counterstrikesharp::modules {
|
||||
@@ -34,7 +36,7 @@ class CModule
|
||||
|
||||
void* FindSignature(const char* signature);
|
||||
|
||||
void* FindSignature(const byte* pData, size_t iSigLength);
|
||||
void* FindSignature(const std::vector<int16_t>& sigBytes);
|
||||
|
||||
void* FindInterface(const char* name);
|
||||
|
||||
|
||||
@@ -26,19 +26,6 @@
|
||||
namespace counterstrikesharp {
|
||||
std::vector<ValveFunction*> m_managed_ptrs;
|
||||
|
||||
byte* ConvertToByteArray(const char* str, size_t* outLength)
|
||||
{
|
||||
size_t len = strlen(str) / 4; // Every byte is represented as \xHH
|
||||
byte* result = (byte*)malloc(len);
|
||||
|
||||
for (size_t i = 0, j = 0; i < len; ++i, j += 4) {
|
||||
sscanf(str + j, "\\x%2hhx", &result[i]);
|
||||
}
|
||||
|
||||
*outLength = len;
|
||||
return result;
|
||||
}
|
||||
|
||||
void* FindSignatureNative(ScriptContext& scriptContext)
|
||||
{
|
||||
auto moduleName = scriptContext.GetArgument<const char*>(0);
|
||||
|
||||
Reference in New Issue
Block a user