Skocz do zawartości

Rekomendowane odpowiedzi

Składnia nowa czy stara?

 

1. Wprowadzenie - Co to w ogóle jest składnia?
W językach programowania, składnia jest to swoista pisemna specyfikacja tego jak dany język ma zostać napisany. W innych słowach, składnia to 'zasady pisowni', które narzucają nam sposób w jaki ma wyglądać napisany przez nas kod, by kompilator zrozumiał co piszemy. Dla każdego języka programowania składnia jest inna.
Do początku roku 2015, Sourcepawn miał tak zwaną starą składnie. Czwartego lutego 2015 został opublikowany SourceMod w wersji 1.7, który zaprezentował nam nową składnię. Sourcepawn jest bardzo starym językiem, dlatego jego developerzy chcieli popchnąć jego rozwój w kierunku innych nowoczesnych i popularnych języków takich jak Java czy C. Z tego powodu nowa składnia bardzo przypomina składnie z tych języków.

 

2. Jakie widoczne zmiany zaszły w składni i wersji 1.7?

I. Deklaracja zmiennych została zmieniona z systemu 'tagów':

Spoiler
new iZmiennaInteger;
new Float:fZmiennaFloat;
new String:sZmiennaString[];

 

Na bardziej formalny (i znajomy z innych języków) system:

Spoiler
int iZmiennaInteger;
float fZmiennaFloat;
char cZmiennaChar[];

 

System tagów (Float: / String:) był przestarzały. Nie dość że w trakcie działania programu można było je zmieniać (co mogło powodować zdziwienie osób patrzących w kod, czemu nagle zmienna zdeklarowana jako Float: przyjmowała wartości String:?), to to, iż oznaczyliśmy zmienną jako Float: wcale nie znaczyło że program postrzega tą zmienną jako typ zmiennoprzecinkowy. Nowa składnia daje nam typy zmiennych z prawdziwego zdarzenia: int, float, char, void.
Typ String: zostaje zamieniony na typ char. Co to za zmiana i czemu jest ważna? Typ char reprezentuje (tak jak wcześniej String: ) znak, lub najczęściej zdeklarowaną tablicę znaków. Poprzedni zapis był bardzo mylący, ponieważ w innych językach typ 'string' jest zupełnie inny niż char. Taka zmiana mocniej wskazuje co dana zmienna char w sobie posiada oraz otwiera drogę developerom na zaimplementowanie prawdziwego typu string w przyszłych wersjach SourceModa.

Ponadto, zmienia się również sposób zapisu funkcji z:

Spoiler
public Action:SpawnPost(new client);
public DoSomething(new param1, new Float: param2);
SetPlayerHP(new client, new health);

 

Na:

Spoiler
public Action SpawnPost(int client);
public void DoSomething(int param1, float param2);
stock void SetPlayerHP(int client, int health);

 

 

II. Możliwa implementacja Metodmap (Methodmaps)
Są to struktury zorientowane obiektowo. Przyczepiają metody do enumów. Może jaśniej będzie, jeśli przedstawię przykład Metodmapy

Spoiler
enum Player
{
	SERVER_PLAYER = 0
}

methodmap Player
{
	public void WyrzucGracza(const char[] wiadomosc)
	{
		KickClient(this.Index, "%s", wiadomosc);
	}
	
	public void ZabijGracza()
	{
		ForcePlayerSuicide(this.Index);
	}
	
	property int Zycie
	{
		public get()
		{
			return GetClientHealth(this.Index);
		}
	}
	
	property bool Zywy
	{
		public get()
		{
			return IsPlayerAlive(this.Index);
		}
	}
	
	property int Index
	{
		public get()
		{
			return int(this);
		}
	}
}

 

Dzięki temu zapisowi, możemy napisać następujący kod:

Spoiler
Player gracz = new Player();

//Jakiś tam kod

CheckPlayer(gracz);

//Jakiś tam kod

void CheckPlayer (Player player)
{
	if (player.Zycie < 0 && player.Zyje)
	{
		player.ZabijGracza();
		
		if (player.Zyje)
		{
			player.WyrzucGracza("Wow, naprawdę masz jakiegoś godmoda, trzeba Cię wyrzucić");
		}
	}
}

 

Zamiast używać zwykłych funkcji na indeksie klienta, Metodmapa daje nam możliwość  napisania działających funkcji na danym obiekcie (w tym przypadku indeksy klienta) i używania ich później w kodzie. Jest to duży krok w stronę obiektowości języka, który poniekąd jest łatwiejszy w użyciu i łatwiej się czyta kod napisany obiektowo. Z drugiej strony, jest trudniejszy w implementacji, najczęściej z tego względu że nauka programowania w szkołach zaczyna się od programowania strukturalnego, nie obiektowego.

 

III. Obiektowo napisane funkcje
W dokumentacji, pliki adt_trie.inc, adt_array.inc oraz menus.inc zostały przepisane na język obiektowy.
Przykład kodu, który można było napisać kiedyś:

Spoiler
new Handle:menu = CreateMenu(Menu_Handler)
AddMenuItem(menu, "de_dust", "Dust")
AddMenuItem(menu, "cs_assault", "Assault")
AddMenuItem(menu, "cs_thunder", "Thunder")
SetMenuExitButton(menu, true)
DisplayMenu(menu, client)

//jakieś działanie kodu
  
//zamknięcie uchwytu menu
CloseHandle(menu);  

 

Przykład kodu który można napisać teraz:

Spoiler
Menu menu = Menu(MenuHandler);
menu.AddItem("de_dust", "Dust");
menu.AddItem("cs_assault", "Assault");
menu.AddItem("cs_thunder", "Thunder");
menu.ExitButton = true;
menu.Display(client);

//Jakieś działanie kodu

//Zwolnienie pamięci gdzie znajduje się menu i usunięcie zmiennej
delete menu;

 

 

3. pragma newdecls required - Jak używać nowej składni w kodzie?
Wystarczy, że gdzieś na początku pliku umieścimy kod:

#pragma newdecls required

Wtedy kompilator będzie od nas wymagał nowej składni i da nam znać przy kompilacji, jeśli coś jest napisane w starej składni.

 

4. To dlaczego używać nowej składni?
Jeśli zależy Ci na schludnym wyglądzie kodu, podążaniem za duchem czasu i nadążanie za nowymi technologiami w dziedzinie IT zawsze dobrze jest zaznajomić się z nowinkami technicznymi. A przejście na nową składnie umożliwia również łatwiejsze poznanie składni innych języków.

 

Bibliografia
Ten tutorial został napisany na podstawie https://www.sourcemod.net/index.php , https://forums.alliedmods.net/showthread.php?t=244092 , https://wiki.alliedmods.net/SourcePawn_Transitional_Syntax Z jednego z tych linków skopiowałem również kody programu

 

*Uprasza się o nie kopiowanie poradnika bez wcześniejszego zapytania autora o zgodę

Sygnatura użytkownika

Hej! Pamiętaj uhonorować reputacją KAŻDEGO użytkownika który Ci pomógł! 👮‍♂️

 

Moje pluginy: Ultimate Weather | XiaolinMod | Knife Round | Storm Circle |  AutoBunnyHop | Remove Weapons RoundEnd
Moje artykuły: Przejrzysty kod | Optymalizacja warunków IF | Usuń martwy kod | Notacja węgierska | Co to backdoor? | Jak wgrać plugin? | Lokalna kompilacja | Licencja na plugin | Wektory | Nowa składnia sm | Funkcje czasowe | Spolszczenie pluginu

  • Lubię to!
Odnośnik do odpowiedzi
Udostępnij na innych stronach
  • 4 miesiące temu...

Co do methodmaps to zauważyłem jak kompilowałem, że 

property int Index
{
	public get()
	{
		return int(this);
	}
}

musi być zdefiniowane na początku, ponieważ kompilator potem nie widzi tego Indexu

error 105: cannot find method or property Player.index
methodmap Player
{
  	property int Index
	{
		public get()
		{
			return int(this);
		}
	}
  
	public void WyrzucGracza(const char[] wiadomosc)
	{
		KickClient(this.Index, "%s", wiadomosc);
	}
	
	public void ZabijGracza()
	{
		ForcePlayerSuicide(this.Index);
	}
	
	property int Zycie
	{
		public get()
		{
			return GetClientHealth(this.Index);
		}
	}
	
	property bool Zywy
	{
		public get()
		{
			return IsPlayerAlive(this.Index);
		}
	}
}

I przy okazji wdarła Ci się literówka bo zamiast KickClient jest KickClent ?

  • Lubię to!
Odnośnik do odpowiedzi
Udostępnij na innych stronach

Ostatnio przeglądający ten temat (5 użytkowników)

Dołącz do dyskusji

Możesz dodać zawartość już teraz a zarejestrować się później. Jeśli posiadasz już konto, zaloguj się aby dodać zawartość za jego pomocą.

Gość
Dodaj odpowiedź do tematu...

×   Wklejono zawartość z formatowaniem.   Usuń formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Odnośnik został automatycznie osadzony.   Przywróć wyświetlanie jako odnośnik

×   Przywrócono poprzednią zawartość.   Wyczyść edytor

×   Nie możesz bezpośrednio wkleić grafiki. Dodaj lub załącz grafiki z adresu URL.

×
×
  • Dodaj nową pozycję...