Quantcast
Channel: SA-MP Forums - Tutorials
Viewing all 106 articles
Browse latest View live

[Tutorial] How to fix the SA-MP addon error after uninstalling it

$
0
0
It mostly happens that when you install sa-mp addon through the installer, and then after some time uninstall it, you get an error which says something regarding the SA-MP addon, even though you uninstalled it from the control panel. SA-MP addon modifies your SA-MP img and files in the "SAMP" folder due to which it gives that error. So in order to get rid of that error, all you have to do is just delete the "libraries" folder, created by SAMP addon in your GTA SA directory and reinstall SA-MP again. I'm pretty sure that will solve your problem.

[Tutorial] How to create Gate ??

$
0
0
HOW TO CREATE GATE ?

First add this include to top script

Code:

#include <a_samp> // at the top of the script
#include <zcmd> // at the top of the script

Now define this abbreviations
Code:

#define SCM SendClientMessage // Abbreviations
#define PI PlayerInfo // Abbreviations

Code:

new gate; // Add to the top of the script
Under Ongamemode to add the object in this way, in the map editor place the gate where you want and go
show code and only from the gate we put this as https://imgur.com/j4NxWKL


gate = CreateObject (980, 1082.85352, -952.63611, 44.33330, 0.00000, 0.00000, 2.74000);
it should look like this https://imgur.com/NPc32Xy

Now, let's get the command to open and close the gate
Code:

