30.04.2010, 20:43
2.10 Writing your first sucky but fully working code
For this, we need to define the existence of a new function. Therefore, it can be used. Most commonly, there is a kind of reference used to indicate the existence of a code that isn't defined yet. But first, Let's talk about the function types:
Public/Global || This statement indicates a function that will be defined globally. This usually indicates the existence and usability of a function that can be accessed thorough the complete application
Private // Not available in pawn I believe || you could say private equals stock
Stock || stock, a statement that indicates a function defined locally. Only functions in the same stream can access these functions. They cannot have a reference and therefore they need to be defined before the other functions can make any use of it. Nevertheless, a stock takes lesser memory space.
referencing in pawno is quite easy though.
there is a statement called forward for this.
let's say we want to forward the statement OnPlayerKissMonkeyAss(playerid);
Wasn't that easy?
that was all that was needed to write your own function.
Now to define more than one statement:
explanation:
OnPlayerKissMonkeyAss is the functions name
( Open up bracket to indicate the existence of arguments or not.
playerid Indicate existence of argument integer called playerid
, Indicate the existence of another argument yet to come
funnystring[] New argument as string/array with unknown size, passed down with the entered value upon call.
, Indicate the existence of another argument yet to come
Float:lolz Indicate the existence of argument float called lolz
) Close up bracket to indicate that no more arguments are going to be defined, which completes the function header.
basicly that is all about creating your own functions. If you don't get it, well I don't know what to say.
2.20 Effective coding
This might be the most important thing in the whole programming business.
It's something even some of the pros here cannot do properly.
Sample one: Assigning starting arrays
to create such array with starting value, where the id is entry position, (in the sample above, the first entry is zero, the ID is zero!, and id 1 is 105)
there is a simple trick to it.
Now the same but for a multi-dimensional array:
[/pawn]
if else, loop return:
So far for efficiency. If you haven't noticed, this code is far from efficient.
In any case, you should imagine that the function you create will be called every second, for a year long.
now think about it, you are going to loop for all players that are there, and for every second a new variable is created.
now let's do a basic calculation:
there are 365 days in a year.
there are 60*60*24 = 86400 seconds in one day.
365*86400=31536000
basicly, this function needs to declare a new variable 31536000 times ( if you assume the server always is on and never restarts )
let's calculate back to a minute, which is 60 times
even though defining 60 times a minute isn't that much at all, 31536000 surely is. Therefore, even the little things can have a big impact over time.
Please know that using this method, you do need more computer memory but not processor power. The goal of this is to convert computer processor power into ram memory instead. Since variables take so less space, I strongly recommend this method! However when dealing with non-array smaller lesser used variables, it is better to declare them as a new variable. This is because resetting a variable ( jumping to the address of the variable, set information to null, then jump back) is as fast as registering new space that automaticly has no information in it. ( address jumping required).
about if else conditions. Yes, I am telling you not to use else conditions at all. Use return instead. the function is created to exit a code, therefore efficient enough to stop a code from executing unwanted codes. you will need to add a return value on the end of the function to use it, however lines are not important.
If you think the number of lines are important, jump in front of a train because it's not about how many lines you have, but about how you put them down!
optimised version would be:
why return and not else?
Why not? I mean else statement isn't that efficient as it looks like. So exiting a code when you can is better then checking if a condition is true else jumping to another code location. having this doesn't require certain routines to be called which in massive usage could slow down the complete process.
besides, putting else if everywhere doesn't seem that nice looking at to me.
The biggest mistake ever: Looping all players
I rarely see people actually being smart. They keep on looping through all playerslots and sometimes even checking whether they are online or not.
What is the use of looping through slots that aren't used? Since when is there any use in slots that are empty except when it comes to bots?
Therefore, I will put down a certain code to optimise your looping through active players only, looping through active slots only and no non-taken or bots.
This is more like a source code with explanation though, so bear with me:
Usage would be:
So how does this works, how is this more efficient?
first about why this is more efficient:
AddSlot(playerid): This function assigns the newly connected player to the latest available entry.
RemoveSlots(playerid): This function loops from the position of the playerslot leaving, and moves all players after this slot back by 1, making the leaving playerslot to be filled with the other connected players leaving no gap in the Playerloop.
PlayerLooper(&ref): uses a refence to add 1 to the loop, and assigns ii as the playerid of the player looped.
LoopAllPlayers: Calls the valid ID for ID zero, then loops through the rest of the array.
StopPlayerLoop(): Stops a playerloop by setting used variable to loop end value
StartPlayerLooper(): Retrieve the information for SlotID 0
In short:
When you call LoopAllPlayers, it will loop through an array that only holds valid connected ids.
Therefore, any playerslot that isn't connected will not be handled.
Calling functions onplayerconnect and onplayerdisconnect is fine. They aren't called that often so you will get no lag whatsoever from these functions on pretty much any connection.
Does your server has around 500 slots where normally 50 are occupied? Or even 100 maybe? Using this method is strongly recommended.
It saves alot of processor power especially when it comes with loops inside loops.
Many commands loop these players and therefore saves much computer effort.
2.25 Explanation why the hell you should do that
For obvious reasons actually. To preserve pressure on the computer and application and probably trade it for RAM memory.
However RAM memory isn't a problem at all nowadays.
3.10 Creating a concept
Actually, before you start coding anything, you should consider concept before doing anything.
For example, if you want to have a property system, you must think for the following event and conditions:
When should I be able to enter and exit?
What are the limits of a property?
What are the general usage of a prop?
How many properties can you build at maximum?
Can they be destroyed or motified in any way?
when creating a concept, you should ask yourself these kind of questions. When doing so, yo should consider this in various conditions.
for example for the question When should I be able to enter and exit?, you should consider things like the following:
Can I enter with a car?
Can I enter when I am moving?
Can I enter only if I am in range?
basicly, you have to ask questions on the basic questions.
3.20 Extending the concept
Once the base of a concept is there, you should consider extending it to integrate it with another concept. 1 giant concept is better than 2 lesser concepts.
Not just that, you can merge variables better when you combine these concepts together.
3.30 Why the shit you need it
Writing out of mind without a concept (written or unwritten) is possible, but is far from efficient. You could compare it with having your room full of junk. You can live in it, but not without stepping on the junk. If your room is clean, you don't need to mind the yunk since it isn't there.
4.10 Seemly unnoticable powerz of pawn called classes/local-remote functions
For those who do not know what classes are, keep on reading. Else skip to 'usage'
http://en.wikipedia.org/wiki/Class_%...ter_science%29
However, pawn isn't really object orientated.
A class is a group of functions. However when calling a class function, the function that calls the class function will not care how it is achieved as long as there is a result.
For example, if you loop outside an array, the code normally would return false and stop immediately. However, when putting the same code as a class function, it will return false as function value upon the same crash, but the code still continues. This is one benefit of class functions.
Usage
Even though classes aren't really available in Pawn(o), something else that makes a public function act the same as if it is in a class.
These features can be called by functions CallLocalFunction and CallRemoteFunction.
CallLocalFunction calls a public function that is defined inside the same main stream. This basicly means it only will search for this function inside the same document the function is called from.
CallRemoteFunction calls All public function in all documents loaded. So it will call the function in filterscripts and gamemode.
5.10 Error Handling
The thing people struggle the most of the times.
Sucky somehow impossible errors.
I will tell you how you can solve these problems.
Let's see:
\RandomGM.pwn(6 : error 029: invalid expression, assumed zero
On line 68 is an error occurring. The funny part is, the real error is located at line 67.
What happens is that a certain line is improperly closed or used. Therefore, a new statement is seen as invalid part of the improper code. Therefore, it will error on that line.
error 029 is most likely caused when you have a certain action, such as a loop, but you haven't closed it properly and therefore it takes another statement as the ending statement. Obviously, since it's not the expected statement, it will error. This example was a loop. This could happen to If and else conditions aswell, aswell for switch.
1000 Being smart
Ok this is the most important point of all, be smart.
Over the years, I seen enough of you asking for the most impossible things.
Most important and stupid question is the following:
Hey, I can't/can script myself, but I would like to have a scripter.
Now the most funny thing:
I will grant you right to admin or I might pay you.
I rolfmao'ed so hard the first time I read this thing.
Since when do scripters who can build a complete gamemode theirselves agree with such offer? Putting in paid vip would make the producer getting more profit than you will ever will pay. Admin? Lol seriously running your own server and be the server owner. Highest rank possible and you are the one in control.
This is the point where I realised, people grow up. You kids should start brighten up. Lame offers aren't going to fool anyone.
Of course some of these people actually fall for such an offer. I call them lameys.
Anyways, before you do something as a producer,think about it. Is it realistic? Don't work on faith only, do some research.
Copying this tutoral IS allowed. All I ask is some credit for writing this crap.
PS: I haven't tested anything I wrote down. Therefore some information listed might be "slightly" wrong.
Please pm me with the flaud and I will correct it.
For this, we need to define the existence of a new function. Therefore, it can be used. Most commonly, there is a kind of reference used to indicate the existence of a code that isn't defined yet. But first, Let's talk about the function types:
Public/Global || This statement indicates a function that will be defined globally. This usually indicates the existence and usability of a function that can be accessed thorough the complete application
Private // Not available in pawn I believe || you could say private equals stock
Stock || stock, a statement that indicates a function defined locally. Only functions in the same stream can access these functions. They cannot have a reference and therefore they need to be defined before the other functions can make any use of it. Nevertheless, a stock takes lesser memory space.
referencing in pawno is quite easy though.
there is a statement called forward for this.
let's say we want to forward the statement OnPlayerKissMonkeyAss(playerid);
pawn Code:
forward OnPlayerKissMonkeyAss(playerid);
//note that forward statement only is used in pawn to define a public
//another note: The number of and the arguments itself inside the forward MUST equal to the arguments in the defined public!
public OnPlayerKissMonkeyAss(playerid)
{
return 1;//Public functions cannot return arrays and must return any value. Don't ask me why.
}
that was all that was needed to write your own function.
Now to define more than one statement:
pawn Code:
forward OnPlayerKissMonkeyAss(playerid, funnystring[],Float:lolz);
public OnPlayerKissMonkeyAss(playerid, funnystring[],Float:lolz)
{
return 1;//Public functions cannot return arrays and must return any value. Don't ask me why.
}
OnPlayerKissMonkeyAss is the functions name
( Open up bracket to indicate the existence of arguments or not.
playerid Indicate existence of argument integer called playerid
, Indicate the existence of another argument yet to come
funnystring[] New argument as string/array with unknown size, passed down with the entered value upon call.
, Indicate the existence of another argument yet to come
Float:lolz Indicate the existence of argument float called lolz
) Close up bracket to indicate that no more arguments are going to be defined, which completes the function header.
basicly that is all about creating your own functions. If you don't get it, well I don't know what to say.
2.20 Effective coding
This might be the most important thing in the whole programming business.
It's something even some of the pros here cannot do properly.
Sample one: Assigning starting arrays
pawn Code:
new Skins[] = {//No need to define the index, this will happen automaticly and it saves effort aswell.
0,105,106,107,269,270,271,102,103,104,114,
115,116,108,109,110,173,174,175,183,122,12,
10,101,12,13,136,14,142,143,144,15,151,156,
168,169,17,170,180,182,54,18,184,263,75,186,
185,188,19,216,20,206,21,22,210,214,215,220,
221,225,226,222,223,227,231,228,234,76,235,
236,89,88,24,218,240,25,250,261,28,40,41,
35,37,38,36,44,69,43,46,9,93,39,48,47,
262,229,58,59,60,232,233,67,7,72,55,94,95,
98,56,224,230,239,249,241,242,252,253,255,29,
30,49,50,57,61,62,66,73,77,82,83,84,11,141,
147,148,150,153,167,68,171,176,177,172,179,187,
189,203,204,155,205,209,217,211,219,260,16,27,
70,134,135,137,181,213,212,78,79,258,259,26,51,
52,80,81,23,96,99,152,178,237,238,243,244,207,
245,246,85,256,257,64,63,87,90,128,129,130,131,
132,133,157,158,159,160,196,197,198,199,161,162,
200,201,202,31,32,33,34,138,139,140,145,146,
154,251,92,97,45,18,190,191,192,193,194,195,
71,274,275,276,277,278,279,287,166,165,286,280,
281,282,283,288,265,266,267,264
};
there is a simple trick to it.
pawn Code:
new array[[i]ENTER NO SIZE[/i]]=
{//assign the following values as part of the array
value1,//== ID 0
value2,// == ID 1
value3 // == id 2
}//close assigning information
//Note, in some cases it is important to leave the , (comma) away in the last entry.
pawn Code:
new positions[][3]={//For a multi-dimensional array you have to assign a size //Open up assigning
{//Open up another assigning, indicating that the following values are part of 1 entry
1,2,3
//Again, the last value shouldn't have a comma ,
}//close assigning entry 1
, indicate that another assignment is going to happen
{2,3,4}
,
{5,6,7}
}//close the multi-dimensional array
//The same array without the comments and nicely indented:
[pawn]new positions[][3]={
{1,2,3},
{2,3,4},
{5,6,7}}
if else, loop return:
pawn Code:
public OnRequestAnswer(playerid)
{
if(You=="stupid")
{
for(new i=0;i<everyone;i++)
{
Message("%d is stupid!",playerid);
}
}else
if(you=="smart")
{
Message("I do not believe you!");
}
}
In any case, you should imagine that the function you create will be called every second, for a year long.
now think about it, you are going to loop for all players that are there, and for every second a new variable is created.
now let's do a basic calculation:
there are 365 days in a year.
there are 60*60*24 = 86400 seconds in one day.
365*86400=31536000
basicly, this function needs to declare a new variable 31536000 times ( if you assume the server always is on and never restarts )
let's calculate back to a minute, which is 60 times
even though defining 60 times a minute isn't that much at all, 31536000 surely is. Therefore, even the little things can have a big impact over time.
Please know that using this method, you do need more computer memory but not processor power. The goal of this is to convert computer processor power into ram memory instead. Since variables take so less space, I strongly recommend this method! However when dealing with non-array smaller lesser used variables, it is better to declare them as a new variable. This is because resetting a variable ( jumping to the address of the variable, set information to null, then jump back) is as fast as registering new space that automaticly has no information in it. ( address jumping required).
about if else conditions. Yes, I am telling you not to use else conditions at all. Use return instead. the function is created to exit a code, therefore efficient enough to stop a code from executing unwanted codes. you will need to add a return value on the end of the function to use it, however lines are not important.
If you think the number of lines are important, jump in front of a train because it's not about how many lines you have, but about how you put them down!
optimised version would be:
pawn Code:
new i;//automatic assign zero
public OnRequestAnswer(playerid)
{
if(You=="stupid")
{
for(i=0;i<everyone;i++)
{
Message("%d is stupid!",playerid);
}
return 1;
}
if(you=="smart")
{
Message("I do not believe you!");
return 2;
}
return 0;
}
Why not? I mean else statement isn't that efficient as it looks like. So exiting a code when you can is better then checking if a condition is true else jumping to another code location. having this doesn't require certain routines to be called which in massive usage could slow down the complete process.
besides, putting else if everywhere doesn't seem that nice looking at to me.
The biggest mistake ever: Looping all players
I rarely see people actually being smart. They keep on looping through all playerslots and sometimes even checking whether they are online or not.
What is the use of looping through slots that aren't used? Since when is there any use in slots that are empty except when it comes to bots?
Therefore, I will put down a certain code to optimise your looping through active players only, looping through active slots only and no non-taken or bots.
This is more like a source code with explanation though, so bear with me:
pawn Code:
#define MAX_SLOTS MAX_PLAYERS
new UsedSLots[MAX_SLOTS]=-1; //do not use default value zero, since zero is a valid playerid
new ConnectdPlayers;//Do use zero, since the amount of connected players is zero upon (re)start.
//Temporary used variable:
new plx[2];
new ii;
//Define the player loop
#define LoopAllPlayers StartPlayerLooper();for(plx[1]=0;plx[1]<ConnectedPlayers;PlayerLooper(plx[1]))
//Define the existence of the functions we are going to use
forward AddSlot(playerid);
forward RemoveSlot(playerid);
forward PlayerLooper(&ref);
public OnPlayerConnect(playerid)
{
AddSlot(playerid);//add this to onplayerconnect
return 1;
}
public OnPlayerDisconnect(playerid, reason)
{
RemoveSlot(playerid);
return 1;
}
public PlayerLooper(&ref){ref++;ii=UsedSLots[ref];}
stock StartPlayerLooper()
{
ii=UsedSLots[0];
}
stock StopPlayerLoop()plx[1]=ConnectedPlayers;
//PlayerLooper only with spaces and such
public PlayerLooper(&ref)
{
ref++;
ii=UsedSLots[ref];
}
public RemoveSlot(playerid)
{
for(plx[0]=0;plx[0]<MAX_SLOTS;plx[0]++)if(playerid==UsedSLots[plx[0]])break;
ii=plx[0];
ConnectedPlayers--;
//from here, plx[0] holds the index of the variable that holds the playerid
for(plx[0]=ii;plx[0]<(MAX_SLOTS-1);plx[0]++)
{
UsedSLots[plx[0]]=UsedSLots[(plx[0]+1)];
}
UsedSLots[MAX_SLOTS-1]=-1;
return 1;
}
public AddSlot(playerid)
{
UsedSLots[ConnectedPlayers]=playerid;
GetPlayerName(playerid,PlayerName[playerid],MAX_PLAYER_NAME);
PlayerAdminName[playerid]=PlayerName[playerid];
GetPlayerIp(playerid,Playerip[playerid],17);
format(PlayerFile[playerid],MAX_FILE_NAME,"Accounts/%s.sav",PlayerName[playerid]);
PlayerShotTimer[playerid]=-1;
return ConnectedPlayers++;
}
pawn Code:
Public SendGlobalMessage()
{
LoopAllPlayers
{
Message(ii,"Hello there folks");
}
return 1;
}
first about why this is more efficient:
- 1. It calls localfunction, therefore playerlooper will act as if it is inside a class, which over time can optimise speed if you compare the speeds.
- 2. It loops all active playerslots only. Meaning all players who are active are always inside that array, the others who are not are not in the array.
- 3. Not sizeof, but a variable that holds the players connected. The function sizeof counts the maximum amount of indexes available. Not what we need at all.
- 4. It uses globally declared variables. It doesn't need to create new variables every time it gets used.
- 5. It looks nicer in my opinion.
AddSlot(playerid): This function assigns the newly connected player to the latest available entry.
RemoveSlots(playerid): This function loops from the position of the playerslot leaving, and moves all players after this slot back by 1, making the leaving playerslot to be filled with the other connected players leaving no gap in the Playerloop.
PlayerLooper(&ref): uses a refence to add 1 to the loop, and assigns ii as the playerid of the player looped.
LoopAllPlayers: Calls the valid ID for ID zero, then loops through the rest of the array.
StopPlayerLoop(): Stops a playerloop by setting used variable to loop end value
StartPlayerLooper(): Retrieve the information for SlotID 0
In short:
When you call LoopAllPlayers, it will loop through an array that only holds valid connected ids.
Therefore, any playerslot that isn't connected will not be handled.
Calling functions onplayerconnect and onplayerdisconnect is fine. They aren't called that often so you will get no lag whatsoever from these functions on pretty much any connection.
Does your server has around 500 slots where normally 50 are occupied? Or even 100 maybe? Using this method is strongly recommended.
It saves alot of processor power especially when it comes with loops inside loops.
Many commands loop these players and therefore saves much computer effort.
2.25 Explanation why the hell you should do that
For obvious reasons actually. To preserve pressure on the computer and application and probably trade it for RAM memory.
However RAM memory isn't a problem at all nowadays.
3.10 Creating a concept
Actually, before you start coding anything, you should consider concept before doing anything.
For example, if you want to have a property system, you must think for the following event and conditions:
When should I be able to enter and exit?
What are the limits of a property?
What are the general usage of a prop?
How many properties can you build at maximum?
Can they be destroyed or motified in any way?
when creating a concept, you should ask yourself these kind of questions. When doing so, yo should consider this in various conditions.
for example for the question When should I be able to enter and exit?, you should consider things like the following:
Can I enter with a car?
Can I enter when I am moving?
Can I enter only if I am in range?
basicly, you have to ask questions on the basic questions.
3.20 Extending the concept
Once the base of a concept is there, you should consider extending it to integrate it with another concept. 1 giant concept is better than 2 lesser concepts.
Not just that, you can merge variables better when you combine these concepts together.
3.30 Why the shit you need it
Writing out of mind without a concept (written or unwritten) is possible, but is far from efficient. You could compare it with having your room full of junk. You can live in it, but not without stepping on the junk. If your room is clean, you don't need to mind the yunk since it isn't there.
4.10 Seemly unnoticable powerz of pawn called classes/local-remote functions
For those who do not know what classes are, keep on reading. Else skip to 'usage'
http://en.wikipedia.org/wiki/Class_%...ter_science%29
However, pawn isn't really object orientated.
A class is a group of functions. However when calling a class function, the function that calls the class function will not care how it is achieved as long as there is a result.
For example, if you loop outside an array, the code normally would return false and stop immediately. However, when putting the same code as a class function, it will return false as function value upon the same crash, but the code still continues. This is one benefit of class functions.
Usage
Even though classes aren't really available in Pawn(o), something else that makes a public function act the same as if it is in a class.
These features can be called by functions CallLocalFunction and CallRemoteFunction.
CallLocalFunction calls a public function that is defined inside the same main stream. This basicly means it only will search for this function inside the same document the function is called from.
CallRemoteFunction calls All public function in all documents loaded. So it will call the function in filterscripts and gamemode.
5.10 Error Handling
The thing people struggle the most of the times.
Sucky somehow impossible errors.
I will tell you how you can solve these problems.
Let's see:
\RandomGM.pwn(6 : error 029: invalid expression, assumed zero
On line 68 is an error occurring. The funny part is, the real error is located at line 67.
What happens is that a certain line is improperly closed or used. Therefore, a new statement is seen as invalid part of the improper code. Therefore, it will error on that line.
error 029 is most likely caused when you have a certain action, such as a loop, but you haven't closed it properly and therefore it takes another statement as the ending statement. Obviously, since it's not the expected statement, it will error. This example was a loop. This could happen to If and else conditions aswell, aswell for switch.
1000 Being smart
Ok this is the most important point of all, be smart.
Over the years, I seen enough of you asking for the most impossible things.
Most important and stupid question is the following:
Hey, I can't/can script myself, but I would like to have a scripter.
Now the most funny thing:
I will grant you right to admin or I might pay you.
I rolfmao'ed so hard the first time I read this thing.
Since when do scripters who can build a complete gamemode theirselves agree with such offer? Putting in paid vip would make the producer getting more profit than you will ever will pay. Admin? Lol seriously running your own server and be the server owner. Highest rank possible and you are the one in control.
This is the point where I realised, people grow up. You kids should start brighten up. Lame offers aren't going to fool anyone.
Of course some of these people actually fall for such an offer. I call them lameys.
Anyways, before you do something as a producer,think about it. Is it realistic? Don't work on faith only, do some research.
Copying this tutoral IS allowed. All I ask is some credit for writing this crap.
PS: I haven't tested anything I wrote down. Therefore some information listed might be "slightly" wrong.
Please pm me with the flaud and I will correct it.