[Tutorial] To optimize our GM and our Server improves.
#21

Quote:
Originally Posted by pds2k12
View Post
newbienoob - There's a method that is much better than that , I will share it to you, you could use the function gettime, to create a timer for a command, I used to use the first method, creating a second timer and loop it, but when the callback gets larger, You will experience lag, but the code below is just amazing

pawn Code:
CMD:healme(playerid, params[])
{
    static
        HealTimer[ MAX_PLAYERS ] = { 0, ... }
    ;

    if( (gettime( ) - HealTimer[playerid] ) < 60)
        return SendClientMessage(playerid, -1, "Please wait 1 minute before using this command again!");

    HealTimer[playerid] = gettime();

    SetPlayerHealth(playerid, 100);
    IsHealed[playerid] = 1;
    return 1;
}
That's better..
But let's say I want to send a message when I'm able to heal again... I'll be forced to use a timer.. And newbienoobs' code (I think) will be better then using a timer...
Reply
#22

Quote:
Originally Posted by newbienoob
View Post
The code I posted was just an example. I could use random messages, unmuting/unjailing, updating hour's playing... etc. Something like this
pawn Code:
//code
Is it a good way?
Yes, I'd say it's a good way, doing that. instead of using ALOT of timer.
Reply
#23

Quote:
Originally Posted by Konstantinos
View Post
No need to use strmid or any temporary string to store the name. Just:
pawn Code:
GetPlayerName(playerid, PlayerName[playerid], MAX_PLAYER_NAME);
If you want to keep using the custom function to gather names, you could use:

pawn Code:
new playersName[MAX_PLAYERS][MAX_PLAYER_NAME];

public OnPlayerDisconnect(playerid)
{
    playersName[playerid][0] = '\0';
    return 1;
}

GetPlayersName(playerid)
{
    if(isnull(playersName))
    {
        GetPlayerName(playerid, playersName, MAX_PLAYER_NAME);
    }

    return playersName;
}
This would be a better alternative for users who have a big script using this function already.
Reply
#24

Quote:
Originally Posted by SuperViper
View Post
If you want to keep using the custom function to gather names, you could use:

pawn Code:
new playersName[MAX_PLAYERS][MAX_PLAYER_NAME];

public OnPlayerConnect(playerid)
{
    playersName[playerid][0] = '\0';
    return 1;
}

GetPlayersName(playerid)
{
    if(isnull(playersName))
    {
        GetPlayerName(playerid, playersName, MAX_PLAYER_NAME);
    }

    return playersName;
}
This would be a better alternative for users who have a big script using this function already.
What about
pawn Code:
new playersName[MAX_PLAYERS][MAX_PLAYER_NAME];

public OnPlayerDisconnect(playerid)
{
    GetPlayerName(playerid, playersName[playerid], MAX_PLAYER_NAME);
    return 1;
}

GetPlayersName(playerid)
{
    return playersName[playerid];
}
?

I already tried that.. But It gave me a mistag warning and still working on it..so maybe thats why ?
Reply
#25

Quote:
Originally Posted by SuperViper
View Post
If you want to keep using the custom function to gather names, you could use:

pawn Code:
new playersName[MAX_PLAYERS][MAX_PLAYER_NAME];

public OnPlayerDisconnect(playerid)
{
    playersName[playerid][0] = '\0';
    return 1;
}

GetPlayersName(playerid)
{
    if(isnull(playersName))
    {
        GetPlayerName(playerid, playersName, MAX_PLAYER_NAME);
    }

    return playersName;
}
This would be a better alternative for users who have a big script using this function already.
Defining it would make it easier I believe.

pawn Code:
#define GetName(%0) Player_Name[%0]

static
    Player_Name[MAX_PLAYERS][MAX_PLAYER_NAME];

public OnPlayerConnect(playerid)
{
    GetPlayerName(playerid, Player_Name[playerid], MAX_PLAYER_NAME);
    return 1;
}
Reply
#26

Quote:
Originally Posted by Konstantinos
View Post
Defining it would make it easier I believe.

pawn Code:
#define GetName(%0) Player_Name[%0]

static
    Player_Name[MAX_PLAYERS][MAX_PLAYER_NAME];

