TheVVaS Opublikowano 23 Kwietnia 2014 Udostępnij Opublikowano 23 Kwietnia 2014 Cześć! Ostatnio przy robieniu gry napotykam sporo problemów, które w wersji 8.0 są trudne albo niemożliwe do naprawienia. Z kolei patrząc na dokumentację do GMS'a widzę sporo fajnych rzeczy(np. support pada :D). I teraz bardzo chciałbym przerzucić się na GMS'a, lecz tu rodzi się problem - NETWORKING :( Sporo szukałem, lecz skończyło się na tym, że znajdowałem tylko BARDZO skomplikowane wzory albo takie, które nie działają :( I teraz moje pytanko po małym rozpisaniu :D Czy ktoś z was miszcze GM'a mógłby: 1. wytłumaczyć zielonemu jak działa networking w GMS'ie? 2. Zrobić/wskazać prosty wzór podstawowego networkingu client-server? (Wybierz jedno, ewentualnie dwa :D) Wcześniej pracowałem na 39dll.dll, lecz ten coś nie chce działać na GMSie :( Na razie to chyba będzie wszystko. Odnośnik do komentarza Udostępnij na innych stronach Więcej opcji udostępniania...
TheVVaS Opublikowano 27 Kwietnia 2014 Autor Udostępnij Opublikowano 27 Kwietnia 2014 Trochę poszukałem i popytałem o networkingu i jedyne co udało mi się znaleźć to napisany na szybko wzór client-server przez kumpla. Wszystko byłoby fajnie, ale ten wzór coś nie działa :( A kumpel magiczne się rozpłynął i coś nie wraca. Mógłby ktoś zerknąć na ten wzór i powiedzieć Co jest nie tak? Przydałyby się także wytłumaczenia co za co odpowiada. Dał mi gdzieś jeszcze link do jakiegoś mocno rozbudowanego wzory, niestety gdzieś go zapodziałem, postaram się go znaleźć. Wzór networkingu?! Odnośnik do komentarza Udostępnij na innych stronach Więcej opcji udostępniania...
I am vader Opublikowano 27 Kwietnia 2014 Udostępnij Opublikowano 27 Kwietnia 2014 Zacznę od podstaw: Jak korzystać z networking: Aby korzystać z networking musisz stworzyć w jakimś obiekcie event Asynchronous>Networking, gdyż poprzez ten event możesz jedynie obsługiwać pakiety. Aby wysyłać dane musisz posiadać bufor. Aby stworzyć bufor użyj funkcji buffer_create, na przykład w następujący sposób: GML DataBuffer=buffer_create(1024,buffer_grow,1); Taki bufor jest potrzebny zarówno dla klienta jak i serwera, jeśli oba masz w jednej aplikacji, pojedyńczy bufor starczy dla obu stron, jeśli masz oddzielnie program klienta i serwera, to w obu potrzebny jest jakiś bufor. Jak połączyć się... Serwer: Zakładasz serwer za pomocą funkcji network_create_server(type,port,maxclients) w argumencie typ podajesz jedną z trzech zmiennych w zależności od typu połączenia GML network_socket_tcp network_socket_udp network_socket_bluetooth GML network_create_server(network_socket_udp,30666,32); (przykładowe ustawienie) Jeśli funkcja zwróci ujemną wartość to serwera nie udało się założyć. Klient: Wpierw musisz przygotować socket dla klienta, korzystając z funkcji network_create_socket(type) W argumencie podajesz typ połączenia jaki będzie obsługiwany, np. network_socket_udp dla UDP - musi to być ten sam typ na który nasłuchuje serwer GML GameSocket = network_create_socket(network_socket_udp); Połączenie nawiązuje się korzystając z funkcji network_connect(socket,ip,port); przykładowo... GML network_connect(ChatSocket,"127.0.0.1",30666); Jeśli funkcja zwróci liczbę ujemną, nie udało się połączyć z serwerem. Socket którego użyłeś do połączenia z serwerem będziesz wykorzystywać do wysyłania danych do niego KOMUNIKACJA: Teraz najważniejsza część, czyli jak obsługiwać odbieranie i wysyłanie danych. Wysyłanie Do wysyłania danych potrzebujesz bufor, ale takowy już przygotowaliśmy wcześniej. Na początek musisz go wyzerować GML buffer_seek(DataBuffer,buffer_seek_start,0); Dane, które chcesz wysłać, musisz załadować do buforu korzystając z funkcji buffer_write(buffer, type, value) W argumencie "buffer" podajesz nazwę swojego buforu, w typie podajesz typ danych(poszukaj pełenej listy w dokumentacji), w argumencie "value" podajesz dane które mają zostać wysłane. przykład: GML buffer_write(DataBuffer,buffer_string,"Siemano ludziska!"); Kiedy wrzucimy do buforu wszystko co chcemy wysłać korzystamy z funkcji network_send_packet(socket, buffer, size) W argumencie "socket" podajemy socket serwera, jak mówiłem wcześniej, po to jest nam potrzebny. W argumencie "buffer" podajemy bufor z danymi które chcemy wysłać. W argumencie "size" podaje się wielkość buforu, aby to zrobić użyj funkcji buffer_tell(buffer) Jeżeli masz nazwy zmiennych takie jak ja podałem to poniższa linia zadziała w każdym przypadku gdy chcesz wysłać pakiet od klienta do serwera: GML network_send_packet(GameSocket,DataBuffer,buffer_tell(DataBuffer)); Odbieranie: Odbieranie danych dzieje się w evencie Asynchronous>Networking Za każdym razem gdy dostaniesz jakieś dane od serwera/klienta ten event zostanie wywołany. W momencie wywołania, przysłane dane zostaną automatycznie zapisane do ds_map'y pod nazwa "async_load". Aby móc z pełnym zrozumieniem korzystać z odbierania danych, musisz wiedzieć jak działa ds_map. Możesz to sprawdzić w dokumentacji. Odebrane dane są jednego z trzech rodzajów: network_type_data - Kiedy odebrane są jakieś dane network_type_connect - Kiedy połączysz się z serwerem/klientem network_type_disconnect - Kiedy rozłączy się klient/serwer Typ przysłanych danych zapisany jest w kluczu "type", a więc odczytanie go wygląda następująco: GML ds_map_find_value(async_load,"type") Zwróconą wartością będzie jedna z 3 powyższych. Odczytywanie z odebranego buforu Dane przysłane, np. od klienta do serwera, pozostają przysłane w formacie buforu, więc aby je odczytać musisz skorzystać z funkcji buffer_read(buffer, type) W tym przypadku 'buffer' to bufor zapisany w ds_map pod kluczem "buffer". 'type' to typ danych jaki został przysłany. Jeżeli klient przysłał bufor w którym jest string, to jako string musi zostać odczytany, inaczej będą błędy. przykład: GML buffer_read(ds_map_find_value(async_load,"buffer"),buffer_string); (powyższe wczyta przysłane dane jako string) Skąd wiedzieć jaki typ danych został przesłany? To bardzo ważne pytanie. Jeśli klient prześle swoje X i Y a nie np. nazwę gracza, a serwer spróbuje odczytać odebrane dane jako string, to cały serwer się wysypie. Musi więc istnieć sposób na rozpoznanie jakie dane wysyłamy. Jak to bylo w średniowieczu? Nie było łatwego i szybkiego kontaktu a wszyscy nosili puszki i miecze, dzidy. Po czym poznawano przynależność armii? Po banerze. Zanim przejdziemy do wysłania faktycznej wiadomości dodajmy na samym początku małą informację co tak naprawdę znajduje się w środku. Taki banner mówiący kim jesteśmy. Ta informacja zawsze będzie danego typu (np. u8) więc nigdy nic się nei wysypie, dopóki podamy odpowiednią informację. Założmy, że chcemy wysyłać 2 rodzaje informacji: 1: X,Y,image_angle 2: HP,nick_gracza Pierwszy typ informacji więc nazwijmy "grupą 1", zaś drugi "grupą 2". Przykład dla wysłania grupy 1: GML buffer_seek(DataBuffer,buffer_seek_start,0); // Czyszczenie buforu buffer_write(DataBuffer,buffer_u8,1); // W pierwszej wyslanej informacji mowimy ze w buforze jest grupa 1! buffer_write(DataBuffer,buffer_u32,x); buffer_write(DataBuffer,buffer_u32,y); buffer_write(DataBuffer,buffer_u32,image_angle); network_send_packet(GameSocket,DataBuffer,buffer_tell(DataBuffer)); Jak widzisz, na sam początek wrzuciliśmy liczbę 1. Kiedy serwer dostanie pakiet, sprawdzi jaka liczba jest na początku, będzie mógł sprawdzić czy będzie to 1 czy 2 i dzięki temu będzie wiedział czy powinien odczytać x,y,image_angle czy hp i nick Odnośnik do komentarza Udostępnij na innych stronach Więcej opcji udostępniania...
TheVVaS Opublikowano 27 Kwietnia 2014 Autor Udostępnij Opublikowano 27 Kwietnia 2014 Dzięki za wytłumaczenie co jest za co odpowiedzialne, wcześniej udawało mi się jedynie znaleźć szczątkowe informacje. Natrafiałem także na wzory, lecz było tam w nich stanowczo za dużo i po prostu w nich gubiłem. Byłbym wdzięczny gdybyś stworzył projekt z podstawami podstaw networkingu, wtedy miałbym lepszy zarys jak to ma wyglądać. Ps. Jak ten wbudowany system networkingu przypisuje ID poszczególnym graczom? (Oczywiście chodzi mi o client-server) Oraz jak znaleźć id danego gracza? EDIT1: Dzięki tobie zaczyna mi już świtać coś na temat wysyłania/odbierania w tym wbudowanym networkingu. Po dłuższym wglądzie jest trochę podobny do 39dll. Odnośnik do komentarza Udostępnij na innych stronach Więcej opcji udostępniania...
I am vader Opublikowano 27 Kwietnia 2014 Udostępnij Opublikowano 27 Kwietnia 2014 (rozszerzyłem to trochę gdy pisałeś, zajrzyj do góry) Jeśli przysłana informacja jest typu "network_type_connect" to w ds_map znajduje się ID gracza pod kluczem "socket", więc: GML IDGracza = ds_map_find_value(async_load,"socket") Odnośnik do komentarza Udostępnij na innych stronach Więcej opcji udostępniania...
TheVVaS Opublikowano 27 Kwietnia 2014 Autor Udostępnij Opublikowano 27 Kwietnia 2014 Czyli gdybym chciał poinformować gracza, który właśnie dołączył do serwera to musiałbym zrobić to mniej więcej tak:? GML IDGracza = ds_map_find_value(async_load,"socket"); buffer_seek(DataBuffer,buffer_seek_start,0); //Czyszczę bufor? buffer_write(DataBuffer,buffer_u8,1); //Jako pierwsze wysyłam 1 - jest to informacja o "Panie drogi client zaraz dostaniesz swoje ID" buffer_write(DataBuffer,buffer_u8,IDGracza); network_send_packet(GameSocket,DataBuffer,buffer_get_size(DataBuffer)); Póki co ten async_load mnie zastanawia, bo nigdzie nie mogę znaleźć o nim informacji. Szukałem w dokumentacji - nic nie znalazłem, pewnie źle szukałem :/ PS. ds_map_find_value(async_load,"socket"); Rozumiem, że "socket" pobrany z async_load podaje ID drugiej strony? Odnośnik do komentarza Udostępnij na innych stronach Więcej opcji udostępniania...
I am vader Opublikowano 27 Kwietnia 2014 Udostępnij Opublikowano 27 Kwietnia 2014 CO do przykładu tak, w ten sposób byś poinformował klienta jakie ma ID. Naturalnie przyda mu się aby Cię informować kim jest. I tak, "socket" z async_load podaje ID adresata(wydaje mi sie ze tylko przy connect i disconnect, niech ktos mnie poprawi jesli sie myle) Edit: Co do async_load samego w sobie, to jest to jedynie zmienna wykorzystywana przez GM do tymczasowego przetrzymywania ds_map'y gdy przyjdą dane, mapa jest usuwana gdy event się skończy. Odnośnik do komentarza Udostępnij na innych stronach Więcej opcji udostępniania...
TheVVaS Opublikowano 27 Kwietnia 2014 Autor Udostępnij Opublikowano 27 Kwietnia 2014 1. Jest gdzieś informacja o async_load? 2. Jeśli wysyłam albo odbieram bufory to ZAWSZE w Asynchronous>Networking? 3. Mógłbyś skombinować podstawowy wzór networkingu? :D Odnośnik do komentarza Udostępnij na innych stronach Więcej opcji udostępniania...
I am vader Opublikowano 27 Kwietnia 2014 Udostępnij Opublikowano 27 Kwietnia 2014 1. Skoro nie znalazłeś to wątpię, ale tam nawet nie byłoby nic do czytania, to zwykła zmienna w której jest ID mapy. 2. Wysyłanie w dowolnym miejscu o dowolnym czasie, odbieranie ZAWSZE w Asynchronous>Networking 3. Może później Odnośnik do komentarza Udostępnij na innych stronach Więcej opcji udostępniania...
pablo1517 Opublikowano 30 Kwietnia 2014 Udostępnij Opublikowano 30 Kwietnia 2014 1. Jest gdzieś informacja o async_load? 2. Jeśli wysyłam albo odbieram bufory to ZAWSZE w Asynchronous>Networking? 3. Mógłbyś skombinować podstawowy wzór networkingu? :D 1. W helpie/dokumentacji GMa... 2. Odbieranie Tak. Wysyłanie skąd chcesz. 3. Jest do sciagniecia wsrod przykladow GMa. Odnośnik do komentarza Udostępnij na innych stronach Więcej opcji udostępniania...
DangBean Opublikowano 30 Kwietnia 2014 Udostępnij Opublikowano 30 Kwietnia 2014 Bardzo przejrzyście opisane :) , ale wkradł się mały błąd: ServerSocket = network_create_socket(network_socket_udp); network_create_server(ServerSocket,30666,32); zgodnie z dokumentacją pierwszym argumentem network_create_server jest "The type of server to create", a nie nr socketu. Czyli w przypadku hosta network_craeate_socket jest niepotrzebny, wystarczy: GML ServerSocket = network_create_server(network_socket_udp, 30666, 32); Druga uwaga: network_send_packet(GameSocket,DataBuffer,buffer_get_size(DataBuffer)); powyższy kod wysyła cały bufor (1024 bytes), lepiej wysyłać tylko dane, bez śmieci - do tego służy buffer_tell: GML network_send_packet(GameSocket, DataBuffer, buffer_tell(DataBuffer)); Odnośnik do komentarza Udostępnij na innych stronach Więcej opcji udostępniania...
I am vader Opublikowano 30 Kwietnia 2014 Udostępnij Opublikowano 30 Kwietnia 2014 Co do pierwszego - rzeczywiście, pisałem z pogmatwanego, wielomiesięcznego kodu, do którego nie zaglądałem od dawna i musiałem coś pomylić, nie wiem jak to się tam znalazło. Zaraz to poprawię. Co do drugiego - interesujące, nie wiedziałem o tym. Z pewnością się przyda w optymalizacji! Dzięki :thumbsup: Edit: Oba poprawione...chyba Odnośnik do komentarza Udostępnij na innych stronach Więcej opcji udostępniania...
kriso99 Opublikowano 30 Kwietnia 2014 Udostępnij Opublikowano 30 Kwietnia 2014 no i sie znowu czegos dowiedzialem:-) mam pytanie: jak sprawdzic ip przy połączeniu bluetooth na mobilkach? Odnośnik do komentarza Udostępnij na innych stronach Więcej opcji udostępniania...
I am vader Opublikowano 1 Maja 2014 Udostępnij Opublikowano 1 Maja 2014 Dokumentacja twierdzi, że połączenie bluetooth nie jest jeszcze wprowadzone. Ale to może być błąd. Odnośnik do komentarza Udostępnij na innych stronach Więcej opcji udostępniania...
kriso99 Opublikowano 1 Maja 2014 Udostępnij Opublikowano 1 Maja 2014 thx Odnośnik do komentarza Udostępnij na innych stronach Więcej opcji udostępniania...
TheVVaS Opublikowano 1 Maja 2014 Autor Udostępnij Opublikowano 1 Maja 2014 A jak wygląda wysyłanie danych do konkretnego clienta? Rozumiem, że to: GML network_send_packet(GameSocket,DataBuffer,buffer_tell(DataBuffer)); Wysyła dane do WSZYSTKICH clientów, tak? Odnośnik do komentarza Udostępnij na innych stronach Więcej opcji udostępniania...
I am vader Opublikowano 1 Maja 2014 Udostępnij Opublikowano 1 Maja 2014 Akurat ten kod podałem jako przykład wysyłania od klienta do serwera. Jeśli przysłana informacja jest typu "network_type_connect" to w ds_map znajduje się ID gracza pod kluczem "socket", więc: GML IDGracza = ds_map_find_value(async_load,"socket") Innymi słowy masz tablicę lub ds_listę lub cokolwiek w której zapisujesz sobie sockety do klientów i potem wysyłasz oddzielnie do każdego. Tylko taki szybki tip, jak do każdego wysyłasz tę samą informację nie musisz za każdym razem resetować i przepisywać bufera, po prostu robisz jakąś pętlę i wysyłasz do każdego po kolei. GML (kawalekkodu) // (...) <jakis switch czy cos> case network_type_connect: ds_list_add(PlayerList,ds_map_find_value(async_load,"socket")); // Zapisanie do ds_list socketa podlaczonego gracza break; // (...)</span></span> GML (wysylaniemasowe) // < wrzucanie informacji do bufera > for(var i=0; i<ds_list_size(PlayerList); i++ ) { network_send_packet(ds_list_find_value(PlayerList,i),DataBuffer,buffer_tell(DataBuffer)); } Edit: Naprawcie te tagi GML bo 5 lat poprawiania "</span>" i "quotnazwaeventaquot" robi sie nudne.. i jak zwykle pisze z glowy wiec mądrzejszych ode mnie proszę o bezczelne wytykanie błędów Odnośnik do komentarza Udostępnij na innych stronach Więcej opcji udostępniania...
Rekomendowane odpowiedzi
Jeśli chcesz dodać odpowiedź, zaloguj się lub zarejestruj nowe konto
Jedynie zarejestrowani użytkownicy mogą komentować zawartość tej strony.
Zarejestruj nowe konto
Załóż nowe konto. To bardzo proste!
Zarejestruj sięZaloguj się
Posiadasz już konto? Zaloguj się poniżej.
Zaloguj się