Counter - Strike Raid Attack V1

Một bản mod của nhóm SKIN COUNTER - STRIKE

CS - AVA ( Alliance of Valiant Arms )

Bản Mod được phát triển bởi AVG4 theo hướng AVA

CSFIRED

CSFIRED một thể loại game bắn súng offline được mod theo hướng CrossFire (Đột kích) với hình ảnh sắc nét, âm thanh sống động tạo cho người chơi cảm giác như mình đang sống trong thế giới ảo

Counter Strike he Magic Athletics CD 1.0.0.2

Game do Trung Quốc làm. Dựa trên nền tảng Compete King.

Counter Strike CE

Game do Trung Quốc làm. Đang rất hot trên Group SKIN COUNTER - STRIKE

Counter-Strike NTN 2014

Counter-Strike NTN là một bản mod của Counter-Strike 1.6 huyền thoại, được mod lại với mục đích cải thiện chất lượng đồ họa và âm thanh cũng như hệ thống vũ khí Counter-Strike 1.6 với đặc điểm nổi bật.

Saturday, May 31, 2014

Modules and efficient scripting - Mô-đun và kịch bản hiệu quả


Hướng dẫn này là dành cho tất cả các scripters arround amxx, đề nghị cho scripters trung gian.

Một plugin hiệu quả là đầu tiên của tất cả những gì?
Một plugin hiệu quả là sử dụng ít CPU và bộ nhớ.

Hãy để tôi đưa ra một ví dụ:
Chúng ta hãy cố gắng nghĩ ra một phương pháp để xem thời tiết một người chơi đã bị giết chết. Phương pháp này có thể được thực hiện nhiều cách khác nhau nhưng tôi sẽ chỉ ra 2 trong số họ, một tốt và một xấu.

Một trong những tốt là khi chúng ta nối các sự kiện DeathMsg
PHP Code:
register_event("DeathMsg""event_death""a")

public 
event_death()
{
    new 
attacker read_data(1)
    new 
victim read_data(2)

}  
Một xấu là chúng ta sử dụng PreThink và kiểm tra các người chơi đã bị giết, trong phương pháp này, tôi sẽ sử dụng các mô-đun engine
PHP Code:
public client_PreThink(id)
{
    if (!
is_user_alive(id))
    {
        new 
attacker get_user_attacker(id)
    }
}  
Những gì vấn đề hiệu quả * chúng ta có ở đây?
Vâng vấn đề là PreThink được gọi là> 30 lần mỗi giây và điều đó có nghĩa rằng chúng tôi đang kiểm tra quá nhiều lần người chơi đã bị giết chết. Đây là một vấn đề bởi vì nó sẽ gây ra rất nhiều sử dụng CPU, một vấn đề mà các máy tính nhỏ không thể xử lý. Bởi rất nhiều sử dụng CPU có nghĩa là chúng tôi sẽ có rất nhiều lag.

Chúng ta hãy một lần nữa cho một ví dụ tốt hơn inefficency nhưng một subtile hơn.
Chúng ta hãy cố gắng hook các sự kiện DeathMsg và nhận được tất cả các thông tin mà chúng tôi cần.
Đây là phương pháp tốt nhất của việc lấy các thông tin chúng ta cần là trong ví dụ đầu tiên. Điều thứ hai sẽ sử dụng quá nhiều hàm trong trường hợp này là không cần thiết ...
PHP Code:
register_event("DeathMsg""event_death""a")

public 
event_death()
{
    new 
attacker read_data(1)
    new 
victim read_data(2)
    new 
weapon_name[33],weapon_id
    
// get the weapon name
    
read_data(4,weapon_name,32)
    
format(weapon_name,32,"weapon_%s",weapon_name)
    
weapon_id get_weaponid(weapon_name)
}  
PHP Code:
register_event("DeathMsg""event_death""a")

public 
event_death()
{
    new 
victim read_data(2)
    new 
attacker get_user_attacker(victim)
    new 
weapon get_user_weapon(attacker)
}  
Những vấn đề hiệu quả * chúng ta có ở đây? 
Vâng vấn đề là cho đến khi tất cả các forwards event_death sẽ được gọi là, các dữ liệu mà chúng tôi có sẽ được lưu trữ trong lõi, và nó sẽ được truy cập thông qua read_data () chức năng. Vì vậy, trong trường hợp này là không cần thiết để truy cập vào các công cụ một lần nữa để có được thông tin này từ cốt lõi đã chuẩn bị cho chúng tôi.

Các mô-đun hiệu quả nhất là gì? 
Vâng câu hỏi này phụ thuộc vào những điều bạn muốn làm trong một plugin. 
Hầu hết mọi người nói rằng FakeMeta là module tốt nhất arround nhưng nó không phải là hiệu quả nhất! Module này sử dụng rất nhiều CPU bởi vì cơ sở dữ liệu lớn của chức năng mà nó cung cấp. Cho câu hỏi này là câu trả lời: tất cả các mô-đun có những điều tốt đẹp để cung cấp, chúng ta phải sử dụng các chức năng đặc biệt được cung cấp bởi mỗi mô-đun.

Điều đó có nghĩa là khi chúng ta có thể làm một điều trong engine hoặc fun, ham nó sẽ là tốt nhất để sử dụng engine / fun / ham thay vì fakemeta do rất nhiều sử dụng CPU. 
Tôi sẽ cung cấp cho bạn một ví dụ. 

