Skocz do zawartości

Zaawansowany Skript [#1] Pakiety i NMS


Rekomendowane odpowiedzi

Uwaga
Umiejętności zaprezentowane w tym poradniku wymagają odpowiedniej znajomości języka Java (małej, wystarczy wiedzieć, co to klasy, interfejsy, katalogi, pola, konstruktory i inne pierdoły), a także w pewnym stopniu wtyczki skript-reflect. Tu jest PORADNIK do skript-reflect: https://tpgamesnl.gitbook.io/skript-reflect albo tu https://skript.pl/temat/34737-skript-reflect-java-w-skrypcie Omawiane protokoły działają tylko i wyłącznie na wersjach 1.17.X (opcjonalnie 1.16.X, w sumie to nie pamiętam). Definicja pakietów się zmieniała na przestrzeni wielu wersji Minecraft, np. przed wersją 1.16, klasy były nazwane inaczej, oraz były rozlokowane w katalogu net/minecraft/server. Jest to też pierwsza część mojej serii poradników do zaawansowanego Skripta.

Definicja pakietu i NMS
Pakiety (albo protokoły) w Minecraft są to pakiety danych wysyłane przez serwer do klienta lub vice versa. Klient oznacza gracza, a serwer oznacza (...) Każdy pakiet jest nazwany odpowiednio: PacketPlayXY, gdzie X może oznaczać In (od incoming, czyli pakiet klient -> serwer), lub może oznaczać Out (od outcoming, klient <- serwer); natomiast Y to nazwa danego pakietu (przykład: PacketPlayInUpdateSign, pakiet, który wysyła klient do serwera w momencie, kiedy skończy pisać na tabliczce). Klasy pakietów, które serwer używa do wysyłania informacji lub jej odbierania, znajdują się w pliku /cache/patched_x.x.x.jar w katalogu net/minecraft/network/protocol/game, więc nie jest już to popularne "nms" od net/minecraft/server. Mogą one służyć do wysyłania wybranym graczom informacji, których serwer nie posiada np. wyrenderować komuś blok nieistniejący na serwerze.

NMS to skrót od net.minecraft.server, spopularyzowanego katalogu pliku .jar, który jest wymagany do uruchomienia serwera. Uprzednio, w tym katalogu znajdowały się wszystkie pakiety, które można było wysyłać i odbierać, obecnie natomiast, pakiety są rozlokowane w innej części pliku, więc nms jest technicznie rzecz biorąc pojęciem nieaktualnym, aczkolwiek wiele osób używa tego terminu do dziś, i teoretycznie można o nim mówić dalej.

Pakiety w Skript
Jest wiele sposobów na użycie pakietów, np. używanie przestarzałych i niedziałających na nowsze wersje wtyczek typu ThatPacketAddon natomiast dla mnie najbardziej odpowiadającym jest użycie wtyczki skript-reflect, która posiada wiele rozmaitych i wspaniałych możliwości. Przed prowadzonymi eksperymentami z pakietami jest wymagane nauczyć się używania wspomnianego dodatku. Odsyłacze są na dole poradnika. Dodatkowo, niektóre pakiety można wysyłać za pośrednictwem niczego innego niż Spigot API (Player#sendBlockChange(), Player#sendChunkChange() <- przestarzałe, Player#sendSignChange(), Player#sendBlockDamage()) ale jak widać jest ich za mało, by móc się w pełni bawić pakietami.

Wysyłanie pakietów do klienta gry
Aby wysłać pakiet do klienta, należy go najpierw skonstruować, bo każdy pakiet wychodzący ma konstruktor w swojej klasie. Żeby go znać, można zdekompilować (np. programem jd-gui) wspomniany w początkowej sekcji plik .jar, i dojść do danego pakietu, albo można skorzystać z tej strony: https://wiki.vg/Protocol. W tym przykładzie wyślę do klienta trudny do skonstruowania pakiet PacketPlayOutExplosion, tworzący eksplozje widoczne dla jednego klienta, a jest trudny, bo wymaga wykorzystania innych klas w tym pliku .jar. Pierwsze co należy zrobić, to zaimportować klasę pakietu. 

Naprawdę polecam skorzystać z dekompilatora. PO PIERWSZE, na wspomnianej stronie jest kilka błędów. PO DRUGIE, rzeczy związane z tym popularnym "nms" są bardzo słabo udokumentowane, częściowo zaszyfrowane i nie kompilują się między wersjami. Poniższy screen pokazuje konstruktor pakietu. Jak widać, wymagane jest podać 6 parametrów. Pierwsze 3 argumenty definiują miejsce efektu eksplozji. Następny argument określa jaki typ cząsteczki wygeneruje eksplozja, np. liczba większa od 2.0 wygeneruje "minecraft:explosion_emitter", a w przeciwnym wypadku "minecraft:explosion". Następny parametr to lista obiektów BlockPosition.class (a nie mówiłem, że trzeba umieć trochę Javy) określających bloki które mają być zastąpione powietrzem. Ostatni to niby opcjonalny, ale jak się go nie wpisze to się popsuje skrypt, czyli wektor o jaki ma zostać popchnięty gracz.

unknown.png

Definicja 4 pierwszych będzie banalnie prosta. Dwa ostatnie parametry wymagają użycia klas z tego samego pliku .jar. Wystarczy trochę długo poszukać i dostanie się sposób na zapisanie parametrów. Protip: na górze klasy pakietu są importowane inne potrzebne klasy, więc tam są podpowiedzi jak dostać się do jej kodu. Tworzymy najpierw grupową zmienną obiektów BlockPosition.class. Później trzeba trochę pomyśleć jak to wszystko skleić ze sobą w całość. W końcu został ostatni parametr, łatwo go skonstruować, wystarczy podać 3 liczby i tyle. Cała komenda będzie wyglądać następująco:

import:
	net.minecraft.network.protocol.game.PacketPlayOutExplosion
	net.minecraft.core.BlockPosition
	java.util.Arrays
	net.minecraft.world.phys.Vec3D

command /eksplozja:
	trigger:
		set {_loc} to target block
		loop all blocks in radius 3 of {_loc}:
			add new BlockPosition(loop-block's x-coord, loop-block's y-coord, loop-block's z-coord) to {_lista::*}
		set {_pakiet} to new PacketPlayOutExplosion({_loc}'s x-coord, {_loc}'s y-coord, {_loc}'s z-coord, 3.0, Arrays.asList([{_lista::*} as BlockPosition]), new Vec3D(0, 2, 0))

W KOŃCU, tyle paplaniny żeby skonstruować jakiś pakiecik, ale jak go teraz wysłać? Oczywiście do tego służy metoda CraftPlayer#getHandle() <- tzw. "zcastowanie" klasy CraftBukkitowej klasy gracza do klasy nms, EntityPlayer#b <- pole klasy PlayerConnection, PlayerConnection#sendPacket() <- wysłanie pakietu.

player.getHandle().b.sendPacket({_pakiet})

Odbieranie pakietów klienta
Dobra, odbieranie pakietów to ostatnia rzecz która pozwala zarządzać tymi całymi pakietami. Pakietów przychodzących (klient -> serwer) nie można modyfikować i konstruować, należy je jedynie odbierać i przetwarzać ich dane. Aby nasłuchiwać pakietów, trzeba mieć ze sobą oddzielny, bardzo długi skrypt na nasłuchiwanie, ale na szczęście ktoś bardzo mądry stworzył tzw. snippet, czyli kawałek kodu, który możemy sobie wykorzystać do słuchania pakietów klient-serwer. Nie jest on oczywiście mojego autorstwa 🚎

Jak to zwykle robimy, to ten skrypt wczytujemy w oddzielnym pliku. Teraz powinniśmy się zrelogować, żeby całość działała poprawnie. JAK NASŁUCHIWAĆ PAKIETÓW? Na przykład wtedy, kiedy klient zakończy edytowanie tabliczki, czyli kliknie "Done" lub "Gotowe"?

import:
	net.minecraft.network.protocol.game.PacketPlayInUpdateSign

on nmspacket PacketPlayInUpdateSign:
	send "Pakiet %event-string%: W pierwszej linii napisałeś: %nmspacket.c()[0]%" to event-player

Bardzo proste! Każdy pakiet ma ze sobą jakieś dane, np. ten ma dane na temat linii tabliczki i jej koordynaty (tylko klient widzi tę tabliczkę). nmspacket.c() to jest to samo co naprzykład event-block, ale kod który można sobie zdekompilować jest częściowo zaszyfrowany, dlatego są jakieś literki, zamiast fajnych nazw metod. WARTO również wspomnieć że w eventach pakietowych zawsze jest coś typu event-player i event-string (nazwa pakietu). Pakiety przychodzące można anulować efektem cancel event. W niżej pokazanej klasie interesują nas metody rozpoczynające się od b(). Aby otrzymać dane pakietu klient-serwer trzeba napisać wspomniane nmspacket.c() czyli w tym przypadku chcę otrzymać tekst na tabliczce. [0] oznacza, że chcę otrzymać pierwszą linię tabliczki. A na przykład b() da nam lokalizację tabliczki.

unknown.png

Kolejny przykład

Jakieś linki i dokumentacje

Edytowane przez 3meraldK
Odnośnik do komentarza
https://skript.pl/temat/50940-zaawansowany-skript-1-pakiety-i-nms/
Udostępnij na innych stronach

  • 3meraldK zmienił(a) tytuł na Zaawansowany Skript [#1] Pakiety i NMS

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ą.

Nieaktywny
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.

  • Ostatnio przeglądający   0 użytkowników

    • Brak zarejestrowanych użytkowników przeglądających tę stronę.
×
×
  • Dodaj nową pozycję...