Discord sunucumuz açılmıştır, hepinizi bekleriz

https://discord.gg/43gGDQe6tS

Eklentilerde Optimizasyon

Hazır fonksiyonlar, kütüphaneler, düzenleme programları/araçları/gereçleri, editörler kısacası geliştirme ortamı

Moderatör: Moderatörler

Kullanıcı avatarı

Konu Sahibi
Colditz
Mesajlar: 2574
Kayıt: Çrş Ağu 23, 2017 9:17 pm

Eklentilerde Optimizasyon

Mesaj gönderen Colditz »

Hepinize merhaba arkadaşlar. Birçok yazar arkadaşımız eklentilerini kaba taslak yapıyor. Bunun içinde yazarlığa yeni başlamış arkadaşlar çoğunlukla bulunmakta. (Kimse üstüne alınmasın lütfen.) Daha doğrusu kimseden yardım istemediği veya araştırma yapmadığı için kendi bildiği gibi kodluyor. Burada birkaç optimize kodları hakkında anlatım yapacağım. Bu anlatım yabancı siteden alınmıştır.
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)

Resim
Giriş (Kısaltılmıştır) :
Resim
Ç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.)

Resim
Derleyici Optimizasyonları :
Resim
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.

Resim
* Her zaman sonuçları kayıt et :
Resim
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
}
Bu, "sonuçlarınızı önbelleğe al" ın hafif bir örneğidir. Derleyici bu şekilde çalışacaktır.

Kod: Tümünü seç

CALL get_user_team
COMPARE+BRANCH
CALL get_user_team
COMPARE+BRANCH
CALL get_user_team
COMPARE+BRANCH
Sorunu fark ettiniz mi? Biz çağrıda get_user_team komutunu gereğinden fazla kez kullandık. Bunu böyle kayıt edebiliriz.

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 
}
Şimdi derleyici bu şekilde çalışacaktır.

Kod: Tümünü seç

CALL get_user_team 
COMPARE + BRANCH 
COMPARE + BRANCH 
COMPARE + BRANCH
Resim
* If yerine switch kullan :
Resim
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...
}
Derleyici, case olarak adlandırlan yerleri kontrol edecektir. Derleyici bu şekilde çalışacaktır.

Kod: Tümünü seç

CALL get_user_team 
COMPARE 
COMPARE 
COMPARE
Resim
* Dizileri İndexlemeyin :
Resim
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)
}
Derleyici bu şekilde çalışacaktır.

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
Ne olduğunu gördünüz mü? Derleyici indexi (players) önbelleğe almaz. Biz players komutunu defalarca kullandık.
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)
}
Derleyici bu şekilde çalışacaktır.

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
Büyük bir döngüde kodları bu şekilde büyük ölçüde azaltabilirsiniz.

Resim
* Küresel vs Yerel (Global vs Local) ve Döngülerdeki Değişkenler :
Resim
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)
}
Eğer 32 oyuncu varsa, bu döngü aslında bir satırda 32 kez sıfırlanacaktır ve tekrardan yazılacaktır. İyi değil!
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)
}
Bu komutlar çok fazla çalışma süresi yükünü büyük ölçüde azaltır.

Resim
* Statik vs Küresel (Static vs Global) :
Resim
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");
}
Resim
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);
	}
}
Herkesin ismini teker teker algılayacağı için bu değişkende statik değişken kullanmamalıyız.

Resim
* Sabit Değişkenler :
Resim
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"
Bu, değişkenin değişmesini engeller. Aslında, değişkeni bir değere kilitlediniz.
Ek olarak, sabit değişkenler genellikle daha hızlı ve daha küçük kodla sonuçlanacak şekilde optimize edilir.

Resim
* Döngü Karşılaştırmaları (for komutu) :
Resim
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
Önceden benzer bir prensip yürütülür: önbellek sonuçları. Derleyici, döngü uzunluğunu, döngüdeki her yinelemede yeniden hesaplar.
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
Resim
* Arama Tabloları :
Resim
Örnek olarak silah endekslerinin isimlere eleştirildiğini varsayalım.

Kod: Tümünü seç

if (weapon == CSW_AK47)
   copy(name, len, "weapon_ak47")
Amx Mod X içinde get_weapon_name komutu olduğu gerçeğini yok saymak verimsizdir.
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
};
Resim
* Yerel Dizeler :
Resim
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)
Bu komut gerçekten zarar vermez iken, eklentinizin boyutunu arttırır.
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)
Bu karışıklıktan kurtulmanın tek yolu, global değişken kullanmaktır.

Kod: Tümünü seç

new AMX_GABEN[] = "amx_gaben"
set_cvar_num(AMX_GABEN, get_cvar_num(AMX_GABEN) + 1)
Yine, gerekli olmasa da, bu eklentinin boyutunu hafızada ve diskte azaltacaktır. Zaten tanımlar kullanıyorsanız,
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)
Şimdi mükemmel bir güvenli saklama yöntemi kullanılmış oldu.

Resim
Kullanabileceğiniz Daha Hızlı Komutlar :
Resim