Nếu chúng ta sử dụng fm_is_in_viewcone, tôi sẽ đánh dấu những nơi mà các plugin liên lạc với các mô-đun:
PHP Code:
stock bool:fm_is_in_viewcone(index, const Float:point[3]) {
    new 
Float:angles[3];
    
pev(indexpev_anglesangles); // COMUNICATION WITH MODULE
    
engfunc(EngFunc_MakeVectorsangles); // COMUNICATION WITH MODULE
    
global_get(glb_v_forwardangles); // COMUNICATION WITH MODULE
    
angles[2] = 0.0;

    new 
Float:origin[3], Float:diff[3], Float:norm[3];
    
pev(indexpev_originorigin); // COMUNICATION WITH MODULE
    
xs_vec_sub(pointorigindiff);
    
diff[2] = 0.0;
    
xs_vec_normalize(diffnorm);

    new 
Float:dotFloat:fov;
    
dot xs_vec_dot(normangles);
    
pev(indexpev_fovfov); // COMUNICATION WITH MODULE
    
if (dot >= floatcos(fov M_PI 360))
        return 
true;

    return 
false;
}  
Trong chức năng này, chúng ta thấy 5 Liên lạc với các mô-đun.

Khi chúng ta sử dụng engine ví dụ:
PHP Code:
is_in_viewcone entityFloat:origin[3] ) // COMUNICATION WITH MODULE  
Chúng tôi chỉ có một liên lạc với các mô-đun.

Đây là những gì sẽ xảy ra khi chúng tôi sử dụng fakemeta:
PLUGIN -> FAKEMETA -> METAMOD -> GAME ENGINE -> METAMOD -> FAKEMETA -> PLUGIN

Nhân với 5 lần và chúng ta sẽ thấy thời gian thực hiện của fm_is_in_viewcone. 

Đây là những gì sẽ xảy ra khi chúng tôi sử dụng mô-đun engine:
PLUGIN -> ENGINE -> METAMOD -> GAME ENGINE -> METAMOD -> ENGINE -> PLUGIN
Chỉ có một lần.
Nó cũng phụ thuộc vào dữ liệu chúng tôi muốn nhận hoặc thiết lập.

Đây là lý do tại sao trong một số trường hợp chúng ta nên sử dụng fun hoặc engine hơn fakemeta. Chúng không sử dụng nhiều CPU và có sử dụng bộ nhớ thấp trong tình huống này.
Để xác nhận những gì tôi đã nói về Liên lạc module tôi sẽ trả lời ở đây một số tiêu chuẩn sẽ so sánh fakemeta với các mô-đun cstrike và engine mô-đun natives / stocks. Bạn sẽ thấy rằng điều này làm cho sự khác biệt.

Entity_set_origin vs. fm_entity_set_origin [fakemeta vs engine]
Code:
type |                             name |      calls | time / min / max
-------------------------------------------------------------------
   n |                  register_plugin |          1 | 0.000008 / 0.000008 / 0.000008
   n |                   register_clcmd |          1 | 0.000017 / 0.000017 / 0.000017
   n |                     random_float |      60000 | 0.134438 / 0.000001 / 0.000116
   n |                       server_cmd |          1 | 0.000006 / 0.000006 / 0.000006
   p |                      plugin_init |          1 | 0.000010 / 0.000010 / 0.000010
   p |                          profile |          1 | 0.182920 / 0.182920 / 0.182920
   
   n |                entity_set_origin |      10000 | 0.035055 / 0.000002 / 0.000082
   
   n |                              pev |      20000 | 0.044686 / 0.000001 / 0.000183
   n |                          engfunc |      20000 | 0.052677 / 0.000002 / 0.000073
   f |             fm_entity_set_origin |      10000 | 0.113504 / 0.000008 / 0.000373
0 natives, 0 public callbacks, 2 function calls were not executed.
Fm_is_in_viewcone vs is_in_viewcone. [fakemeta vs engine]
Code:
type |                             name |      calls | time / min / max
-------------------------------------------------------------------
   n |                       server_cmd |          1 | 0.000008 / 0.000008 / 0.000008
   p |                      plugin_init |          1 | 0.000007 / 0.000007 / 0.000007
   p |                          profile |          1 | 0.112695 / 0.112695 / 0.112695
   n |                  register_plugin |          1 | 0.000004 / 0.000004 / 0.000004
   n |                   register_clcmd |          1 | 0.000016 / 0.000016 / 0.000016
   
   n |                      floatsqroot |      10000 | 0.022363 / 0.000001 / 0.000038
   n |                         floatdiv |      10000 | 0.022110 / 0.000001 / 0.000036
   n |                              pev |      30000 | 0.067148 / 0.000001 / 0.000086
   n |                          engfunc |      10000 | 0.025055 / 0.000001 / 0.000011
   n |                       global_get |      10000 | 0.022244 / 0.000001 / 0.000031
   n |                         floatcos |      10000 | 0.022657 / 0.000001 / 0.000209
   n |                     random_float |      30000 | 0.066903 / 0.000001 / 0.000035
   f |             operator/(Float:,_:) |      10000 | 0.022434 / 0.000001 / 0.000077
   f |        operator>=(Float:,Float:) |      10000 | 0.021916 / 0.000001 / 0.000011
   f |                         xs_rsqrt |      10000 | 0.067513 / 0.000004 / 0.000110
   f |                       xs_vec_sub |      10000 | 0.021978 / 0.000001 / 0.000009
   f |                 xs_vec_normalize |      10000 | 0.045749 / 0.000003 / 0.000073
   f |                       xs_vec_dot |      10000 | 0.022200 / 0.000001 / 0.000047
   f |                fm_is_in_viewcone |      10000 | 0.271947 / 0.000022 / 0.000220
   
   n |                   is_in_viewcone |      10000 | 0.025373 / 0.000002 / 0.000104
   