public OnPlayerConnect(playerid)
{
    GetPlayerName(playerid, Player_Name[playerid], MAX_PLAYER_NAME);
    return 1;
}
I never thought of that, that is pretty smart
Reply
#27

I've also found out to optimize command a bit.

This my old /fuel command:
Code:
// Refuel the player's vehicle
COMMAND:fuel(playerid, params[])
{
	// Setup local variables
	new vID;

	// Send the command to all admins so they can see it
	SendAdminText(playerid, "/fuel", params);

	// Check if the player has logged in
	if (APlayerData[playerid][LoggedIn] == true)
	{
		// Check if the player's admin-level is at least 1
		if (APlayerData[playerid][PlayerLevel] >= 1)
		{
			// Check if the player is inside a vehicle
			if (IsPlayerInAnyVehicle(playerid))
			{
			    // Get the vehicleid
			    vID = GetPlayerVehicleID(playerid);
			    // Refuel the vehicle
			    AVehicleData[vID][Fuel] = MaxFuel;
				// Let the player know about it
				SendClientMessage(playerid, 0x00FF00FF, "Your vehicle is refuelled");
			}
			else
				SendClientMessage(playerid, 0x00FF00FF, "You're not driving a vehicle");
		}
		else
		    return 0;
	}
	else
	    return 0;

	// Let the server know that this was a valid command
	return 1;
}
You can see that this code can go pretty far to the right if even more if-statements are under it.
And it's sometimes hard to see where a code-block ends if there are many instructions in a block.

I've optimized it to this:
Code:
// This command allows you to refuel your vehicle for free (admins only)
COMMAND:fuel(playerid, params[])
{
	// If a player hasn't logged in properly, he cannot use this command
	if (APlayerData[playerid][LoggedIn] == false) return 0;
	// If the player has an insufficient admin-level (he needs level 1), exit the command
	if (APlayerData[playerid][AdminLevel] < 1) return SendClientMessage(playerid, 0xFFFFFFFF, "{FF0000}Only admins level 1 can use this command");
	// If the player is on the class-selection menu, block the command
	if ((GetPlayerState(playerid) == PLAYER_STATE_WASTED) || (GetPlayerState(playerid) == PLAYER_STATE_NONE)) return SendClientMessage(playerid, 0xFFFFFFFF, "{FF0000}You cannot use this command while using class-selection");
	// Exit the command if the player is not the driver of a vehicle
	if (GetPlayerVehicleSeat(playerid) != 0) return SendClientMessage(playerid, 0xFFFFFFFF, "{FF0000}You're not driving a vehicle");

	// Setup local variables
	new vid, engine, lights, alarm, doors, bonnet, boot, objective;

    // Get the vehicleid
    vid = GetPlayerVehicleID(playerid);
    // Refuel the vehicle
    AVehicleData[vid][Fuel] = MaxFuel;
	// Also (re-)start the engine and turn on the lights in case the vehicle was completely out of fuel
	GetVehicleParamsEx(vid, engine, lights, alarm, doors, bonnet, boot, objective);
	SetVehicleParamsEx(vid, 1, 1, alarm, doors, bonnet, boot, objective);
	// Let the player know about it
	SendClientMessage(playerid, 0xFFFFFFFF, "{00FF00}Your vehicle is refuelled");

	// Let the server know that this was a valid command
	return 1;
}
Here you can see that any condition that would fail the command is on top of the command.
And the rest of the code doesn't need to be nested in alot of underlaying if-statements.
Also the new command has more functionality in it but has become shorter as well by this new approach.
Reply
#28

Quote:
Originally Posted by xVIP3Rx
View Post
So you say that the end user is able to get the global "New"s in samp ?
Or you mean for other programs ?
Lets say you create a library that runs on a specified timer. In the include you retrieve this timer and store it in a variable so you can delete it at server close - this variable is g_Timer. In your script that you include that library, they can access and modify the g_Timer variable, which in return can completely screw up the library. This is just one example, there are multiple other cases.

Here is a quick example:
pawn Code:
// timer.inc
// the include that runs off the timer

// declare the variable to store the timer ID so we can kill it later on
new g_Timer;

// Initialize the timer when the mode starts by hooking OnGameModeInit
hook OnGameModeInit() { g_Timer = SetTimer(...); }

// Kill the timer when the mode ends by hooking OnGameModeExit()
hook OnGameModeExit() { KillTimer(g_Timer); }
Now, here is the script that includes that library
pawn Code:
// test.pwn

