Raised This Month: $12 Target: $400
 3% 

Small scripting tutorials, and how to fix some common errors


Post New Thread Closed Thread   
 
Thread Tools Display Modes
Author Message
devicenull
Veteran Member
Join Date: Mar 2004
Location: CT
Old 08-01-2004 , 14:38   Small scripting tutorials, and how to fix some common errors
#1

Last Update: August 01, 2004 01:44:16 PM
Note: PM me with comments.
Note2: If you have a tutorial you want posted here, PM me with it
So you want to start creating plugins.
By the time you get here, I assume you know how to compile plugins, the basic syntax of some small commands, and how to declare variables. If you don't know either, I suggest you read some more before you get here.

Here are some good things to read to get the basics of Pawn:
Tutorial #1 Introduction to Pawn
Tutorial #2 Intro to AMX Mod X Scripting
Tutorial #3 Pawn Tutorial
Pawn Language Documentation (PDF) *Note: This is a little more advanced, I suggest reading it after you learn the basics

Tutorials in this thread:
Basic Scripting Tutorial (devicenull)
SQL Scripting Tutorial (devicenull)

Some common errors, and how to fix them.
Error: I get no errors, but I get a 0kb output file, and/or the compiler crashes
Solution: Somewhere in your code, you forgot to close something. This is usually caused by forgetting to put a " at the end of text, but it can also be caused by forgetting a ) or }

Error: warning 202: number of arguments does not match defintion
Solution: On the line it says, you don't have enough paramaters. You forgot to put something in, and the compiler noticed. Just go to that line, compare the command you used to the one in the include file. It might be something as simple as you put a period instead of comma.