6 natives, 0 public callbacks, 2 function calls were not executed.
Fm_entity_range vs entity_range [fakemeta vs engine]
Code:
type |                             name |      calls | time / min / max
-------------------------------------------------------------------
   n |                  register_plugin |          1 | 0.000008 / 0.000008 / 0.000008
   n |                   register_clcmd |          1 | 0.000016 / 0.000016 / 0.000016
   
   n |                       server_cmd |          1 | 0.000004 / 0.000004 / 0.000004
   p |                      plugin_init |          1 | 0.000011 / 0.000011 / 0.000011
   p |                          profile |          1 | 0.046530 / 0.046530 / 0.046530
   
   n |                     entity_range |      10000 | 0.022555 / 0.000001 / 0.000056
   
   f |                  fm_entity_range |      10000 | 0.092081 / 0.000006 / 0.000087
   n |                              pev |      20000 | 0.044973 / 0.000001 / 0.000037
   n |                   get_distance_f |      10000 | 0.022852 / 0.000001 / 0.000025
0 natives, 0 public callbacks, 2 function calls were not executed.
Ctrike module vs Fakemeta module.
Code:
type |                             name |      calls | time / min / max
-------------------------------------------------------------------
   n |                    get_pdata_int |     300000 | 0.647404 / 0.000001 / 0.000253
   n |                    set_pdata_int |     150064 | 0.328161 / 0.000001 / 0.000331
   n |                   get_user_msgid |          2 | 0.000006 / 0.000003 / 0.000004
   n |                   emessage_begin |     150064 | 0.379386 / 0.000002 / 0.000309
   n |                      ewrite_long |     100000 | 0.238946 / 0.000001 / 0.000458
   n |                      ewrite_byte |     225160 | 0.518973 / 0.000001 / 0.000357
   n |                     emessage_end |     150064 | 0.374745 / 0.000002 / 0.000218
   n |                          set_pev |      50064 | 0.110391 / 0.000001 / 0.000077
   n |                    ewrite_string |      50064 | 0.121614 / 0.000001 / 0.000250
   n |                  register_plugin |          1 | 0.000007 / 0.000007 / 0.000007
   n |                   register_clcmd |          1 | 0.000016 / 0.000016 / 0.000016
   n |                           random |     300000 | 0.648347 / 0.000001 / 0.000217
   n |                       server_cmd |          1 | 0.000004 / 0.000004 / 0.000004
   p |                        benchmark |          1 | 2.511592 / 2.511592 / 2.511592
   p |                      plugin_init |          1 | 0.000007 / 0.000007 / 0.000007
   
   n |                cs_get_user_money |     100000 | 0.220167 / 0.000001 / 0.000414
   f |             fm_cs_get_user_money |     100000 | 0.446478 / 0.000003 / 0.000413
   
   n |                cs_set_user_money |     100000 | 0.276739 / 0.000002 / 0.000329
   f |             fm_cs_set_user_money |     100000 | 1.344050 / 0.000010 / 0.001747
   
   n |               cs_get_user_defuse |     100000 | 0.220294 / 0.000001 / 0.000094
   f |            fm_cs_get_user_defuse |     100000 | 0.452164 / 0.000003 / 0.000161
   
   n |               cs_set_user_defuse |     100000 | 0.336809 / 0.000002 / 0.000270
   f |            fm_cs_set_user_defuse |     100000 | 1.294073 / 0.000003 / 0.000333
Bây giờ chúng ta sẽ nói về mô-đun forwards. Chúng ta có thể thấy rằng chúng tôi có rất nhiều forwards mô-đun của chúng tôi có thể cung cấp. Ở đây chúng tôi sẽ đề cập đến chỉ fakemeta, engine và forwards hamsandwich. 
Sự khác biệt giữa các mô-đun forwards là gì? Vâng sự khác biệt chính của forwards là phương pháp đăng ký. 

Mô-đun cung cấp Những tiền đạo hiệu quả nhất? 
Sự khác biệt khi chúng ta nói về hiệu quả * sẽ được gần như không đáng kể.

Code:
type |                             name |      calls | time / min / max
-------------------------------------------------------------------
   n |                  register_plugin |          1 | 0.000010 / 0.000010 / 0.000010
   n |                 register_forward |          1 | 0.000008 / 0.000008 / 0.000008
   n |                       server_cmd |          1 | 0.000016 / 0.000016 / 0.000016
   p |                   playerPreThink |       2001 | 0.004775 / 0.000002 / 0.000007
   p |                      plugin_init |          1 | 0.000007 / 0.000007 / 0.000007