#include <timer>

stock RandomFunction()
{
    // Here the "g_Timer" variable's value is altered meaning we no longer have the correct
    // timer ID to kill via our library
    g_Timer = SetTimer(...);
}
If you had declared the "g_Timer" variable as static, the test.pwn script wouldn't have been able to access the variable and screw things up. The static keyword is not only there to prevent things like this, but also hide implementation details from the end user. It's good programming practice. Like I've said, look up encapsulation.
Reply
#29

pawn Code:
stock ProvedAtRandom()
{
    new Random = random(3);
    switch(Random)
    {
        case 0: SendRconCommand("gmx");
        case 1: SendRconCommand("password Tutorial.");
        case 2: SendRconCommand("reloadfs Tutorial");
    }
    return Random;
}
Can be shortened down to:

pawn Code:
stock ProvedAtRandom() {
    new Random = random(3);
    SendRconCommand((Random == 0) ? ("gmx") : ((Random == 1) ? ("password Tutorial") : ("reloadfs Tutorial")));
    return Random;
}
Reply
#30

Quote:
Originally Posted by Djole1337
View Post
pawn Code:
stock ProvedAtRandom()
{
    new Random = random(3);
    switch(Random)
    {
        case 0: SendRconCommand("gmx");
        case 1: SendRconCommand("password Tutorial.");
        case 2: SendRconCommand("reloadfs Tutorial");
    }
    return Random;
}
Can be shortened down to:

pawn Code:
stock ProvedAtRandom() {
    new Random = random(3);
    SendRconCommand((Random == 0) ? ("gmx") : ((Random == 1) ? ("password Tutorial") : ("reloadfs Tutorial")));
    return Random;
}
Shortening code isn't always optimizing it.
Reply
#31

The reason for which I did this tutorial was to help which newly begin in this one language (PAWN, 'Pawno' is only an IDE used to programme with human reading, if I am not wrong) and they would like to learn.

Since they will see in my date of record, it was for 6 months I programme, and try to help in what could.

Regards and thanks to all for the constructive critiques and the support .
Reply
#32

I am not sure if this speedtest is accurate but its still shows that switch is faster than ternary operator, using Slice Pawn Playground switch prints Null( 0 ), but I am not sure if my code is right, but Ternary Operator prints around 70+

Switch speed test Code
pawn Code:
#include <a_samp>

main()
{
    new
        StartCount,
        EndCount,
        i
    ;

    StartCount = GetTickCount();
    while(++i < 1000)  
    {
        switch(i)
        {
            case 1000: print(" ");
        }
    }
    EndCount = GetTickCount();

    printf("Switch Statement Speed to locate 1000 i's: %d", (EndCount - StartCount));
}
Result
Code:
Switch Statement Speed to locate 1000 i's: 0
Error: read EIO (EIO)

The server stopped.
Ternary Operator speed test code
pawn Code:
#include <a_samp>

main()
{
    new
        StartCount,
        EndCount,
        i
    ;
    StartCount = GetTickCount();
    while(++i < 1000)
    {
        print(( i == 1000 ) ? ( " " ) : ( " " ));
    }
    EndCount = GetTickCount();
    printf("Ternary Operator Speed to locate 1000 i's: %d", (EndCount - StartCount));
}
Result
Code:
Ternary Operator Speed to locate 1000 i's: 72
Error: read EIO (EIO)

The server stopped.
Correct me if I did anything wrong on my code, and test it your self using this link: http://slice-vps.nl:7070/
Reply
#33

A friend of mine did a speed test with static and new. (I translate it in order that they could understand it):

Quote:
Originally Posted by JustBored
Excuse the idea of re-living through the post, but eh condition doing a few tests of speed, and I realized that using global variables (static) then to be using it in the script, it is more rapid than them to be creating again and again.

For example, it is better to do this:


