Object-oriented programming w PAWN

Jest to pokaz jak prostymi technikami można uzyskać ciekawy efekt.

Tak naprawdę jest to pewien koncept aby trochę uabstrakcyjnić pisanie pluginów. Chciałem poprzez odpowiednie makrodefinicje uzyskać efekt użycia obiektów.

Oczywiście makrodefinicje są prostym mechanizmem ale przy dobrym użyciu pozwalają uzyskać ciekawe efekty.
Jeśli chcesz dowiedzieć się wiecej o preprocesorze i makrodefinicjach sprawdź ten poradnik http://darkgl.pl/2014/12/18/pawn-pre-processor-czesc-1/

Spójrzmy najpierw na wycinek kodu

public plugin_cfg(){
	findPluginsAndPause();
	
	ConfigClass.loadConfig();
	
	MapManager.constructor();
	
	switch( ConfigClass.getLoadFrom() ){
		case LOAD_FROM_FILE :{
			new szFileMaps[ 256 ];
			
			formatex( szFileMaps[ get_configsdir( szFileMaps , charsmax( szFileMaps ) ) ] , charsmax( szFileMaps ) - strlen( szFileMaps ) , "/%s/%s" , folderConfig , mapsFile );
			
			LoadClass.loadFromFile( MapManager.getNormalObject() , szFileMaps );
		}
		case LOAD_FROM_FOLDER : {
			new szFolderMaps[ 256 ];
			
			formatex( szFolderMaps[ get_basedir( szFolderMaps , charsmax( szFolderMaps ) ) ] , charsmax( szFolderMaps ) - strlen( szFolderMaps ) , "/maps" );
			
			
			LoadClass.loadFromFolder( MapManager.getNormalObject() , szFolderMaps );
		}
	}
}

Czymś nowym w pawnie na pewno jest użycie tego typu konstrukcji

LoadClass.loadFromFolder( MapManager.getNormalObject() , szFolderMaps );

normalnie kompilator czegoś takiego nam oczywiście nie skompiluje ale jednak jakoś się udało 😉

Plik LoadClass

#define LoadClass. __loadClass__

stock LoadClass.loadFromFile( MapsObject: object , const szFile[] ){
}

stock LoadClass.loadFromFolder( MapsObject: object , const szFolder[] ){
}

Plik MapManager

#define MapManager. __mapmngClass__

stock MapManager.constructor(){
	normalMaps = MapsClass.constructor();
	littleMaps = MapsClass.constructor();
}

stock MapManager.destructor(){
	MapsClass.destructor( normalMaps );
	MapsClass.destructor( littleMaps );
}

stock MapsObject: MapManager.getNormalObject(){
	return normalMaps;
}

Odrazu widać tutaj jak sztuczkę wykorzystuję

define MapManager. __mapmngClass__

W momencie działania preprocesora tego typu kod:

stock MapManager.constructor()

Zostanie zamieniony na

stock __mapmngClass__constructor(){

Dzięki temu że definicje są dziedziczone mimo iż sama definicja jest zdefiniowana w pliku inc i tak obowiązuje w głownym pliku.

Kolejny przykład „klasy” tym razem z prywatnymi składowymi klasy

#include <amxmodx>
#include <amxmisc>

#define LogClass. __logClass__
#define Private.LogClass. __prilogClass__

enum LogClass.logType {
	LOG_CONSOLE_SERVER
}

stock LogClass.logInfo( logTo , const szFormat[] , any:... ){
	new szLogMessage[ 256 ];
	
	vformat( szLogMessage , charsmax( szLogMessage ) , szFormat , 3 );
	
	switch( logTo ){
		case LOG_CONSOLE_SERVER:{
			Private.LogClass.logInfConsole( szLogMessage );
		}
	}
}

stock Private.LogClass.logInfConsole( const szMessage[] ){
	
	new szLogMessage[ 256 ];
	
	copy( szLogMessage , charsmax( szLogMessage ) , szMessage );
	
	Private.LogClass.addPrefixConsole( szLogMessage , charsmax( szLogMessage ) );
	
	log_amx( szLogMessage );
}

stock Private.LogClass.addPrefixConsole( szMessage[] , maxSize ){
	copy( szMessage , maxSize , pluginPrefixLogConsole );
}

Dodatkowo pełny projekt do przeglądania na własnym komputerze: OOP Pawn.zip Download

4 komentarzy o “Object-oriented programming w PAWN

  1. „W momencie działania preprocesora tego typu kod:”
    Błąd w kodzie pod tym. Źle zamknięte [pawn]

    Tylko to wciąż wydawać się może że to jest to na co wygląda a tak naprawdę to są funkcje i stocki które właśnie tak są nazwane. Fajnie jak by można było zrobić kilka stocków a następnie do klas można było te funkcje swobodnie przypisywać zamiast każdej z osobna je robić.

    1. Wiesz jest to tylko dobre użycie preprocesora można się zastanowić jak to inaczej zrobić i pracuje nad jedna rzeczą która mam nadzieje pomoże trochę to rozwinać.

      Ps. Czy Twoje rozwiązanie to nadal OOP 😉 ?

Dodaj komentarz