0 natives, 0 public callbacks, 2 function calls were not executed.


date: Mon Mar 30 15:46:09 2009 map: de_dust2
type |                             name |      calls | time / min / max
-------------------------------------------------------------------
   n |                  register_plugin |          1 | 0.000005 / 0.000005 / 0.000005
   n |                       server_cmd |          1 | 0.000016 / 0.000016 / 0.000016
   p |                  client_PreThink |       2001 | 0.004718 / 0.000002 / 0.000018
   p |                      plugin_init |          1 | 0.000004 / 0.000004 / 0.000004
Bây giờ chúng ta so sánh các thao tác tài sản thực thể của engine so với fakemeta. Fakemeta sẽ có một chút chậm hơn so với engine nhưng đủ tốt để sử dụng.
Code:
type |                             name |      calls | time / min / max
-------------------------------------------------------------------
   n |                  register_plugin |          1 | 0.000009 / 0.000009 / 0.000009
   n |                   register_clcmd |          1 | 0.000013 / 0.000013 / 0.000013
   n |                     random_float |     300000 | 0.665777 / 0.000001 / 0.000323
   n |                          set_pev |     100000 | 0.222021 / 0.000001 / 0.000154
   n |                entity_set_vector |     100000 | 0.220881 / 0.000001 / 0.000152
   n |                       server_cmd |          1 | 0.000008 / 0.000008 / 0.000008
   p |                      plugin_init |          1 | 0.000007 / 0.000007 / 0.000007
   p |                          profile |          1 | 1.132186 / 1.132186 / 1.132186
0 natives, 0 public callbacks, 2 function calls were not executed.
Code:
type |                             name |      calls | time / min / max
-------------------------------------------------------------------
   n |                   precache_model |          1 | 0.015410 / 0.015410 / 0.015410
   n |                  register_plugin |          1 | 0.000007 / 0.000007 / 0.000007
   n |                   register_clcmd |          1 | 0.000016 / 0.000016 / 0.000016
   n |                       server_cmd |          1 | 0.000007 / 0.000007 / 0.000007
   p |                      plugin_init |          1 | 0.000008 / 0.000008 / 0.000008
   p |                  plugin_precache |          1 | 0.000008 / 0.000008 / 0.000008
   p |                          profile |          1 | 0.466186 / 0.466186 / 0.466186
   
   n |                        pev_valid |     100000 | 0.228750 / 0.000001 / 0.000165
   n |                     is_valid_ent |     100000 | 0.226901 / 0.000001 / 0.000095
Bây giờ chúng ta phải nghĩ rằng đó là tốt để lưu lại kết quả hay không. 
Lợi thế đó sẽ xuất hiện một khi chúng ta bộ nhớ đệm chúng là gì? 
Tốt lợi thế là nó sẽ sử dụng ít CPU và nó sẽ làm cho một sự khác biệt lớn khi chúng ta nói về kiểm tra lặp đi lặp lại (như forwards prethink), bất lợi là nó sử dụng bộ nhớ. 

Có nghĩa là gì để kết quả bộ nhớ đệm? 
Ví dụ chúng tôi muốn biết một người chơi là một bot. 
Thay vì sử dụng chức năng này tất cả các thời gian:
PHP Code:
is_user_bot(id)  
Nó là tốt hơn để làm điều này:
PHP Code:
new bool:cl_is_bot[33]
public 
client_putinserver(id)
{
    if (
is_user_bot(id))
        
cl_is_bot[id] = true;
}
// now we only use cl_is_bot[id] not is_user_bot(id)  
Thay vì mất thời gian với mô-đun Liên lạc chúng tôi chỉ cần truy cập vào bộ nhớ Mà sẽ làm cho mọi việc nhanh hơn nhiều!
Bạn phải nhớ rằng việc này sẽ làm cho bạn Plugin khó khăn hơn để thực hiện.

Đây là một ví dụ với kết quả bộ nhớ cache và các bài kiểm tra, bạn sẽ thấy rằng chúng ta sẽ có một sự khác biệt lớn, vì vậy nó sẽ được khuyến khích sử dụng bộ nhớ đệm để làm cho một plugin hiệu quả.
Đây là ý tưởng chính của những gì MeRcyLeZZ muốn làm để cải thiện các plugin của mình.
http://forums.alliedmods.net/showpos...91&postcount=1
Đây là kết quả
http://forums.alliedmods.net/showpos...28&postcount=3

Tôi sẽ trích quan điểm về Fakemate của Hawk552s (fakemeta sử dụng chung).
Quote:
Originally Posted by Hawk552 View Post
I didn't say that. Porting stuff to Fakemeta is not a be-all end-all solution. There are many, many reasons not to use Fakemeta. Here are some of them:
  • Multiforwards as used in Engine and Fun are far more efficient once more than one plugin is using it
  • Engine and Fun are simpler to use and easier to read
  • Engine and Fun natives often require less parameters and as such the VM layer can run faster
  • More people know how to use Engine and Fun
  • Fakemeta has far less protection against bad use and can crash a server much more easily
  • Engine and Fun are better documented with more available support and example code
  • Engine and Fun themselves act as wrappers which means that if an update breaks something, plugins do not have to be recompiled - AMXX can just be updated. This is also beneficial as less code is run in the VM layer, making it faster
