Nowoczesne, wyłącznie nagłówkowe i wysokopoziomowe SDK C++ do tworzenia wtyczek i modułów dla SA-MP.
- Português: README
- Deutsch: README
- English: README
- Español: README
- Français: README
- Italiano: README
- Русский: README
- Svenska: README
- Türkçe: README
- SA-MP SDK
- Języki
- Spis Treści
- 1. Wprowadzenie i filozofia projektowania
- 2. Konfiguracja i środowisko
- 3. Obszerny przewodnik po API
- 3.1. Cykl życia wtyczki
- 3.2. Eksportowanie Funkcji Pluginu
- 3.3.
Plugin_Public: przechwytywanie zdarzeń Pawn - 3.4.
Plugin_Native: tworzenie funkcji natywnych w C++ - 3.5.
Plugin_Native_Hook: przechwytywanie istniejących natywnych funkcji SA-MP - 3.6. Makra
Pawn_*: wywoływanie funkcji Pawn z C++ - 3.7.
Plugin_Module: zarządzanie dynamicznymi modułami - 3.8.
Plugin_Call: wywoływanie wewnętrznych natywnych funkcji wtyczki - 3.9. Funkcje narzędziowe SDK
- 4. Kompilacja i wdrożenie
- Licencja
API wtyczek SA-MP to interfejs programowania w języku C. Choć funkcjonalny i podstawowy, stwarza on wyzwania związane z programowaniem niskopoziomowym:
- Ręczne zarządzanie pamięcią: Funkcje takie jak
amx_Allotiamx_Releasewymagają od programisty jawnego alokowania i zwalniania pamięci na stercie AMX. Jest to częsta przyczyna wycieków pamięci i błędów wykonawczych. - Słabe typowanie i ręczne konwersje: Parametry są przekazywane jako tablica
cells, wymuszając jawne (i często niebezpieczne) konwersje międzycell,int,floatichar*. - Wielomówność i boilerplate: Wyodrębnianie wielu parametrów z tablicy
cell* params, obsługa długości ciągów znaków i zarządzanie stosem AMX dla wywołań zwrotnych C++ do Pawn wymaga powtarzającego się kodu. - Kruchość interfejsu: Brak sprawdzania typów w czasie kompilacji (type safety) oznacza, że błędy w przekazywaniu parametrów lub typów mogą pozostać niezauważone aż do wykonania, powodując awarie lub niezdefiniowane zachowanie.
SA-MP SDK rozwiązuje te problemy, dostarczając potężną warstwę abstrakcji w C++:
- RAII (Resource Acquisition Is Initialization): Automatyczne zarządzanie pamięcią w AMX.
Amx_Scoped_Memorygwarantuje, że zaalokowana pamięć zostanie zwolniona. - Bezpieczeństwo typów: Automatyczna i bezpieczna konwersja parametrów między C++ a Pawn. Działasz bezpośrednio z
int,float,std::string. - Zwięzła i idiomatyczna składnia: Makra i szablony zapewniają czyste API, które bardziej przypomina nowoczesne C++ niż tradycyjne API C.
- Solidne przechwytywanie: Zaawansowany silnik hakowania umożliwia przezroczyste przechwytywanie wywołań zwrotnych Pawn (
Plugin_Public), tworzenie nowych natywnych (Plugin_Native) oraz hakowanie i łączenie istniejących natywnych funkcji SA-MP (Plugin_Native_Hook). - Wysoka wydajność: Szerokie wykorzystanie haszowania w czasie kompilacji (FNV1a), buforowanie funkcji i optymalizacje
thread_localw celu zminimalizowania narzutu abstrakcji.
SDK składa się wyłącznie z plików nagłówkowych (.hpp, .h).
- Zalety:
- Uproszczona integracja: Brak bibliotek do zbudowania, połączenia lub dystrybucji. Wystarczy dołączyć nagłówki.
- Optymalizacje kompilatora: Kompilator ma pełny wgląd w kod SDK i twojej wtyczki, co pozwala na agresywne wbudowywanie i optymalizacje czasu linkowania, co może skutkować szybszymi binariami.
- Implikacje:
- Czas kompilacji: W przypadku bardzo dużych projektów kompilacja może trwać dłużej z powodu wielokrotnego dołączania kodu SDK. Jest to łagodzone przez strażników dołączeń i zasadę C++ „dołączaj tylko to, co jest potrzebne”.
- Makra implementacyjne: Konieczność makra
SAMP_SDK_IMPLEMENTATIONjest konsekwencją modelu tylko nagłówkowego, aby uniknąć redefinicji symboli.
- Kompilator C++: Zgodny z C++17 lub nowszym.
- GCC (wersja 8+)
- Clang (wersja 5+)
- MSVC (Visual Studio 2017+)
- Architektura: x86 (32-bit). SA-MP działa wyłącznie na tej architekturze. SDK zawiera sprawdzenia w pliku
platform.hpp, które spowodują błędy kompilacji w przypadku wykrycia nieprawidłowej architektury. - System operacyjny: Windows lub Linux.
Dla przejrzystości i organizacji, powszechne jest organizowanie SDK w podfolderze samp-sdk.
meu_plugin/
├── samp-sdk/
│ ├── // Outros arquivos do SDK
│ └── samp_sdk.hpp // Główny nagłówek do dołączenia
│
├── src/
│ ├── main.cpp // Gdzie definiuje się SAMP_SDK_IMPLEMENTATION
│ └── my_custom_logic.cpp // Opcjonalnie, do organizacji kodu
│
└── CMakeLists.txt (ou .vcxproj, Makefile)
Zawsze definiuj te makra przed dołączeniem samp_sdk.hpp.
- Cel: Sygnalizuje kompilatorowi, że ten plik
.cpppowinien generować implementacje funkcji eksportowych wtyczki (Supports,Load,Unload,AmxLoad,AmxUnload,ProcessTick). SDK automatycznie zajmuje się eksportem tych funkcji, eliminując potrzebę plików.def(w systemie Windows) lub deklaracji__attribute__((visibility("default")))(w systemie Linux) dla tych funkcji. - Wpływ techniczny: Bez tego makra linker nie znajdzie wymaganych eksportów, a serwer SA-MP nie będzie w stanie załadować Twojej wtyczki.
- Podstawowa zasada: Zdefiniuj to makro w TYLKO JEDNYM pliku
.cppw całym swoim projekcie. Zdefiniowanie go w więcej niż jednym pliku spowoduje błąd linkowania „zduplikowanego symbolu”.
// main.cpp
#define SAMP_SDK_IMPLEMENTATION // Makro powoduje, że SDK automatycznie eksportuje wymagane funkcje.
#include "samp-sdk/samp_sdk.hpp"
// ... twój kod wtyczki ...- Cel: Włącza wywołania zwrotne cyklu życia skryptu Pawn (
OnAmxLoad,OnAmxUnload) oraz możliwość tworzenia nowych funkcji natywnych w C++ (Plugin_Native). - Włączone funkcje:
- Wywołania zwrotne
OnAmxLoad(AMX* amx)iOnAmxUnload(AMX* amx). - Deklarowanie i rejestrowanie nowych natywnych funkcji C++ za pomocą
Plugin_Native. - Makro
Plugin_Calldo wywoływania natywnych funkcji stworzonych za pomocąPlugin_Nativewewnątrz własnej wtyczki.
- Wywołania zwrotne
- Wpływ techniczny: Kiedy to makro jest zdefiniowane, SDK automatycznie zbiera wszystkie Twoje
Plugin_Natives. W funkcjiSupports(), flagaSUPPORTS_AMX_NATIVESjest automatycznie dodawana, jeśli w Twoim projekcie znajdują się jakieśPlugin_Natives. - Elastyczność: Możesz zdefiniować to makro w wielu plikach
.cpp. System rejestracji statycznej SDK skonsoliduje wszystkie natywne z różnych jednostek kompilacji w jedną globalną listę.
// my_natives.cpp (może być oddzielnym plikiem od main.cpp)
#define SAMP_SDK_WANT_AMX_EVENTS // Tylko do włączenia Plugin_Native i wywołań zwrotnych OnAmxLoad/OnAmxUnload
#include "samp-sdk/samp_sdk.hpp"
Plugin_Native(MyCustomNative, AMX* amx, cell* params) {
// ...
return 0;
}- Cel: Włącza wywołanie zwrotne
OnProcessTick(), które jest regularnie wywoływane przez serwer. - Wpływ techniczny: Automatycznie dodaje flagę
SUPPORTS_PROCESS_TICKw funkcjiSupports().
// main.cpp
#define SAMP_SDK_IMPLEMENTATION
#define SAMP_SDK_WANT_PROCESS_TICK
#include "samp-sdk/samp_sdk.hpp"
void OnProcessTick() {
// Logika wykonywana co "takt" serwera (np. 20 ms)
// Ostrożnie z ciężkimi operacjami tutaj!
}Ten plik dostarcza wszystkie znane stałe i limity SA-MP, takie jak MAX_PLAYERS, INVALID_PLAYER_ID, PLAYER_STATE_ONFOOT, WEAPON_DEAGLE, DIALOG_STYLE_LIST itp. Jest automatycznie dołączany przez samp_sdk.hpp i powinien być używany do zapewnienia kompatybilności i czytelności kodu.
Poniższe funkcje są punktami wejścia i wyjścia Twojej wtyczki, automatycznie eksportowanymi przez SDK.
- Opis: Pierwsza funkcja wywoływana przez serwer SA-MP po pomyślnym załadowaniu Twojej wtyczki do pamięci.
- Użycie: Idealne do inicjalizacji dowolnego systemu, ładowania konfiguracji, otwierania połączeń z bazami danych lub ładowania modułów (
Plugin_Module). - Zwraca:
true: Wtyczka została pomyślnie zainicjowana, a ładowanie jest kontynuowane.false: Wtyczka nie powiodła się podczas inicjalizacji. Ładowanie zostanie przerwane, a wtyczka zostanie odładowana.
// main.cpp
bool OnLoad() {
Samp_SDK::Log("Inicializando MeuPlugin v1.0...");
// Przykład: Ładowanie modułu (więcej szczegółów w sekcji 3.6)
if (!Plugin_Module("my_database_module", "plugins/db_connector", "Módulo de Banco de Dados carregado.")) {
Samp_SDK::Log("ERRO: Falha ao carregar o módulo de banco de dados!");
return false; // Przerywa ładowanie głównej wtyczki
}
return true;
}- Opis: Ostatnia funkcja wywoływana przez serwer SA-MP przed odładowaniem Twojej wtyczki z pamięci.
- Użycie: Idealne do czyszczenia zasobów, zamykania połączeń, zapisywania stanów i zapewniania, że żadne zasoby nie wyciekną. SDK automatycznie zarządza odładowywaniem modułów (
Plugin_Module).
// main.cpp
void OnUnload() {
Samp_SDK::Log("MeuPlugin descarregado. Liberando recursos...");
// Nie są wymagane żadne ręczne działania dla modułów ładowanych za pomocą Plugin_Module;
// SDK zajmuje się tym.
}- Opis: Informuje serwer SA-MP, które funkcje Twoja wtyczka obsługuje i chce używać.
- Użycie: Zawsze zwracaj
SUPPORTS_VERSION(lubSAMP_PLUGIN_VERSION). FlagiSUPPORTS_AMX_NATIVESiSUPPORTS_PROCESS_TICKsą automatycznie dodawane przez SDK, jeśli istniejąPlugin_Natives i/lub jeśli makroSAMP_SDK_WANT_PROCESS_TICKjest zdefiniowane, odpowiednio. Upraszcza to konserwację i zapobiega błędom.
// main.cpp
unsigned int GetSupportFlags() {
return SUPPORTS_VERSION; // SDK automatycznie dodaje niezbędne flagi.
}- Wymaga:
SAMP_SDK_WANT_AMX_EVENTS - Opis: Wywoływana za każdym razem, gdy nowy skrypt Pawn (Gamemode lub Filterscript) jest ładowany i inicjowany na serwerze.
- Użycie: Jeśli potrzebujesz specyficznej logiki dla każdego skryptu AMX lub chcesz zainicjować dane specyficzne dla skryptu.
// main.cpp (z zdefiniowanym SAMP_SDK_WANT_AMX_EVENTS)
void OnAmxLoad(AMX* amx) {
// amx reprezentuje nową, załadowaną instancję skryptu.
Samp_SDK::Log("Script AMX carregado: %p", (void*)amx);
}- Wymaga:
SAMP_SDK_WANT_AMX_EVENTS - Opis: Wywoływana, gdy skrypt Pawn jest odładowywany z serwera.
- Użycie: Do czyszczenia wszelkich zasobów, które zaalokowałeś lub powiązałeś z danym
AMX*.
// main.cpp (z zdefiniowanym SAMP_SDK_WANT_AMX_EVENTS)
void OnAmxUnload(AMX* amx) {
Samp_SDK::Log("Script AMX descarregado: %p", (void*)amx);
}- Wymaga:
SAMP_SDK_WANT_PROCESS_TICK - Opis: Wywoływana wielokrotnie co "takt" serwera (zazwyczaj 20 razy na sekundę, czyli co 50 ms).
- Użycie: Do ciągłej logiki w tle, timerów, aktualizacji stanu, które nie zależą od zdarzeń graczy, lub synchronizacji danych.
- Ostrożnie: Unikaj operacji blokujących lub wymagających dużej mocy obliczeniowej, ponieważ mogą one powodować opóźnienia na serwerze.
// main.cpp (z zdefiniowanym SAMP_SDK_WANT_PROCESS_TICK)
static int tick_count = 0;
void OnProcessTick() {
tick_count++;
if (tick_count % 200 == 0) // Co 10 sekund (20 taktów/s * 10 s = 200 taktów)
Samp_SDK::Log("Servidor ativo por %d segundos.", tick_count / 20);
}Aby serwer SA-MP mógł wywoływać funkcje twojego pluginu (Load, Supports, itp.), muszą one zostać "wyeksportowane" z pliku DLL (Windows) lub SO (Linux). SDK automatyzuje eksport standardowych funkcji cyklu życia, ale również dostarcza narzędzia, dzięki którym możesz eksportować własne niestandardowe funkcje, jeśli potrzebujesz interoperacyjności z innymi programami.
Metoda eksportowania funkcji różni się w zależności od kompilatora.
W systemie Windows z MSVC najłatwiejszym sposobem eksportowania niestandardowych funkcji jest użycie makra Export_Plugin, zdefiniowanego w exports.hpp.
- Składnia:
Export_Plugin("Funkcja", "Stos") Funkcja: Dokładna nazwa funkcji do wyeksportowania.Stos: Całkowita liczba bajtów, które parametry funkcji zajmują na stosie. Dla konwencji__stdcall(standard SDK w systemie Windows) obliczenie to4 * (Liczba Parametrów).
#include "samp-sdk/exports.hpp"
// Przykład: Eksportowanie niestandardowej funkcji, która mogłaby być wywołana
// przez inny program lub plugin, który zna jej sygnaturę.
const char* SAMP_SDK_CALL GetPluginVersion() {
return "1.0.0";
}
Export_Plugin("GetPluginVersion", "0");Warning
Ograniczenie Export_Plugin
To makro działa tylko z kompilatorem MSVC (Visual Studio). Wykorzystuje dyrektywę #pragma specyficzną dla Microsoft, która jest ignorowana przez inne kompilatory takie jak GCC i Clang.
Dla GCC i Clang (w systemie Windows lub Linux) eksport jest zarządzany przez makro SAMP_SDK_EXPORT, zdefiniowane w platform.hpp. Po prostu umieszczasz je przed definicją funkcji.
- Mechanizm: W systemie Linux dodaje
__attribute__((visibility("default"))). W systemie Windows z GCC/Clang dodaje__attribute__((dllexport)). - Użycie: SDK już stosuje
SAMP_SDK_EXPORTdo wszystkich funkcji cyklu życia (Load,Unload, itp.), więc ich eksport jest w pełni automatyczny dla tych kompilatorów. Dla swoich niestandardowych funkcji po prostu zrób to samo.
// Dla GCC/Clang definicja funkcji z SAMP_SDK_EXPORT jest wystarczająca.
SAMP_SDK_EXPORT const char* SAMP_SDK_CALL GetPluginVersion() {
return "1.0.0";
}Makro Plugin_Public jest głównym pomostem do odbierania wywołań zwrotnych z Pawn w Twoim kodzie C++.
Plugin_Public(NazwaPubliczna, Typ1 Param1, Typ2 Param2, ...)- Nazwa funkcji C++, którą deklarujesz, musi być taka sama jak nazwa wywołania zwrotnego Pawn (np.
OnPlayerConnect). - Typy parametrów C++ (
int,float,std::string) są automatycznie konwertowane przez SDK.
// Przechwytuje OnPlayerText(playerid, text[])
Plugin_Public(OnPlayerText, int playerid, std::string text) {
Samp_SDK::Log("Jogador %d disse: %s", playerid, text.c_str());
return PUBLIC_CONTINUE;
}SDK automatycznie obsługuje odczytywanie stosu cell AMX i konwersję do określonych typów C++:
int: Konwertowane bezpośrednio zcell.float: Konwertowane zcellza pomocąamx::AMX_CTOF.std::string: SDK odczytuje adres ciągu znaków w AMX, alokujestd::stringw C++ i kopiuje zawartość.
Wartość zwracana przez Twoją funkcję Plugin_Public jest kluczowa i określa przepływ wykonania wywołania zwrotnego:
return PUBLIC_CONTINUE;(wartość1): Wskazuje, że wykonanie wywołania zwrotnego powinno być kontynuowane. Jeśli istnieją inne wtyczki, które również przechwytują to wywołanie zwrotne, zostaną one wywołane (w odwrotnej kolejności ładowania). Następnie zostanie wywołana oryginalnapublicw skrypcie Pawn.return PUBLIC_STOP;(wartość0): Wskazuje, że wykonanie wywołania zwrotnego powinno zostać przerwane. Żadna inna wtyczka (o niższym priorytecie) ani oryginalnapublicw skrypcie Pawn nie zostanie wywołana dla tego zdarzenia. Jest to idealne rozwiązanie do implementacji systemu, który „nadpisuje” lub „blokuje” standardowe zachowanie SA-MP.
// main.cpp
Plugin_Public(OnPlayerCommandText, int playerid, std::string cmdtext) {
if (cmdtext == "/freeze") {
Pawn_Native(TogglePlayerControllable, playerid, 0); // Zamraża gracza
Pawn_Native(SendClientMessage, playerid, -1, Plugin_Format("Jogador %d congelado.", playerid));
return PUBLIC_STOP; // Zapobiega przetwarzaniu polecenia przez inne skrypty.
}
return PUBLIC_CONTINUE; // Pozwala na przetwarzanie innych poleceń.
}Zaawansowaną funkcją Plugin_Public jest obsługa „Ghost Callbacks”. Oznacza to, że możesz przechwycić wywołanie zwrotne Pawn, nawet jeśli nie jest ono obecne w skrypcie .amx trybu gry lub skryptu filtrującego. SDK „oszukuje” serwer, aby i tak wywołał Twój hook C++. Jest to przydatne w przypadku wywołań zwrotnych wewnętrznych lub do tworzenia nowych funkcji bez zależności od obecności public w skrypcie Pawn.
// Możesz zdefiniować wywołanie zwrotne, którego skrypt Pawn nie posiada, ale Twoja wtyczka będzie go nasłuchiwać.
Plugin_Public(OnMyCustomInternalEvent, int data1, float data2) {
Samp_SDK::Log("Evento interno customizado recebido: %d, %.2f", data1, data2);
return PUBLIC_CONTINUE;
}
// Aby "wyzwolić" to zdarzenie z innego miejsca w Twoim kodzie C++:
// Pawn_Public(OnMyCustomInternalEvent, 123, 45.67f);
// Wywołanie trafi do Twojego Plugin_Public powyżej, nawet jeśli w Pawn nie ma OnMyCustomInternalEvent.Plugin_Native pozwala rozszerzyć funkcjonalność Pawn o wysokowydajny kod C++.
Plugin_Native(NativeName, AMX* amx, cell* params)- Funkcja C++ musi mieć dokładnie tę sygnaturę:
cell NativeName(AMX* amx, cell* params). NativeNameto nazwa, której będą używać skrypty Pawn.
// Pawn: native GetPlayerPingAverage(playerid);
Plugin_Native(GetPlayerPingAverage, AMX* amx, cell* params) {
// ... Implementacja ...
return 0;
}Note
Nie musisz ręcznie wywoływać amx_Register. SDK wykrywa wszystkie Twoje Plugin_Natives (w dowolnym pliku .cpp, który dołączył samp_sdk.hpp i zdefiniował SAMP_SDK_WANT_AMX_EVENTS) i automatycznie rejestruje je w każdym załadowanym skrypcie AMX (OnAmxLoad).
- Opis: Prostszy pomocnik do sekwencyjnego wyodrębniania wielu parametrów.
- Użycie:
Register_Parameters(zmienna1, zmienna2, ...) - Ograniczenia: Dotyczy parametrów wejściowych. Nie obsługuje parametrów opcjonalnych ani dostępu według indeksu.
- Obsługiwane typy:
int,float,std::string.
// Pawn: native SetPlayerSkinAndMoney(playerid, skinid, money);
Plugin_Native(SetPlayerSkinAndMoney, AMX* amx, cell* params) {
int playerid, skinid, money;
Register_Parameters(playerid, skinid, money); // Wyodrębnia 3 parametry
Pawn_Native(SetPlayerSkin, playerid, skinid);
Pawn_Native(GivePlayerMoney, playerid, money);
return 1;
}- Opis: Klasa opakowująca, która zapewnia obiektowy interfejs do dostępu do parametrów natywnej funkcji. Potężniejsza dla złożonych scenariuszy.
- Konstrukcja:
Native_Params p(amx, params);
- Opis: Zwraca liczbę parametrów przekazanych do natywnej funkcji.
- Użycie: Niezbędne do obsługi parametrów opcjonalnych.
- Opis: Wyodrębnia parametr wejściowy według indeksu i konwertuje go na typ
T. - Obsługiwane typy:
int,float,std::string.
// Pawn: native GetPlayerWeaponAmmo(playerid, weaponid = -1);
Plugin_Native(GetPlayerWeaponAmmo, AMX* amx, cell* params) {
Native_Params p(amx, params);
int playerid = p.Get<int>(0);
int weaponid = (p.Count() > 1) ? p.Get<int>(1) : Pawn_Native(GetPlayerWeapon, playerid);
return Pawn_Native(GetPlayerAmmo, playerid, weaponid);
}- Opis: Pobiera wartość parametru referencyjnego (wskaźnik Pawn) i przechowuje ją w
out_value. - Użycie: Do odczytywania wartości, które zostały przekazane przez referencję z Pawn.
- Zwraca:
true, jeśli adres AMX jest prawidłowy,falsew przeciwnym razie.
// Pawn: native CheckPlayerStats(playerid, &Float:health, &money);
Plugin_Native(CheckPlayerStats, AMX* amx, cell* params) {
Native_Params p(amx, params);
int playerid = p.Get<int>(0);
float health = 0.0f;
int money = 0;
// Pobiera wartości referencji (Pawn przekazał adresy)
p.Get_REF(1, health); // Odczytuje wartość Float:health
p.Get_REF(2, money); // Odczytuje wartość money
Samp_SDK::Log("Jogador %d, Health: %.1f, Money: %d", playerid, health, money);
// Teraz je modyfikujemy
health = 50.0f;
money += 100;
// I zapisujemy z powrotem do pamięci Pawn
p.Set_REF(1, health);
p.Set_REF(2, money);
return 1;
}- Opis: Zwraca
std::optional<T>do odczytania parametru referencyjnego. Bezpieczniejsze dla C++17 i nowszych.
- Opis: Zapisuje wartość
Tdo parametru referencyjnego Pawn (adres, który Pawn przekazał). - Użycie: Do modyfikacji wartości, które zostały przekazane przez referencję, sprawiając, że Pawn widzi zmianę.
- Zwraca:
true, jeśli zapis powiódł się,falsew przeciwnym razie.
- Twoja funkcja
Plugin_Nativemusi zwracaćcell. - Aby zwrócić
intlubbool, użyj rzutowania nacell. - Aby zwrócić
float, użyjamx::AMX_FTOC(mój_float).
// Zwraca bool
Plugin_Native(IsPlayerSpawned, AMX* amx, cell* params) {
int playerid;
Register_Parameters(playerid);
return (Pawn_Native(GetPlayerState, playerid) == PLAYER_STATE_SPAWNED) ? 1 : 0;
}
// Zwraca float
Plugin_Native(GetPlayerMaxHealth, AMX* amx, cell* params) {
return amx::AMX_FTOC(100.0f); // Zwraca 100.0f
}Makro Plugin_Native_Hook pozwala przechwycić i zmodyfikować zachowanie dowolnej istniejącej funkcji natywnej SA-MP lub innych wtyczek. Jest to potężny mechanizm do rozszerzania lub zmiany standardowej logiki serwera.
Plugin_Native_Hook(NativeName, AMX* amx, cell* params)- Funkcja C++ musi mieć dokładnie tę sygnaturę:
cell NativeName(AMX* amx, cell* params). NativeNamemusi być dokładną nazwą natywnej funkcji, którą chcesz zahakować (np.SendClientMessage,SetPlayerPos).
// Przechwytuje natywną funkcję SendClientMessage
Plugin_Native_Hook(SendClientMessage, AMX* amx, cell* params) {
// ...
return Call_Original_Native(SendClientMessage); // Ważne, aby wywołać oryginalną
}Note
Nie musisz ręcznie wywoływać amx_Register ani definiować SAMP_SDK_WANT_AMX_EVENTS specjalnie dla Plugin_Native_Hook. SDK automatycznie wykrywa i rejestruje Twoje hooki. Przy pierwszym uruchomieniu skryptu AMX, SDK zastępuje wskaźnik natywnej funkcji w tabeli "trampoliną", która przekierowuje do Twojej funkcji Plugin_Native_Hook. Ten proces zapewnia bezpieczne łączenie hooków z wielu wtyczek.
Wewnątrz funkcji Plugin_Native_Hook MUSISZ użyć makra Call_Original_Native(NativeName) do wywołania oryginalnej funkcji (lub kolejnego hooka w łańcuchu). Jest to kluczowe dla:
- Zachowania funkcjonalności: Jeśli nie wywołasz oryginalnej funkcji, zahakowana funkcja natywna po prostu przestanie działać dla innych wtyczek lub serwera.
- Łączenia hooków: Pozwala wielu wtyczkom zahakować tę samą funkcję natywną i wykonanie wszystkich hooków w sekwencji.
- Manipulacji wartością zwracaną: Możesz sprawdzić, a nawet zmodyfikować wartość zwracaną przez
Call_Original_Nativeprzed zwróceniem jej z funkcji hooka.
// Przykład: blokowanie SendClientMessage, jeśli zawiera określone słowo
Plugin_Native_Hook(SendClientMessage, AMX* amx, cell* params) {
Native_Params p(amx, params);
// Wyodrębnia parametry do analizy
int playerid = p.Get<int>(0);
// int color = p.Get<int>(1); // Nie potrzebujemy koloru do tej logiki
std::string message = p.Get_String(2); // Pobiera ciąg znaków wiadomości
if (message.find("BADWORD") != std::string::npos) {
Samp_SDK::Log("MENSAGEM BLOQUEADA para playerid %d: %s", playerid, message.c_str());
return 0; // Zwraca 0 (false) do Pawn, wskazując, że wiadomość nie została wysłana.
// I co ważniejsze, NIE wywołujemy Call_Original_Native, blokując wiadomość.
}
// Jeśli wiadomość nie zawiera zakazanego słowa, wywołujemy oryginalną funkcję natywną
// i zwracamy jej wartość, zapewniając, że wiadomość zostanie wysłana normalnie
// i że inne hooki (jeśli istnieją) zostaną wykonane.
return Call_Original_Native(SendClientMessage);
}#define SAMP_SDK_IMPLEMENTATION
// SAMP_SDK_WANT_AMX_EVENTS nie jest ściśle wymagane dla hooków, ale jest często używane do obsługi OnAmxLoad/Unload
// #define SAMP_SDK_WANT_AMX_EVENTS
#include "samp-sdk/samp_sdk.hpp"
// Hook dla natywnej funkcji CreateVehicle
Plugin_Native_Hook(CreateVehicle, AMX* amx, cell* params) {
Native_Params p(amx, params);
// Wyodrębnia parametry natywnej funkcji CreateVehicle do inspekcji
int modelid = p.Get<int>(0);
float x = p.Get<float>(1);
float y = p.Get<float>(2);
float z = p.Get<float>(3);
float angle = p.Get<float>(4);
int color1 = p.Get<int>(5);
int color2 = p.Get<int>(6);
int respawn_delay = p.Get<int>(7);
bool addsiren = p.Get<bool>(8);
Samp_SDK::Log("HOOK: CreateVehicle chamado! Model: %d, Pos: (%.2f, %.2f, %.2f)", modelid, x, y, z);
// Przykład, jak *zmodyfikować* parametr wejściowy
// Jeśli model to 400 (Landstalker), zmieniamy go na 401 (Bravura)
if (modelid == 400) {
// Modyfikujemy bezpośrednio tablicę 'params' dla oryginalnego wywołania
params[1] = static_cast<cell>(401); // Model znajduje się na pozycji 0 w tablicy parametrów (params[1])
Samp_SDK::Log(" -> Model 400 alterado para 401 antes da criação.");
}
// Wywołujemy oryginalną funkcję natywną (lub następny hook w łańcuchu) z ewentualnie zmodyfikowanymi parametrami
cell original_retval = Call_Original_Native(CreateVehicle);
Samp_SDK::Log("HOOK: CreateVehicle retornou: %d (ID do veículo)", (int)original_retval);
// Tutaj możesz zmodyfikować wartość zwracaną przed zwróceniem jej do Pawn.
// Przykład: jeśli tworzenie pojazdu nie powiodło się, zwróć niestandardowy nieprawidłowy ID.
if ((int)original_retval == INVALID_VEHICLE_ID) {
Samp_SDK::Log(" -> Criação de veículo falhou na native original.");
return -1; // Zwraca inną wartość do Pawn.
}
return original_retval; // Zwraca wartość, którą zwróciła oryginalna natywna funkcja (lub zmodyfikowana powyżej).
}
unsigned int GetSupportFlags() {
return SUPPORTS_VERSION;
}
// Minimalne implementacje dla cyklu życia
bool OnLoad() {
Samp_SDK::Log("Plugin de Exemplo de Native Hook carregado!");
return true;
}
void OnUnload() {
Samp_SDK::Log("Plugin de Exemplo de Native Hook descarregado!");
}
// Te wywołania zwrotne będą dostępne tylko wtedy, gdy zdefiniowano SAMP_SDK_WANT_AMX_EVENTS
/*void OnAmxLoad(AMX* amx) {
Samp_SDK::Log("AMX Load detectado: %p", (void*)amx);
}
void OnAmxUnload(AMX* amx) {
Samp_SDK::Log("AMX Unload detectado: %p", (void*)amx);
}*/Warning
Bezpośrednia manipulacja tablicą cell* params w celu zmiany parametrów wejściowych wymaga ostrożności. Upewnij się, że rozumiesz kolejność i typy parametrów. W większości przypadków użycia p.Get(...) do inspekcji i Call_Original_Native(...) do kontynuowania łańcucha jest wystarczające. Bezpośrednia zmiana params powinna być wykonywana tylko wtedy, gdy wiesz, że parametr jest wartością i musi zostać zmodyfikowany dla oryginalnego wywołania. W przypadku ciągów znaków i tablic, modyfikacja jest bardziej złożona i zazwyczaj wymaga amx::Set_String do zapisu w istniejącym adresie lub realokacji, co może być łatwiejsze do zarządzania, wywołując funkcję natywną za pomocą Pawn_Native z nowymi wartościami i zwracając 0 z hooka, aby anulować oryginalne wywołanie.
Te makra są odwrotnością Plugin_Public i Plugin_Native: pozwalają Twojemu kodowi C++ wywoływać funkcje Pawn.
- Cel: Zalecany sposób wywoływania natywnych funkcji SA-MP (lub innych wtyczek) z C++.
- Mechanizm: Wyszukuje wskaźnik natywnej funkcji w wewnętrznej pamięci podręcznej SDK (wypełnionej przez
Amx_Register_Detour). Jeśli zostanie znaleziony, wykonuje natywną funkcję w środowiskuAmx_Sandbox(fałszywa i izolowana instancja AMX). - Wydajność: Najbardziej efektywna, ponieważ pozwala uniknąć kosztownego wyszukiwania
publicsi bezpośrednio współdziała ze wskaźnikiem natywnej funkcji.
- Cel: Wywołuje określoną funkcję publiczną w skrypcie Pawn.
- Mechanizm: Przegląda instancje
AMX*zarządzane przezAmx_Manager, wyszukujepublicpo nazwie i wykonuje ją. - Wydajność: Mniej efektywna niż
Pawn_Nativez powodu wyszukiwania i rzeczywistegoamx_Exec. Ogólnie,publicssą wolniejsze niżnatives. - Użycie: Idealne do wywoływania niestandardowych zdarzeń w Twoich Gamemode/Filterscriptach, które nie są natywnymi funkcjami.
- Cel: Wygodne makro, które próbuje odgadnąć, czy funkcja jest natywna czy publiczna.
- Mechanizm: Najpierw próbuje wywołać jako
Pawn_Native. Jeśli to się nie uda (nie znaleziono natywnej funkcji), próbuje wywołać jakoPawn_Public. - Wydajność: Może być nieco wolniejsza niż
Pawn_Native, jeśli funkcja jest natywna, z powodu podwójnej próby wyszukiwania. W przypadkupublicswydajność jest taka sama jakPawn_Public. - Użycie: Dla funkcji, w przypadku których nie masz pewności, czy są natywne czy publiczne, lub aby uniknąć powtarzania kodu, próbując jednej, a potem drugiej.
- Nazwa funkcji: Zawsze używaj nazwy funkcji Pawn bezpośrednio, bez cudzysłowów. SDK wewnętrznie przekonwertuje ją na ciąg znaków.
- Parametry: Przekazuj parametry C++ bezpośrednio.
// Poprawnie:
Pawn_Native(SetPlayerPos, playerid, 100.0f, 200.0f, 300.0f);
// Błędnie (ale technicznie zadziałałoby z powodu haszowania, unikaj):
Pawn_Native("SetPlayerPos", playerid, 100.0f, 200.0f, 300.0f); SDK konwertuje Twoje typy C++ na format cell AMX, zarządzając pamięcią w razie potrzeby:
int,bool,long,enum->cellfloat,double->cell(używającamx::AMX_FTOC)const char*,std::string,std::string_view(C++17+) ->cell(alokuje pamięć w AMX, kopiuje ciąg znaków i przekazuje adresamx_addr)
void Send_Formatted_Message(int playerid, const std::string& msg) {
Pawn_Native(SendClientMessage, playerid, 0xFFFFFFFF, msg);
}Jest to kluczowa funkcja zapewniająca wygodę i bezpieczeństwo. Dla funkcji Pawn, które oczekują wskaźnika (referencji), SDK automatyzuje cały proces alokacji/zwalniania pamięci i kopiowania danych.
- Jak używać: Wystarczy przekazać zmienną przez referencję (
&). - Mechanizm: SDK alokuje pamięć na stercie AMX, przekazuje adres AMX do funkcji Pawn, oczekuje, że funkcja Pawn wypełni ten adres, odczytuje wartość z powrotem i zwalnia pamięć AMX. Wszystko w sposób przezroczysty.
- Z
std::string&: SDK alokuje standardowy bufor (256 komórek) w AMX dla ciągu znaków.
void Get_Player_Location(int playerid) {
float x, y, z;
int interiorid, worldid;
std::string name;
Pawn_Native(GetPlayerPos, playerid, x, y, z);
Pawn_Native(GetPlayerInterior, playerid, interiorid);
Pawn_Native(GetPlayerVirtualWorld, playerid, worldid);
Pawn_Native(GetPlayerName, playerid, name, MAX_PLAYER_NAME);
Samp_SDK::Log("Localização de %s (ID:%d): Pos(%.2f, %.2f, %.2f) Interior:%d World:%d", name.c_str(), playerid, x, y, z, interiorid, worldid);
}Wszystkie wywołania Pawn_* zwracają obiekt Callback_Result. Obiekt ten jest bezpiecznym opakowaniem dla wyniku wywołania Pawn.
Callback_Result() noexcept: Domyślny konstruktor, wskazuje na niepowodzenie (success_ = false).Callback_Result(bool success, cell value) noexcept: Konstruktor dla sukcesu lub niepowodzenia z wartością.explicit operator bool() const: Umożliwia użycieif (result)do sprawdzenia, czy wywołanie zakończyło się pomyślnie.operator cell() const: Umożliwia konwersję wyniku nacellw celu uzyskania wartości.float As_Float() const: Wygoda uzyskania wyniku jakofloat.cell Value() const: Zwraca surową wartośćcell.bool Success() const: Zwracatrue, jeśli wywołanie Pawn zakończyło się pomyślnie.int Get_Amx_Error() const: Zwraca kod błędu AMX, jeśli wywołanie zakończyło się niepowodzeniem (0 dla sukcesu).
// Przykład: Pobieranie życia gracza.
// Natywna funkcja GetPlayerHealth(playerid, &Float:health) oczekuje playerid i referencji do życia.
int playerid = 0; // Przykładowe ID gracza
float player_health = 0.0f;
// Wywołujemy GetPlayerHealth, przekazując playerid i player_health przez referencję.
// SDK zajmie się marszowaniem dla parametru wyjściowego 'health'.
Callback_Result result = Pawn_Native(GetPlayerHealth, playerid, player_health);
if (result) { // Sprawdza, czy wywołanie zakończyło się pomyślnie (operator bool)
// Wartość zwrócona przez result.As_Float() lub result (operator cell)
// byłaby wartością zwracaną przez *natywną funkcję*, a nie parametrem wyjściowym.
// Wartość życia została już zaktualizowana w 'player_health' dzięki marszowaniu parametru wyjściowego.
Samp_SDK::Log("Jogador %d tem %.1f de vida.", playerid, player_health);
}
else {
// Wywołanie nie powiodło się, być może gracz nie istnieje lub natywna funkcja nie została znaleziona.
Samp_SDK::Log("Erro ao obter vida do jogador %d. Código AMX: %d", playerid, result.Get_Amx_Error());
}
// W przypadku natywnych funkcji, które zwracają wartość i używają parametrów wyjściowych (mniej powszechne, ale możliwe),
// użyłbyś obu:
// Callback_Result other_result = Pawn_Native(SomeNative, param1, output_param, param2);
// if (other_result) {
// cell returned_value = other_result;
// // output_param jest już zaktualizowany
// }Makro Plugin_Module pozwala Twojej wtyczce działać jako „ładowarka” dla innych wtyczek, tworząc modułową i rozszerzalną architekturę. Moduł załadowany w ten sposób jest traktowany jako pełnoprawna wtyczka, z własnym cyklem życia zdarzeń zarządzanym przez wtyczkę-hosta.
Plugin_Module(const char* nazwa_pliku_bazowego, const char* katalog_modułu, const char* opcjonalna_wiadomość_sukcesu)nazwa_pliku_bazowego: podstawowa nazwa pliku modułu, bez rozszerzenia (np. dlamy_module.dlllubmy_module.so, użyj"my_module"). SDK automatycznie doda odpowiednie rozszerzenie.dlllub.so.katalog_modułu: Ścieżka do katalogu, w którym znajduje się plik modułu (np."plugins/my_custom_modules"). Nie dołączaj tutaj nazwy pliku. SDK utworzy pełną ścieżkę (katalog_modułu/nazwa_pliku_bazowego.rozszerzenie).opcjonalna_wiadomość_sukcesu: Opcjonalna wiadomość do zalogowania w konsoli serwera, jeśli moduł zostanie pomyślnie załadowany.
// main.cpp, wewnątrz OnLoad()
// Ładuje moduł 'core_logic.dll' (lub 'core_logic.so')
// który znajduje się w folderze 'modules/custom/' serwera.
if (!Plugin_Module("core_logic", "modules/custom", "Módulo de Lógica Core carregado com sucesso!"))
return (Samp_SDK::Log("ERRO FATAL: Falha ao carregar o módulo 'core_logic'!"), false);
// Ładuje moduł 'admin_system.dll' (lub 'admin_system.so')
// który znajduje się bezpośrednio w folderze 'plugins/' serwera.
if (!Plugin_Module("admin_system", "plugins", "Módulo de Administração ativado."))
Samp_SDK::Log("AVISO: Módulo de Administração não pôde ser carregado.");Moduł musi eksportować funkcje Load, Unload i Supports, podobnie jak normalna wtyczka. SDK zarządza cyklem życia modułu w następujący sposób:
-
Ładowanie: Gdy wywołane zostanie
Plugin_Module, SDK:- Tworzy pełną ścieżkę do pliku (np.
modules/custom/core_logic.dll). - Używa
Dynamic_Library(LoadLibrary/dlopen) do załadowania pliku binarnego. - Pobiera wskaźniki do WSZYSTKICH funkcji cyklu życia modułu:
- Obowiązkowe:
Load,Unload,Supports. Jeśli którakolwiek brakuje, ładowanie modułu kończy się niepowodzeniem. - Opcjonalne:
AmxLoad,AmxUnload,ProcessTick.
- Obowiązkowe:
- Wywołuje funkcję
Loadmodułu, przekazującppDataz głównej wtyczki. - Jeśli
Loadzwrócitrue, moduł jest dodawany do wewnętrznej listy załadowanych modułów.
- Tworzy pełną ścieżkę do pliku (np.
-
Przekazywanie zdarzeń: Wtyczka-host automatycznie przekazuje zdarzenia do wszystkich załadowanych modułów.
Important
Aby zdarzenia były poprawnie przekazywane, wtyczka-host (ta, która wywołuje Plugin_Module) musi być skonfigurowana do odbierania tych zdarzeń.
- Aby
AmxLoadiAmxUnloaddziałały w modułach, wtyczka-host musi zdefiniować makroSAMP_SDK_WANT_AMX_EVENTS. - Aby
ProcessTickdziałał w modułach, wtyczka-host musi zdefiniować makroSAMP_SDK_WANT_PROCESS_TICK.
- Odładowywanie: Podczas
OnUnloadTwojej głównej wtyczki, SDK odładowuje wszystkie moduły, które zostały załadowane za pomocąPlugin_Module. Odbywa się to w odwrotnej kolejności do ładowania (ostatni załadowany jest pierwszym odładowywanym), co jest kluczowe dla zarządzania zależnościami i zapewnienia prawidłowego zwalniania zasobów.
- Organizacja kodu: Podziel duże wtyczki na mniejsze, łatwe w zarządzaniu komponenty, każdy w osobnym pliku modułu.
- Ponowne użycie: Twórz ogólne moduły (np. moduł bazy danych, moduł zaawansowanego systemu logowania), które mogą być używane przez różne wtyczki, promując ponowne użycie kodu.
- Niezależne komponenty: Twórz moduły, które są całkowicie zorientowane na zdarzenia i niezależne. Moduł może mieć własne
Plugin_Natives, przechwytywaćPlugin_Publics i mieć własną logikęOnProcessTick, działając jako autonomiczna wtyczka, ale ładowana przez hosta. - Dynamiczne aktualizacje: W kontrolowanych scenariuszach pozwala na aktualizację części systemu (zastępowanie pliku
.dlllub.somodułu) bez konieczności ponownej kompilacji i ponownego uruchamiania głównej wtyczki lub całego serwera (choć wymaga to rygorystycznego zarządzania wersjami i kompatybilnością).
Użyj Plugin_Call, aby wywołać Plugin_Native zdefiniowaną wewnątrz Twojej własnej wtyczki.
Plugin_Call(NativeName, Param1, Param2, ...)- Zaleta: Unika narzutu związanego z wyszukiwaniem natywnej funkcji w tablicy natywnych AMX. SDK utrzymuje bezpośrednią mapę skrótów nazw na wskaźniki funkcji dla własnych natywnych funkcji, co czyni to najszybszym sposobem ich wywoływania wewnętrznie.
- Wymaga:
SAMP_SDK_WANT_AMX_EVENTS.
// main.cpp
Plugin_Native(InternalCheckPlayerLevel, AMX* amx, cell* params) {
int playerid;
Register_Parameters(playerid);
// Logika sprawdzania poziomu
return (playerid % 2 == 0) ? 1 : 0; // Przykład: poziom parzysty dla parzystych ID
}
void Check_All_Players_Level() {
for (int i = 0; i < MAX_PLAYERS; ++i) {
if (Pawn_Native(IsPlayerConnected, i)) {
if (Plugin_Call(InternalCheckPlayerLevel, i)) // Wywołuje własną funkcję natywną
Samp_SDK::Log("Jogador %d está em um nível alto!", i);
}
}
}- Opis: Wyświetla wiadomości w konsoli serwera i w pliku
server_log.txt. Bezpieczny wrapper dlalogprintf. - Użycie: Do debugowania, wiadomości o statusie i błędach.
- Mechanizm: Wewnętrznie SDK pobiera wskaźnik do
logprintfpoprzezppData[PLUGIN_DATA_LOGPRINTF]. Funkcja bezpiecznie obsługuje formatowanie ciągów znaków.
// W dowolnym miejscu w Twojej wtyczce
Samp_SDK::Log("O plugin foi inicializado com um valor %d e uma string '%s'.", 123, "teste");- Opis: Bezpiecznie formatuje ciąg znaków (podobnie do
sprintf) i zwracastd::string. Jest to zalecany i najbardziej idiomatyczny sposób formatowania ciągów znaków do użycia w Twojej wtyczce. - Użycie: Idealne do konstruowania sformatowanych wiadomości przed przekazaniem ich do
Samp_SDK::Log,Pawn_Native(SendClientMessage, ...), lub do innych potrzeb związanych z ciągami znaków w Twoim kodzie C++. - Mechanizm: Wewnętrznie
Plugin_Formatto makro, które wywołujeSamp_SDK::Format. Wykorzystujevsnprintfdo określenia dokładnej długości sformatowanego ciągu znaków i alokujestd::stringo wystarczającej pojemności, zapobiegając przepełnieniom bufora.
int playerid = 0; // Przykładowe ID
int health = 50;
Pawn_Native(SendClientMessage, playerid, 0xFFFFFFFF, Plugin_Format("Jogador %d, sua vida atual é %d.", playerid, health));
// Może być również używany do wewnętrznych logów
Samp_SDK::Log(Plugin_Format("DEBUG: Processando status para o ID %d", playerid));- Opis: Podstawowa funkcja implementacji formatowania ciągów znaków, znajdująca się w przestrzeni nazw
Samp_SDK. - Użycie: Zazwyczaj nie jest wywoływana bezpośrednio przez użytkownika. Makro
Plugin_Formatjest dostarczone jako wygoda dla tej funkcji, zgodnie z konwencją nazewnictwa innych makr SDK (Plugin_Public,Plugin_Native). Wywołałbyś ją bezpośrednio tylko wtedy, gdybyś chciał uniknąć makraPlugin_Formatz jakiegoś konkretnego powodu.
// Przykład działania Samp_SDK::Format, ale preferuj Plugin_Format
std::string raw_status = Samp_SDK::Format("Apenas para uso interno: %d.", 42);- Opis: Konwertuje adres ciągu znaków AMX (
cell amx_addr) nastd::stringC++. - Użycie: Głównie w
Plugin_NativeiPlugin_Native_Hook, gdy potrzebujesz dostępu do ciągów znaków, które nie są automatycznie konwertowane przezRegister_ParameterslubNative_Params(np. jeśli parametr Pawn jestconststringi nie został zadeklarowany jakostd::stringw TwoimPlugin_NativelubPlugin_Publicdla automatycznego marszowania).
Plugin_Native(PrintRawAmxString, AMX* amx, cell* params) {
Native_Params p(amx, params);
cell amx_string_addr = p.Get<cell>(0); // Pobiera adres ciągu znaków w AMX
std::string cpp_string = Samp_SDK::Get_String(amx, amx_string_addr);
Samp_SDK::Log("String da AMX: %s", cpp_string.c_str());
return 1;
}- Twoja wtyczka MUSI być skompilowana dla architektury x86 (32-bit).
- Obsługiwane platformy: Windows (.dll) i Linux (.so).
- Utwórz nowy projekt „Dynamic-Link Library (DLL)”.
- W ustawieniach projektu ustaw „Platforma rozwiązania” na x86.
- Upewnij się, że standard języka C++ to co najmniej C++17.
# Dla wtyczki o nazwie 'my_plugin.so' z 'main.cpp'
g++ -m32 -shared -std=c++17 -O2 -fPIC -Wall -Wextra -Wl,--no-undefined main.cpp -o my_plugin.so-m32: Kompiluje dla 32-bit.-shared: Tworzy bibliotekę współdzieloną (.so).-std=c++17: Ustawia standard C++ na C++17 (może byćc++20, ale C++17 jest minimum).-O2: Poziom optymalizacji 2.-fPIC: Generuje kod niezależny od pozycji, niezbędny dla bibliotek współdzielonych.-Wall -Wextra: Włącza dodatkowe ostrzeżenia, aby pomóc wychwycić błędy.-Wl,--no-undefined: Zapobiega tworzeniu biblioteki, jeśli istnieją niezdefiniowane symbole.
# Dla wtyczki o nazwie 'my_plugin.dll' z 'main.cpp'
g++ -m32 -shared -std=c++17 -O2 -static-libstdc++ -static-libgcc -Wl,--no-undefined main.cpp -o my_plugin.dll-static-libstdc++: Statycznie łączy standardową bibliotekę C++. Niezbędne, aby Twoja wtyczka nie zależała od konkretnych dla kompilatora bibliotek wykonawczych DLL, które mogą nie być obecne w systemie użytkownika.-static-libgcc: Statycznie łączy bibliotekę GCC.
- Nazwa pliku: Twoja wtyczka powinna mieć rozszerzenie
.dll(Windows) lub.so(Linux). Np.my_plugin.dll. - Lokalizacja: Umieść skompilowany plik w folderze
plugins/Twojego serwera SA-MP. - server.cfg: Dodaj nazwę swojej wtyczki (jeśli to Windows, bez rozszerzenia) do linii
pluginswserver.cfg.plugins my_plugin (jeśli to Linux, my_plugin.so)
Copyright © AlderGrounds
To oprogramowanie jest licencjonowane na warunkach licencji MIT ("Licencja"); możesz korzystać z tego oprogramowania zgodnie z warunkami Licencji. Kopię Licencji można uzyskać pod adresem: MIT License
Niniejsza licencja bezpłatnie przyznaje każdej osobie otrzymującej kopię tego oprogramowania i powiązanych plików dokumentacji następujące prawa:
- Używanie, kopiowanie, modyfikowanie, łączenie, publikowanie, rozpowszechnianie, sublicencjonowanie i/lub sprzedaż kopii oprogramowania bez ograniczeń
- Zezwalanie osobom, którym oprogramowanie jest dostarczane, na to samo, pod warunkiem przestrzegania poniższych warunków
Wszystkie kopie lub istotne części oprogramowania muszą zawierać:
- Powyższą informację o prawach autorskich
- Niniejsze zezwolenie
- Poniższe wyłączenie odpowiedzialności
Oprogramowanie i cała powiązana dokumentacja są chronione prawami autorskimi. AlderGrounds zachowuje oryginalne prawa autorskie do oprogramowania.
OPROGRAMOWANIE JEST DOSTARCZANE "TAK JAK JEST", BEZ JAKIEJKOLWIEK GWARANCJI, WYRAŹNEJ LUB DOROZUMIANEJ, W TYM MIĘDZY INNYMI GWARANCJI PRZYDATNOŚCI HANDLOWEJ, PRZYDATNOŚCI DO OKREŚLONEGO CELU I NIENARUSZANIA PRAW.
W ŻADNYM WYPADKU AUTORZY LUB POSIADACZE PRAW AUTORSKICH NIE PONOSZĄ ODPOWIEDZIALNOŚCI ZA JAKIEKOLWIEK ROSZCZENIA, SZKODY LUB INNE ZOBOWIĄZANIA, CZY TO W RAMACH DZIAŁAŃ UMOWNYCH, DELIKTOWYCH CZY INNYCH, WYNIKAJĄCYCH Z OPROGRAMOWANIA LUB ZWIĄZANYCH Z NIM LUB Z JEGO UŻYTKOWANIEM LUB INNYMI CZYNNOŚCIAMI W OPROGRAMOWANIU.
Szczegółowe informacje o licencji MIT można znaleźć pod adresem: https://opensource.org/licenses/MIT