-
Notifications
You must be signed in to change notification settings - Fork 19
Examples
IllidanS4 edited this page Mar 9, 2018
·
8 revisions
// Modify SendClientMessageToAll(color, const message[]), replacing any occurences of "const x[]" with "AmxString:x".
native SendClientMessageToAllStr(color, AmxString:message) = SendClientMessageToAll;
// Creating a dynamic string from a string buffer.
stock String:GetPlayerNameStr(playerid)
{
new name[MAX_PLAYER_NAME];
GetPlayerName(playerid, name, sizeof(name));
return str_new(name);
}
public OnPlayerConnect(playerid)
{
// Dynamic strings are tagged "String". The + operator can be used to concat them. str_val converts any value to a string.
new String:name = GetPlayerNameStr(playerid);
new String:msg = str_new("Player ")+name+str_new(" (")+str_val(playerid)+str_new(") has joined the server.");
// Calls SendClientMessageToAll but passes a dynamic string instead of an array as the second parameter.
SendClientMessageToAllStr(-1, msg);
}
native print_s(AmxString:string) = print;
// "GlobalString" tag denoted a global string, whose lifetime can only end with a call to str_free.
// In contrast, local strings (tagged "String") are garbage collected as soon as the top-level callback ends.
new GlobalString:str;
public OnFilterScriptInit()
{
str = str_new("Goodbye world!");
// The lifetime of "str" would end here were it tagged "String". In this case however, the assignment
// hides a call to str_to_global which moves the string to the global string pool (no copying involved).
}
public OnFilterScriptExit()
{
print_s(str);
// If you intend to work with the string before freeing it, consider using str_to_local instead.
// That way, your script can safely return and forget the string, and it is guaranteed to be freed.
str_free(str);
// Set the variable to STRING_NULL so that it doesn't create a dangling pointer.
// STRING_NULL is a special kind of a (global) string that can be used by any function expecting a string,
// but its value is immutable.
str = STRING_NULL;
}
native SendClientMessageStr(playerid, color, AmxString:message) = SendClientMessage;
public OnPlayerCommandText(playerid, cmdtext[])
{
new String:cmd = str_new(cmdtext);
new String:name = cmd;
new String:args = STRING_NULL;
// Finding a space in a string and using it to split it.
new len = str_len(cmd);
for(new i = 0; i < len; i++)
{
if(str_getc(cmd, i) == ' ')
{
name = str_sub(cmd, 0, i);
args = str_sub(cmd, i+1);
break;
}
}
// Comparing with a string value.
if(name == str_new("/test"))
{
SendClientMessageStr(playerid, -1, args);
return true;
}
return false;
}
stock Countdown()
{
SendClientMessageToAll(-1, "3");
wait_ms(1000); // Non-blocking sleep (i.e. there is no code running and checking the time).
SendClientMessageToAll(-1, "2");
wait_ms(1000); // await task_ms(1000); can be also used
SendClientMessageToAll(-1, "1");
wait_ms(1000);
SendClientMessageToAll(-1, "0");
}
// Note: Waiting blocks the execution of the whole code up to the first public function. To make a function that returns immediately, use CallLocalFunction.
public OnFilterScriptInit()
{
new ret = CallLocalFunction(#Func, "");
printf("%d", ret);
}
forward Func();
public Func()
{
yield 12;
// The execution of the code is paused every time a call to wait_ms occurs, but the calling function still
// expects a result. Call yield to provide the immediate result to the calling function.
wait_ms(1000);
return 13; // This value is lost. 12 is printed instead (immediately on script init).
}
// A MoveObject wrapper returning a waitable task, representing the event of finishing the movement of a certain object.
stock task:MoveObjectTask(objectid, Float:X, Float:Y, Float:Z, Float:Speed, Float:RotX = -1000.0, Float:RotY = -1000.0, Float:RotZ = -1000.0)
{
// A task represents an abstract process which can be finished, optionally having a result.
// task_new creates a new empty (unfinished) task.
new task:t = task_new();
// This registers a new handler for the OnObjectMoved callback. Public function SingleFireObjectTask
// will be called every time OnObjectMoved is to be called (before it).
// Additional parameters can be prepended to the handler, whose values are passed to pawn_register_callback.
// Format specifier "e" doesn't require its value and is translated to the ID of the handler instance
// (the same ID is also returned from pawn_register_callback).
pawn_register_callback(#OnObjectMoved, #SingleFireObjectTask, "edd", t, objectid);
MoveObject(objectid, X, Y, Z, Speed, RotX, RotY, RotZ);
return t;
}
stock ObjectTest()
{
new obj = CreateObject(19300, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
print("Object created!");
// awaits pauses the execution. The function will be executed when the task is completed.
await MoveObjectTask(obj, 0.0, 0.0, 10.0, 5.0);
print("Object moved!");
}
// The new handler of OnObjectMoved is extended with three new parameters (id, task, obj)
// whose values are determined in pawn_register_callback. The rest of the parameters comes
// from the callback itself.
// The point of this handler is to compare the third argument with the fourth, complete a task
// in the case of success, and unregister itself. It can be used for any single entity event
// (players, vehicles, actors, objects etc.).
forward SingleFireObjectTask(callback:id, task:task, obj, objectid);
public SingleFireObjectTask(callback:id, task:task, obj, objectid)
{
if(obj == objectid)
{
// The handler is unregistered if the handled object triggered the callback.
pawn_unregister_callback(id);
// The respective task is set to completed.
task_set_result(task, objectid);
}
}
public OnFilterScriptInit()
{
new String:str = str_new("Hello world!");
str_to_global(str);
// Since the lifetime of the string would normally end here (wait_ms returns from the callback),
// it has to be moved to the global pool. You don't have to assign it to any global variable
// because the instance remains the same and the reference will be stored in the AMX memory.
wait_ms(1000);
// After the wait, better move the string to the local pool again in case you forget to free it.
str_to_local(str);
print_s(str);
}
stock task:WhenPlayerReturns(ip[])
{
new task:t = task_new();
pawn_register_callback(#OnPlayerConnect, #SingleFireIpTaskHandler, "eds", t, ip); //"e" does not need an argument
return t;
}
// A handler that checks the IP address of a player and compares it to the one it is bound to.
forward SingleFireIpTaskHandler(callback:id, task:task, ip[], playerid);
public SingleFireIpTaskHandler(callback:id, task:task, ip[], playerid)
{
new ip2[16];
GetPlayerIp(playerid, ip2, sizeof ip2);
if(!strcmp(ip, ip2))
{
pawn_unregister_callback(id);
task_set_result(task, playerid);
}
}
public OnPlayerConnect(playerid)
{
new ip[16];
GetPlayerIp(playerid, ip, sizeof ip);
new task:t = task_new();
pawn_register_callback(#OnPlayerDisconnect, #SingleFireIdTaskHandler, "eds", t, playerid);
await t;
// GetPlayerIp does not work on disconnect, so it is temporarily stored here.
printf("%d disconnected!", playerid);
playerid = await(WhenPlayerReturns(ip));
printf("%d is back!", playerid);
}
forward SingleFireIdTaskHandler(callback:id, task:task, stored_id, test_id);
public SingleFireIdTaskHandler(callback:id, task:task, stored_id, test_id)
{
if(stored_id == test_id)
{
pawn_unregister_callback(id);
task_set_result(task, test_id);
}
}