-[PhariseuS]- Opublikowano 17 Lutego 2015 Udostępnij Opublikowano 17 Lutego 2015 Być może są tu tacy, którzy mnie pamiętają. Ja w każdym razie kojarzę parę ksywek.Ostatnio ponownie zainteresowałem się GM. I kojarzę tę trzecią odsłonę GMClan-owego forum. I kojarzę, że pamiętam jeszcze hasło. Nie lubię pożegnań ani powitań, więc z tym zapraszam ew. na PW. A wszystkich innych witam serdecznie po raz pierwszy. Koniec offtopa. Będzie rozlegle. <funkcja base91_init> GML /* basE91. Czyli system liczbowy oparty na podstawie 91. Tak się jakoś składa, że 91 znaków ASCII (litery, liczby i znaki specjalne - z pominięciem znaków ' \ - oraz znaków tzw. niedrukowalnych) mogą być świetnie użyte do reprezentacji danych binarnych. Dzięki temu można przesyłać tekst, muzykę, obrazy, pliki wykonywalne etc. bez obawy o utratę danych w przypadku, gdy obie strony używają różnych kodowań. W praktyce - oznacza to także możliwość wygenerowania binarnego pliku na serwerze dynamicznie, "karmiąc" skrypt zakodowanymi danymi poprzez HTTP - w tym także w Game Makerze. Innymi słowy - wysyłanie i odbieranie plików jedynie poprzez odpowiednie spreparowanie odnośnika. basE91 ma najwyższą efektywność - ok. 82% [źr. Wikipedia]. Oznacza to, że na 100 wysłanych bajtów jedynie 18 z nich stanowi nadwyżkę - będącą efektem zmiejszenia liczby dostępnych znaków do wyświetlenia. I tak... http://example.com/upload/dJR2LwoZ?Xx=nuH*!Bf!rvpa$iDu_8l*@E=C1]OCy$Fn:Eso:zYh>w^C}!n3B Sprawiłoby, by serwer example.com odebrał plik UTF-8 ze swojsko brzmiącą zawartością: Pchnąć w tę łódź jeża lub ośm skrzyń fig Dopóki przesyłany jest tekst w standardzie rozszerzo- nego ASCII (jeden znak zajmuje jeden bajt) - co wyklucza wszystkie języki poza angielskim, który składa się ze "standardowych" liter łacińskiego alfabetu, można bez obawy korzystać z konkurencyjnych metod konwersji danych binarnych na tekst, jak znany wielu base64 czy uuencode. Problemem jest jednak złe radzenie sobie z UTF-8 (standard kodowania wykorzystywany także przez GM Studio - i dziękujmy Morganowi Freemanowi, że tak się stało! Unicode bardzo wiele ułatwia) oraz nadmiar danych. Jeżeli nadal nie widzisz do czego przydaje się konwersja binarno-tekstowa, spróbuj kiedyś wysłać z GM zrzut ekranu z gry na serwer przy użyciu eventu z rodziny Asynchronous. Co do skryptu: nie jestem autorem samego algorytmu. Ba, nawet nie całkiem go rozumiem. Wydał mi się jednak na tyle interesujący i użyteczny, iż postanowiłem zaimplementować go w GM Studio. Autorem oryginalnego algorytmu jest Joachim Henke. Udostępnia go on na licencji BSD, pod adresem http://base91.sourceforge.net/ Autorem tej implementacji / tłumaczenia jest Phariseus. Nie włożył on w nią zbyt dużo wysiłku. Jest pewny, że wiele rzeczy możnaby zrobić lepiej, szybciej, tu zoptymizować, tam kokardkę nakleić. Jest też pewny, że znajdą się ludzie, którym się zechce to zrobić. W związku z tym i powyższym, ta implementacja również udostępniona jest na licencji BSD. Wykonana została dla portalu GMClan.org - Game Maker Polska, do którego autor implementacji żywi ponad 10-letni sentyment - mimo bardzo, bardzo długiego okresu bezczynności. basE91 nie jest standardem ISO, lecz jest implementowany na wielu platformach. Stanowi także wolne oprogramowanie. A za każdym razem, gdy nabywasz, modyfikujesz i udostępniasz wolne oprogramowanie, Richardowi Stallmanowi rośnie jeden włos na brodzie. GMowa implementacja jest dosyć prosta, na chwilę obecną przyjmuje na wejściu ciągi znaków. (wkrótce: pliki). Do adremu, jak to mawiają. - Nicodemus "Phariseus" J. Bernards, 2015 PS: Skrypt jest wybitnie nie-idiotoodporny. Karmisz nieoczekiwanymi / pustymi / nieprawidłowymi wartościami na własną odpowiedzialność. */ /* Zacznijmy od zainicjowania funkcyi. Ta funkcja powinna być wywołana przed pierwszym zakodowaniem lub zdekodowaniem. Definiujemy dwie globalne tablice. Pierwsza, b91_enc, zawiera znaki systemu dziewięćdziesięciojedynkowego (zgadzam się, idiotyczna nazwa), które posłużą za "cyfry". Jeżeli intryguje cię to zagadnienie, polecam http://pl.wikipedia.org/wiki/System_liczbowy Druga tablica tłumaczy z owego egzotycznego systemu na ludzki, czyli dziesiętny. Nic nie stoi na przeszkodzie, by wykorzystać ds_list. Ja byłem na to zbyt leniwy. */ global.b91_enc[0]='A'; global.b91_enc[1]='B'; global.b91_enc[2]='C'; global.b91_enc[3]='D'; global.b91_enc[4]='E'; global.b91_enc[5]='F'; global.b91_enc[6]='G'; global.b91_enc[7]='H'; global.b91_enc[8]='I'; global.b91_enc[9]='J'; global.b91_enc[10]='K'; global.b91_enc[11]='L'; global.b91_enc[12]='M'; global.b91_enc[13]='N'; global.b91_enc[14]='O'; global.b91_enc[15]='P'; global.b91_enc[16]='Q'; global.b91_enc[17]='R'; global.b91_enc[18]='S'; global.b91_enc[19]='T'; global.b91_enc[20]='U'; global.b91_enc[21]='V'; global.b91_enc[22]='W'; global.b91_enc[23]='X'; global.b91_enc[24]='Y'; global.b91_enc[25]='Z'; global.b91_enc[26]='a'; global.b91_enc[27]='b'; global.b91_enc[28]='c'; global.b91_enc[29]='d'; global.b91_enc[30]='e'; global.b91_enc[31]='f'; global.b91_enc[32]='g'; global.b91_enc[33]='h'; global.b91_enc[34]='i'; global.b91_enc[35]='j'; global.b91_enc[36]='k'; global.b91_enc[37]='l'; global.b91_enc[38]='m'; global.b91_enc[39]='n'; global.b91_enc[40]='o'; global.b91_enc[41]='p'; global.b91_enc[42]='q'; global.b91_enc[43]='r'; global.b91_enc[44]='s'; global.b91_enc[45]='t'; global.b91_enc[46]='u'; global.b91_enc[47]='v'; global.b91_enc[48]='w'; global.b91_enc[49]='x'; global.b91_enc[50]='y'; global.b91_enc[51]='z'; global.b91_enc[52]='0'; global.b91_enc[53]='1'; global.b91_enc[54]='2'; global.b91_enc[55]='3'; global.b91_enc[56]='4'; global.b91_enc[57]='5'; global.b91_enc[58]='6'; global.b91_enc[59]='7'; global.b91_enc[60]='8'; global.b91_enc[61]='9'; global.b91_enc[62]='!'; global.b91_enc[63]='#'; global.b91_enc[64]='$'; global.b91_enc[65]='%'; global.b91_enc[66]='&'; global.b91_enc[67]='('; global.b91_enc[68]=')'; global.b91_enc[69]='*'; global.b91_enc[70]='+'; global.b91_enc[71]=','; global.b91_enc[72]='.'; global.b91_enc[73]='/'; global.b91_enc[74]=':'; global.b91_enc[75]=';'; global.b91_enc[76]='<'; global.b91_enc[77]='='; global.b91_enc[78]='>'; global.b91_enc[79]='?'; global.b91_enc[80]='@'; global.b91_enc[81]='['; global.b91_enc[82]=']'; global.b91_enc[83]='^'; global.b91_enc[84]='_'; global.b91_enc[85]='`'; global.b91_enc[86]='{'; global.b91_enc[87]='|'; global.b91_enc[88]='}'; global.b91_enc[89]='~'; global.b91_enc[90]='"'; global.b91_dec[ord('A')]=0; global.b91_dec[ord('B')]=1; global.b91_dec[ord('C')]=2; global.b91_dec[ord('D')]=3; global.b91_dec[ord('E')]=4; global.b91_dec[ord('F')]=5; global.b91_dec[ord('G')]=6; global.b91_dec[ord('H')]=7; global.b91_dec[ord('I')]=8; global.b91_dec[ord('J')]=9; global.b91_dec[ord('K')]=10; global.b91_dec[ord('L')]=11; global.b91_dec[ord('M')]=12; global.b91_dec[ord('N')]=13; global.b91_dec[ord('O')]=14; global.b91_dec[ord('P')]=15; global.b91_dec[ord('Q')]=16; global.b91_dec[ord('R')]=17; global.b91_dec[ord('S')]=18; global.b91_dec[ord('T')]=19; global.b91_dec[ord('U')]=20; global.b91_dec[ord('V')]=21; global.b91_dec[ord('W')]=22; global.b91_dec[ord('X')]=23; global.b91_dec[ord('Y')]=24; global.b91_dec[ord('Z')]=25; global.b91_dec[ord('a')]=26; global.b91_dec[ord('b')]=27; global.b91_dec[ord('c')]=28; global.b91_dec[ord('d')]=29; global.b91_dec[ord('e')]=30; global.b91_dec[ord('f')]=31; global.b91_dec[ord('g')]=32; global.b91_dec[ord('h')]=33; global.b91_dec[ord('i')]=34; global.b91_dec[ord('j')]=35; global.b91_dec[ord('k')]=36; global.b91_dec[ord('l')]=37; global.b91_dec[ord('m')]=38; global.b91_dec[ord('n')]=39; global.b91_dec[ord('o')]=40; global.b91_dec[ord('p')]=41; global.b91_dec[ord('q')]=42; global.b91_dec[ord('r')]=43; global.b91_dec[ord('s')]=44; global.b91_dec[ord('t')]=45; global.b91_dec[ord('u')]=46; global.b91_dec[ord('v')]=47; global.b91_dec[ord('w')]=48; global.b91_dec[ord('x')]=49; global.b91_dec[ord('y')]=50; global.b91_dec[ord('z')]=51; global.b91_dec[ord('0')]=52; global.b91_dec[ord('1')]=53; global.b91_dec[ord('2')]=54; global.b91_dec[ord('3')]=55; global.b91_dec[ord('4')]=56; global.b91_dec[ord('5')]=57; global.b91_dec[ord('6')]=58; global.b91_dec[ord('7')]=59; global.b91_dec[ord('8')]=60; global.b91_dec[ord('9')]=61; global.b91_dec[ord('!')]=62; global.b91_dec[ord('#')]=63; global.b91_dec[ord('$')]=64; global.b91_dec[ord('%')]=65; global.b91_dec[ord('&')]=66; global.b91_dec[ord('(')]=67; global.b91_dec[ord(')')]=68; global.b91_dec[ord('*')]=69; global.b91_dec[ord('+')]=70; global.b91_dec[ord(',')]=71; global.b91_dec[ord('.')]=72; global.b91_dec[ord('/')]=73; global.b91_dec[ord(':')]=74; global.b91_dec[ord(';')]=75; global.b91_dec[ord('<')]=76; global.b91_dec[ord('=')]=77; global.b91_dec[ord('>')]=78; global.b91_dec[ord('?')]=79; global.b91_dec[ord('@')]=80; global.b91_dec[ord('[')]=81; global.b91_dec[ord(']')]=82; global.b91_dec[ord('^')]=83; global.b91_dec[ord('_')]=84; global.b91_dec[ord('`')]=85; global.b91_dec[ord('{')]=86; global.b91_dec[ord('|')]=87; global.b91_dec[ord('}')]=88; global.b91_dec[ord('~')]=89; global.b91_dec[ord('"')]=90; <función base91_encode> GML //Funkcja przyjmuje jeden argument - ciąg znaków. //Zwraca ona także jeden argument. I także ciąg znaków. d=argument[0]; //łańcuch znaków do zakodowania l = string_length(d); //liczba znaków łańcucha b=0; //tajemnicza zmienna numer 1 n=0; //tajemnicza zmienna number b (co, że niby powinno być 2?) o=''; //łańcuch znaków do zwrócenia /* Teraz stworzymy plik, na którym będziemy pracować. Tak, funkcja tworzy tymczasowy plik. Bardzo tymczasowy. Tak tymczasowy, że usuwany jest on jeszcze podczas wykonywania funkcji. Za chwilę dowiemy się, dlaczego. Oto co musimy zrobić: Otwieramy plik w trybie tekstowym do zapisu. Wpisujemy wartość łańcucha wejściowego do pliku. Zamykamy plik. Otwieramy plik w trybie binarnym do odczytu. Zapamiętujemy rozmiar pliku w bajtach. Wartość każdego bajta zapamiętujemy w tablicy bajtów. I dopiero wtedy przechodzimy do głównej pętli funkcji. Jej pierwsza linia odczytuje i-ty bajt z tablicy bajtów, przesunięty bitowo w lewo o wartość n. Dobra, chwila. Ale właściwie po co tyle zachodu? Czy nie łatwiejsze byłoby użycie gołej funkcji ord, zwracającej kod ascii danego znaku, zamiast wielokrotne operowanie na plikach? Problemem są polskie litery. I nie tylko polskie. I nie tylko litery. Właściwie wszystko, co przekracza zakres 8 bitów, czyli rozszerzone ASCII. Jako że ta implementacja funkcji operuje na pojedynczych bajtach - a na przykład polskie litery kodowane w utf8 składają się z dwóch bajtów - więcej patyczkowania byłoby z "rozstrzeliwaniem" znaków na bajty poprzez funkcję. O wiele łatwiej jest najpierw zapisać łańcuch wejściowy tekstowo, a odczytać bajt po bajcie - wtedy dzieje się to automatycznie. Poniżej moja implementacja basE91. Jest to niemalże dosłowne tłumaczenie z PHP4, z kilkoma niezbędnymi zmianami. Oryginalnym autorem algorytmu jest Joachim Henke. Udostępnia on pliki źródłowe pod adresem http://base91.sourceforge.net/ jako wolne oprogramowanie na licencji BSD. Wyobraźmy sobie Portugalczyka, który nauczył się hiszpańskiego. Nie było to szczególnie trudne. I ten oto Portugalczyk znalazł hiszpański wiersz, który chciał przetłumaczyć na ojczysty język. No więc przetłumaczył. Dosłownie lub używając najbliższych odpowiedników. Nie zgłębiał się w analizę treści. Nie domyślał się ukrytych znaczeń parafraz, anafor, metafor i kalafior. To tylko ciąg słów, które brzmią podobnie w obu językach. Nie było takiej potrzeby. Porównał oryginał i tłumaczenie i po prostu stwierdził: "Działa? No to działa. Nie próbuję się nawet zgadywać co podmiot liryczny miał na myśli". I ja jestem tym Portugalczykiem. Przyznaję się bez bicia, że BARDZO powierzchownie rozumiem logikę stojącą za tym algorytmem. Uważam, że nie ma sensu wyważać otwartych drzwi. Ważne, że działa jak powinno działać. OK, koniec tego dobrego. Oto główna pętla. */ temp=file_text_open_write(".encodetemp"); file_text_write_string(temp,d); file_text_close(temp); btemp=file_bin_open(".encodetemp",0); encsize=file_bin_size(btemp); for (bi=1; bi<=encsize; bi++) { byte[bi]=file_bin_read_byte(btemp); } for (i=1; i<=encsize; i++) { b |= byte << n; n+=8; if (n>13) { v = b & 8191; if (v > 88) { b = b >> 13; n-=13; } else { v = b & 16383; b = b >> 14; n -= 14; } o = o + global.b91_enc[v%91] + global.b91_enc[v/91]; } } if (n) { o = o + global.b91_enc[b%91]; if (n > 7 || b > 90) o = o + global.b91_enc[b/91]; } //Czas na zamknięcie i skaskowanie bardzo tymczasowego pliku file_bin_close(btemp); file_delete(".encodetemp"); return o; <funç?o base91_decode> GML /* Jeżeli w miarę ogarniasz mechanizm kodowania, spodoba ci się dekodowanie. Obie funkcje mają dość podobną strukturę. Jedyna różnica to to, że podczas dekodowania wszystko dzieje się w drugą stronę. Poniżej cała masa mądrze wyglądających zmiennych. Wydają się znajome. */ d=argument[0]; l = string_length(d); b=0; n=0; o=""; v=-1; /* Otwieramy bardzo tymczasowy plik binarny do zapisu. */ btemp=file_bin_open(".encodetemp",1); /* Autorem oryginalnego algorytmu jest Joachim Henke. Udostępnia on basE91 na licencji BSD, pod adresem http://base91.sourceforge.net. W pętli znajdują się niezbędne zmiany naniesione przeze mnie w tej implementacji. */ for (i = 1; i<=l; i++) { c=global.b91_dec[ord(string_char_at(d,i))]; if (v < 0) v = c; else { v+=c*91; b |= v << n; if (v & 8191 > 88) n+=13; else n+=14; while (n > 7) do { file_bin_write_byte(btemp,(b & 255)); b = b >> 8; n-=8; } v = -1; } } if (v + 1) file_bin_write_byte(btemp,chr((b | v << n) & 255)); /* Zamkykamy plik otwarty binarnie i otwieramy go tekstowo do odczytu. */ file_bin_close(btemp); temp=file_text_open_read(".encodetemp"); ret=file_text_read_string(temp); /* Ponownie zamykamy plik otwarty tekstowo. Zamykamy go na dobre i kasujemy. */ file_text_close(temp); file_delete(".encodetemp"); return ret; Plik gmx (LINK) Powyższy przykład pozwoli kontynuować zaplanowany przeze mnie cykl dotyczący komunikacji pomiędzy GM Studio a serwerem HTTP. Dzięki temu stworzymy działającą grę, do której będzie można się zarejestrować, zalogować, uczestniczyć w rankinkach z innymi użytkownikami - a wszystko dzięki GML, językowi PHP oraz bazom danych MySQL. I tutaj pojawia się moje pytanie: czy w związku z obecnością w przykładzie innych języków programowania niż GML - jednakże jedynie w stopniu umożliwiającym zobrazowanie przykładu - kontynuacja powinna odbywać się w dziale Inne języki? Sugestie/poprawki/pytania/dyskusje/żale - zapraszam. 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ę