Tell me: can you know whether the user is already running a plugin using Engine or Fun? Would it even be worth the resources to check?

Why are we fretting over these trivial optimizations (which you're actually largely part wrong about being faster in the first place) as opposed to making code legible? Why should I write code that is 4x as long and is slower just because the API I'm using is more capable? Why don't we just use ASM, under that reasoning?

We've had this debate before. GHW_Chronic made it a requirement for plugins to only use Fakemeta. This makes absolutely no sense. There's no reason we can't use Fun and Engine for everything other than the things only Fakemeta can do.

I've written many APIs (see Apollo RP in my signature); I can guarantee you, far more than you have. From that experience, I know that capability is not the most important quality of an API. An API, especially for something like AMXX, should be simple. The way we have the APIs divided up is great. We should only encourage people to use Fakemeta when it is necessary and no other module can accomplish the task at hand.

There is absolutely no reason to make a point of using Fakemeta exclusively unless you're trying to appear intelligent or you actually know it better than Engine and Fun. Stop telling beginners to use Fakemeta, it will only confuse them and makes things more complicated than they have to be.
Conclusions:
We must use the module when it has a specific good function that others don't provide. 
The less module comunications the better!!!
And remember this tutorial does not want to say not to use fakemeta! It advises to use it only when it needs to be used!
A plugin isn't bad if it uses 10 modules instead of just 2...
If you propose to cache some results in a plugin, it will be more efficient but there will be a problem when we talk about easy scripting.

Good tutorials that fit in with this one:
http://forums.alliedmods.net/showthread.php?t=43049
http://forums.alliedmods.net/showthread.php?t=40340
http://forums.alliedmods.net/showthr...296#post809296

Benchmark tool, for the people who want to do some more tests, if you want feel free to post the results in the efficency tutorial: 
http://forums.alliedmods.net/showthread.php?t=67752

My comment: Hope that it is ok, if you would like to add some more please tell me. I'm not used on writing such long posts... [Hope that my english was fine ...]
I thank all that spend their time reading this tutorial, suggested improvements and contributed to this tutorial!

Debugging Plugins (AMX Mod X) - Gỡ Rối Chương Trình


Debugging Plugins (AMX Mod X)

AMX Mod X features a greatly enhanced plugin debugger over AMX Mod. If your plugin is giving runtime errors, you should enable the debugger by opening amxmodx/configs/plugins.ini and appending " debug" to your plugin's entry, like so:
myplugin.amxx debug
When you get a runtime error, it will show a full trace of the problem:
L 09/15/2004 - 17:38:17: [AMXX] Run time error 4 (index out of bounds) 
     on line 46 (file "debug.sma").
L 09/15/2004 - 17:38:17: [AMXX] Debug Trace =>
L 09/15/2004 - 17:38:17: [AMXX]       [0] Line 40, File "debug.sma"
L 09/15/2004 - 17:38:17: [AMXX]       [1] Line 25, File "debug.sma" 
This type of error is called an AMX run time error - one that occured directly in the plugin interpreter. From this output, we know that this order of events happened:
  1. Line 25 was called in debug.sma
  2. Line 25 jumped to line 40 in debug.sma
  3. Line 40 jumped to line 46 in debug.sma, where an error occured
This specific error is one of the three common errors. It means that an array was improperly indexed, for example:
new array[5]
new x = 500
array[x] = x
Will generate this message. Another common message is AMX_ERR_STACKERR, which means your plugin ran out of memory. The fix for this is to increase the default size from 16KB:
#pragma dynamic 32768 
This will increase the memory allocated to 128KB. The dynamic size is measured in cells, which are four bytes each (eight bytes on AMD64). AMX_ERR_STACKLOW and AMX_ERR_HEAPLOW are similar. The most common error by far is AMX_ERR_NATIVE, which means a native function in the AMX Mod X core signaled an error message.
Native errors are usually caused by some error checking failure on the part of the script programmer. For example, supplying an invalid connection id to an SQL function, or trying to modify the data on a player that doesn't exist. These errors will usually give a more helpful error message along with the call trace, as well as the actual name of the native that failed.

Code Styling & Good Programming Habits - Phong cách lập trình


Before we begin, this article is for anyone of any skill level. If you're just starting out, this will help you avoid nasty habits that you may pick up now or later. If you're an intermediate level scripter, you're probably relatively capable in terms of producing something that people can use, but may have trouble helping others understand your code properly.


This is an addendum to this post, which I don't feel is complete enough and needed some additions.

This article will teach you what I believe are the best coding styles. I don't even follow all of these because I started out with some bad habits and they are hard to break. All of these are tried and tested but may still be up for debate. Some of these are indisputable while others are highly subjective. For those which I think are subjective, I'll always leave multiple options and state that they are not conventions. So without further ado, here we go.

The Opening Comment Block

The best place to start is, logically, the beginning of the plugin, where you place comments explaining what the plugin is and does. I often ignore this section for small plugins or ones which I'm not going to release. This is, however, good form for a plugin which you are planning on releasing on its own. A typical comment block may look like this:

PHP Code:
/*

Copyleft 2008
Plugin thread: http://forums.alliedmods.net/showthread.php?p=633284

DUEL MOD
========

Description
This mod is designed to allow dueling, where players challenge each
other and engage in battle. It is designed for the mod "The Specialists",
but can be used on other mods.

Commands
say /duel - Will challenge the player being looked at to a duel.
say /accept - Will accept a challenge. Note that you can also use /duel,
but you must be looking at the person who challenged you. With /accept,
the last person to challenge you will be accepted.
say /punchingbag - Turns the player into a punching bag
(requires amx_duel_punchingbag to be set to 1).

Credits
Havoc9 Community - Testing help (specifically SaderBiscut and Jimmy Striker).
Lord_Destros - Testing help.
Steely - Testing help.
sawyer - Testing help.
Frost - Testing help.
coderiz - New semiclip method.
Charming - Encouragement.

Changelog:

    Jun 1, 2008 - v1.0 -    Initial release
    Jun 2, 2008 - v1.1 -    [FIXED] Some repeated variables
                [FIXED] Message printing incorrectly
                [FIXED] Duel off not working properly
                [ADDED] Punching bag mode
                [ADDED] True semiclip
                [ADDED] Attack blocking between
                duelists <-> players
                [ADDED] God mode to normal players
    Jun 4, 2008 - v1.2 -    [ADDED] Deny command
                [ADDED] Pair command
                [ADDED] Name parameter to /duel command
                [ADDED] Glow cvar
                [FIXED] Messages printing incorrectly
 
*/  
This is a strong opening because it does a number of things:
  • It clearly states what the plugin is and does.
  • It clearly states the plugin thread (this is, by far, the most important of all of these).
  • It clearly states which game it works for.
  • It clearly states commands. Cvars are optional, but I typically leave them in the plugin thread to keep it uncluttered in the source code.
  • It clearly states credits. You should always list these both in the source code and in the plugin thread.
  • It has a clear and informative changelog so users know which version they're looking at just by glancing at it.
The copyleft notification is unnecessary but may be considered good form just to remind people that all AMXX plugins are GPL'd.

Your opening comment block can look however you want it to, but the most important thing is that it gets the information out. If you find your style is impeding this, it's probably a good idea to revise it.

Macros and the Preprocessor

This section includes stuff such as your header inclusions (a.k.a. "#include") and compiler definitions (a.k.a. "#define"). There's not a whole lot you can do here in terms of messing up convention, but one of the important things to remember is that all macros should be capitalized from beginning to end. For example,

PHP Code:
#define MAX_ITEMS 10  
... as opposed to ...

PHP Code:
#define max_items 10  
This avoids mistaking macros for variables and is a widely held convention - it is not really up for debate. The only exception to this is for macro function definitions, an example of which being:

PHP Code:
#define MyNewIsUserAlive(%1) is_user_alive( %1 )  
This is acceptable because the macro essentially acts as a function as opposed to a location of data in memory.

Another stylistic consideration is that your header inclusions should be as minimalistic as possible. For example, if you don't use any FakeMeta functions, don't include the fakemeta.inc file as it is useless clutter.

One other important thing you should know about preprocessor styling is that conditions should generally be left untabbed. This makes it very clear where blocks of code will operate and where they won't. For example:

PHP Code:
PunishUserid )
{
#if defined KILL_USER
    
user_killid )
    
client_print0print_chat"[Kill] The user has been killed")#else // KILL_USER
    
user_slapid)
    
client_print0print_chat"[Kill] The user has been slapped")#endif // KILL_USER}  
Some people tab it out to whatever level the code is already at, but I think it's easy to miss that a preprocessor condition is necessary for any of it to run. Both are acceptable but I believe not tabbing out the condition macros is better.

The final thing you should know is that, as in my previous example, it's a good idea to leave a comment at each #else, #elseif and #endif command denoting what exactly it's checking.

Indentation, Tabbing and Spacing

Tabbing should always be done whenever you open a code block (which will be discussed more in detail later). A standard tab is either done using the "Tab" key or using 4 spaces. Less commonly, people use 1, 3 or 8 spaces for their tabs, but this is very rare and generally frowned upon. Almost everyone uses the "Tab" key because then other people can set their tab-size higher or lower in their text editors.

There are also many styles of spacing, but I believe the best (despite my not using it personally) is to add a space whenever you put a parameter in brackets, after a comma, immediately after a condition/loop keyword and before/after any operators which take two parameters on the left and right. For example:

PHP Code:
if ( !cmd_accessidlevelcid ) )  
... or...

PHP Code:
for ( new i10i++ )  
This allows you to easily distinguish functions from conditions/loops and also allows you to easily pick out parameters, operators, etc.

This is by no means standard and is highly up for debate, but to me this makes the most logical sense and is what I would use if I had the option of immediately wiping my habits and picking a new set of them. I would, however, advise you to always add spaces between operators with two parameters and after commas.

You may also consider adding two carriage returns as opposed to one between functions as it may make them easier to read. This is by no means a convention but I recommend it personally.

Case

This is important mostly for variables and functions. I'm putting this here because I'm going to be implying it in my next section, which covers global variables. This section is largely up for debate, but I believe the strongest and most legible way of doing it is what is commonly referred to as "camel case".

There's a slight variant of camel case called "mixed case" which I believe is slightly better. Here's how it goes:

