Last active
December 15, 2015 06:39
-
-
Save Zeex/5217723 to your computer and use it in GitHub Desktop.
CallNative()
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <cstring> | |
#include <sampgdk/amx.h> | |
#include <sampgdk/core.h> | |
cell CallNative(AMX *amx, AMX_NATIVE native, int num_params) { | |
int params_size = num_params * sizeof(cell); | |
amx_Push(amx, params_size); | |
cell *params; | |
amx_GetAddr(amx, amx->stk, ¶ms); | |
amx->paramcount = 0; | |
cell retval = native(amx, params); | |
amx->stk += params_size + sizeof(cell); | |
return retval; | |
} | |
AMX_NATIVE FindNative(const char *name) { | |
const AMX_NATIVE_INFO *natives = sampgdk_get_natives(); | |
int num_natives = sampgdk_num_natives(); | |
for (int i = 0; i < num_natives; i++) { | |
if (std::strcmp(natives[i].name, name) == 0) { | |
return natives[i].func; | |
} | |
} | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef CALLNATIVE_H | |
#define CALLNATIVE_H | |
#include <sampgdk/amx.h> | |
template<typename T> | |
class NativeArgument { | |
public: | |
NativeArgument(AMX *amx, cell x) { | |
amx_Push(amx, x); | |
} | |
}; | |
template<> | |
class NativeArgument<float> { | |
public: | |
NativeArgument(AMX *amx, float x) { | |
amx_Push(amx, amx_ftoc(x)); | |
} | |
}; | |
template<> | |
class NativeArgument<const char *> { | |
public: | |
NativeArgument(AMX *amx, const char *s): amx_(amx) { | |
amx_PushString(amx, &address_, 0, s, 0, 0); | |
} | |
~NativeArgument() { | |
amx_Release(amx_, address_); | |
} | |
private: | |
AMX *amx_; | |
cell address_; | |
}; | |
template<> | |
class NativeArgument<std::string> { | |
public: | |
NativeArgument(AMX *amx, std::string s) : amx_(amx) { | |
amx_PushString(amx, &address_, 0, s.c_str(), 0, 0); | |
} | |
~NativeArgument() { | |
amx_Release(amx_, address_); | |
} | |
private: | |
AMX *amx_; | |
cell address_; | |
}; | |
template<typename T = cell> | |
struct ConvertCell { | |
static cell Convert(cell x) { return x; } | |
}; | |
template<> | |
struct ConvertCell<bool> { | |
static bool Convert(cell x) { return x != 0; } | |
}; | |
template<> | |
struct ConvertCell<float> { | |
static float Convert(cell x) { return amx_ctof(x); } | |
}; | |
template<> | |
struct ConvertCell<void> { | |
static cell Convert(cell x) { return 0; } | |
}; | |
cell CallNative(AMX *amx, AMX_NATIVE native, int num_params); | |
template<typename R> | |
R DoCallNative(AMX *amx, AMX_NATIVE native, int num_params) { | |
return ConvertCell<R>::Convert(CallNative(amx, native, num_params)); | |
} | |
template<typename R> | |
R CallNative(AMX *amx, AMX_NATIVE native) { | |
return DoCallNative<R>(amx, native, 0); | |
} | |
template<typename R, typename T1> | |
R CallNative(AMX *amx, AMX_NATIVE native, T1 x1) { | |
NativeArgument<T1> a1(amx, x1); | |
return DoCallNative<R>(amx, native, 1); | |
} | |
template<typename R, typename T1, typename T2> | |
R CallNative(AMX *amx, AMX_NATIVE native, T1 x1, T2 x2) { | |
NativeArgument<T2> a2(amx, x2); | |
NativeArgument<T1> a1(amx, x1); | |
return DoCallNative<R>(amx, native, 2); | |
} | |
template<typename R, typename T1, typename T2, typename T3> | |
R CallNative(AMX *amx, AMX_NATIVE native, T1 x1, T2 x2, T3 x3) { | |
NativeArgument<T3> a3(amx, x3); | |
NativeArgument<T2> a2(amx, x2); | |
NativeArgument<T1> a1(amx, x1); | |
return DoCallNative<R>(amx, native, 3); | |
} | |
template<typename R, typename T1, typename T2, typename T3, typename T4> | |
R CallNative(AMX *amx, AMX_NATIVE native, T1 x1, T2 x2, T3 x3, T4 x4) { | |
NativeArgument<T4> a4(amx, x4); | |
NativeArgument<T3> a3(amx, x3); | |
NativeArgument<T2> a2(amx, x2); | |
NativeArgument<T1> a1(amx, x1); | |
return DoCallNative<R>(amx, native, 4); | |
} | |
template<typename R, typename T1, typename T2, typename T3, typename T4, typename T5> | |
R CallNative(AMX *amx, AMX_NATIVE native, T1 x1, T2 x2, T3 x3, T4 x4, T5 x5) { | |
NativeArgument<T5> a5(amx, x5); | |
NativeArgument<T4> a4(amx, x4); | |
NativeArgument<T3> a3(amx, x3); | |
NativeArgument<T2> a2(amx, x2); | |
NativeArgument<T1> a1(amx, x1); | |
return DoCallNative<R>(amx, native, 5); | |
} | |
template<typename R, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6> | |
R CallNative(AMX *amx, AMX_NATIVE native, T1 x1, T2 x2, T3 x3, T4 x4, T5 x5, T6 x6) { | |
NativeArgument<T6> a6(amx, x6); | |
NativeArgument<T5> a5(amx, x5); | |
NativeArgument<T4> a4(amx, x4); | |
NativeArgument<T3> a3(amx, x3); | |
NativeArgument<T2> a2(amx, x2); | |
NativeArgument<T1> a1(amx, x1); | |
return DoCallNative<R>(amx, native, 6); | |
} | |
template<typename R, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7> | |
R CallNative(AMX *amx, AMX_NATIVE native, T1 x1, T2 x2, T3 x3, T4 x4, T5 x5, T6 x6, T7 x7) { | |
NativeArgument<T7> a7(amx, x7); | |
NativeArgument<T6> a6(amx, x6); | |
NativeArgument<T5> a5(amx, x5); | |
NativeArgument<T4> a4(amx, x4); | |
NativeArgument<T3> a3(amx, x3); | |
NativeArgument<T2> a2(amx, x2); | |
NativeArgument<T1> a1(amx, x1); | |
return DoCallNative<R>(amx, native, 7); | |
} | |
template<typename R, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8> | |
R CallNative(AMX *amx, AMX_NATIVE native, T1 x1, T2 x2, T3 x3, T4 x4, T5 x5, T6 x6, T7 x7, T8 x8) { | |
NativeArgument<T8> a8(amx, x8); | |
NativeArgument<T7> a7(amx, x7); | |
NativeArgument<T6> a6(amx, x6); | |
NativeArgument<T5> a5(amx, x5); | |
NativeArgument<T4> a4(amx, x4); | |
NativeArgument<T3> a3(amx, x3); | |
NativeArgument<T2> a2(amx, x2); | |
NativeArgument<T1> a1(amx, x1); | |
return DoCallNative<R>(amx, native, 8); | |
} | |
template<typename R, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9> | |
R CallNative(AMX *amx, AMX_NATIVE native, T1 x1, T2 x2, T3 x3, T4 x4, T5 x5, T6 x6, T7 x7, T8 x8, T9 x9) { | |
NativeArgument<T9> a9(amx, x8); | |
NativeArgument<T8> a8(amx, x8); | |
NativeArgument<T7> a7(amx, x7); | |
NativeArgument<T6> a6(amx, x6); | |
NativeArgument<T5> a5(amx, x5); | |
NativeArgument<T4> a4(amx, x4); | |
NativeArgument<T3> a3(amx, x3); | |
NativeArgument<T2> a2(amx, x2); | |
NativeArgument<T1> a1(amx, x1); | |
return DoCallNative<R>(amx, native, 9); | |
} | |
AMX_NATIVE FindNative(const char *name); | |
#endif // !CALLNATIVE_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "callnative.h" | |
#include "fakeamx.h" | |
bool MySendClientMessage(int playerid, int color, const char *message) { | |
static AMX_NATIVE native = FindNative("SendClientMessage"); | |
return CallNative<bool>(FakeAmx::Instance().amx(), native, playerid, 0x0000FFFF, message); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <cstring> | |
#include <limits> | |
#include "fakeamx.h" | |
static const std::size_t INITIAL_HEAP_SIZE = 1024; | |
FakeAmx &FakeAmx::Instance() { | |
static FakeAmx instance; | |
return instance; | |
} | |
FakeAmx::FakeAmx(): | |
heap_(INITIAL_HEAP_SIZE) | |
{ | |
std::memset(&hdr_, 0, sizeof(hdr_)); | |
std::memset(&amx_, 0, sizeof(amx_)); | |
hdr_.magic = AMX_MAGIC; | |
hdr_.file_version = MIN_FILE_VERSION; | |
hdr_.amx_version = MIN_AMX_VERSION; | |
hdr_.dat = reinterpret_cast<int32_t>(&heap_[0]) - | |
reinterpret_cast<int32_t>(&hdr_); | |
amx_.base = reinterpret_cast<unsigned char*>(&hdr_); | |
amx_.data = reinterpret_cast<unsigned char*>(&heap_[0]); | |
amx_.callback = amx_Callback; | |
amx_.stp = std::numeric_limits<cell>::max(); | |
amx_.error = AMX_ERR_NONE; | |
} | |
FakeAmx::~FakeAmx() { | |
} | |
AMX *FakeAmx::amx() { | |
return &amx_; | |
} | |
const AMX *FakeAmx::amx() const { | |
return &amx_; | |
} | |
cell FakeAmx::Push(std::size_t cells) { | |
cell address = amx_.hea; | |
amx_.hea += cells * sizeof(cell); | |
if (amx_.hea/sizeof(cell) >= static_cast<cell>(heap_.size())) { | |
heap_.resize(amx_.hea/sizeof(cell)); | |
} | |
return address; | |
} | |
cell FakeAmx::Push(const char *s) { | |
std::size_t size = std::strlen(s) + 1; | |
cell address = Push(size); | |
amx_SetString(&heap_[0] + address/sizeof(cell), s, 0, 0, size); | |
return address; | |
} | |
void FakeAmx::GetData(cell address, cell &value) const { | |
value = heap_[address/sizeof(cell)]; | |
} | |
void FakeAmx::GetData(cell address, char *value, std::size_t size) const { | |
const cell *ptr = &heap_[0] + address/sizeof(cell); | |
amx_GetString(value, ptr, 0, size); | |
} | |
void FakeAmx::Pop(cell address) { | |
if (amx_.hea > address) { | |
amx_.hea = address; | |
} | |
} | |
cell FakeAmx::CallNative(AMX_NATIVE native, cell *params) { | |
return native(&amx_, params); | |
} | |
bool FakeAmx::CallBooleanNative(AMX_NATIVE native, cell *params) { | |
return CallNative(native, params) != 0; | |
} | |
FakeAmxHeapObject::FakeAmxHeapObject(FakeAmx &fa): | |
fa_(fa), | |
size_(1), | |
address_(fa.Push(1)) | |
{ | |
} | |
FakeAmxHeapObject::FakeAmxHeapObject(FakeAmx &fa, std::size_t cells): | |
fa_(fa), | |
size_(cells), | |
address_(fa.Push(cells)) | |
{ | |
} | |
FakeAmxHeapObject::FakeAmxHeapObject(FakeAmx &fa, const char *s): | |
fa_(fa), | |
size_(std::strlen(s) + 1), | |
address_(fa.Push(s)) | |
{ | |
} | |
FakeAmxHeapObject::~FakeAmxHeapObject() { | |
fa_.Pop(address_); | |
} | |
cell FakeAmxHeapObject::address() const { | |
return address_; | |
} | |
std::size_t FakeAmxHeapObject::size() const { | |
return size_; | |
} | |
cell FakeAmxHeapObject::GetAsCell() const { | |
cell value; | |
fa_.GetData(address_, value); | |
return value; | |
} | |
bool FakeAmxHeapObject::GetAsBool() const { | |
return GetAsCell() != 0; | |
} | |
float FakeAmxHeapObject::GetAsFloat() const { | |
cell value = this->GetAsCell(); | |
return amx_ctof(value); | |
} | |
void FakeAmxHeapObject::GetAsString(char *s, std::size_t size) const { | |
fa_.GetData(address_, s, size); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef FAKEAMX_H | |
#define FAKEAMX_H | |
#include <cstddef> | |
#include <vector> | |
#include <sampgdk/amx.h> | |
class FakeAmx { | |
public: | |
static FakeAmx &Instance(); | |
~FakeAmx(); | |
AMX *amx(); | |
const AMX *amx() const; | |
cell Push(std::size_t cells); | |
cell Push(const char *s); | |
void GetData(cell address, cell &value) const; | |
void GetData(cell address, char *value, std::size_t size) const; | |
void Pop(cell address); | |
cell CallNative(AMX_NATIVE native, cell *params); | |
bool CallBooleanNative(AMX_NATIVE native, cell *params); | |
private: | |
FakeAmx(); | |
FakeAmx(const FakeAmx &); | |
void operator=(const FakeAmx &); | |
private: | |
AMX amx_; | |
AMX_HEADER hdr_; | |
std::vector<cell> heap_; | |
}; | |
class FakeAmxHeapObject { | |
public: | |
FakeAmxHeapObject(FakeAmx &fa); | |
FakeAmxHeapObject(FakeAmx &fa, std::size_t cells); | |
FakeAmxHeapObject(FakeAmx &fa, const char *s); | |
~FakeAmxHeapObject(); | |
cell address() const; | |
std::size_t size() const; | |
cell GetAsCell() const; | |
bool GetAsBool() const; | |
float GetAsFloat() const; | |
void GetAsString(char *s, std::size_t size) const; | |
private: | |
FakeAmxHeapObject(const FakeAmxHeapObject &); | |
void operator=(const FakeAmxHeapObject &); | |
private: | |
FakeAmx &fa_; | |
cell address_; | |
std::size_t size_; | |
}; | |
#endif // !FAKEAMX_H | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment