Orjinalini okuyabilirsiniz; (Çeviri tıpa tıp aynısı değildir, bazıları doğru bazıları kendi eklediklerimdir)
https://wiki.alliedmods.net/Optimizing_ ... Scripting)
Giriş (Kısaltılmıştır) :
Çoğu kişi, yazılan eklenti için şunları varsaymaktadır:
* Önceden derlenmiş eklentileri daha optimize edemeyiz. Onlar zaten optimize edilmiş halde.
* Ayrıntılar, sadece "komut dosyası (sma)" olduğu için önemli değil
Öncelikle bunların hiçbiri doğru değil. Derleyici, aslında opitimize etme konusunda çok zayıftır ve eklentilerinizin hızını
ve verimliliğini birkaç kural göz önünde bulundurarak büyük ölçüde arttırabilirsiniz. Unutmayın ki;
Talimatları en aza indirmek, kod satırlarını en aza indirmekten daha iyidir.
( Yani kod satırı az olan eklentiler, çok olanlardan kesin daha hızlı çalışır diye bir şey yok.)
Derleyici Optimizasyonları :
Bu optimizasyonlar kodunuzun nasıl derleneceğini değiştirmekle ilgilidir. Sözdizimi aynı kalabilse bile,
sadece derleme süresini arttırmakla kalmaz, aynı zamanda eklentinin verimliliğini ve hızını da arttırırsınız.
* Her zaman sonuçları kayıt et :
Aşağıdaki örnek kodu inceleyiniz
Kod: Tümünü seç
if (get_user_team(player) == TEAM_T)
{
//...code
} else if (get_user_team(player) == TEAM_CT) {
//...code
} else if (get_user_team(player) == TEAM_SPECTATOR) {
//...code
}
Kod: Tümünü seç
CALL get_user_team
COMPARE+BRANCH
CALL get_user_team
COMPARE+BRANCH
CALL get_user_team
COMPARE+BRANCH
Kod: Tümünü seç
new team = get_user_team ( player )
if ( team == TEAM_T )
{
//...code
} else ise ( team == TEAM_CT ) {
//...code
} else ise ( team == TEAM_SPECTATOR ) {
//. ..code
}
Kod: Tümünü seç
CALL get_user_team
COMPARE + BRANCH
COMPARE + BRANCH
COMPARE + BRANCH
* If yerine switch kullan :
Eğer yapabiliyorsanız, if yerine switch komutunu kullanın. Bunun nedeni, derleyici aynı komutu defalarca kontrol ediyor.
Yukardaki örneği bu şekilde değiştirebiliriz.
Kod: Tümünü seç
new team = get_user_team(player)
switch (team)
{
case TEAM_T:
//code...
case TEAM_CT:
//code...
case TEAM_SPECTATOR:
//code...
}
Kod: Tümünü seç
CALL get_user_team
COMPARE
COMPARE
COMPARE
* Dizileri İndexlemeyin :
Eskiden yaygın bir hataydı. Artık o kadar kullanılmıyor fakat bunu da silmek istemedim. Sorun; dizileri yeniden diziye eklerek,
yer tasarrufu yapmaktır. Derleyicide yer tasarrufu yapıp bu şekilde eklentinizi kodlamayınız. Aşağıdaki koda bakalım;
Kod: Tümünü seç
new players[32], num, team
get_players(players, num, "h")
for (new i=0; i<num; i++)
{
team = get_user_team(players[i])
set_user_frags(players[i], 0)
}
Kod: Tümünü seç
:LOOP_BEGIN
LOAD i
LOAD players
CALC
LOAD players[i]
CALL get_user_team
LOAD i
LOAD players
CALC
LOAD players[i]
CALL set_user_frags
Bu yüzden tekrar tekrar oyuncuları kontrol etti. Bunun yerine bu şekilde kullanmak daha iyi olacaktır;
Kod: Tümünü seç
new player
for (new i=0; i<num; i++)
{
player = players[i]
team = get_user_team(player)
set_user_frags(player, 0)
}
Kod: Tümünü seç
:LOOP_BEGIN
LOAD i
LOAD players
CALC
LOAD players[i]
STORE player
CALL get_user_team
LOAD player
CALL set_user_frags
* Küresel vs Yerel (Global vs Local) ve Döngülerdeki Değişkenler :
Bu konuyu kısa bir şekilde, anlayacağınız şekilde anlatacağım. Bazı şu anlık ilk başlayanlar için anlamsız yerleri sildim.
Döngüler içindeki dizileri bildirmekten kaçının. Aşağıdaki örneğe bir bakalım.
Kod: Tümünü seç
for (new i=0; i<num; i++)
{
new message[255], name[32], player
player = players[i]
get_user_name(player, name, 31)
format(message, 254, "Hello, %s", name)
}
Bunu dizenin ilk karakterini sıfırlayarak optimize edebiliriz. Aşağıdaki koda bir bakalım.
Kod: Tümünü seç
new message[255], name[32], player
for (new i=0; i<num; i++)
{
player = players[i]
name[0] = '^0'
message[0] = '^0'
get_user_name(player, name, 31)
format(message, 254, "Hello, %s", name)
}
* Statik vs Küresel (Static vs Global) :
new yerine static anahtar kelimesiyle bildirilen bir değişken, bir global yapıda olduğu gibi çalışır.
Yani yalnızca bir kez oluşturulur. Ancak değişken işlevi yereldir; Bu kodun hızını önemli ölçüde geliştirirken okunması daha kolay
olduğu anlamına gelir; Örnek:
Kod: Tümünü seç
stock SomeBigFunction()
{
static gaben[255];
format(gaben, "%L", LANG_SERVER, "STUFF");
}
NOT: Bir değişken statik olduğunda, işleviniz yinelemeli olarak veya aynı yığın içerisinde birden fazla kez
çağrılıyorsa, statik değişken kullanmamalısınız demektir. Yani değişkeni sadece salisede bir kere çalışan yığınlarda
veya herhangi bir yığında değişmeyen komut olması şartıyla kullanabilirsiniz. Bir örnek vereyim, bu örnekteki gibi kullanmayınız.
Kod: Tümünü seç
public PurposeLess_Ornek()
{
static name[32];
new players[32], inum;
static Uid;
get_players(players, inum);
for(new i=0; i<inum; i++)
{
Uid = players[i];
name[0] = '^0';
get_user_name(Uid, name, charsmax(name));
client_print_color(Uid, Uid, "Isminiz: %s", name);
}
}
* Sabit Değişkenler :
Değişken adından önce "const" anahtar sözcüğünü ekleyerek sabit değişkenini bildirebilirsiniz.
Kod: Tümünü seç
new const AMX_GABEN[] = "amx_gaben"
Ek olarak, sabit değişkenler genellikle daha hızlı ve daha küçük kodla sonuçlanacak şekilde optimize edilir.
* Döngü Karşılaştırmaları (for komutu) :
Yaygın bir hata bu şekilde kullanımdır.
Kod: Tümünü seç
new string[256] = "something long"
for (new i=0; i<strlen(string); i++)
//...code
Dize orta döngü değiştirilirse, bunun daha kötü etkileri olacaktır. Daha mantıklı bir yöntem.
Kod: Tümünü seç
new string[256] = "something long"
new len = strlen(string)
for (new i=0; i<len; i++)
//...code
* Arama Tabloları :
Örnek olarak silah endekslerinin isimlere eleştirildiğini varsayalım.
Kod: Tümünü seç
if (weapon == CSW_AK47)
copy(name, len, "weapon_ak47")
Bu sonucu bir tabloda önceden yapabiliriz;
Kod: Tümünü seç
new g_WeaponNamesTable[TOTAL_WEAPONS][] = {
//..0 to CSW_AK47-1
"weapon_ak47",
//..CSW_AK47+1 to TOTAL_WEAPONS-1
};
* Yerel Dizeler :
Bir sabit kodlu dizeyi eklentinizde çok kez kullanırsanız çok farklı kez görünecektir (kullanılacaktır).
Örnek;
Kod: Tümünü seç
set_cvar_num("amx_gaben", get_cvar_num("amx_gaben") + 1)
Benzer olarak, bu aynı sorun var.
Kod: Tümünü seç
#define AMX_GABEN "amx_gaben"
set_cvar_num(AMX_GABEN, get_cvar_num(AMX_GABEN) + 1)
Kod: Tümünü seç
new AMX_GABEN[] = "amx_gaben"
set_cvar_num(AMX_GABEN, get_cvar_num(AMX_GABEN) + 1)
bu anahtarı kolay şekilde yapabilirsiniz.
Bunun değişmesini önlemek için, onu sürekli olarak bildirmek isteyebilirsiniz. (const kullanabilirsiniz)
Kod: Tümünü seç
new const AMX_GABEN[] = "amx_gaben"
set_cvar_num(AMX_GABEN, get_cvar_num(AMX_GABEN) + 1)
Kullanabileceğiniz Daha Hızlı Komutlar :
* Cvar Pointers :
Cvar komutunu pointer ile kullanmak düzinelerce kat daha hızlı olan kritik bir optimizasyondur. Örneğin;
Kod: Tümünü seç
new g_enabled = register_cvar("csdm_enabled", "1")
//OR
new g_enabled = get_cvar_pointer("csdm_enabled")
stock SetCSDM(num)
set_pcvar_num(g_enabled, num)
stock GetCSDM()
return get_pcvar_num(g_enabled)
get_cvar_pointer veya register_cvar ile cvarları önbelleğe alabilirsiniz.
FormatEX :
format ile formatex komutu neredeyse aynı olarak çalışır. Fakat format komutu, geri kopyalama yeteneğine sahiptir.
Bir kaynak girdisi, çıktısı arabelleği ile aynı ise, formatex kullanılamaz. Örneğin; bunlar geçersiz;
Kod: Tümünü seç
new buffer[255]
formatex(buffer, charsmax(buffer), "%s", buffer);
formatex(buffer, charsmax(buffer), buffer);
formatex(buffer, charsmax(buffer), "%d %s", buffer[2]);
daha hızlı çalışır.
FM_Touch (fakemeta.inc) | Ham_Touch (hamsandwich.inc) | register_touch(engine.inc):
Dokunanı algılamak için kullanacağınız komut istisna durumları hariç register_touch olmalıdır.
Diğer komutlardan daha hızlı çalıştığı yabancı forum AMX Mod X Plugin Approver yani eklenti onaylayıcısı tarafından denenmiştir.
[Kaynak:https://forums.alliedmods.net/showthread.php?t=213075]
Örnek kullanım; (oyuncu oyuncuya değerse)
Kod: Tümünü seç
register_touch("player", "player", "touch_player");
public touch_player(touched, toucher)
{
static name[32], name2[32];
get_user_name(touched, name, charsmax(name));
get_user_name(toucher, name2, charsmax(name2));
client_print_color(touched, touched, "%s adli kisi size dokundu", name2);
client_print_color(toucher, toucher, "%s adli kisiye dokundunuz", name);
}
Stock | Bool | Tagsız Komutlar [Hangisini kullanmalıyız?]
Eklentilerde bazen bir komutu veya bir düşünceyi tekrar tekrar kullanabiliyoruz. Bunun için kısayol tarzı bir şey yaptığımız da oluyor.
Peki bunlarda stock mu bool mu yoksa hiçbir tag kullanmayacak mıyız?
Öncelikle hiçbir eklentinizde stock kullanmayın. stock komutu çoğunlukla include yani kütüphanelerde kullanılıyor.
Eklentide kullanılması önerilmiyor.
; [Kaynak : https://forums.alliedmods.net/showpost. ... stcount=13]
Bool ve tagsız komutlar için örneklere bakalım.You shouldn't be using "stock" in the .sma files. This tag is used only if there is a possibility that the function will not be used at all. Since this is your code and you added the function,
you're probably going to use it as well, so remove the "stock" tag. Only use "stock" in include files where not all functions must be used in the code when included.
"bool" is pretty self-explainatory. If the variable is tagged with "bool", then the return value of the function should also be "bool". Bools can be only true or false.
Oyuncular glow verme komutunu ele alabiliriz. 4 komutu kullanmak yerine bir komuta bağlayıp, o komutu kullanıyoruz.
Kod: Tümünü seç
rg_set_user_rendering(index, fx = kRenderFxNone, {Float,_}:color[3] = {0.0,0.0,0.0}, render = kRenderNormal, Float:amount = 0.0)
{
set_entvar(index, var_renderfx, fx);
set_entvar(index, var_rendercolor, color);
set_entvar(index, var_rendermode, render);
set_entvar(index, var_renderamt, amount);
}
daha iyi olacaktır.
Kod: Tümünü seç
bool:is_user_stuck(index)
{
static Float:origin[3];
get_entvar(index, var_origin, origin);
engfunc(EngFunc_TraceHull, origin,origin, IGNORE_MONSTERS, get_entvar(index, var_flags) & FL_DUCKING ? HULL_HEAD : HULL_HUMAN, 0, 0);
return (get_tr2(0, TR_StartSolid)) ? true:false;
}
Bunu true false olarak sabitlemek için bool kullanmaniz daha iyi olacaktır. Gömülü ise true, değilse false.
Dosya yazılımı :
Hala yaygın olarak kullanılan bir hatadır. Amx Mod X ısrarla bu komutları kullanmayın demesine rağmen hala kullanılmakta.
read_file, write_file gibi komutlar yerine fopen, fgets, fputs, fclose gibi komutlar kullanılmalıdır.
+
Verdiğim siteden hangi komutun ne işe yaradığını ve nasıl çalıştığını öğrenebilirsiniz. Sorularınızı ve anlamadığınız yerleri sorabilirsiniz.
Umarım yardımcı olabilmişimdir. Sunucular için optimize edilmiş eklentiler yapmanız dileğiyle :)
Site: https://amxx-bg.info/api/
Get_players mi yoksa maxplayers mi? :
Oyuncu çekmek için en iyi yöntem get_players komutudur.
get_maxplayers ile yaptığınız kodlar sunucu 32 olmadığı zaman gereksiz komut kullanır. Bu yüzden tavsiye etmem.
Şu şekilde kullanabilirsiniz.
Kod: Tümünü seç
new players[32], inum;
static Uid;
get_players(players, inum); // burayi yasayan olu vs gibi editlemeniz gerekebilir.
for(new i=0; i<inum; i++)
{
Uid = players[i];
// yapilacak islemler
}