Komunikacja z graczem
Scripting AMXX
Cel
Nauka podstawowych metod komunikacji gracza z serwerem
Wymagania
- Informacje wstępne
Spoiler - Zrozumienie istoty działania AMXX
- Znajomość podstawowych funkcji
- Umiejętność imptowania bibliotek
- Zwracanie odpowiedniej wartości funkcji
- Odczytywanie argumentów wiadomości
Jak już wiemy z poprzedniego kursu, funkcja register_event pozwala nam zarejestrować dowolne zdarzenie silnika HLDS.
Jednakże, możemy rejestrować także wystąpienie pewnych wiadomości poprzez funkcję register_logevent
Funkcja register_logevent jednak, jako, że rejestruje jedynie wystąpienie wiadomości, będącej wynikiem
wywołania danej operacji, nie może na tę operację wpływać, a jedynie pozyskać informację o wykonaniu danej operacji.
Pierwszym argumentem funkcji register_event jest nazwa funkcji, wykonywanej w momencie odnotowania danego zdarzenia.
Drugim parametrem jest liczba argumentów, które będziemy odczytywać. W kolejnych, opcjonalnych argumentach, możemy ograniczyć
notowane zdarzenia funkcji filtrami, operując na poszczególnych parametrach, licząc argumenty od 0. Liczba kolejnych
argumentów filtrujących jest dowolna, a niespełnienie choć jednego z nich, nie wywoła funkcji z pierwszego parametru.
Filtry logevents
Do dyspozycji mamy następujące filtry:
- Równość
arg=val
Argument nr arg musi być dokładnie taki, jak podana wartość val, np."0=World triggered"
- Nierówność
arg!val
Argument nr arg nie może zawierać podanej wartości val, np."0!World triggered"
- Większość
arg>val
Argument nr arg musi być większy, niż podana wartość val, np."1>2"
- Mniejszość
arg<val
Argument nr arg musi być mniejszy, niż podana wartość val, np."3<4"
- Zawieranie
arg&val
Argument nr arg musi zawierać wartość val, np."1&spawn"
register_logevent("spawnedWithBomb", 3, "1=triggered", "2=Spawned_With_The_Bomb");
Jednakże, co w przypadku, gdy chcielibyśmy zarejestrować zarówno spawn z bombą,
jak i otrzymanie bomby (np. poprzez podniesienie z ziemi) za pomocą register_event?
Jak pamiętamy, funkcja zostanie wywołana, o ile koniunkcja warunków z argumentów opcjonalnych zostanie spełniona.
W przypadku chęci rejestracji otrzymania bomby (czy to przez podniesienie, czy otrzymanie wraz ze spawnem) bowiem,
potrzebujemy alternatywy tych warunków. I na to jest rozwiązanie! Z pomocą przychodzi nam funkcja read_logargv.
read_logargv
Funkcja ta odczytuje zawartość zadanego w pierwszym argumencie, parametru zdarzenia logowanego (licząc od zera)
i zapisuje do tablicy o nazwie z drugiego argumentu o maksymalnym rozmiarze z trzeciego argumentu funkcji read_logargv.
Zobaczmy to na przykładzie:
#include <amxmodx>Rejestrujemy logevent i ograniczamy go jedynie do równości drugiego argumentu z "triggered".
public plugin_init(){
register_plugin("Bomb get detect", "0.1", "benio101");
register_logevent("playerTriggered", 3, "1=triggered");
}
public playerTriggered(){
new akcja[64];
read_logargv(2, akcja, 64);
if(
equali(akcja, "Spawned_With_The_Bomb") ||
equali(akcja, "Got_The_Bomb")
){
// Jakis gracz otrzymal bombe
}
}
Następnie, w funkcji playerTriggered, pobieramy zawartość trzeciego argumentu do zmiennej akcja.
Jeśli akcją jest otrzymanie bomby lub spawn z bombą, co sprawdzamy w warunku połączonym alternatywą,
to oznacza, że Jakiś gracz otrzymał bombę. Teraz pozostanie nam odczytać jego id i napiszemy mu to.
#include <amxmodx>Pobraliśmy tutaj zawartość pierwszego argumentu do zmiennej arg0, następnie pobraliśmy nick gracza za pomocą funkcji parse_loguser,
public plugin_init(){
register_plugin("Bomb get detect", "0.1", "benio101");
register_logevent("playerTriggered", 3, "1=triggered");
}
public playerTriggered(){
new akcja[64];
read_logargv(2, akcja, 64);
if(
equali(akcja, "Spawned_With_The_Bomb") ||
equali(akcja, "Got_The_Bomb")
){
// Jakis gracz otrzymal bombe
new arg0[64], name[64], argid, id;
read_logargv(0, arg0, 64);
parse_loguser(arg0, name, 64, argid);
id=find_player("k", argid);
client_print(id, print_chat, "Otrzymales bombe!");
}
}
by na końcu odnaleźć jego właściwe id za pomocą funkcji find_player i wyświetlić mu komunikat o otrzymaniu bomby.
Komunikacja serwera z graczem
Rozgrywka multiplayer na serwerze możliwa jest dzięki komunikowaniu się klientów gry oraz serwera HLDS.
Każde kliknięcie myszy, nachylenie się, czy zmiana pozycji u gracza, a także wywołania jakiejś komendy,
wpływają na informacje przesyłane od klienta do serwera gry. Z drugiej strony, serwer także systematycznie
komunikuje się z nami, przesyłając informacje o naszej pozycji, punktach zdrowia, czy pojawiającym się nowym granacie dymnym i jego lokalizacji.
Podczas, gdy większość operacji wykonywana jest po stronie serwera (jak spawny graczy, ruch zakładników, czy tykanie bomby),
to część wykonywana jest po stronie gracza i serwer nie ma na nie wpływu, jak np. ruch gracza, czy ustalanie odrzutu broni przy strzale.
Informacje nieosiągalne
Poza operacjami, których charakterystyka, dokładny opis, bądź których informacja o wykonaniu, są przesyłane pomiędzy serwerem HLDS, a klientami,
istnieją także operacje, które nie zostają ujawnione dla drugiej strony, zarówno po stronie serwera, jak i u klienta.
Przykładem tych drugich jest np. wywołanie komendy zmiany slotu bądź łączenia się z określonym serwerem.
Warto więc zapamiętać, że nie na wszystkie operacje mamy wpływ, a niektóre czynności gracza mogą nie być dla nas dostępne nawet do odczytania.
Jak już wspomniałem, m.in. informacja o wywołaniu niektórych komend, czyli wpisaniu ich w konsolę, są przesyłane do serwera, a więc możemy je odnotować.
Komendy gracza
Tutaj z pomocą przychodzi nam funkcja register_clcmd, która rejestruje daną komendę u gracza i pozwala na wykonanie danych operacji.
#include <amxmodx>W powyższym kodzie widzimy zarejestrowaną komendę test (pierwszy parametr), która zostanie wysłana do AMXX i wywołana zostanie funkcja test (za nazwę funkcji do wywołania odpowiada drugi parametr). Nic nie stoi na przeszkodzie, by nazwa rejestrowanej komendy oraz funkcji, były takie same.
public plugin_init(){
register_plugin("Komenda klienta", "0.1", "benio101");
register_clcmd("test", "test");
}
Dodamy zatem funkcję, która zostanie wywołana po wpisaniu przez klienta, polecenia "test" i wyświetlimy na chacie ogólnym temu graczowi, słowo "test".
#include <amxmodx>
public plugin_init(){
register_plugin("Komenda klienta", "0.1", "benio101");
register_clcmd("test", "test");
}
public test(id){
if(is_user_connected(id)){
client_print(id, print_chat, "test");
}
}
W praktyce jednak, najczęściej korzysta się z komendy say, która zbindowana jest u większości graczy pod klawiszami y oraz u.
Chat czy team_chat, to nic innego, jak komenda say z danym parametrem, który podajemy w trakcie gry bez potrzeby otwierania konsoli.
client_print
Funkcja client_print wysyła dla gracza o id podanym w pierwszym parametrze, tekst z trzeciego argumentu w określone miejsce drugim parametrem.
- print_notify (alternatywnie 1) wyśle wiadomość do konsoli gracza, o ile jest w trybie deweloperskim (rzadko używane)
- print_console (alternatywnie 2) wyśle wiadomość do konsoli gracza bez względu na to, czy jest w trybie deweloperkim, czy nie
- print_chat (alternatywnie 3) wyśle wiadomość na chat gracza, widoczny w grze (najczęściej używana opcja)
- print_center (alternatywnie 4) wyśle wiadomość na samym środku ekranu gracza (trudno ją przegapić)
Podanie w pierwszym argumencie zera zamiast numeru gracza, wiadomość zostanie wysłana do wszystkich graczy na serwerze.
Chat i TeamChat
Tak więc, zarejestrowanie wydania komendy na chacie jest możliwe, poprzez dodanie prostego "say " lub "say_team " przed
komendą, gdyż docelowo, klient wysyła właśnie komendę poprzedzoną tymi poleceniami do serwera.
Zarejestrujemy teraz przykładową komendę "test" powiedzianą na chacie oraz na team_chacie.
#include <amxmodx>Przejdziemy teraz do bardziej praktycznego zastosowania, czyli do ukrycia na chacie wpisania komendy,
public plugin_init(){
register_plugin("Komenda klienta", "0.1", "benio101");
register_clcmd("say test", "test");
register_clcmd("say_team test", "test");
}
public test(id){
if(is_user_connected(id)){
client_print(id, print_chat, "Powiedziales test");
}
}
rozpoczynającej się slashem, które zwyczajowo oznaczają specjalną komendę, jak /me czy /hp, wyświetlającą obrażenia.
Ukrycie wpisanych komend
Poza ujrzeniem zadanych, czy otrzymanych obrażeń, nie chcemy, by wszyscy widzieli ten wpis na chacie.
W tym celu zarejestrujemy funkcję say oraz say_team i będziemy blokować wysyłanie komendy do silnika gry,
o ile pierwszym znakiem będzie slash, za pomocą zwrócenia PLUGIN_HANDLED_MAIN. Main, ponieważ nie chcemy
blokować dalszego przepływu informacji innym pluginom, wpisanym niżej w pliku konfiguracyjnym serwera, plugins.ini
#include <amxmodx>
public plugin_init(){
register_plugin("Niewyswietlanie komend ze slashem", "0.1", "benio101");
register_clcmd("say", "say");
register_clcmd("say_team", "say");
}
public say(id){
new txt[192];
read_args(txt,192);
remove_quotes(txt);
if(equali(txt[0],"/")){
return PLUGIN_HANDLED_MAIN;
}
return PLUGIN_CONTINUE;
}
Blokada kupowania broni
Teraz przejdziemy do bardzie praktycznego przykładu, mianowicie
postaramy się zablokować możliwość kupowania broni, granatów i tarczy.
W tym celu będziemy rejestrować daną komendę na kupowanie,
a następnie blokować jej wysyłanie do silnika gry HLDS.
Najpierw jednak, musimy zadać sobie pytanie, w jaki sposób dokonywany jest zakup?
Otóż, standardowo, można korzystać z 2 rodzai menu, bądź poprzez komendę na kupno.
Ostatecznie, komenda w menu, docelowo i tak wysyła do serwera komendę na kupno broni.
Tak więc, pozostaje nam jedynie, wszelkie takie komendy zablokować i kupowanie nie będzie możliwe.
Tutaj odsyłam do podstawowych informacji o broniach: CS Weapons Information
Nazwy komend do blokowania widnieją w kolumnach BUYNAME oraz BUYNAME2.
Druga Kolumna komend na kupowanie, zawiera nazwy ze starszych wersji CSa,
które wciąż są dostępne, by zachować kompatybilność skryptów bindujących.
Nie uwzględnienie tych komend w procesie blokowania, pozwoli nam na kupowanie broni
poprzez wpisanie alternatywnych komend w konsolę, a funkcja, która działa częściowo,
działa źle, gdyż dalej pozostaje możliwość zakupu broni, czego nie chcielibyśmy.
Do spisu komend broni, dodamy kupowanie amunicji (priamammo i secammo), kamizelki (vest i vesthelm),
noktowizora (nvgs), zestawu rozbrajającego (defuser) oraz komend kupowania autobuy i rebuy.
Profilaktycznie, zablokujemy także komendy cl_[set](auto|re)buy oraz komendę buy.
Mając pełen spis komend, wystarczy zarejestrować je wszystkie i następnie zablokować.
Żeby nie tworzyć niepotrzebnie mnóstwa podobnych komend (czyli stosując zasadę DRY),
wpiszemy te wszystkie komendy w tablicę i zarejestrujemy te komendy przy użyciu pętli.
#include <amxmodx>
new static weaponsBuyNames[][]={
"p228", "shield", "scout", "hegren", "xm1014", "mac10", "aug", "sgren", "elites", "fn57",
"ump45", "sg550", "galil", "famas", "usp", "glock", "awp", "mp5", "m249", "m3", "m4a1",
"tmp", "g3sg1", "flash", "deagle", "sg552", "ak47", "p90", "228compact", "autoshotgun",
"bullpup", "fiveseven", "krieg550", "defender", "clarion", "km45", "9x19mm", "magnum",
"smg", "12gauge", "mp", "d3au1", "nighthawk", "krieg552", "cv47", "c90", "primammo",
"secammo", "vest", "vesthelm", "nvgs", "defuser", "autobuy", "rebuy",
"cl_autobuy", "cl_setautobuy", "cl_setrebuy", "cl_rebuy", "buy"
}
public plugin_init(){
register_plugin("Blokada kupowania", "0.1", "benio101");
for(new i=0; i<sizeof weaponsBuyNames; ++i){
register_clcmd(weaponsBuyNames[i], "block");
}
}
public block(){
return PLUGIN_HANDLED_MAIN;
}
Użytkownik benio101 edytował ten post 09.12.2012 03:07
+kot.