For functions, you always capitalize the first letter of every word. For example:

PHP Code:
public EventDeathMsg()  
With variables that are untagged, you capitalize the first letter of every word after the first. For tagged variables, you capitalize the first letter of every word other than the tag. For example:

PHP Code:
new gMyVariable
new myVariable
new userKills  
In full camel case, you would capitalize the first letter of every word, regardless of whether or not it was the first word in the variable name or not. For example,

PHP Code:
new MyVariable
new UserKills  
The problem with this method is that it doesn't distinguish local variables from functions effectively. That's why mixed case is the best way to case your variables. 

Mixed/camel case more or less necessitates totally avoiding using underscores. For example, this looks really weird:

PHP Code:
new My_Variable  
As such, you should either use underscores and avoid mixed/camel case or use mixed/camel case and avoid underscores.

Also, as noted earlier, macros should be full upper-case.

Global Variables and Type Prefixing

Lots of confusion can come from not knowing that something is global. As such, all global variables should be prefixed with some sort of tag identifying them as such. For example:

PHP Code:
new gMyVariable  
Another way of tagging variables is by using the "g_" prefix. For example:

PHP Code:
new g_MyVariable  
While both are perfectly acceptable, I personally prefer the former slightly more although I use the latter for almost all of my works. It is simply a recommendation of form based on my experience.

You should add a carriage return at the end of every global variable as it makes it easier to search out any variables you need. For example:

PHP Code:
new gMyVariable
new gMyOtherVariable  
... as opposed to...

PHP Code:
new gMyVariablegMyOtherVariable  
Some people also tag their variable names with the type that they are associated with. This idea is highly up for debate and almost everyone has moved away from it as it is relatively archaic (Microsoft used to use it, but then moved away from it). This form of tagging is commonly referred to as "Hungarian Notation" (HN, for short). While I personally believe you should avoid using it, being a user of it myself at one point, it is still important to be able to read and understand. HN goes something like this:
  • g or g_ - globals (this is perfectly acceptable to use although you should avoid the others)
  • p or p_ - pointers (this is also perfectly acceptable to use)
  • i - integers/cells
  • f or fl - floats
  • sz - strings
  • b - bools
  • h - handles (can also be used in place of the pointer tag since either is technically correct)
  • v - vectors (not standard to HN but still useful)
  • fn - function (very rarely used even by people who use HN)
There are many more tags, but these are the only ones you can use in Pawn. Here are a few examples of variables tagged in HN:

PHP Code:
// a global cell
new g_iKills
// a global float
new Float:g_flSpeed
// a bool
new bool:bFlag
// a function
public fnEventResetHUD()
// a pointer
new g_pCvar  
If you're not using full HN, I advise you to use "g" as opposed to "g_", as shown in the beginning of this section.

In terms of a technical analysis, HN for anything other than global variables and pointers doesn't make any sense. Pawn is typeless and therefore incapable of actual data types. Booleans are actually just a meaningless tag and floats are cells which are converted by the virtual machine (AMXX's C++ side) whenever they are needed. There are many situations where HN will make variable casting/detagging confusing.

Code Blocks

A code block is anything that is separated by curly braces. While this may be an imprecise definition since in many code blocks the curly braces can simply be left out, I'm going to be addressing this style anyway.

The first thing I'd like to address is spacing. There are two common ways of spacing your code blocks, one of which I believe is vastly superior. The first is by adding a return before the condition opening a block, the second is not doing this. For example:

PHP Code:
MyFunction()
{  
... or...

PHP Code:
MyFunction() {  
I prefer the first much more as the entering and exit brackets will always line up properly and it just looks cleaner anyway. There's no real reason to do the latter and I can't see it as being easier to read.

Another very important concept in code blocks is whether or not to drop them entirely. Under some very special circumstances, you can actually ignore the brackets denoting a code block. There are two cases which make this acceptable:
  • There is a single function call or operation inside it, even if it itself requires data from other function calls (i.e. log_amx( "%d", get_user_kills( id ) )).
  • There is a single code block inside it, even if it contains a lot more code that does not fit in a single function call.
Here are examples of these:

1.
PHP Code:
MyFunctionid )
    
user_killid )  
2.
PHP Code:
MyFunctionid )
    if( 
is_user_aliveid ) )
    {
        
client_print0print_chat"We are now killing %d"id )
        
user_killid )
    }  
Both of these are perfectly valid and will compile without warnings/errors (context exclusive).

This method of dropping brackets is highly subjective. There are many arguments both for and against each. Dropping brackets allows you to type less code, but including them makes it less ambiguous. It can be argued, however, that ambiguity is resolved by tabbing even if there's no brackets. This style is up to you and either way is perfectly acceptable.

Commenting

Commenting is one of the most important things you can do for your code. Even if you break all of these habits, you can still get away with it if your commenting is good enough.

Large blocks of text outside of functions should be commented using the "/* ... */" operators, as in the first section which covered the opening code block. All other sections should be commented using the "//" operator. The reason for this is that Pawn does not support nested comments, i.e.:

PHP Code:
/*
    this is the first comment
    /* this is a nested comment */
                                               
*/  
Just look at how the code looks from this view. The last "*/" is green, showing that the interpreter doesn't actually understand what's going on here.