Error: error 035: argument type mismatch (argument X)
Solution: One of your arguments is the wrong type. This usually happens when the command is expecting a float, and you gave it an integer (I didn't go over floats here, they can be annoying). Or it could be the command expected a string, and you gave it an integer.

Last edited by Xanimos; 02-02-2007 at 02:47. Reason: Updating the old information.
devicenull is offline
devicenull
Veteran Member
Join Date: Mar 2004
Location: CT
Old 08-01-2004 , 15:40  
#2

Let's start off with how to get some arguments from the commandline. We will create a basic amx_kick plugin.
Here's the code for it, I will explain it after.
Code:
#include <amxmodx> public plugin_init() {     register_plugin("Amx-Kick","0.1","devicenull")     register_concmd("amx_kick2","do_kick",ADMIN_KICK," user Kicks the specified user") } public do_kick(id) {     if (!(get_user_flags(id)&ADMIN_KICK)) {         console_print(id,"[AMXX] No access")         return PLUGIN_HANDLED     }     if (read_argc() == 0) {         console_print(id,"[AMXX] You must specify a user")         return PLUGIN_HANDLED     }     new user[32], uid     read_argv(1,user,32)     uid = find_player("bh",user)     if (uid == 0) {         console_print(id,"[AMXX] Invalid User Id")         return PLUGIN_HANDLED     }     client_cmd(uid,"echo Kicked from server!")     client_cmd(uid,"disconnect")     console_print(id,"Kicked player!")     return PLUGIN_HANDLED }

Code:
#include <amxmodx>
The first thing I do is include a file called "amxmodx.inc". This file contains basic commands for working with players, and is included in every plugin. Open this file up, its located in amxx\scriping\include. As you can see, every command in it is documented. There are different includes you can use in addition to this one, if you are working with other modules, like engine or cstrike.

Code:
public plugin_init() {     register_plugin("Amx-Kick","0.1","devicenull")     register_concmd("amx_kick2","do_kick",ADMIN_KICK," user Kicks the specified user") }
In register_plugin, I tell AmxX the name of my plugin, the version, and the author name. This line is in almost every plugin, except for some very very small ones. Its a good idea to put this line in your plugins.
Next, in register_concmd, I tell AmxX that I am creating a new command called "amx_kick2", that it should call "do_kick" when a client uses this command. It also specifys the access level needed (ADMIN_KICK) and the help for the command. You almost always have several of these, and there are different types:
  • register_srvcmd() - This is used for commands that are only done in the server console (And over RCON)
  • register_clcmd() - This is used for commands that are only done on clients
  • register_concmd() - This is used for commands that can be done anywhere

Code:
public do_kick(id) {
This is the code that will be executed for amx_kick2. The variable id is the id of the player that called this command. It is a number from 1-32, representing a slot on the server. This is the first number you see in a "status" display.

Code:
if (!(get_user_flags(id)&ADMIN_KICK)) {     console_print(id,"[AMXX] No access")     return PLUGIN_HANDLED }
This bit of code is used to make sure the player has the correct access. There are a few different ways of doing this, and this is the one that seems simplest to me. I could explain how it works, but its really not that important to know. If the player does not have the correct access, "[AMXX] No access" is printed to their console, and the "return PLUGIN_HANDLED" stops code execution

Code:
if (read_argc() == 0) {     console_print(id,"[AMXX] You must specify a user")     return PLUGIN_HANDLED }
Here we check if they executed the command correctly, it needs to have a user after it (amx_kick2 Username). If it doesn't, we can't kick anyone, because we don't know who to kick. read_argc() returns the number of arguments after the command. If there are no arguments, then it prints "[AMXX] You must specify a user", and we stop code execution.

Code:
new user[32], uid
Here we declare two variables, an array named user, and an integer named uid. Arrays are used to hold strings in small.

Code:
read_argv(1,user,32)
With this command, we get the first argument of the command, and put it into the user variable. The maximum length of the argument that we would get is 32 characters.

Code:
uid = find_player("bh",user)
With this, we take the argument, and try and match it to a username. The "bh" means Ignore bots and find users with the given part of the name.

Code:
    if (uid == 0) {     console_print(id,"[AMXX] Invalid User Id")     return PLUGIN_HANDLED }
This makes sure that the user we found was an actual user. It works just like the other checks we did above.

Code:
client_cmd(uid,"echo Kicked from server!") client_cmd(uid,"disconnect")
Here, we execute two commands on the targets computer. One echos "Kicked from server!" into their console, the other disconnects them from the game. There are many ways to kick clients, this is one of the simpler ones.

Code:
console_print(id,"Kicked player!")
This prints a message to the client that kicked the player, telling them that the player was kicked.

Code:
    return PLUGIN_HANDLED }
This halts code execution.

A note, the "return PLUGIN_HANDLED" prevents Half life from displaying "Command not found".
devicenull is offline
devicenull
Veteran Member
Join Date: Mar 2004
Location: CT
Old 08-01-2004 , 15:41  
#3

NOTE: THIS IS AN OLD VERSION OF SQL, USE SQLX INSTEAD
So, you want to learn how to use SQL in AmxX plugins?
To do this, you need the following things
  • You need to know the SQL commands, I can't teach you the basics of using it, if you don't understand SQL
  • You need to know small. I won't be explaining things other then the SQL commands.

Note: This tutorial is going to be using the 0.20 version of SQL, not the 0.16 version. You can get the include file to look at it from the CVS.

And the plugin I will be explaining:
A note: In the interest of clarity, I don't tell the user why the plugin didn't work
Code:
#include <amxmodx> #include <dbi> new Sql:dbc new Result:result public plugin_init() {     register_plugin("SQL-Tut","0.1","devicenull")     register_concmd("sql_insert","sql_insert",ADMIN_KICK," <value> Inserts a value into our table")     register_concmd("sql_display","sql_display",ADMIN_KICK," Displays values")     set_task(Float:10.0,"sql_init") } public sql_init() {     new host[64], username[32], password[32], dbname[32], error[32]     get_cvar_string("amx_sql_host",host,64)     get_cvar_string("amx_sql_user",username,32)     get_cvar_string("amx_sql_pass",password,32)     get_cvar_string("amx_sql_db",dbname,32)     dbc = dbi_connect(host,username,password,dbname,error,32)     if (dbc == SQL_FAILED)         log_amx("[AMXX] SQL Connection Failed")     else         dbi_query(dbc,"CREATE TABLE IF NOT EXISTS `tutorial` ( `value` VARCHAR(32) NOT NULL )") } public sql_insert(id) {     if (dbc == SQL_FAILED)  return PLUGIN_HANDLED     if (!(get_user_flags(id)&ADMIN_KICK))   return PLUGIN_HANDLED     if (read_argc() == 0) return PLUGIN_HANDLED         new arg[32]     read_argv(1,arg,32)     result = dbi_query(dbc,"INSERT INTO tutorial VALUES ( '%s' )",arg)     if (result == RESULT_OK) dbi_free_result(result)     if (result == RESULT_FAILED) return PLUGIN_HANDLED     new dbitype[32]     dbi_type(dbitype,32)     console_print(id,"[SQL] Inserted value into %s table succesfully",dbitype)     return PLUGIN_HANDLED } public sql_display(id) {     if (dbc == SQL_FAILED)  return PLUGIN_HANDLED     if (!(get_user_flags(id)&ADMIN_KICK))   return PLUGIN_HANDLED         result = dbi_query(dbc,"SELECT * FROM tutorial WHERE 1 LIMIT 5")     new value[32]     for (new i=1;i<=dbi_num_rows(result);i++) {         dbi_nextrow(result)         dbi_result(result,"value",value[32])         console_print(id,"Value: %s",value)     }     dbi_free_result(result)     return PLUGIN_HANDLED }

This really isn't that hard to explain..

Code:
new Sql:dbc new Result:result
Data base connections are the type Sql, results are type Result

Code:
dbc = dbi_connect(host,username,password,dbname,error,32)
Connects to the DB.. get the proper values out of the cvars.. you can just copy the entire init_sql() sub and use it where ever you want

Code:
if (dbc == SQL_FAILED)
Makes sure we actually connected to the database, you can use dbi_error to get the error message if there is one

Code:
result = dbi_query(dbc,"INSERT INTO tutorial VALUES ( '%s' )",arg)
Does the insertion query, and puts a link to the result in the result variable, you could just do the dbi_query part for insert/delete/update, and not worry about what it returns

Code:
dbi_free_result(result)
You must do this when the returned variable is RESULT_OK, otherwise you get memory leaks, and memory leaks = BAD

Code:
dbi_type(dbitype,32)
Get the type of database you are using.. I really haven't thought of a use for this yet, but its here.

Code:
dbi_num_rows(result)
Returns the number of rows that are in the result.

Code:
dbi_nextrow(result)
Advances to the next row in result.

Code:
dbi_result()
This is kind of annoying. Depending on the datatype expected, you have to use this differently.
Expecting: Use:
Int var = dbi_result(result,"fieldname")
Float dbi_result(result,"fieldname",Float:var)
String dbi_result(result,"fieldname",var,len)

Also, dbi_field() works the same way, with the field number instead of the field name

Code:
dbi_close(dbc)
This would close the sql connection, its not needed unless you create a sql connection and close it in the same sub (Don't do that unless you have to, using one connection for the entire plugin is more efficient). Dbi connections are closed before plugin_end.

You can get most of this from reading the include file, but some of it is a bit annoying to figure out

Last edited by devicenull; 04-14-2007 at 03:30.
devicenull is offline
Closed Thread


Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -4. The time now is 06:26.


Powered by vBulletin®
Copyright ©2000 - 2024, vBulletin Solutions, Inc.
Theme made by Freecode