Resim
* Cvar Pointers :
Resim
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)
Tüm cvar komutları [set_cvar_string hariç] set_pcvar_* get_pcvar_* komutları ile eşleşir.
get_cvar_pointer veya register_cvar ile cvarları önbelleğe alabilirsiniz.

Resim
FormatEX :
Resim
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]);
Bu komutlarda format kullanılmalıydı. Geri dönüş olmadığı sürede formatex kullanabilirsiniz. Genellikle format komutundan
daha hızlı çalışır.

Resim
FM_Touch (fakemeta.inc) | Ham_Touch (hamsandwich.inc) | register_touch(engine.inc):
Resim
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);
}
Resim
Stock | Bool | Tagsız Komutlar [Hangisini kullanmalıyız?]
Resim
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]
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.
Bool ve tagsız komutlar için örneklere bakalım.
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);
}
Doğru veya yanlış şeklinde geri dönüş almamız gerekmediği için buna bir şey koymamıza gerek yoktur. Eklentide böyle kullanmanız
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;
}
Burada oyuncunun gömülü olup olmadığını algıladığı için bize bir sonuç verecek ya doğru ya yanlış.
Bunu true false olarak sabitlemek için bool kullanmaniz daha iyi olacaktır. Gömülü ise true, değilse false.

Resim
Dosya yazılımı :
Resim
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/

Resim
Get_players mi yoksa maxplayers mi? :
Resim

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
}

Link:
Linklerini gizle
Linki Kopyala
Kullanıcı avatarı

EnesReiS`
Mesajlar: 1136
Kayıt: Sal Eyl 12, 2017 10:22 am
Clan İsmi: RESPECT CLAN

Eklentilerde Optimizasyon

Mesaj gönderen EnesReiS` »

güzel bir düşünce,konu üzerindede çok uğraşmışsın aynı şekilde eklenti üzerindede uğraşmışsın teşekkürler.

Link:
Linklerini gizle
Linki Kopyala
Kullanıcı avatarı

Taha Demirbaş
Mesajlar: 10424
Kayıt: Cum Tem 08, 2016 10:05 pm
Konum: Türkiye
İletişim:

Eklentilerde Optimizasyon

Mesaj gönderen Taha Demirbaş »

Daha iyi olmuş. İşine yarayan insanlar optimizasyon yaparken bu konudan daha kolay yararlanacaklardır.

Link:
Linklerini gizle
Linki Kopyala
Kullanıcı avatarı

specified
Mesajlar: 1008
Kayıt: Prş Ara 24, 2015 1:58 pm
Server Ip/DNS: csX.csduragi.com
Clan İsmi: FCS Gaming
İletişim:

Eklentilerde Optimizasyon

Mesaj gönderen specified »

eline, emeğine sağlık.

Link:
Linklerini gizle
Linki Kopyala
Kullanıcı avatarı

mr1mr2
Mesajlar: 519
Kayıt: Çrş Oca 24, 2018 1:04 pm
Konum: Ankara
İletişim:

Eklentilerde Optimizasyon

Mesaj gönderen mr1mr2 »

Emek var , başarılı teşekkürler...

Link:
Linklerini gizle
Linki Kopyala
Kullanıcı avatarı

Konu Sahibi
Colditz
Mesajlar: 2574
Kayıt: Çrş Ağu 23, 2017 9:17 pm

Eklentilerde Optimizasyon

Mesaj gönderen Colditz »

Eklenmesini istediğiniz veya anlamadığınız yeri sorabilirsiniz :)

Link:
Linklerini gizle
Linki Kopyala
Kullanıcı avatarı

BY FURKAN !
Mesajlar: 939
Kayıt: Pzt Tem 09, 2018 9:01 pm
Konum: Türkiye
Server Ip/DNS: CSDuraği
Clan İsmi: CSDuraği

Eklentilerde Optimizasyon

Mesaj gönderen BY FURKAN ! »

Güzel bir paylaşim .

Link:
Linklerini gizle
Linki Kopyala
Kullanıcı avatarı

oCezaMelegi
Mesajlar: 909
Kayıt: Sal Kas 10, 2015 10:41 pm
Konum: Türkiye
Server Ip/DNS: 213.238.173.18
Clan İsmi: [I]ncredibLe'S
İletişim:

Eklentilerde Optimizasyon

Mesaj gönderen oCezaMelegi »

Emek var eline sağlık

Link:
Linklerini gizle
Linki Kopyala
Kullanıcı avatarı

Taha Demirbaş
Mesajlar: 10424
Kayıt: Cum Tem 08, 2016 10:05 pm
Konum: Türkiye
İletişim:

Eklentilerde Optimizasyon

Mesaj gönderen Taha Demirbaş »

Konu güncellenmiştir.

Link:
Linklerini gizle
Linki Kopyala
Kullanıcı avatarı

Konu Sahibi
Colditz
Mesajlar: 2574
Kayıt: Çrş Ağu 23, 2017 9:17 pm

Eklentilerde Optimizasyon

Mesaj gönderen Colditz »

Bilmek istediğinizi veya hatalarımı bildirebilirsiniz. Yanlış düşünüyorsun vs diye. Her türlü eleştiriye açığım.
Müsait oldukça devamını getireceğim :)

Link:
Linklerini gizle
Linki Kopyala
Cevapla