CMD: open (playerid, params [])
{
***************if (IsPlayerInRangeOfPoint (playerid, 25.0, we put this if the player is not near the gate that he can not open)) // gate
***************{
**********************if (PI [playerid] [Admin]> = 0) Return SCM (playerid, -1, You are not admin ");
**********************{
***********************************MoveDynamicObject (gate, 1082.85352, -952.63611, 40.33330, 2.5); // since we open the gate we need to reduce "Z" as shown in https://imgur.com/klU0mu9
***********************************SCM (playerid, -1, "open gate"); // it should be so excited https://imgur.com/H9j7FMu
**********************}
****************return 1;

Code:

CMD: close (playerid, params [])
{
**********if (IsPlayerInRangeOfPoint (playerid, 25.0, put here if the player is not near the gate that he can not close)) // gate
***************{
**********************if (PI [playerid] [Admin]> = 0) Return SCM (playerid, -1, You are not admin ");
**********************{
***********************************MoveDynamicObject (gate, 1082.85352, -952.63611, 44.33330, 2.5); // after closing the gate we only need to return z as in the code we received
***********************************SCM (playerid, -1, "close gate"); // it should be so excited https://imgur.com/NPc32Xy
**********************}
****************return 1;
}

[Tutorial] Gamemode as includes

$
0
0
How to make a gamemode in the form of includes??

NOTE: This is my first tutorial, so please if you found any mistake tell me and I'll fix it, don't give me negative energy..

Alright so, This had been some kind of a - not very common - question, Many famous scripts are using this method to create their gamemode, They find it easy to edit, helps in reducing the percentage of having the whole gamemode bugged, even if you had a bug, it will be easy to find, It clearly reduces the number of lines inside the gamemode, So let's get this started..

What do I need to do it?

It's just normal, nothing hard, All what you need is scripting knowledge - to start this script from scratch - and You will also need y_hooks as it will help you very much, thanks to YSI, in addition to the very normal includes like streamer, any command processor and I suggest pawncmd myself..

So let's get deep into this..

How should I divide?

So this is simple, You just add the callbacks in the main gamemode, like OnGameModeInIt and etc.. put them in the pwn file which you're going to compile.. and you can leave them empty and just add
PHP Code:

return 1

if you want to completely divide the script into includes, but if you'd like to do some basic systems like accounts and etc inside the main gamemode, which I don't highly recommend, then feel free to use the main functions for these systems.. (By the way I suggest keeping the main gamemode for only saving/loading and the bases of the gamemode itself not the in game..

After that, you get to start the first system which you wanna start, for example, accounts.. Create a new pwn file with the name "accounts" and open it,add on top of it
PHP Code:

#include <YSI\y_hooks> 

and add the enums and the functions, save/load if you want to.. But here comes the question,

How could I use a callback like OnGameModeInIt while it's previously defined in the main gamemode?!

Here comes the role of y_hooks.. You now go ahead instead of using

PHP Code:

public OnGameModeInIt() 

as we can't use it no more..

we can just use this..

PHP Code:

hook OnGameModeInIt()
{
      
//Your code here


Just like that, And it also applies for all the callback, all what you need is just including y_hooks on top of every include..

Now after we finish, How to link the main gamemode with the include??

Here we go, go to the main gamemode, and Go to the buttom of the script (to avoid any error) and do the following..

Let's say for example that we have the accounts file in the folder "includes" which is inside the folder "gamemode"

Let's do it like that..

PHP Code:

#include "..\gamemodes\includes\accounts.pwn" 

As you can see, I added the ".." to go to the root directory, Then picked the specific folder and I must add the extension of ".pwn" at the end so that the gamemode know which file is getting included and adapt itself to it..

At the end I'd like to thank YSI for inspiring me the idea of this tutorial, as he was going to do it himself, But I thought of doing it first, And also thanks for the same YSI for creating us this useful y_hooks, The last credits is for me tho :D I hope you liked the thread, If I have any mistake please tell me it and I'll fix it, As I said before, It's my first tutorial..

[Tutorial] How NOT To Store Your Users' Passwords

$
0
0
How NOT To Store Your Users' Passwords

By Sasinosoft

The first thing we must be aware of when programming anything that will ask the user to enter a password, is that the user is giving us their trust. It is our duty to keep their password as safe as possible, so that in case of attack to our servers, the attacker will not be able to read their password. You might think that "it is just a game", so the security of the game accounts is not so serious, but a poll showed that 59% of people use the same password everywhere or almost everywhere. [source] If the attacker gets access to your game database, he will most likely obtain all your users' nicknames and passwords, and if they are not properly hashed, then you have made his work easier. After getting this information, the attacker will proceed to check for each user if he is registered on the main websites, such as Go0gle, Microsoft, mail providers, using the passwords and user names he just stole.
Here are a few hints to make his work harder.

1. DO NOT Store Passwords In Plain Text

It is believed that at least 30% of the websites store the passwords in plain text. [source] This is really a shame, and it must come to an end. If any website emails your password back in plain text, then he is surely storing your password as such, and compromising your security in all the websites that you used the same password.

You must never do so. In the case of a San Andreas Multiplayer server, as soon as you receive the user password in the inputtext parameter of OnDialogResponse, you must one-way hash it. Fortunately, the developers of SA-MP added the SHA256_PassHash function in version 0.3.7 R2-1, so there is no more excuse for those who don't like to use external plugins. [great tutorial]

Said that, I will also add that since there are better algorithms than SHA-256, it would be better if you used another one: bcrypt (the best, as I will show in the next section), SHA-512 or Whirlpool. On SA-MP Forums you can find plugins for bcrypt [link], SHA-512 [link] and Whirlpool [link]


2. DO NOT Simply Hash The Password And Store it

Hashing the password and store it will add very little security; most users' passwords are simple words or numbers which can be found in dictionaries. If this is the case, the attacker will easily detect the password of the user, simply by searching the hash in rainbow tables; these are per-algorithm tables which already contain the hashes of the most common passwords and more, and they are publicly available on the internet. [example]

To avoid this problem, and force the attacker to use brute-force attacks, thus wasting his time, money and energy, you must put salt on your passwords.


A prudent programmer putting salt on the password of his users.

The salt is a value that is concatenated to the password before hashing it, and there are different ways to do this, and different opinions about how this should be done. [tutorial for SA-MP - Whirlpool] The salt is unique for each user, and it is never secret: its value is stored in plain text into the database at the moment of registration, and it is read by your program when the user attempts to log in.

3. DO NOT Use The Username As Salt

If your SA-MP Server does this, and another website that your user is registered on with the same username and the same password does the same, both databases will contain the same password hash for the user. If the attacker, after getting a copy of your database and that of the other website, notices this coincidence, then he will most likeley focus on this particular user.

If you implemented a system to let the user change his password, you are then going to hash it with the same salt as before. This needs to be avoided.

The best practice is to generate a random string the first time the user registers, and to store it into the database in a separate column. When the user wants to change his password, your program will generate a new random string, and update the value in the database.

4. DO NOT Write Your Own Hashing Function

Do not do this, unless you work for the NSA and your algorithm has been tested for years. Do not do this even if you have studied cryptography and security. This is because, even if you think that your algorithm is strong enough, it has not been tested enough against all the possible kinds of attack. Do not risk, and if you have written one, just keep it as your personal project.

5. Use bcrypt

In this post I mentioned different hashing algorithms whose implementations are also available for SA-MP Servers. I must also say that the best option you have is to use bcrypt.
The primary reason is that bcrypt, unlike the other algorithms mentioned here, aims at being slow to execute, especially on GPUs. When we are computing our hash during user registration or login, we don't care if it takes 1 second or more, because most likely the user will not notice it, instead we really care about the attacker being as slow as possible at brute/dictionary attacking our hashed password. SHA and Whirlpool are aimed at being as fast as possible to execute, and while this means that the user's password is checked in the blink of an eye, it also means that the attacker is able to crack the password in fewer time (with the appropriate equipment).
By using bcrypt, we make almost impossible for an attacker to crack the password, definitely not worth it for him.

6. Additional Tips
  • Also put pepper. Pepper is another value that is added to the algorithm before the final hash, but instead of being a different value for each user, it is a single constant string which is used for every hash, and it is secretly hardcoded in your code. Of course, after your first user is registered, you must never change it again.
  • Force the user to use a password of a certain minimum length, and made of multiple words.
  • In your register dialog, tell the user not to use the same password as other websites or SA-MP Servers, and not to tell his password to anyone.
  • Ask the user to input his password twice during registration and password changing procedure.
  • Kick the user and prevent him from logging in again for a certain time if he fails to log in for a certain number of times. This makes unpractical using direct brute force attacks to your server.
  • Implement a system to change the password, and encourage your users to change it when they feel it is compromised.

[Tutorial] 0.3.DL: How to add custom skin, object and use the Redirect()

$
0
0
SA-MP 0.3.DL
How to add custom skin, object and use the Redirect()
It's necessary use SA-MP 0.3.DL
  • How to add custom skins in server-side
    • You must open models folder inside in your sa-mp server.

    • After this, you will add the .dff and .txd skin files over there.

    • After add the skin files inside of the models folder, you must edit the file artconfig.txt. (This file is located in the same folder)

      Use the params AddCharModel(baseid, newid, dffname[], txdname[]); in the artconfig.txt.
      • baseid - This is the skin base, he will copy the anim, voice and basic sounds to apply in your custom skin. Note: You can use only default sa-mp skins (0-311).
      • newid - This is will be the new skin ID between 20000 and 30000. (e.g. 20012).
      • dffname[] - Here you will be put the location of skin file .dff, starting in folder models.
      • txdname[] - Here you will be put the location of skin file .txd, starting in folder models.

      Example:
      Code:

      AddCharModel(280, 25000, "police_asiatic.dff", "police_asiatic.txd");


    • After edit your artconfig.txt go to server.cfg and put this params to active the artwork.
      Code:

      useartwork 1
    • Start up your samp-server.exe and enjoy.
    • All custom skins will be downloaded before you enter in server.

    • The custom skins are downloaded by client-side and will be placed in folder GTA San Andreas User Files\SAMP\cache\server_ip:port\. The files has different names that are defined by sa-mp script using some criptografy to make that.
  • How to add custom objects in server-side
    • You must open models folder inside in your sa-mp server.

    • After this, you will add the .dff and .txd skin files over there.

    • After add the skin files inside of the models folder, you must edit the file artconfig.txt. (This file is located in the same folder)

      Use the params AddSimpleModel(virtualworld, baseid, newid, dffname[], txdname[]); in the artconfig.txt.
      • virtualworld - This is the virtual world wherein the object to be visible. If you put value -1 the object will be visible in all virtual worlds.
      • baseid - This is the native objejct, he will copy the colission and anothers params. Note: If you use some object without colission you new object wont have colission.
      • newid - This is will be the new skin ID between -1000 and -30000. (e.g. -24121).
      • dffname[] - Here you will be put the location of custom object file .dff, starting in folder models.
      • txdname[] - Here you will be put the location of custom object file .txd, starting in folder models.

      Example:
      Code:

      AddSimpleModel(-1, 18865, -1000, "AxomCamPOLICE1.dff", "AxomCamPOLICE1.txd");


    • After edit your artconfig.txt go to server.cfg and put this params to active the artwork.
      Code:

      useartwork 1
    • Start up your samp-server.exe and enjoy.
    • All custom objects will be downloaded before you enter in server.

    • The custom skins are downloaded by client-side and will be placed in folder GTA San Andreas User Files\SAMP\cache\server_ip:port\. The files has different names that are defined by sa-mp script using some criptografy to make that.
  • How to use Redirect()
    • All files placed in your Redirect will must be same to files in samp-server folder models/.
    • Open your gamemode.
    • Put the native OnPlayerRequestDownload(playerid, type, crc) in your script, I suggest on top of the native OnGameModeInit.
      Code:

                              public OnPlayerRequestDownload(playerid, type, crc)
                              {
                             
                                      return 1;
                              }

    • Create a new global variable without size, on top of the OnPlayerRequestDownload with name SERVER_DOWNLOAD.
      Code:

                              new SERVER_DOWNLOAD[];
                              public OnPlayerRequestDownload(playerid, type, crc)
                              {
                             
                                      return 1;
                              }

    • Put the URL with place of your models in your website. For example, I will use the website http://www.dev-wil.com/downloads/038/models.
      Code:

                              new SERVER_DOWNLOAD[] = "http://www.dev-wil.com/downloads/038/models";
                              public OnPlayerRequestDownload(playerid, type, crc)
                              {
                             
                                      return 1;
                              }

    • Now, create the parameters of your OnPlayerRequestDownload so that it replaces the download with sa-mp server by the one of your site. Enter a condition to check if the player is connected. Create conditions with the DOWNLOAD_REQUEST_TEXTURE_FILE and DOWNLOAD_REQUEST_MODEL_FILE types to define the function that will fetch the .txd or the .dff file, respectively.
      Code:

                              new SERVER_DOWNLOAD[] = "http://www.dev-wil.com/downloads/038/models";
                              public OnPlayerRequestDownload(playerid, type, crc)
                              {
                                      if(!IsPlayerConnected(playerid))
                                              return 0;
                                     
                                      if(type == DOWNLOAD_REQUEST_TEXTURE_FILE)
                                              {}
                                      else if(type == DOWNLOAD_REQUEST_MODEL_FILE)
                                              {}
                                      return 1;
                              }

    • Add the functions FindTextureFileNameFromCRC(crc, retstr[], retstr_size) and FindModelFileNameFromCRC(crc, retstr[], retstr_size) to the sa-mp server write the txd and dff files names to be a find inside of the website.
      Code:

                              new SERVER_DOWNLOAD[] = "http://www.dev-wil.com/downloads/038/models";
                              public OnPlayerRequestDownload(playerid, type, crc)
                              {
                                      if(!IsPlayerConnected(playerid))
                                              return 0;
                                     
                                      if(type == DOWNLOAD_REQUEST_TEXTURE_FILE)
                                              FindTextureFileNameFromCRC(crc, retstr[], retstr_size);
                                      else if(type == DOWNLOAD_REQUEST_MODEL_FILE)
                                              FindModelFileNameFromCRC(crc, retstr[], retstr_size);
                                      return 1;
                              }

    • Create a local variable to be replace a retstr and alter the retstr_size to sizeof(new_local_var)
      Code:

                              new SERVER_DOWNLOAD[] = "http://www.dev-wil.com/downloads/038/models";
                              public OnPlayerRequestDownload(playerid, type, crc)
                              {
                                      if(!IsPlayerConnected(playerid))
                                              return 0;
                                             
                                      new filename[64];
                                     
                                      if(type == DOWNLOAD_REQUEST_TEXTURE_FILE)
                                              FindTextureFileNameFromCRC(crc, filename, sizeof(filename));
                                      else if(type == DOWNLOAD_REQUEST_MODEL_FILE)
                                              FindModelFileNameFromCRC(crc, filename, sizeof(filename));
                                             
                                      return 1;
                              }

    • The functions FindTextureFileNameFromCRC e FindModelFileNameFromCRC will be return 1 if find the file or 0 if case is not. Add local variable to be a storage this value and go to next step.
      Code:

                              new SERVER_DOWNLOAD[] = "http://www.dev-wil.com/downloads/038/models";
                              public OnPlayerRequestDownload(playerid, type, crc)
                              {
                                      if(!IsPlayerConnected(playerid))
                                              return 0;
                                             
                                      new filename[64], filefound;
                                     
                                      if(type == DOWNLOAD_REQUEST_TEXTURE_FILE)
                                              filefound = FindTextureFileNameFromCRC(crc, filename, sizeof(filename));
                                      else if(type == DOWNLOAD_REQUEST_MODEL_FILE)
                                              filefound = FindModelFileNameFromCRC(crc, filename, sizeof(filename));
                                             
                                      return 1;
                              }

    • Now make a condiction if the local variable is 1.
      Code:

                              new SERVER_DOWNLOAD[] = "http://www.dev-wil.com/downloads/038/models";
                              public OnPlayerRequestDownload(playerid, type, crc)
                              {
                                      if(!IsPlayerConnected(playerid))
                                              return 0;
                                             
                                      new filename[64], filefound;
                                     
                                      if(type == DOWNLOAD_REQUEST_TEXTURE_FILE)
                                              filefound = FindTextureFileNameFromCRC(crc, filename, sizeof(filename));
                                      else if(type == DOWNLOAD_REQUEST_MODEL_FILE)
                                              filefound = FindModelFileNameFromCRC(crc, filename, sizeof(filename));
                                             
                                      if(filefound)
                                              {}
                                     
                                      return 1;
                              }

    • Make a local variable with a size of 256. This variable will be responsible for storing a final URL of the file, containing a main URL and location of the file at that address. Create a format for the variable and insert the URL using the global variable SERVER_DOWNLOAD and the variable filename.
      Code:

                              new SERVER_DOWNLOAD[] = "http://www.dev-wil.com/downloads/038/models";
                              public OnPlayerRequestDownload(playerid, type, crc)
                              {
                                      if(!IsPlayerConnected(playerid))
                                              return 0;
                                             
                                      new filename[64], filefound, final_url[256];
                                     
                                      if(type == DOWNLOAD_REQUEST_TEXTURE_FILE)
                                              filefound = FindTextureFileNameFromCRC(crc, filename, sizeof(filename));
                                      else if(type == DOWNLOAD_REQUEST_MODEL_FILE)
                                              filefound = FindModelFileNameFromCRC(crc, filename, sizeof(filename));
                                             
                                      if(filefound)
                                      {
                                              format(final_url, sizeof(final_url), "%s/%s", SERVER_DOWNLOAD, filename);
                                      }
                                     
                                      return 1;
                              }

    • Now insert the function RedirectDownload(playerid, url[]), when the url[] is a last created local variable.
      Code:

                              new SERVER_DOWNLOAD[] = "http://www.dev-wil.com/downloads/038/models";
                              public OnPlayerRequestDownload(playerid, type, crc)
                              {
                                      if(!IsPlayerConnected(playerid))
                                              return 0;
                                             
                                      new filename[64], filefound, final_url[256];
                                     
                                      if(type == DOWNLOAD_REQUEST_TEXTURE_FILE)
                                              filefound = FindTextureFileNameFromCRC(crc, filename, sizeof(filename));
                                      else if(type == DOWNLOAD_REQUEST_MODEL_FILE)
                                              filefound = FindModelFileNameFromCRC(crc, filename, sizeof(filename));
                                             
                                      if(filefound)
                                      {
                                              format(final_url, sizeof(final_url), "%s/%s", SERVER_DOWNLOAD, filename);
                                              RedirectDownload(playerid, final_url);
                                      }
                                      return 1;
                              }

    • Turn on the SA-MP Server and go to inside the server, you will perceive a massive speed downloading your custom skins and objects;
    • If the error (22) HTTP Response co... appears is because the URL way find is wrong. Make a debug and find the soluction.

If you have any doubt please comment this thread. If you find any error or bad translation send me a PM.
Sorry my bad english, I am not native speaker.

[Tutorial] ColAndreas

$
0
0
Hi everybody. I would like an tutorial how to use ColAndreas (I never used it or MapAndreas).
I'm creating an submarine script and i want to "stop the submarine" when it "hit" ground under water , ground and other objectes , but idk how to use it :D . Thanks.

[Tutorial] Discord PM system

$
0
0
hello all
Disclaimer : this method I explored alone in a test server in ultra-h and it won't be existing in another gamemode and if it is ,we're thinking same way and i don't might annoy anyone who does like me .

here we start

first add this in top of script .
Code:

new DCC_Channel:PmedChannel[MAX_PLAYERS];
new PmedUser[32][MAX_PLAYERS];

this store channel of DiscordUser That pmed Bot that is connected to server in a DM channel so we could pm back ,and store name too ;D

now let's add this function to pm any channel easly but we'll pm DM channel
Code:

stock SendMessageToChannel(ChannelId[],const string[])
{
        #if defined dcconnector_included
                new DCC_Channel:TargetChannel;
                if (_:TargetChannel == 0)
                TargetChannel = DCC_FindChannelById(ChannelId); // Discord channel ID
                DCC_SendChannelMessage(TargetChannel, string);
        #else
                format(ChannelId,36,"rgtsd %s",string); // to not get stupid warnnings (non effectable)
        #endif
        return 1;
}

you don't need to focus in this code alot
main part is the callback

Code:

public DCC_OnChannelMessage(DCC_Channel:channel, DCC_User:author, const message[])
{
        new channel_name[100],DCC_ChannelType:type,user_name[32],idaw[3],dest[128],bool:is_bot;

        if(!DCC_GetChannelName(channel, channel_name)) return 0; // invalid channel
        if (!DCC_GetUserName(author, user_name)) return 0; // invalid user
        DCC_GetChannelId(DCC_Channel:channel, dest); new chann = strval(dest); // getting channel id to pm back channel easly
        DCC_GetUserId(DCC_User:author, idaw); new userid = strval(idaw); // for security stuffs
        DCC_IsUserBot(DCC_User:author, is_bot); // to avoid bot spam and rate limit .
    DCC_GetChannelType(DCC_Channel:channel, DCC_ChannelType:type); // getting channel type and if type is 1 the channel type is DM is when you pm the bot especially
        if(!is_bot)
          {
        switch(type)
            {
                        case 1:
                        {
                            new pmstring[256];
                                new xTempCMD[16], xTempCMD2[256],xTempCMD3[256];
                                sscanf(message[1], "s[16]s[3]s[256]", xTempCMD, xTempCMD2, xTempCMD3);// ah you need sscanf between
                                if(message[0] = "/")
                                {
                                        if(!strcmp(xTempCMD, "pm", true))// checking if you insert '/pm'
                                        {
                                                new id = strval(xTempCMD2); // getting second params 'id'
                                                if(IsPlayerConnected(id))//checking if player connected
                                                {
                                                    if(pInfo[id][pLogged] == 1) //something like this if player logged in his acc ,you can delete it if you want
                                                        {
                                                                if(pAcc[id][Blockpm] == 0) // check if the tarjet players blocking his pm ,you may delete or change it like your script
                                                                {
                                                                        format(pmstring,sizeof(pmstring),"{007AFF}[Discord]{faf000} PM From {fcf111}%s(%i): {faf000}%s",user_name,userid,xTempCMD3);// sending message to player
                                                                        SendClientMessage(id,-1,pmstring);
                                                                        PmedChannel[id] = channel ; //stoting channel .
                                                                        format(PmedUser[id],128,"%s",user_name); //storing name
                                                                }
                                                                SendMessageToChannel(dest,"[BrainBot] : Requested Player Is Blocking Pms"); // back a message
                                                        }
                                                        SendMessageToChannel(dest,"[BrainBot] : Requested Player didn't Log In Yet"); // obvious
                                                }
                                                SendMessageToChannel(dest,"[BrainBot] : Requested Player Is not connected"); // obvious
                                }
                        }
                        }
            }
        }
        return 1;
}

i think i explained there everything .
now we finished :D
wops forget responding command ,my fault

Code:

CMD:r(playerid,params[])
{
        if(pInfo[playerid][pLogged] == 1)
        {
                new message[256],pmstring[256];
                if(sscanf(params,"s[256]", message)) return SendClientMessage(playerid,-1,"{0F0F0F}[SYNTAX]:{FF1111}/pm [playerid] [message]");//sscanf of course :D
                if(pInfo[playerid][pLogged] == 1)
                {
                                #if defined dcconnector_included
                            new stringme[256],dest[128];

                            format(stringme,sizeof(stringme),"[PM] Reply From %s(%i): %s",PlayerName(playerid),playerid,message);
                            DCC_GetChannelId(PmedChannel[playerid], dest);
                                SendMessageToChannel(dest, stringme);// backing message to channel
                                               
                            format(pmstring,sizeof(pmstring),"{007AFF}[Discord]{faf000} PM To {fcf111}%s : {faf000}%s",PmedUser[playerid],message);
                                SendClientMessage(playerid,-1,pmstring); // showing what player wronte in the message
                        #endif
                }
        }
        return 1;
}

please rep my work and feedback if you got any problem ,remember its pain in ass to upload test to server and doing this took time ,so reps me :D

[Tutorial] How to make Admin cars

$
0
0
HOW TO MAKE ADMIN CARS

Welcome to my first tutorial! I will try to explain to you step-by-step how to make Admin cars.8)

Step #1:

First, we must define our maximum amount of Admin cars(without 0). In this case it's 5.

Code:

#define ADMIN_CARS 5
Ok, now we need to create a new variable for our cars.

Code:

new AdminCar[ADMIN_CARS];
Ok we created the variable AdminCar that has the maximum amount of Admin cars, that means we can create 5 cars with numbers: 0,1,2,3,4.

And we need one more variable to hold the maximum amount of 3D text labels attached to a vehicle.

Code:

new Text3D:vehicle3Dtext[MAX_VEHICLES];
Step #2:

Now we need to create our cars! You need the coordinates for your cars, I will be using AddStaticVehicleEx.

But before adding the cars we must tell the script that it's an Admin car. So we put the variable AdminCar with a car number(Admin car number with 0 at the beginning). Like this:

Code:

AdminCar[0] = AddStaticVehicleEx(405,-2063.2510,-2497.4910,30.5000,142.3958,75,1,-1);
          AdminCar[1] = AddStaticVehicleEx(405,-2059.6921,-2499.8555,30.5742,137.8902,75,1,-1);
          AdminCar[2] = AddStaticVehicleEx(405,-2081.6641,-2555.3242,30.4238,319.9079,75,1,-1);
          AdminCar[3] = AddStaticVehicleEx(415,-2045.9122,-2564.6289,30.3960,40.9819,36,1,-1);
          AdminCar[4] = AddStaticVehicleEx(415,-2051.2244,-2569.9460,30.3961,39.8471,36,1,-1);

(We put this code in OnGameModeInit.)

Step #3:

Now we will create our 3D text that will tell the players it's an Admin car. We will use the variable we created in the first step. Like this:

Code:

vehicle3Dtext[AdminCar[0]] = Create3DTextLabel("[ADMIN]",COLOR_YELLOW, 0.0, 0.0, 0.0, 50.0, 0, 1);
          vehicle3Dtext[AdminCar[1]] = Create3DTextLabel("[ADMIN]",COLOR_YELLOW, 0.0, 0.0, 0.0, 50.0, 0, 1);
          vehicle3Dtext[AdminCar[2]] = Create3DTextLabel("[ADMIN]",COLOR_YELLOW, 0.0, 0.0, 0.0, 50.0, 0, 1);
          vehicle3Dtext[AdminCar[3]] = Create3DTextLabel("[ADMIN]",COLOR_YELLOW, 0.0, 0.0, 0.0, 50.0, 0, 1);
          vehicle3Dtext[AdminCar[4]] = Create3DTextLabel("[ADMIN]",COLOR_YELLOW, 0.0, 0.0, 0.0, 50.0, 0, 1);

So now we just have to attach the Text Labels to our cars. There is a very simple command for that:

Code:

Attach3DTextLabelToVehicle(vehicle3Dtext[AdminCar[0]], AdminCar[0], 0.0, 0.0, 0.0);
          Attach3DTextLabelToVehicle(vehicle3Dtext[AdminCar[1]], AdminCar[1], 0.0, 0.0, 0.0);
          Attach3DTextLabelToVehicle(vehicle3Dtext[AdminCar[2]], AdminCar[2], 0.0, 0.0, 0.0);
          Attach3DTextLabelToVehicle(vehicle3Dtext[AdminCar[3]], AdminCar[3], 0.0, 0.0, 0.0);
          Attach3DTextLabelToVehicle(vehicle3Dtext[AdminCar[4]], AdminCar[4], 0.0, 0.0, 0.0);

Just like that! But now we will have to remove them when the gamemode changes or server shuts down. In OnGameModeExit we put:

Code:

Delete3DTextLabel(vehicle3Dtext[AdminCar[0]]);
          Delete3DTextLabel(vehicle3Dtext[AdminCar[1]]);
          Delete3DTextLabel(vehicle3Dtext[AdminCar[2]]);
          Delete3DTextLabel(vehicle3Dtext[AdminCar[3]]);
          Delete3DTextLabel(vehicle3Dtext[AdminCar[4]]);

Perfect.

Step #4:

Our cars have been created, and text labels attached. Everything we have to do is, if a non-Admin player tries to enter the car, he can't. And we will add a cool text with the message.

Under OnPlayerEnterVehicle we must add a for loop.

Code:

for(new i = 0; i < sizeof(AdminCar); i ++)
{
}

This loop combined with this if statement will check if the player is an Admin and if it's an Admin vehicle.

Code:

if(vehicleid == AdminCar[i] && !IsPlayerAdmin(playerid))
{
}

It should look something like this:

Code:

for(new i = 0; i < sizeof(AdminCar); i ++)
{
  if(vehicleid == AdminCar[i] && !IsPlayerAdmin(playerid))
  {
  }
}

So if the player is not an RCON Admin, we must stop the player from entering and send him a message. Like this:

Code:

ClearAnimations(playerid);
GameTextForPlayer(playerid,"~r~ Admins only!",2000,4);

So now our for loop should look something like this:

Code:

for(new i = 0; i < sizeof(AdminCar); i ++)
{
        if(vehicleid == AdminCar[i] && !IsPlayerAdmin(playerid))
        {
                ClearAnimations(playerid);
                GameTextForPlayer(playerid,"~r~ Admins only!",2000,4);
        }
}

The End

That's it for this tutorial! Hope you enjoyed and learned something from it.

Thanks for reading!;)

[Tutorial] PAWN Compiler In Notepad++

$
0
0
Hello guys i saw some tutorials based on the same topics, as i saw some are not good enough and some threads links are down so i have made this tutorial for you all in easy method just follow my steps and all will work perfectly.

Steps in Windows 10
  • Install Latest version of Notepad++.
    (Link: Notepad++ [7.5.8])
  • Download Plugin Manager.
    (Link: Plugin Manager [1.4.9])
  • Installed the notepad++? Open your notepad++
    (Directory: 'C:\Program Files\Notepad++') extract the plugin manager.
  • Now right click on notepad++.exe.
  • Make it permanent open with as administrator.
  • Now it will ask for updating plugin manager, update it.
  • Search for NppExec plugin, install it.
  • Download the pawn.xml.
    (Link: PAWN.xml)
  • Open notepad++ directory
    (Directory: 'C:\Program Files\Notepad++\plugins\APIs\') copy/paste the PAWN.xml their.
  • Now press CTRL+R to open run.
    (Directory: %appdata%/notepad++)
  • Copy/paste the UserDefineLang.XML
    (Link: UserDefineLang.xml)
  • Again open the same directory (Directory: %appdata%/notepad++/plugins)
  • Copy/paste the config folder.
    (Link: Config Folder)
  • Open notepad++ as administrator and follow screenshots.

[hr]

[hr]

[hr]

[hr]

[hr]

[hr]

[hr]
After this save your file as .pwn and it will ready to be compiled :D
enjoy hope you like the tutorial.

[Tutorial] Register/Login System with dini2.inc

$
0
0
Introduction
I just made a simple register/login system using dini2.inc so I thought I should share it on the forums to see how well I did. Anyways this would be my first post so expect mistakes and use of unprofessional ways in the code.

Tutorial
Step 1 :-
First of all we'll have to add the include, define the dialog IDs, color codes and the file pathway where our accounts will be saved.
PHP Code:

#include <a_samp>
#include <dini2>
#include <dudb>

#define COLOR_GREY 0xAFAFAFAA
#define COLOR_GREEN 0x33AA33AA
#define COLOR_ORANGE 0xFF9900AA
#define COLOR_RED 0xAA3333AA
#define COLOR_YELLOW 0xFFFF00AA

#define DIALOG_REGISTER    1
#define DIALOG_LOGIN    2

#define _USER_FILE "Account/%s.ini" 

Step 2 :-
Second, we'll have to add the Enumerators and a few variables. The first would just do the same work as the enumerators and the second one will determine whether the player is logged in or not.
PHP Code:

enum pInfo
{
    
pAdminLevel,
    
pCash,
    
pScore,
}
new 
PlayerInfo[MAX_PLAYERS][pInfo];
new 
gPlayerLogged[MAX_PLAYERS]; 

Step 3 :-
After that, we'll show player dialogs to register or login. For this, we use the callback named "OnPlayerConnect". I'll try my best to explain every single part.
PHP Code:

public OnPlayerConnect(playerid)
{
    
gPlayerLogged[playerid] = 0// Setting his login status to not logged in.
    
new name[MAX_PLAYER_NAME], file[256];
    
GetPlayerName(playeridnamesizeof(name));
    
format(filesizeof(file), _USER_FILEname);
    if (!
dini_Exists(file)) // If the file with the player name doesn't exit
    
{
        
ShowPlayerDialog(playeridDIALOG_REGISTERDIALOG_STYLE_INPUT,"Register an account""Enter your password below to register an account""Register""Exit");
    }
    if(
fexist(file)) // If the file with the player name exists
    
{
        
ShowPlayerDialog(playeridDIALOG_LOGINDIALOG_STYLE_INPUT"Login to your account""Enter your password below to login to your account""Login""Exit");
    }
    return 
1;


Step 4 :-
Now we'll set the response of the when the player enters his/her password to register or login. Once again, will try my best to explain.
PHP Code:

public OnDialogResponse(playeriddialogidresponselistiteminputtext[])
{
    if (
dialogid == DIALOG_REGISTER// If it was the registeration dialog
    
{
        new 
name[MAX_PLAYER_NAME], file[256];
        
GetPlayerName(playeridnamesizeof(name));
        
format(filesizeof(file), _USER_FILEname);
        if(!
response) return Kick(playerid); // Kick the player if he chooses the "exit" option
        
if (!strlen(inputtext)) return // Show player the registeration dialog again if he presses enter with no password
                
ShowPlayerDialog(playeridDIALOG_REGISTERDIALOG_STYLE_INPUT,"Register an account""Enter your password below to register an account""Register""Exit");
        
dini_Create(file// Create an .ini file to save the player's status 
        
dini_IntSet(file"Password"udb_hash(inputtext)); // save his password
        
dini_IntSet(file"AdminLevel",PlayerInfo[playerid][pAdminLevel] = 0); // save his admin level
        
gPlayerLogged[playerid] = 1// Setting his login status to logged in.
    
}
    if (
dialogid == DIALOG_LOGIN// If it was the login dialog
    
{
        new 
name[MAX_PLAYER_NAME], file[256];
        
GetPlayerName(playeridnamesizeof(name));
        
format(filesizeof(file), _USER_FILEname);
        if(!
response) return Kick(playerid); // Kick the player if he chooses "exit "
        
if (!strlen(inputtext)) return ShowPlayerDialog(playeridDIALOG_LOGINDIALOG_STYLE_INPUT"Login to your account""Enter your password down below to login to your account""Login""Exit"); // showing the player the dialog again if he leaves the password space empty
        
new tmp// creating a new variable
        
tmp dini_Int(file"Password"); // setting the variable as the password
        
if(udb_hash(inputtext) != tmp// if the player enters a wrong password
        
{
            
SendClientMessage(playeridCOLOR_RED"Your password is incorrect."); // Sending him/her a message
            
ShowPlayerDialog(playerid2DIALOG_STYLE_INPUT"Login to your account""Enter your password down below to login to your account""Login""Exit"); // showing him/her the dialog again.
        
}
        else 
// if he/she enters the correct password
        
{
            
gPlayerLogged[playerid] = 1//setting the login status to logged in
            
PlayerInfo[playerid][pAdminLevel] = dini_Int(file"AdminLevel"); // setting him admin if he was previously
            
SetPlayerScore(playeridPlayerInfo[playerid][pScore]); // setting his score that we will save in the next step
            
GivePlayerMoney(playeridPlayerInfo[playerid][pCash]); // setting his money that we will save in the next step
            
SendClientMessage(playerid,COLOR_GREEN"~ Your stats has been restored, welcome back !"); // sending him/her message
        
}
    }
    return 
1;


Step 5 :-
Now we'll set the response of the when the player enters his/her password to register or login. Once again, will try my best to explain.
PHP Code:

public OnPlayerDisconnect(playeridreason)
{
    new 
name[MAX_PLAYER_NAME], file[256];
    
GetPlayerName(playeridnamesizeof(name));
    
format(filesizeof(file), _USER_FILEname);
    if(
gPlayerLogged[playerid] == 1// if he was logged in
    
{
        
dini_IntSet(file"Score"GetPlayerScore(playerid)); // saving his score
        
dini_IntSet(file"Money"GetPlayerMoney(playerid)); //saving his cash
        
dini_IntSet(file"AdminLevel",PlayerInfo[playerid][pAdminLevel]); //saving his admin level
    
}
    return 
1;


Step 6 :-
You will probably face an error while compiling the .pwn file, don't worry. Just use the function down below to fix it.
PHP Code:

#pragma unused ret_memcpy 

Also make sure to create a folder named "Account" in your scriptfiles directory otherwise you won't be able to save the accounts.

Download
Pastebin
dini2


Credits
Orbit ~ Scripting
DracoBlue ~ Original dini include
Gammix ~ Improved version of dini (dini2/gini)

Thanks for reading this topic. I made this for the guys out there who are new to SA-MP scripting like me. It would be great if you take a few minutes and reply on this post to give me feedback. I would really appreciate it.

You are welcomed here if you came to learn, not if you came to copy/paste the code.

[Tutorial] How to properly link tables in MySQL

$
0
0
I see so many gamemodes that get posted to this forum. They all work. Their databases work. So what's the problem?

I'm going to keep this short, sweet and to the point.

First of all, lets look at this MySQL table creation:

Code:

DROP TABLE IF EXISTS `accounts`;
CREATE TABLE `accounts` (
  `DatabaseID` int(11) NOT NULL AUTO_INCREMENT,
  `Username` varchar(20) NOT NULL,
  `Password` varchar(256) NOT NULL,
  `RegisterIP` varchar(20) NOT NULL,
  `LastIP` varchar(20) NOT NULL,
  `PosX` float(50,5) NOT NULL,
  `PosY` float(50,5) NOT NULL,
  `PosZ` float(50,5) NOT NULL,
  `PosA` float(50,5) NOT NULL,
  `Health` float(50,5) NOT NULL,
  `Armour` float(50,5) NOT NULL,
  `Money` int(11) NOT NULL,
  `Accent` int(11) NOT NULL,
  `Skin` int(11) NOT NULL,
  `AdminLevel` int(11) NOT NULL,
  PRIMARY KEY (`DatabaseID`)
);

I'm going to quickly show you how to make this table more RDB-like.

In any database - data should only be stored once. There's multiple areas where we could adjust this table to relfect that statement:

To keep it quick, let us simply evaluate the Admins side of this table. We can remove admin-related data from the accounts table and put it in its own table. This table will simply reference the ID of the account (which I'm not sure why the developer made it DatabaseID), and give them a level:

Code:

drop table if exists 'admins';

create table 'admins' (
        'DatabaseID' int,
        'level' int not null,
       
        foreign key (DatabaseID) references accounts(DatabaseID) on delete cascade
);

The last line in there makes DatabaseID a foreign key that references the DatabaseID in the accounts table. The statement 'on delete cascade' means that when I delete the row from the parent table, the corresponding row in admins will drop too.


We can simply tidy up our accounts table by removing the 'AdminLevel' field in the accounts table. Just think about the cardinality of a field, and its optionality. Why give every single player a 'Weapons' field in a roleplay server database if not every player is definitely going to carry a weapon? Why not create another table called 'player_weapons'?

This is only one example so it might become a bit unclear. However, you should 100% follow this when you're creating databases. If you're inputting the same value more than once - then your database design doesn't follow the conventional RDB design and performance will suffer greatly when your database needs to search through thousands of records. This design I've showed you allows me to search ONLY through the admins table if I need to list the administrators, and stops me from searching an entire table of accounts - the majority of whom are not administrators. It's faster, tidier and is far more plausable than the first table I shown you. There's much more that could be done with that table - but you can work that one out.

[Tutorial] Simple questions test

$
0
0
PHP Code:

#include <a_samp>
#include <crashdetect>
//makes dialog section more readable and manageable
#include <easyDialog>
//questions array | packed strings to save memory
//last value is listitem value what is right for the answer
//first field is for question others are possible answers, but only one is right
static const arrTestQuestions[][][]={
    {!
"1asdasdasdasd",!"asdasdasdasd",!"asdasdasdasd",!"asdasdasdasd",!"asdasdasdasd",!"asdasdasdasd",'0'},
    {!
"2asdasdasdasd",!"asdasdasdasd",!"asdasdasdasd",!"asdasdasdasd",!"asdasdasdasd",!"asdasdasdasd",'1'},
    {!
"3asdasdasdasd",!"asdasdasdasd",!"asdasdasdasd",!"asdasdasdasd",!"asdasdasdasd",!"asdasdasdasd",'2'},
    {!
"4asdasdasdasd",!"asdasdasdasd",!"asdasdasdasd",!"asdasdasdasd",!"asdasdasdasd",!"asdasdasdasd",'3'},
    {!
"5asdasdasdasd",!"asdasdasdasd",!"asdasdasdasd",!"asdasdasdasd",!"asdasdasdasd",!"asdasdasdasd",'4'},
    {!
"6asdasdasdasd",!"asdasdasdasd",!"asdasdasdasd",!"asdasdasdasd",!"asdasdasdasd",!"asdasdasdasd",'4'}
};
static 
    
ansQuestMistakes[MAX_PLAYERS],
    
ansQuestCnt[MAX_PLAYERS];
//example how to start it
main(){}
public 
OnPlayerConnect(playerid){
    
StartTest(playerid);
    return 
1;
}
//will start test sequence
StartTest(pid){
    
//reseting players variables
    
ansQuestCnt[pid]=ansQuestMistakes[pid]=0;
    
//Showing first question
    
ShowTestQuestion(pid);
    return 
1;
}
//will show questions with possible answers
ShowTestQuestion(pid){
    
//creating new variables
    
new bs[5*(90+10)],
        
s[90],
        
cnt=ansQuestCnt[pid];
    
//unpacking packed strings
    
for(new i=1<= 5i++){
        
strunpack(s,arrTestQuestions[cnt][i]);
        
format(bs,sizeof(bs),"%s%d) %s\n",bs,i,s);
    }
    
strunpack(s,arrTestQuestions[cnt][0]);
    
//showing dialog for playerid
    
Dialog_Show(pid,DialogQuesionAnswer,DIALOG_STYLE_LIST,s,bs,"Select","Kick");
    return 
1;
}
//considers players answers
Dialog:DialogQuesionAnswer(pidresponselistiteminputtext[]){
    if(!
response)return Kick(pid);
    
//check if selected listitem is right or wrong
    //'0'+listitem = makes listitem to character
    
if(('0'+listitem)!=arrTestQuestions[ansQuestCnt[pid]][6][0])ansQuestMistakes[pid]++;
    
//increasing question counter
    //if last question is answered it will show results
    
if(++ansQuestCnt[pid]==sizeof(arrTestQuestions)){
        if(
ansQuestMistakes[pid]){
            new 
s[25];
            
format(s,25,"You made %d mistakes.",ansQuestMistakes[pid]);
            
SendClientMessage(pid,-1,s);
        }else{
            
SendClientMessage(pid,-1,"Your answers were right.");
        }
    }else{
        
ShowTestQuestion(pid);
    }
    return 
1;


[Tutorial] The internals of switch and chained else ifs and which one should you use

$
0
0
The internals of switch and chained else ifs and which one should you use

This tutorial takes a look into how if and switch statements work on the assembly level and helps determine, where to use a switch and where to prefer chained else ifs. I decided to write this tutorial, because one of the topics I am about to address is a semi-common issue and currently there is no good place to refer to when it comes to it. In addition to that, the research I did for this tutorial helped me understand the AMX structure quite a bit more than I used to before.

The internals

I used the -a flag to generate the assembly of two simple snippets of code that perform the same task, one using switch and the other using chained else ifs. I also took the time to rewrite them in a more human-readable form (using variable names instead of raw addresses, named labels instead of numbered ones prefixed with l., etc.) and to document them. It is worth noting that while the rewritten assembly is valid, it does not currently compile due to a compiler bug related to forward jumps.

Chained else ifs

Code:

new val;

if (val == 1) {
    // do something here
} else if (2 <= val <= 4) {
    // do something here
} else {
    // do something here
}

For the sake of simplicity I used the form 2 <= val <= 4 instead of val >= 2 && val <= 4 for the range check. If written the other way, the code would use 7 jump instructions instead of 4 and keeping track of the instructions would be more difficult. It would also be a tiny bit slower since it would have to load the value of val to the primary register one more time.

When using chained else ifs, the assembly contains the AMX instructions for each individual check. If the check fails, it jumps to the next check, otherwise it jumps to the end of the chain. Here is the assembly equivalent to this code:

Code:

new val;


// if (val == 1)
#emit LOAD.S.pri    val        // load the value of val to the primary register
#emit EQ.C.pri      1          // compare the value in the primary register to constant 1: they must be equal; store the result in the primary register
#emit JZER          range      // if the result of the comparison is false, jump to "range" to perform the next check
// do something here
#emit JUMP          done        // everything is done, jump to "done"


// else if (2 <= val <= 4)
range:
#emit CONST.pri    2          // store the constant value 2 in the primary register
#emit LOAD.S.alt    val        // load the value of val to the alternate register
#emit SLEQ                      // compare the values in the registers to eachother: 2 (primary) must be less than or equal to val (alternate); store the result in the primary register
#emit PUSH.pri                  // load the value to the primary register (the result of the comparison) in the stack
#emit CONST.pri    4          // store the constant value 4 in the primary register
#emit SGEQ                      // compare the values in the registers to eachother: 4 (primary) must be greater than or equal to val (alternate); store the result in the primary register
#emit POP.alt                  // load the value of the first comparison from the stack to the alternate register
#emit AND                      // check if both of the comparisons were true by checking if both registers contain a non-zero value
#emit JZER          otherwise  // if the result of the comparison is false, jump to "otherwise"
// do something here
#emit JUMP          done        // everything is done, jump to "done"

// else
otherwise:
// do something here
// no jump needed since "done" is just after this code


done:

If the value of val is 1, the code uses four instructions:

Code:

LOAD.S.pri  val
EQ.C.pri    1
JZER        range ; the jump does not happen, but the instruction is still used
JUMP        done

If the value of val is 2, 3 or 4, the code uses 13 instructions:

Code:

LOAD.S.pri  val
EQ.C.pri    1
JZER        range
CONST.pri  2
LOAD.S.alt  val
SLEQ
PUSH.pri
CONST.pri  4
SGEQ
POP.alt
AND
JZER        otherwise ; the jump does not happen, but the instruction is still used
JUMP        done

If the value is not matched by any of the previous checks, the code uses 12 instructions:

Code:

LOAD.S.pri  val
EQ.C.pri    1
JZER        range
CONST.pri  2
LOAD.S.alt  val
SLEQ
PUSH.pri
CONST.pri  4
SGEQ
POP.alt
AND
JZER        otherwise

The longer your chain is and the more failed checks there are, the more instructions the code uses. Each failed single value check adds 3 instructions and each failed range check adds 9 instructions.

switch

Code:

new val;

switch (val) {
    case 1: {
        // do something here
    }

    case 2 .. 4: {
        // do something here
    }

    default: {
        // do something here
    }
}

When using switch, the compiler generates a case table that contains the value and jump address for every single case, including the default case. Here is the assembly equivalent to this code:

Code:

new val;


#emit LOAD.S.pri    val        // load the value of val to the primary register
#emit SWITCH        casetable  // jump to the case table

// case 1:
single:
// do something here
#emit JUMP          done        // everything is done, jump to "done"


range:
// do something here
#emit JUMP          done        // everything is done, jump to "done"


otherwise:
// do something here
#emit JUMP          done        // everything is done, jump to "done"


casetable:
#emit CASETBL
// default:
#emit CASE          4 otherwise // the amount of case table items; the jump address of "default"
// case 1:
#emit CASE          1 single    // the value and jump address of the case
// case 2 .. 4:
#emit CASE          2 range
#emit CASE          3 range
#emit CASE          4 range


done:

Whatever the value of val is 1, the code always uses just three instructions:

Code:

LOAD.S.pri  val
SWITCH      casetable
JUMP        done

The SWITCH instruction jumps to the case table, performs a linear search on the cases and jumps to the correct one. If the search does not find a matching case, it jumps to the default case instead. It is similar to the behaviour of chained else ifs, but since it is done in native code instead of using AMX instructions, the performance is a lot better.

When NOT to use switch?

Large ranges

As seen before, case tables can only use single values as cases, which means that if you use a range of 10000 elements in your switch, the compiler will have to write 10000 entries to the case table and the runtime will have to search through 10000 entries. Using the following benchmarking script I determined that the runtime performance of a case table becomes worse than the one of a single a <= x <= b check at around 30 entries.

Code:

#define MAX 30
#define ITERATIONS 1000000

new tick = GetTickCount();

for (new i; i < ITERATIONS; i++) {
    switch ((i % MAX) + 1) {
        case 1 .. MAX: {}
    }
}

printf("switch: %i", GetTickCount() - tick);


tick = GetTickCount();

for (new i; i < ITERATIONS; i++) {
    if (1 <= (i % MAX) + 1 <= MAX) {}
}

printf("if: %i", GetTickCount() - tick);

However, runtime performance is not the biggest issue. As seen from this forum topic, the amount of time it takes for the compiler to generate large case tables can be so long that it seems for the user that the compiler has ran into an infinite loop. Even ranges small enough to only have a small impact on the compilation time (for example, 1000 elements) can eventually make the compilation process painful if the delays stack up.

Floating point values

When using switch with floating point values, the case table must also contain every single value within the range. The step between two cases grows as the values grow, but it starts at the smallest possible floating point value in the IEEE754 specification, which is 1.4E-45. This means that each entry differs from the previous and next one by just 0.0000000000000000000000000000000000000000000014.

Some examples of ranges with the respective amounts of case table elements:

Code:

|                      Range                      | Amount of entries |
|---------------------------------------------------|-------------------|
| 0.0 .. 0.0000000000000000000000000000000000000001 |      71363      |
|                    1.0 .. 1.01                    |      83887      |
|                  10.0 .. 10.1                    |      104859      |
|                  100.0 .. 101.0                  |      131073      |
|                1000.0 .. 1010.0                  |      163841      |
|                10000.0 .. 10100.0                |      102401      |
|              100000.0 .. 101000.0                |      128001      |

This test should be enough to show that using switch with floating point values relevant in the context of SA-MP (coordinates, health, etc.) is completely unreasonable.

When to use switch?

I would say that everywhere where there are chains of comparisons against constant values. I have seen people saying that switch is faster no matter what and using a switch with two cases is much faster than an if-else. However, their runtime performance is about the same and where an if and an else make more sense, they should be used instead.

Tips and tricks

Using switch with floatcmp to compare floating point values

Comparison operators for variables with the Float tag are overloaded to use the floatcmp native instead of comparing them with AMX instructions. When comparing floating point values to eachother and having different outcomes depending of if one of the values is larger than the other or they are equal, you can save a floatcmp call by comparing them using switch instead. floatcmp returns 0 if the values are equal, 1 if the first value is larger and -1 if the second value is larger, so the following snippets of code are equivalent, but the second one performs better:

Code:

if (a > b) { // floatcmp called implicitly
    // a is larger than b
} else if (a < b) { // floatcmp called implicitly
    // a is smaller than b
} else {
    // a and b are equal
}

Code:

switch (floatcmp(a, b)) {
    case 1: {
        // a is larger than b
    }

    case -1: {
        // a is smaller than b
    }

    case 0: {
        // a and b are equal
    }
}

Using switch to compare strings

Comparing strings with strcmp has been notorious being both slow and tedious for a long time. Although most of that bad reputation came when ZCMD became the goto command processor and strcmp is still very useful elsewhere, there is a grain of truth in every joke. When comparing a string to a long chain of other strings, comparing their hashes would be more efficient and also convenient due to the ability to use switch, because the hashes are in the form of integers. The PAWN language does not support such thing natively, but y_stringhash from YSI does just the job. According to Y_Less’ tests, comparing strings using hashes becomes more efficient than using strcmp at around 10 comparisons. More information about y_stringhash and its usage can be found from this topic.

Code:

if (!strcmp(number, "one")) {

} else if (!strcmp(number, "two") || !strcmp(number, "three")) {

} else {

}

Code:

switch (YHash(number)) {
    case _H<one>: {

    }

    case _H<two>, _H<three>: {

    }

    default: {

    }
}

Credits
  • Yashas for the excellent AMX Assembly documentation.
  • Y_Less for reviewing the tutorial prior to me publishing it.
  • Users of the SA-MP Discord for productive conversations on this topic.

[Tutorial] Making Zone Systems With Textdraws

$
0
0
Hi Guys iam back again with a new Tutorial
To start We need PlayerZone.inc
And Lets Start

First:
1-Write
Code:

#include <PlayerZone>
In the top of your script
2-Write
Code:

new PlayerText:Zone[MAX_PLAYERS];
To make the id of the Textdraw
Second:
1-Write
Code:

public OnPlayerSpawn(playerid)
{
        Zone[playerid] = CreatePlayerTextDraw(playerid,11.000000,423.000000," ");
          PlayerTextDrawFont(playerid,Zone[playerid],1);
              PlayerTextDrawLetterSize(playerid,Zone[playerid],0.600000,2.000000);
              PlayerTextDrawTextSize(playerid,Zone[playerid],400.000000,17.000000);
              PlayerTextDrawSetOutline(playerid,Zone[playerid],1);
              PlayerTextDrawSetShadow(playerid,Zone[playerid],0);
              PlayerTextDrawAlignment(playerid,Zone[playerid],1);
              PlayerTextDrawColor(playerid,Zone[playerid],COLOR_WHITE);
              PlayerTextDrawSetProportional(playerid,Zone[playerid],1);
        PlayerTextDrawShow(playerid,Zone[playerid]);
        PlayerTextDrawLetterSize(playerid,Zone[playerid],0.600000,2.000000);
        PlayerTextDrawTextSize(playerid, Zone[playerid],400.000000,17.000000);
        PlayerTextDrawSetOutline(playerid,Zone[playerid],1);
        PlayerTextDrawSetShadow(playerid,Zone[playerid],1);
        PlayerTextDrawAlignment(playerid,Zone[playerid],1);
        PlayerTextDrawColor(playerid,Zone[playerid],COLOR_WHITE);
        PlayerTextDrawSetProportional(playerid,Zone[playerid],1)
              return 1;
}

To make the Textdraw
2-Make a time for the player when he spawns
Code:

SetTimerEx("Zones", 1, true, "i", playerid);
Under OnPlayerSpawn(playerid)

Third:
1-
Code:

forward Zones(playerid);
To define the public
2-
Code:

public Zones(playerid)
{
  new string[128];
  format(string,sizeof(string),"%s",GetPlayerZone(playerid));
  PlayerTextDrawSetString(playerid,Zone[playerid],string);
  return 1;
}

And Finaly to make the string for the textdraw

Then When you spawn in ur server you will found this textdraw and thanks.
Thanks for Luka P. for the include

[Tutorial] Menu Of Class & Team Selection

$
0
0
Hello,
I Want A Menu (With CreateMenu) That Contains The Class And Team Selection.

I've Done Something Like This:
Code:

new Menu:Team_m;


public OnGameModeInit()
{
        Team_m = CreateMenu("Entekhane Team", 2, 200.0, 100.0, 150.0, 150.0);
        AddMenuItem(Team_m, 0, "Tabriz");
        AddMenuItem(Team_m, 0, "Tehran");
        AddMenuItem(Team_m, 1, "[2 Nafar]");
        AddMenuItem(Team_m, 1, "[3 Nafar]");
        return 1;
}


public OnPlayerRequestClass(playerid, classid)
{
        ShowMenuForPlayer(Team_m, playerid);
        SpawnPlayer(playerid);
        return 1;
}


public OnPlayerSelectedMenuRow(playerid, row)
{
        new Menu:CurrentMenu = GetPlayerMenu(playerid);
        if(CurrentMenu == Team_m)
        {
                switch(row)
                  {
                          case 0: //Tabriz
                              {
                                TogglePlayerControllable(playerid,0);
                                SetPlayerPos(playerid,1068.5148,1884.1439,10.8203);
                                SetPlayerFacingAngle(playerid,-20);
                                SetPlayerSkin(playerid, 285);
                        }
                        case 1: //Tehran
                        {
                                TogglePlayerControllable(playerid,0);
                                SetPlayerPos(playerid,923.1006,2563.9233,10.804);
                                  SetPlayerFacingAngle(playerid,-20);
                                  SetPlayerSkin(playerid, 287);
                        }
                }
        }
        return 1;
}


public OnPlayerExitedMenu(playerid)
{
        TogglePlayerControllable(playerid,1);
        return 1;
}

But It Doesn't Teleport Me To Those Positions....


# And I Haven't AddPlayerClass

[Tool/Web/Other] Check the script for curly bracket mistakes (linux)

$
0
0
Hello samp-forum community,

I had some problems with curly brackets in the past. I read it also very often already, that people had to deal with these problems already.

I just created a tool for finding these curly bracket mistakes and I also tested it. It was really annoying for me to find these curly bracket mistakes. I found them relatively quickly because I know what I have done before etc. but it's better and easier if I use my little tool.

Example code (with the known problem):
Code:

if(ianduisnotme == 1)
{
    put some code in here
}
}

Example code (without the known problem):
Code:

if(ianduisnotme == 1)
{
    put some code in here
}

Use:
Code:

perl syncor.pl -f <file.pwn>
Code:

DL-Link (v. 2): https://drive.******.com/open?id=1qqUwARwxFQQuD7yMtXadxg4MZIGHgnaL


Have fun and enjoy the future without doing a long long search for the curly bracket mistake!

Note: I have to add something for the 2nd cases which I added (Y_Less asked me it). I'm going to delete this note if I'm done with adding it.

-Doddinger

PS. If you have any suggestions, simply write them down and reply here.

[Tutorial] How to fix : ("I couldn't load any gamemode scripts. Please verify your server.cfg")

$
0
0
How to Fix

I couldn't load any gamemode scripts. Please verify your server.cfg


Hello Guys,
I'm G3ORG3, I am a scripter and pawno is kinda easy for me.
This is the error you will get while starting the server!
Quote:

Originally Posted by server-logs.txt
[07:46:03] I couldn't load any gamemode scripts. Please verify your server.cfg
[07:46:03] It needs a gamemode0 line at the very least

READ THIS - IMPORTANT:
[•] Make sure your gamemode name doesnot have dashes and other stuffs. (EG: "-","/","#","!","+","_")
[•] Make sure that your file that contains the gamemode has been named as "gamemodes"
[•] Make sure you gamemode script is compiled and contains ".amx" file.

There are many ways to fix this!

The First Step
Quote:

If you got the following error. You will have to open "server.cfg"

You will see something like this:
PHP Code:

echo Executing Server Config... 
lanmode 1 
rcon_password 
************* 
maxplayers 100 
port 7777 
hostname YourServerName
gamemode0 YourGameModeName
filterscripts YourFilterScripts
announce 1 
plugins YourPlugins
query 1 
chatlogging 0 
weburl 
onfoot_rate 40 
incar_rate 40 
weapon_rate 40 
stream_distance 700.0 
stream_rate 1500 
maxnpc 2 
logtimeformat 
[%H:%M:%S

The Reason for the error:
This Error appears because you have not typed the gamemode name in the "gamemodes" file in your script files and No variable typed for your gamemode

Fixed :
You should type the correct name and then, type "1" in front of it!

Example
PHP Code:

echo Executing Server Config...  
lanmode 1  
rcon_password 
*************  
maxplayers 100  
port 7777  
hostname 
gamemode0 YourGameModeName 1
filterscripts 
announce 1  
plugins YourPlugins 
query 1  
chatlogging 0  
weburl  
onfoot_rate 40  
incar_rate 40  
weapon_rate 40  
stream_distance 700.0  
stream_rate 1500  
maxnpc 2  
logtimeformat  
[%H:%M:%S

If those are correct, the next step
The Second Step
Quote:

Sometimes, That happens because you don't have compiled it. If you don't compile it. The .amx file will not be appeared.

Fixed

You should compile it(.pwn file)!

If those good, step to 3rd
The Third Step
Quote:

The gamemode script is needed to be in the "gamemodes" folder. It must contain the .pwn and the .amx file.
And if that Folder is named as "gamemode", that will make this error!

Fixed


Change the "gamemode" folder nams to "Gamemodes"

---------------------------

Okay, Guys! If you have any problem with this, contact me

Discord : @TR3DI3T3R#1951

Don't forget to repute me if this is helpful for you!

[Tutorial] How to add custom models without RESTART (The base)

$
0
0
So you have seen some servers like LSRP add models ingame without restart? It's not a miracle. I thought at first it was using Pawn.Raknet and sending ModelData and ModelFile RPC's but I found we cannot calculate the RPC using some SAMP function as there is none for it. Turns out, all you have to do is:

AddCharModel OR AddSimpleModel
and then SetPlayerVirtualWorld.

Now, basically what you could do is add all the char models or from a array / using a command. And once all are done, you can setallplayer's virtual world to 999 then back to where they were under onplayerfinisheddownloading.

I'm not going to make a detailed tutorial for this because I only wanted to share this piece of information, sorry if the prefix is misguiding but I did give you the idea.


Here's some sample code:
Code:

new g_ModelsAwaiting = 0;
new p_OldWorld[MAX_PLAYERS] = { 0 };

CMD:addskin(playerid, params[])
{
        new
                skinID,
                baseID,
                skinName[32];
               
        if(sscanf(params, "dds[32]", skinID, baseID, skinName)) return SendClientMessage(playerid, 0xFF0000FF, "/addskin [skinID e.g. 20001] [baseID e.g. 299] [skin name, e.g. wmori]");
       
        new
                txd[32 + 4],
                dff[32 + 4];
               
        format(txd, sizeof txd, "%s.txd", skinName);
        format(dff, sizeof dff, "%s.dff", skinName);
       
        if(AddCharModel(baseID, skinID, dff, txd))
        {
                g_ModelsAwaiting++;
                SendClientMessage(playerid, 0x00FF33FF, "Done! To reload all models, type /reloadmodels to have them all downloaded.");
        }
        else SendClientMessage(playerid, 0xFF0000FF, "Failed! Make sure you did not include .dff or .txd in name and the files are present.");
       
        return 1;
}

public OnPlayerFinishedDownloading(playerid, virtualworld)
{
    if(p_OldWorld[playerid] != 0 && virtualworld == 420)
        {
                SetPlayerVirtualWorld(playerid, p_OldWorld[playerid]);
                p_OldWorld[playerid] = 0;
        }
    return 1;
}

CMD:reloadmodels(playerid)
{
        if(!g_ModelsAwaiting) return SendClientMessage(playerid, 0xFF0000FF, "No models are awaiting reload.");
       
        for(new p = 0, m = GetPlayerPoolSize(); p <= m; p++)
        {
                p_OldWorld[p] = GetPlayerVirtualWorld(p);
                SetPlayerVirtualWorld(p, 420);
        }
        SendClientMessageToAll(0x00FF33FF, "An administrator has reloaded all the models.");
        return 1;
}

Obviously this isn't foolproof, I just gave an example.

Credits: Me (KevY)

[Tutorial] How To Press 'ESC' Close Textdraw

$
0
0
Hello every body , im from Viet Nam


I don't know if this problem has been solved successfully, but the question "How to turn off textdraw with the Esc key" currently has no explanation.

So I share with the community how to turn it off as easily as possible for those who don't know it.

Take a look at my code below

PHP Code:

function showtextdraw(playerid){
     
TextDrawShowForPlayer(playeridTD[1]);
     
setPVarInt(playerid,"checkTD"1); // look here
}
 
OnPlayerClickTextDraw(playerid,Text:clickedid){
    if(
GetPVarInt(playerid"checkTD") == 1){ // look here
       
if(clickedid == Text:INVALID_TEXT_DRAW) { 
             
TextDrawHideForPlayer(playeridTD[1]);
       }
    }


I marked // look here at the point you need to pay attention, usually if you only use: Text: INVALID_TEXT_DRAW then your ESC button is not used to turn off Textdraw, please use 1 link for these 2 things. Thank you for reading my article, goodbye and see you again

Please sympathize because my english is not good.

[GameMode] Giới thiệu một vài nhà cái uy tín nhất hiện nay 2019

$
0
0
Lô đề online, Cá độ bóng đá, Casino trực tuyến… Đây là những điều mà các bạn quan tâm? Cá cược online tổng thể hiện đang là trào lưu. Cách thức làm việc phê chuẩn internet, chuyển tiền và nhận tiền mau chóng bắt kịp thời đại và quản lý tiền một cách tốt nhất. Hiện nay có hàng chục nhà cái đang phát triển các nhà cung cấp này. Vậy đâu là doanh nghiệp uy tín nhất để bạn có thể đầu cơ vốn để cá cược và thu lợi nhuận cao? Chúng tôi sẽ giúp các bạn Tìm hiểu các chỉ tiêu để Tìm hiểu các nhà cái hàng đầu châu âu. đặc biệt l
Top những nhà cái uy tín nhất hiện nay 2019[/b]
Vậy đâu là tổ chức uy tín nhất để các bạn có thể đầu cơ vốn để cá cược và thu lợi nhuận cao? Chúng tôi sẽ giúp bạn Đánh giá các tiêu chí để Nhận định các nhà cái uy tín. đặc thù là giúp bạn tìm kiếm các nhà cái trực tuyến uy tín nhất hiện nay.
Điều kiện, tiêu chí để được xem là một nhà cái uy tín[/b]
Để giúp bạn xác định đâu là nhà cái uy tín. Chúng tôi đưa ra một số tiêu chuẩn dưới đây. các bạn tham khảo để sử dụng làm mục tiêu Phân tích các casino trực tuyến, phân phối lô đề, bóng đá online trước khi tham gia nhé.
  • Nhà cái uy tín phải đảm bảo được tỷ lệ cá cược cao. trong khoảng bóng đá, lô đề đều phải đảm bảo cạnh tranh tốt với tỷ lệ cá cược của đa dạng nhà cái khác.



    Chuyển tiền về account của người thắng cá cược mau chóng.



    Các nhà cái uy tín số một Việt Nam đều có thể bảo đảm tốt cho bạn việc bảo mật thông tin cá nhân.



    Giao diện đẹp, gần gũi, load nhanh và không gặp bất cứ một lỗi nào trong quá trình tham dự chơi và cá cược.



    Số lượng thành viên online đông và đăng ký thành viên phổ quát.



    cung ứng số đông các thể loại từ casino online, cá độ bóng đá, soi kèo bóng đá, soi cầu lô đề…
Để mua được nhà cái uy tín tại việt nam đòi hỏi bạn phải bỏ thời gian để Nhận định các website hoặc trải nghiệm các dịch vụ trong khoảng phổ thông nhà cái không giống nhau. Để giúp bạn tiết kiệm được thời kì, chúng tôi sẽ cung ứng tới các bạn những nhà cái phân phối tốt nhất và uy tín nhất hiện nay.
1 số nhà cái cá cược trực tuyến uy tín nhất hiện nay[/b]
Chúng tôi đã điều tra hàng chục nhà cái không giống nhau và kiếm tìm cho các bạn 3 nhà cái cá cược trực tuyến thuộc Top đầu hiện nay. tham dự vào các nhà cái này quý vị có thể an tâm hoàn toàn về việc bảo mật thông báo, đa dạng dịch vụ tiêu khiển và cá cược, tỷ lệ cá cược…
[img]https://lh5.******usercontent.com/v2_qhU3g7KkiFecnH7TpkpMNFuBmAP2HKInERrdGcVzp_1Lcl6 sk_uX3N0N-q6rAgx7Qit_wJM_8Z2iaBVrM7iYVve3QfbfqLuGjUmTWILo2vz U0aiu2vma6hDiMk81crez0umeJ[/img]
Nhà cái tinycat99[/b]
Nhà cái uy tín số một Việt Nam tinycat99 được biết đến là đơn vị sản xuất các dịch vụ cá cược nổi danh nhất Châu Á. Tinycat99 cung ứng cho bạn số đông các dịch vụ. chẳng hạn như: Lô đề online, Cá độ bóng đá, Casino trực tuyến.... Không những thế các nhà sản xuất miễn phí như soi kèo Tìm hiểu bóng đá, soi cầu lô đề miễn phí, giải mã giấc mơ… tất cả đều tương trợ tốt nhất cho nhu cầu đánh đề, cá cược tỷ số bóng đá và đánh bài trên mạng ăn tiền thật của quý vị và các bạn.
tinycat99 đem lại cực nhiều lợi ích cho người chơi. Với tỷ lệ cá cược cao và đăng ký tài khoản tinycat99 nhận quà giúp người chơi gia tăng xác suất trúng thưởng to và thêm rộng rãi kinh phí phụ lúc cá cược.
Đăng ký account tinycat99 cũng rất đơn giản. các bạn chỉ cần tầm nã cập vào tinycat99 và làm theo hướng dẫn thôi nhé. Mọi thao tác đều nhanh chóng và được tương trợ tới “tận răng”. nếu bạn muốn soi kèo bóng đá và soi cầu lô đề với khả năng thành công cao, hãy đăng ký thành viên tại tinycat99. ví như bạn muốn win100% với tỷ lệ trúng thưởng cao, sẽ không đâu vào đâu cung cấp cho các bạn tốt hơn tinycat99. Chúng tôi sẽ giúp các bạn Nhận định các thông báo đăng ký thành viên ở mục riêng cuối bài viết nhé.
Nhà cái w88[/b]
mặc dầu quy mô và sự chuyện nghiệp, uy tín không thể so sánh bằng tinycat99, nhưng vẫn là Top đầu uy tín so với rộng rãi nhà cái khác. đơn vị này cũng cung cấp đầu đủ các dịch vụ như: casino online ăn tiền thật, thể thao cá độ bóng đá, cá cược lô đề. Giao diện của nhà cái này cũng thời trang, lướt web nhanh, bảo mật thông báo tốt. Sau nhà cái tinycat99 thì đây là một trong những địa chỉ cá cược trực tuyến uy tín mà các bạn không nên bỏ qua.

Nhà cái fb88[/b]
Sánh cộng với sự uy tín của nhà cái tinycat99 và w88 chính là nhà cái FB88. Nhà cái này nổi danh với bóng đá và casino online. các bạn muốn đánh bài trên mạng ăn tiền thật, cá cược bóng đá an toàn thì bạn không nên bỏ qua nhà cái này nhé.
Để giảm thiểu quý vị bị mắc lừa và gặp phải nhà cái ăn gian chúng tôi đã dành thời kì trải nghiệm cả 3 nhà cái trên. Nhà cái tinycat99, Nhà cái w88, Nhà cái FB88 là 3 nhà cái cung cấp nhà cung cấp cá cược trực tuyến to nhất tại Việt Nam. Người chơi tham dự về lĩnh vực này nên Tìm hiểu về 3 nhà cái này nhé. Trong giai đoạn bát nháo thị phần như hiện nay, nhà cái trực tuyến mọc lên như nấm.
chú ý[/b]
Sau khi đăng ký thành viên thành công, các bạn nên đăng nhập account để xem tài khoản của mình đã hoạt động chưa nhé. đặc biệt là chính sáchđăng ký account tinycat99 nhận quà sẽ giúp bạn có thêm tiền và đa dạng phần thưởng lớn.
bạn cũng nên chú ý đến các trang web chính thức của tinycat99 để hạn chế bị lừa trong công đoạn bát nháo công ty sản xuất nhà sản xuất cá cược online như hiện nay nhé.
trợ thì kết[/b]
Hy vọng với những thông tin trên chúng tôi đã giúp quý vị tiết kiệm thời gian kiếm tìm nhà cái trực tuyến. Hiện tinycat99 là liên hệ soi cầu lô đề, giải mã giấc mơ, soi kèo bóng đá uy tín. đơn vị này cũng sở hữu được lượng thành viên đầy đủ đang thực hiện chơi lô đề online, cá cược bóng đá online, chơi bài trực tuyến ăn tiền thật. Chúc quý vị và bạn tiêu khiển và cá cược may mắn trên nhà cái uy tín nhất chỉ cần khoảng đến.
Viewing all 106 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>