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+
3559class PawnScript : public IPawnScript
3660{
3761public:
@@ -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+
111402private:
112403 ICore* serverCore;
113404 AMX amx_;
0 commit comments