If you need nested comments, a little-known way of doing this is by using the preprocessor #if along with the condition 0, i.e.:

PHP Code:
#if 0
    
this is the first comment#if 0
        
this is a nested comment#endif
#endif  
This is, however ugly and is more suited to code which you need to be able to activate and deactivate quickly. As such, you will not see it in production code very often and is generally reserved for debugging.

When commenting, you should keep your comment on each line below 80 characters. This is to prevent the compiler from complaining and is also for people who do not have widescreen displays. The "line below 80 characters" rule applies for any line of code, not just comments. Some people also space their comment out with one extra space (for two spaces in total) after the first line. I believe this makes it more readable, but this is highly subjective.

Your comments should always be as descriptive as possible. You should inform the reader of what you're doing, why and what the result will be. For example, this is a bad comment as it serves no constructive use:

PHP Code:
// Start the for loop.for ( new i7i++ )  
A much better comment would be something like this:

PHP Code:
// There's a strange memory corruption bug in this function.
//  As such, we have to loop through each of the 7 elements
//  in the array and set them to the value that they should be.
for ( new i7i++ )  
Comments should also be placed between large blocks of code (such as functions which are grouped together as they are similar). These can be in the form of titles or just small descriptions. For example:

PHP Code:
//////////////////////////////////
// HELPER FUNCTIONS             //
//////////////////////////////////  
As is implied, it's a good idea to put your functions in an order where they are related to one another. These grouping tags are then much more meaningful.

Whitespace

Whitespace is a very important concept in coding. Although it has technically been covered previously in the "Tabbing and Spacing" section, there is still the issue of when to use carriage returns. If used correctly, whitespace allows people to understand your code more effectively. There are many different styles of using whitespace, but I believe the best is to simply add an extra carriage return whenever you break away from a part of a function which has similar results. For example:

PHP Code:
// Ignore the fact that this function would bear no real
//  useful results when actually used in a server.

MyFunction()
{
    new 
id random_num113 )
    
user_killid )

    
set_pcvar_nump_MyCvar)
}  
As you can see, the cvar setting call has little to do with finding a player and killing them. Thus, we add an extra carriage return to separate it.

Variable and Function Naming

As a rule of thumb, variable and function names should be as descriptive as possible. For example, this is a bad variable name:

PHP Code:
new temp  
It doesn't tell you anything about it other than the fact that it's more or less temporary (although, more often than not, this variable is pivotal to the operation of the function and may be used as part of or the return). A much more descriptive variable name would be something like this:

PHP Code:
new KillsSinceLastSpawn  
This tells you everything you need to know about it while also making you immediately realize that it's probably an integer (cell).

For functions, it is generally advised to follow the same rule except in the situation where you're creating a hook. Often, you should tag your hook callbacks with what type of callback they are. For example, an event might be tagged with "Event" or a forward with "Forward". This can be seen as follows:

PHP Code:
register_forwardFM_Spawn"ForwardSpawn" )  
... or...

PHP Code:
register_event"DeathMsg""EventDeathMsg""a" )  
It matters little what tag you use (many people use ev, Fwd, etc.) but it is generally advised to tag these functions as it distinguishes them from utility functions.

Extras

This section contains things that didn't really fit into other sections.

For starters, you should always use constants whenever they're provided. For example, use:

PHP Code:
return PLUGIN_CONTINUE  
... as opposed to...

PHP Code:
return 0  
This makes it much easier to get into the habit of using your own constants which you have declared in your plugin, which is also a good practice.

Semicolons are useful if you plan on moving to C/C++/PHP or any related language, but are often misused (for example, most people don't know do while loops have to be ended with one) or are passively used. Being a C and other related languages programmer myself, I have no trouble switching between using and not using semicolons. Since it's a convenience Pawn affords, I take it and don't use them. You can force semicolons using the following:

PHP Code:
#pragma semicolon 1  
Sometimes, when writing an API or header, you will have to document your functions so others can understand them. Doxygen (a source code documenting software package) uses a specific format for this, which AMXX has started using since SQLx was introduced. This is probably the best way to do it simply because it's the most readable and can be fed to Doxygen later. Here is an example of a Doxygen-documented utility function:

PHP Code:
/**
 * Print command activity.

 * @param id           Calling admin's id
 * @param key[]      Language key
 * @param any:...    Arguments to the format function (w/out the id/lang key)

 * @return    True on success, False on fail
**/

stock UTIL_PrintActivity(const id, const szLangKey[],any:...)  
Finally, sometimes in a collaborative project you will have difficulty identifying who did what parts. For this reason, I believe it's best to comment your code as follows:

PHP Code:
// Hawk552: Added this function to gather and store player
//  names, then sort them alphabetically.

SortNamesNames[][], NumNamesMaxLength )  
Conclusion

In conclusion, even if you ignore most of these tips, I hope you follow at least some of them as you will find them invaluable as you move along in the process of learning how to code. Ideally, you should follow all of these, but many people find them difficult to use or not as clean as their alternative.

As I think of more stuff to add, I may do this, but for the most part I believe this tutorial is complete. As always, if you have questions or comments, feel free to post or PM me.

EDIT: I bit the bullet and decided to actually learn to use the style that I advocate here. I have posted a plugin that uses this here:
http://forums.alliedmods.net/showthread.php?t=102839