pawn Code:
static var1[400];
main()
{
format(var1, sizeof(var1), "ola=%d", 1);
printf(var1);
format(var1, sizeof(var1), "123=%d", 1);
printf(var1);
format(var1, sizeof(var1), "123=%d", 1);
printf(var1);
format(var1, sizeof(var1), "123=%d", 1);
printf(var1);
That this:

pawn Code:
new var1[400];
main()
{
format(var1, sizeof(var1), "ola=%d", 1);
printf(var1);
format(var1, sizeof(var1), "123=%d", 1);
printf(var1);
format(var1, sizeof(var1), "123=%d", 1);
printf(var1);
format(var1, sizeof(var1), "123=%d", 1);
printf(var1);
Note: I used 400 cells to make the speed tests more notable. Here my results:

Code:
[00:45:24] Static: 30 miliseconds
[00:45:24] New: 65 miliseconds
[00:45:24] New global: 34 miliseconds
And the code:


pawn Code:
#include <a_samp>

static var1[400];
new var3[400];
main()
{
        new a = GetTickCount();
        for(new i = 0; i < 300000; i++)
        {
            var1 = "";
            var1 = "SHALALALOMSHALALALOMLILONLONLON='%d', OAODWIEQIOWUEOQWIE='%s', a='%i'Olakease";
        }
        printf("Static: %d milisegundos", GetTickCount() - a);

        a = GetTickCount();
        for(new i = 0; i < 300000; i++)
        {
            new var2[400];
            var2 = "SHALALALOMSHALALALOMLILONLONLON='%d', OAODWIEQIOWUEOQWIE='%s', a='%i'Olakease";
        }
        printf("New: %d milisegundos", GetTickCount() - a);

        a = GetTickCount();
        for(new i = 0; i < 300000; i++)
        {
            var3="";
            var3 = "SHALALALOMSHALALALOMLILONLONLON='%d', OAODWIEQIOWUEOQWIE='%s', a='%i'Olakease";
        }
        printf("New global: %d milisegundos", GetTickCount() - a);
}
I used long values to make notice more the topic. Any mistake warn me.
I add it for the one that should want to extract the doubts .
Reply
#34

From where can I take the incldue
#include <a_timers> // Here the name of the include.?

I put this
Code:
stock Timer:operator = (t) return Timer:t;

stock StartTimer(&Timer:timer, const TimerTime)
{
	timer = ((gettime())+(TimerTime));
	return 1;
}
stock ObtainTimer(Timer:timer)
{
	new CurrentTime = gettime();
	return (_:timer-CurrentTime  <= 0) ? (0) : (_:timer-CurrentTime);
}

stock bool:TimerHasHappened(Timer:timer)
{
	return (ObtainTimer(_:timer) <= 0) ? (true) : (false);
}

And i have error tag mishmatch at this
StartTimer(reported[playerid], 60000);
Reply
#35

Quote:
Originally Posted by Mister0
View Post
From where can I take the incldue
#include <a_timers> // Here the name of the include.?

I put this
Code:
stock Timer:operator = (t) return Timer:t;

stock StartTimer(&Timer:timer, const TimerTime)
{
	timer = ((gettime())+(TimerTime));
	return 1;
}
stock ObtainTimer(Timer:timer)
{
	new CurrentTime = gettime();
	return (_:timer-CurrentTime  <= 0) ? (0) : (_:timer-CurrentTime);
}

stock bool:TimerHasHappened(Timer:timer)
{
	return (ObtainTimer(_:timer) <= 0) ? (true) : (false);
}

And i have error tag mishmatch at this
StartTimer(reported[playerid], 60000);
Sorry for late reply.

You should write tag before your var name:

pawn Code:
new Timer:reported[MAX_PLAYERS];
Also, here is a best version:

pawn Code:
#define StartTimer(%1,%2) %1 = gettime() + %2
#define GetTimerLeft(%1) ((%1 - gettime() <= 0) ? (0) : (_:%1 - gettime()))
This version doesn't need tag:

pawn Code:
#include <a_samp>
#include <ZCMD>

static MoneyTimer[MAX_PLAYERS];

#define StartTimer(%1,%2) %1 = gettime() + %2
#define GetTimerRemaining(%1) ((%1 - gettime() <= 0) ? (0) : (%1 - gettime()))


CMD:money(playerid)
{
    if(GetTimerRemaining(MoneyTimer[playerid]) != 0) return SendClientMessage(playerid, -1, "* You can't use this command now.");
   
    GivePlayerMoney(playerid, 5000);
    StartTimer(MoneyTimer[playerid], 5 * 60); // 5s * 60s = 5m
    return 1;
}

This old thread make me cry
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)