Skip to content

Commit faf5db1

Browse files
authored
Merge pull request #1128 from openmultiplayer/amir/native-caller
Store natives globally & ability to call them from using SDK
2 parents 443429b + b2866f7 commit faf5db1

File tree

3 files changed

+301
-1
lines changed

3 files changed

+301
-1
lines changed

Server/Components/Pawn/Script/Script.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,15 @@ __attribute__((noinline)) int amx_FindPublic_impl(AMX* amx, const char* name, in
381381

382382
__attribute__((noinline)) int AMXAPI amx_Register_impl(AMX* amx, const AMX_NATIVE_INFO* list, int number)
383383
{
384+
// Register all natives in the global registry
385+
if (list != NULL)
386+
{
387+
for (int j = 0; (j < number || number == -1) && list[j].name != NULL; j++)
388+
{
389+
GlobalNativeRegistry::RegisterNative(list[j].name, list[j].func);
390+
}
391+
}
392+
384393
AMX_FUNCPART* func;
385394
AMX_HEADER* hdr;
386395
int i, numnatives, err;

Server/Components/Pawn/Script/Script.hpp

Lines changed: 291 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@
1717

1818
#include <array>
1919
#include <exception>
20+
#include <functional>
2021
#include <string>
2122
#include <vector>
23+
#include <type_traits>
2224

2325
#include <amx/amx.h>
2426
#include <amx/amxaux.h>
@@ -32,6 +34,28 @@ struct AMXCache
3234
FlatHashMap<String, int> publics; ///< A cache of AMX publics
3335
};
3436

37+
// Global pawn native registry for all registered pawn natives
38+
struct GlobalNativeRegistry
39+
{
40+
static FlatHashMap<String, AMX_NATIVE>& GetRegistry()
41+
{
42+
static FlatHashMap<String, AMX_NATIVE> registry;
43+
return registry;
44+
}
45+
46+
static void RegisterNative(const char* name, AMX_NATIVE func)
47+
{
48+
GetRegistry()[String(name)] = func;
49+
}
50+
51+
static AMX_NATIVE FindNative(const char* name)
52+
{
53+
auto& registry = GetRegistry();
54+
auto it = registry.find(String(name));
55+
return (it != registry.end()) ? it->second : nullptr;
56+
}
57+
};
58+
3559
class PawnScript : public IPawnScript
3660
{
3761
public:
@@ -108,6 +132,273 @@ class PawnScript : public IPawnScript
108132

109133
void tryLoad(std::string const& path);
110134

135+
/// Find native from global registry (works even if script doesn't use it)
136+
AMX_NATIVE FindNativeInRegistry(char const* name) const { return GlobalNativeRegistry::FindNative(name); }
137+
138+
cell CallNativeArray(const char* name, Span<Impl::NativeParam> params) override
139+
{
140+
return CallNativeArrayImpl(name, params);
141+
}
142+
143+
private:
144+
cell CallNativeArrayImpl(const char* name, Span<Impl::NativeParam> params)
145+
{
146+
AMX_NATIVE native = FindNativeInRegistry(name);
147+
if (!native)
148+
{
149+
return 0;
150+
}
151+
152+
size_t argCount = params.size();
153+
if (argCount == 0)
154+
{
155+
cell paramsArray[1] = { 0 };
156+
return native(const_cast<AMX*>(&amx_), paramsArray);
157+
}
158+
159+
DynamicArray<cell> paramsArray(argCount + 1);
160+
paramsArray[0] = argCount * sizeof(cell);
161+
162+
cell amx_addr_save = GetHEA();
163+
164+
struct RefParamInfo
165+
{
166+
cell amx_addr;
167+
void* ref_obj;
168+
enum
169+
{
170+
INT,
171+
FLOAT,
172+
BOOL,
173+
STRING,
174+
VECTOR_INT,
175+
VECTOR_FLOAT
176+
} type;
177+
size_t arraySize;
178+
std::function<void(cell*)> readback;
179+
};
180+
181+
DynamicArray<RefParamInfo> refParams;
182+
183+
for (size_t i = 0; i < argCount; ++i)
184+
{
185+
const auto& param = params[i];
186+
cell amx_addr;
187+
cell* phys_addr;
188+
189+
using ParamType = Impl::NativeParam::Type;
190+
191+
switch (param.type)
192+
{
193+
case ParamType::Int:
194+
paramsArray[i + 1] = static_cast<cell>(param.intValue);
195+
break;
196+
197+
case ParamType::Float:
198+
paramsArray[i + 1] = amx_ftoc(param.floatValue);
199+
break;
200+
201+
case ParamType::Bool:
202+
paramsArray[i + 1] = param.boolValue ? 1 : 0;
203+
break;
204+
205+
case ParamType::String:
206+
PushString(&amx_addr, nullptr, StringView(param.stringValue), false, false);
207+
paramsArray[i + 1] = amx_addr;
208+
break;
209+
210+
case ParamType::ArrayInt:
211+
{
212+
const int* arr = static_cast<const int*>(param.arrayPtr);
213+
DynamicArray<cell> cellArray(param.arraySize);
214+
for (size_t j = 0; j < param.arraySize; ++j)
215+
{
216+
cellArray[j] = static_cast<cell>(arr[j]);
217+
}
218+
PushArray(&amx_addr, nullptr, cellArray.data(), cellArray.size());
219+
paramsArray[i + 1] = amx_addr;
220+
break;
221+
}
222+
223+
case ParamType::ArrayFloat:
224+
{
225+
const float* arr = static_cast<const float*>(param.arrayPtr);
226+
DynamicArray<cell> cellArray(param.arraySize);
227+
for (size_t j = 0; j < param.arraySize; ++j)
228+
{
229+
cellArray[j] = amx_ftoc(arr[j]);
230+
}
231+
PushArray(&amx_addr, nullptr, cellArray.data(), cellArray.size());
232+
paramsArray[i + 1] = amx_addr;
233+
break;
234+
}
235+
236+
case ParamType::RefInt:
237+
{
238+
auto* ref = static_cast<PawnRef<int>*>(param.refPtr);
239+
Allot(1, &amx_addr, &phys_addr);
240+
*phys_addr = static_cast<cell>(ref->get());
241+
refParams.push_back({ amx_addr, param.refPtr, RefParamInfo::INT, 0, nullptr });
242+
paramsArray[i + 1] = amx_addr;
243+
break;
244+
}
245+
246+
case ParamType::RefFloat:
247+
{
248+
auto* ref = static_cast<PawnRef<float>*>(param.refPtr);
249+
Allot(1, &amx_addr, &phys_addr);
250+
auto val = ref->get();
251+
*phys_addr = amx_ftoc(val);
252+
refParams.push_back({ amx_addr, param.refPtr, RefParamInfo::FLOAT, 0, nullptr });
253+
paramsArray[i + 1] = amx_addr;
254+
break;
255+
}
256+
257+
case ParamType::RefBool:
258+
{
259+
auto* ref = static_cast<PawnRef<bool>*>(param.refPtr);
260+
Allot(1, &amx_addr, &phys_addr);
261+
*phys_addr = ref->get() ? 1 : 0;
262+
refParams.push_back({ amx_addr, param.refPtr, RefParamInfo::BOOL, 0, nullptr });
263+
paramsArray[i + 1] = amx_addr;
264+
break;
265+
}
266+
267+
case ParamType::RefString:
268+
{
269+
auto* ref = static_cast<PawnRef<String>*>(param.refPtr);
270+
size_t bufferSize = param.arraySize;
271+
Allot(bufferSize, &amx_addr, &phys_addr);
272+
273+
const String& currentStr = ref->get();
274+
if (!currentStr.empty())
275+
{
276+
SetString(phys_addr, StringView(currentStr.c_str(), currentStr.length()), false, false, bufferSize);
277+
}
278+
else
279+
{
280+
*phys_addr = 0;
281+
}
282+
283+
refParams.push_back({ amx_addr, param.refPtr, RefParamInfo::STRING, bufferSize, nullptr });
284+
paramsArray[i + 1] = amx_addr;
285+
break;
286+
}
287+
288+
case ParamType::RefArrayInt:
289+
{
290+
auto* ref = static_cast<PawnRef<DynamicArray<int>>*>(param.refPtr);
291+
size_t bufferSize = param.arraySize;
292+
Allot(bufferSize, &amx_addr, &phys_addr);
293+
294+
const auto& currentVec = ref->get();
295+
size_t initSize = std::min(currentVec.size(), bufferSize);
296+
for (size_t j = 0; j < initSize; ++j)
297+
{
298+
phys_addr[j] = static_cast<cell>(currentVec[j]);
299+
}
300+
301+
auto readback = [ref, bufferSize](cell* data)
302+
{
303+
auto& vec = ref->ref();
304+
vec.resize(bufferSize, 0);
305+
for (size_t j = 0; j < bufferSize; ++j)
306+
{
307+
vec[j] = static_cast<int>(data[j]);
308+
}
309+
};
310+
311+
refParams.push_back({ amx_addr, param.refPtr, RefParamInfo::VECTOR_INT, bufferSize, readback });
312+
paramsArray[i + 1] = amx_addr;
313+
break;
314+
}
315+
316+
case ParamType::RefArrayFloat:
317+
{
318+
auto* ref = static_cast<PawnRef<DynamicArray<float>>*>(param.refPtr);
319+
size_t bufferSize = param.arraySize;
320+
Allot(bufferSize, &amx_addr, &phys_addr);
321+
322+
const auto& currentVec = ref->get();
323+
size_t initSize = std::min(currentVec.size(), bufferSize);
324+
for (size_t j = 0; j < initSize; ++j)
325+
{
326+
phys_addr[j] = amx_ftoc(currentVec[j]);
327+
}
328+
329+
auto readback = [ref, bufferSize](cell* data)
330+
{
331+
auto& vec = ref->ref();
332+
vec.resize(bufferSize, 0.0f);
333+
for (size_t j = 0; j < bufferSize; ++j)
334+
{
335+
vec[j] = amx_ctof(data[j]);
336+
}
337+
};
338+
339+
refParams.push_back({ amx_addr, param.refPtr, RefParamInfo::VECTOR_FLOAT, bufferSize, readback });
340+
paramsArray[i + 1] = amx_addr;
341+
break;
342+
}
343+
}
344+
}
345+
346+
cell result = native(const_cast<AMX*>(&amx_), paramsArray.data());
347+
348+
// Read back reference parameters
349+
for (auto& refInfo : refParams)
350+
{
351+
cell* phys_addr;
352+
GetAddr(refInfo.amx_addr, &phys_addr);
353+
354+
if (phys_addr)
355+
{
356+
switch (refInfo.type)
357+
{
358+
case RefParamInfo::FLOAT:
359+
{
360+
auto* ref = static_cast<PawnRef<float>*>(refInfo.ref_obj);
361+
ref->ref() = amx_ctof(*phys_addr);
362+
break;
363+
}
364+
case RefParamInfo::BOOL:
365+
{
366+
auto* ref = static_cast<PawnRef<bool>*>(refInfo.ref_obj);
367+
ref->ref() = (*phys_addr != 0);
368+
break;
369+
}
370+
case RefParamInfo::INT:
371+
{
372+
auto* ref = static_cast<PawnRef<int>*>(refInfo.ref_obj);
373+
ref->ref() = static_cast<int>(*phys_addr);
374+
break;
375+
}
376+
case RefParamInfo::STRING:
377+
{
378+
auto* ref = static_cast<PawnRef<String>*>(refInfo.ref_obj);
379+
DynamicArray<char> buffer(refInfo.arraySize + 1);
380+
GetString(buffer.data(), phys_addr, false, refInfo.arraySize);
381+
ref->ref() = String(buffer.data());
382+
break;
383+
}
384+
case RefParamInfo::VECTOR_INT:
385+
case RefParamInfo::VECTOR_FLOAT:
386+
{
387+
if (refInfo.readback)
388+
{
389+
refInfo.readback(phys_addr);
390+
}
391+
break;
392+
}
393+
}
394+
}
395+
}
396+
397+
Release(amx_addr_save);
398+
399+
return result;
400+
}
401+
111402
private:
112403
ICore* serverCore;
113404
AMX amx_;

0 commit comments

Comments
 (0)