• 5 Vote(s) - 4.8 Average
  • 1
  • 2
  • 3
  • 4
  • 5
[Plugin] PawnPlus
#1
What is this about?
PawnPlus is a multi-purpose plugin enhancing the capabilities of Pawn with features like asynchronous programming, dynamic containers and strings, threads, public and native functions hooks, and various other things.

Dynamic strings
Standard strings in Pawn are bound to an array allocated within the AMX. PawnPlus introduces dynamically allocated mutable strings which are not bound to any AMX instance, so they can be shared between scripts without copying, and offers a wide range of functions to manipulate them.

Using PawnPlus strings leads to better memory management (because you don't need to worry about the buffer size) and could increase the efficiency of some functions (because the length of the string is always known). PawnPlus strings can also store the null character without issues.

Moreover, any native function can be adapted to accept a dynamic string instead of a normal one. This transformation is very simple:

Code:
native SendClientMessageStr(playerid, color, AmxString:message) = SendClientMessage;

SendClientMessageStr(playerid, -1, str_new_static("Hello, id ")  str_val(playerid));

PawnPlus strings are garbage-collected, so you don't need to worry about their lifetime much.

Asynchronous programming
The usual way of handling events in Pawn is via a callback, even if the event is directly caused by the script. You may use inline functions from YSI, but the code is still scattered over multiple functions, despite the simple flow of actions.

In PawnPlus, you can represent an action that takes time using a task. In your code, you can call task_await which pauses the execution of the current functions (returning to the caller and not blocking the main thread) and resumes the code in the moment the task is completed.

A task can represent a MySQL query, the selection of an item from a dialog, a time interval or any time-based action you wish. You can create tasks, await them in one part of code and set the result in another, and the code resumes with the original variables preserved.

Code:
SendClientMessage(playerid, -1, "Loading...");
task_await(LoadPlayerAsync(playerid));
SendClientMessage(playerid, -1, "Loaded!");

task_await can be used on any task object, and if the task completes successfully, it returns the result. Tasks can also store AMX errors which you can use to signal exceptional results.

Dynamic containers
PawnPlus offers new efficient container types for use from Pawn: list (vector), linked list, and map. These containers can store values or arrays of any tag, which is stored together with the element as well. This allows for type-safe operations on these collections. You can even use strings as keys in a map.

Variant is another data type introduced in this plugin, which is used as the element type of dynamic collections. In containers, the variant has no identity (only value), but you can extract it from a collection without having to know its tag, and store it in another. Variants are also garbage collected.

All collections can be iterated using iterator objects. Iterators are objects pointing to a specific place in a collection, which can be used to access a single element in it, or to traverse the collection in a simple way. These iterators are safe to use even if the underlying collection is modified or deleted.

All collections are also available to be used as generic containers, restricting the type of values that are stored within. This feature is completely compile-time.

Tags
PawnPlus also extends the Pawn tag system with universally accessible tags, tag operations and tag inheritance. You can create a new dynamic tag, configure its operations, and set it as a tag of a variant, which allows you to call custom code when operations on the variant are performed. You can even override value copy and destruction, allowing you to introduce smart resource management.

Guards
Guards are special objects used to guard other values and destroy them when required. A guarded value will be destroyed when the context in which the guard was created terminates, freeing all resources that were associated with the value. You can set your own destructor via the tag system, and you'll never have to worry about freeing intermediate values ever again.

Threading
PawnPlus allows you to execute any piece of code in a new thread, parallel to the main one. Usually, the new thread will not allow other code to run in the same script (since AMX is not made for parallel execution), but together with forking, it is possible to clone the current script (preserving a specific selection of data) and execute a completely parallel code within it.

This can be combined with tasks to offload a time-consuming action to another thread, and provide a thread-safe method of retrieving the result.

Hooking
PawnPlus offers hooks of callbacks and native functions.

Any callback can be dynamically hooked with a new handler which is called when the original callback is called, and you can even modify the arguments or the return value. Combined with the task system, you can adapt any event-based code to task-based code with this approach.

Any native function can be hooked from your script, even affecting other scripts and plugins. Your code will be called every time when the original function is called, and you are free to modify the arguments or the return value in the same handler. You can even decide to hook a function only to modify some of its arguments and ignore the others, (via input filters), or to modify the return value only (via output filters).

Syntax shortcuts
Several functions can be used from new special pieces of syntax. For example, @ can be used as an alias for str_new_static, @@ can be used for str_val, await instead of task_await or yield instead of task_yield. New for loops are also provided for all collections, and there is special syntax for forked or threaded blocks.

All new syntax features are disabled by default because of to possible conflicts with other includes. You can enable them individually, or all of them by defining PP_SYNTAX.

Other stuff
You can obtain the list of all arguments given to the function, dynamically invoke natives or public functions, share variables in your script with other scripts, raise errors, catch errors, allocate memory on the heap, and fork the script (to protect its state from errors, for example, or to wait for a task locally without pausing the other code).


All these features are described in great detail on the GitHub wiki.
  Reply
#2
best plugin
  Reply
#3
this plugin is a fucking lifechanger. i recommend it to anyone who runs a server!!
  Reply
#4
Great, nice job!
  Reply
#5
9 out of 10 doctors recommend taking your daily dose of PawnPlus
  Reply
#6
i love PP
  Reply
#7
its really helpfull saves time really good! I recommend using it !
  Reply
#8
PawnPlus v1.0.0 released!



Miscellaneous
  • pp_version, pp_version_string, pp_raise_error, pp_module_name.

  • Locale-specific functions can be configured with pp_locale (affects things like str_to_upper and regex).

  • AMX subhook variables are no longer exported.

  • All natives that take an address inside the AMX check its validity.




Handles
  • Several new functions to control the activity of handles.

  • Handles are now immutable.

  • All GC-objects can provide their lifetime handle.




Pawn API
  • pawn_nameof macro can be used to convert a symbol or a tag name to a string (with checking).

  • pawn_cast macro (invokes implicit tag conversion operator).

  • pawn_try_call_native and pawn_try_call_public (suppress and return errors).

  • pawn_native_exists, pawn_native_imported, pawn_public_exists.




AMX API
  • amx_tailcall can replace the caller stack frame with the current stack frame.

  • amx_handle to control the lifetime of an AMX instance.

  • A function can be called in any AMX instance via amx_call_native/amx_call_public.

  • Additional support for native and public functions inspection.

  • Public and native functions names can be encoded in a two-cell packed string via amx_encode_public_name and amx_encode_native_name for faster calling. Custom values can also be specified.




Errors
  • Unhandled C exceptions in natives will be caught and reported.

  • Fixed several bugs related to error handling and conflicts with SAMPGDK.




Strings
  • Regular expressions (match, extraction, replacement).

  • str_format upgraded with new specifiers and syntax for positional arguments.

  • All functions now accept packed strings as well.

  • ConstAmxString added.




Variants
  • var_addr can be used for interop with native functions, similarly to str_addr.

  • Empty array variants are now recognized and produced instead of null variants.




Debug API
  • A multitude of functions to access the debug information produced by the Pawn compiler (at least -d2 is necessary).

  • Allows inspecing all variables and functions. Can be used to set variables (local or global) or to call any Pawn function.




Containers
  • Reduced unnecessary copying of objects.

  • Functions like list_new_args now store all the tags correctly.

  • list_resize, list_find, list_find_last, list_sort.

  • Variants and iterators have functions for both single-dimensional and multi-dimensional access to stored arrays.

  • Simple iterators: iter_range, iter_repeat, var_iter.

  • *_remove_deep and iter_erase_deep (removes the element and releases the object).

  • iter_swap, iter_can_reset, iter_can_insert, and iter_can_erase.




Tasks
  • task_detach useful for fire-and-forget calls. Creates a new context, so inner asynchronous calls will not pause the caller functions.




Threads
  • thread_fix to synchronise the function with the main thread, if called from another. Useful for code called from RCON or console.




Math API
  • Functions for signed and unsigned arithmetics (with overflow checks). signed: and unsigned: tags for simple usage.

  • math_random, math_random_float, math_round, math_floor, math_ceiling, math_truncate




C API
  • A simple mechanism for manipulating PawnPlus from other plugins.

  • Supports addons, tags, strings, variants, lists, linked lists, and maps.

  • Include ppcommon.h.

  Reply
#9
PawnPlus v1.1 released!



Additions

Pools
  • A new type of collection providing support for efficient storage of data using reusable integer indices.

  • When an element is added to a pool, it gets assigned an index which is then used to refer to the element.

  • Pools come in two versions with the same API ? ordered (new indices are assigned in a specific order), and unordered. Ordered pools will always assign the lowest unused index to a newly added element.

  • A pool can grow to any size if there are no unused slots for new elements.




Expressions
  • Dynamic run-time representations of operations.

  • Can be constructed from components in a tree-like manner, or parsed from string with expr_parse.

  • The parser supports all standard Pawn operators and some PawnPlus-specific ones. It can also find and use non-public Pawn variables (via the debug API).

  • Expressions can be used in collections and new types of iterators to easily perform queries on multiple elements.




Async
  • async pseudo-attribute for functions using the async pattern (together with return async).

  • The await macro has an alternative definition supporting multiline expression, but requires additional configuration for all tags (enabled via PP_MULTILINE_AWAIT).

  • await_arr and await_var added.




Collections
  • The API is now more unified, so all collections have roughly the same functions with the same semantics.

  • The capacity of the underlying container can be obtained.




Strings
  • If {?} is used in str_format and it doesn't correspond to a color code or a parameter selector, it is parsed and executed as a piece of code.

  • %f in str_format accepts a width parameter.

  • str_append_format added.




Pawn and AMX
  • pawn_create_callback can be used to create a new callback/public function and attach it to the current script. The function consists of an expression that is executed every time the public function is called.

  • Declarational initializers and finalizers added. Any public function whose name starts with _pp@on_init@ will be called first before every other function, when the script is loaded. Any function whose name starts with _pp@on_exit@ will be called last after all other functions, when the script is unloaded. Macros pawn_on_init and pawn_on_exit can be used for easy creation of these functions.

  • AMX guards introduced. While a Pawn guard protects the object for the duration of the current context (analogous to a local variable), an AMX guard protects it for the duration of the script (analogous to a global/static local variable).

  • Handling public function index incompatibility with SAMPGDK can be resolved by pp_public_min_index or pp_use_funcidx. Callback handlers can be registered for negative indices.

  • Captured arguments (in pawn_register_callback or pawn_add_hook) now accept v, h, and x as new types of values. v corresponds to a Variant: argument which is copied to the closure and loaded when it is restored, h corresponds to a Handle: argument which is prolonged by the closure (so the underlying object is not destroyed) and whose value is loaded when the closure is restored, and x corresponds to an Expression: argument containing an expression which is executed every time the argument is restored.




Error handling
  • Dynamically called external natives that raise a system error/signal do not crash the server, but are handled and reported via PawnPlus errors.




C API
  • Support for errors and serialization.




Changes

Error handling
  • pp_on_error is only called for a native called directly by the script. Errors in internally called natives are handled or propagated by the code that called them. pawn_try_call_native never invokes pp_on_error.




Collections
  • Iterators are invalidated on addition only when necessary (when the underlying buffer needs to be reallocated).




Variants
  • Calling operations on variables that are incompatible (different tags or sizes) now produces an error (used to return null).




Math
  • Dynamically called operations on signed: and unsigned: values can raise an error.




Pawn and AMX
  • Incorrect public function index caused by SAMPGDK is detected and warned about.




Fixes

Variants
  • collect operation is now correctly called in some places.




Async
  • When a context is stored after a call to an asynchronous function, reset_stk and reset_hea are now used to correctly restore the original values of stk and hea, fixing a memory leak that happened when a public function with parameters was stored (because the parameters were not taken into account when stk was restored).




Math
  • signed: and unsigned: subtraction fixed.




Error handling
  • Allocation of more data than the script supports is prevented.




Pawn and AMX
  • Removing a hook handler when it is running will not crash the server.




Examples

Format expressions

Code:
new val1 = 5, val2 = 10;

print_s(str_format("the sum of {val1} and {val2} is {val1  val2}"));



Queries

Code:
new Map:m = map_new();

map_add(m, 1, 10);

map_add(m, 2, 21);

map_add(m, 3, 30);

map_add(m, 4, 41);

map_add(m, 5, 50);

? ?

map_remove_if(m, expr_parse("10*$key != $value")); //removes 2 and 4



Caching expressions

Code:
static Expression:expr;

if(!expr)

{

? ?expr = expr_parse("$value*$value");

? ?amx_guard(expr);

}



Declarational callback handler

Code:
pawn_on_init[callback1]

{

? ?new id = pawn_create_callback("OnPlayerConnect", expr_const(0));

? ?pawn_register_callback(amx_encode_public(id), "MyOnPlayerConnect");

}
  Reply
#10
I can use dynamic containers as a replacement for pawn_memory.
  Reply
#11
Nicee!
????? ??? ?? ?????, ? ????????-??????????? ?????? ??? ???? ? ?? ?????????



[Image: 99XXzyx.gif]


  Reply
#12
This is just so amazing that OpenMP should have something similar.
  Reply
#13
PawnPlus v1.3 released!
  Reply


Forum Jump: