Warsztat - Programowanie gier

Lipiec 30, 2010, 17:37:46 *
Witamy, Gość. Zaloguj się, lub zarejestruj proszę.

Zaloguj się podając nazwę użytkownika, hasło i długość sesji
Aktualności: Warsztat, Regulamin forum, #warsztat, Wiki, FAQ, NoPaste, Mapa
 
   Strona główna   Pomoc Szukaj Zaloguj się Rejestracja  
Strony: 1 [2]
  Drukuj  
Autor Wątek: Jak wypakować plik .spr ?  (Przeczytany 3034 razy)
ConayR
SuperHero Member
******

wiadomości: 1389


Cheers!


Zobacz profil
« Odpowiedz #15 : Styczeń 02, 2010, 15:58:08 »

Program nazywa się "Form1" i został napisany w C# w przypływie kilku minut dobrego humoru.
Zapisane

On the Internet, nobody knows you're a dog
ConayR
SuperHero Member
******

wiadomości: 1389


Cheers!


Zobacz profil
« Odpowiedz #16 : Styczeń 03, 2010, 04:10:42 »

Ok, postanowiłem poświęcić kilka chwil na analizę tego pliku. Jako że temat może zainteresować kogoś, będę starał się opisać co kolejno robię i dlaczego. Nie gwarantuję, że skończy się całość udanym ekstraktorem (a z pewnością nie tej nocy), ale opis procesu i tak może być dla kogoś pomocny w przyszłości.

Zacząłem od lektury forum gry w poszukiwaniu zrzutów ekranu. Dobrze jest wiedzieć jakiej grafiki się w pliku szuka. Napisałem prosty program traktujący cały plik SPR jako RAW 32 x ileśtam i wyświetliłem wynik. Wyglądało to mniej więcej tak:


Oglądałem te źle wyglądające sprajty, aż natrafiłem na coś, co było widać na jednym ze zrzutów ekranu:


W prawym górnym rogu widać kamienną podłogę z kafli. Przesunięty odpowiednio viewer pokazał mi coś takiego:


Zatem sprajty na zrzucie to odpowiednik:


Pierwotnie chciałem porównać wartości kolorów z pliku do wartości kolorów na zrzucie, pojawiły się jednak 3 problemy:
- grafika na zrzucie jest rozciągnięta (sprajty 32x32 z pliku mają 64x64 na zrzucie) przy użyciu (prawdopodobnie) liniowej interpolacji, co zniekształca kolory i porównanie nie jest możliwe
- grafika w grze jest cieniowana przy użyciu źródeł światła (gracz jest jednym z nich), co zniekształca kolory i porównanie nie jest możliwe
- zrzut ekranu był w JPG, co zniekształca kolory i porównanie nie jest możliwe

Jakiekolwiek próby porównania barw odpadają zatem. Daje się jednak zauważyć, że trzy widoczne w pliku SPR sprajty, w przeciwieństwie do tego co widać na zrzucie, mają zupełnie różne odcienie. Może to zatem oznaczać, że plik jest w jakiś prymitywny sposób zakodowany. Na tą chwilę zakładam, że wartości w pliku są XORowane albo dodawana jest jakaś stała. Wartość dla całego sprajta musiałaby być stała, bo sprajt mimo wszystko ma jednorodną barwę.

Zakładając, że mam rację, co w takim razie trzeba zrobić? Znaleźć różnicę między tymi trzema sprajtami w pliku. Ze zrzutu ekranowego wynika, że powinny się w sumie różnić wyłącznie rysą, więc górny brzeg powinny mieć mniej więcej identyczne (oczywiście poza miejscami, w których rysa zahacza o brzeg).

Przesunięcie pierwszego sprajta w pliku to 640556 czyli 0x9C62C. Drugiego to 643633 czyli 0x9D231 a trzeciego to 646710 czyli 0x9DE36. Ktoś, kto liczy uważnie zauważy, że różnica offsetu w pliku między tymi sprajtami 32x32 to nie 3*1024 (czyli 3 bajty na kolor, sprajt 32x32=1024) a 3*1024+5. Oznacza to, że przed lub za każdym sprajtem znajduje się 5 bajtów z jakimiś informacjami. Zakładam, że przed, opiszę za chwilę dlaczego.

Zobaczmy w takim razie początki tych sprajtów. Poniżej 5 bajtów przed sprajtem i pierwszych 10 pikseli (30 bajtów)

** Pierwszy sprajt **
- Pięć bajtów przed nim
68 42 01 E3 E3
- Pierwszych 30 bajtów grafiki
AF AE A2 | AF AE A2 | 5A 59 4E | 5A 59 4E | 5A 59 4E | 5A 59 4E | 5A 59 4E | 5A 59 4E | BA B9 AE | AF AE A2

** Drugi sprajt **
- Pięć bajtów przed nim
13 43 01 14 14
- Pierwszych 30 bajtów grafiki
58 59 55 | 58 59 55 | AD AE B9 | AD AE B9 | AD AE B9 | AD AE B9 | AD AE B9 | AD AE B9 | 4D 4E 59 | 58 59 55

** Trzeci sprajt **
- Pięć bajtów przed nim
0B 44 01 C1 C1
- Pierwszych 30 bajtów grafiki
8D 8C 80 | 8D 8C 80 | 78 7B 6C | 78 7B 6C | 78 7B 6C | 78 7B 6C | 78 7B 6C | 78 7B 6C | 98 9B 8C | 8D 8C 80

Jeśli miałem rację, to powinien się powtarzać wzorzec kolorów. I tak właśnie jest, bo mamy wzorzec: AABBBBBBCA. Zanim jednak ktoś powie: aha! A nie mówiłem?! Plik jest skompresowany. Nie jest (a przynajmniej nie to, co widać do tej pory). Jest tylko badziewnie zakodowany, żeby utrudnić jego czytanie osobom postronnym. Najprawdopodobniej po to.

Zanim przejdę dalej, wrócę do mojej wcześniejszej teorii mówiącej o tym, że to wariacja na temat formatu Tibii. W SPR Tibii występują dwa rodzaje pikseli: barwne i ciąg przezroczyste. Opisane są one jako coś na kształt strumieni: najpierw pojawia się informacja o długości strumienia, później dane strumienia (oczywiście strumień przezroczystości jest pusty). Opisane to zostało tutaj:
http://otfans.net/showthread.php?t=141982
Każdy kafel to:
3B - przeznaczenie nieznane
2B - rozmiar sprajta
(
2B - ilość przezroczystych pikseli
2B - ilość kolorowych pikseli (P)
3B * P - dane kolorowych pikseli
)

Jest to bardzo prymitywna wersja bardzo prymitywnego algorytmu kompresji, RLE. Oznacza to, że nieprzezroczyste sprajty (teren) mają 3*32*32 bajtów, podczas kiedy przezroczyste (broń, przeciwnicy i inne obiekty) oszczędzają nieco miejsca. Widać to na pierwszym zrzucie ekranu z programu, mniej więcej w połowie jego wysokości ilustracji (trzy niższe niż reszta sprajty).

Zobaczmy w takim razie jakie są różnice między sprajtami. Zanim jednak to zrobię, posłużę się małym oszustwem. Wszystkie z trzech analizowanych sprajtów mają jednolitą powierzchnię w prawej górnej ćwiartce. Pozwala to na pobranie z obrazu przybliżonej barwy tego miejsca mimo kompresji JPG (trafiamy bowiem na względnie jednolity blok 8x8).


I tak otrzymujemy:
2E 2F 29 - barwa ze zrzutu ekranu
AF AE A2 - barwa z pierwszego sprajta
88 89 85 - barwa z drugiego sprajta
8D 8C 80 - barwa z trzeciego sprajta
Tak swoją drogą to ze stosunku R do G do B w sprajtach można wnioskować, że nie mamy do czynienia z przesunięciem wartości o stałą a z XORem właśnie. Bo 0xAF - 0xAE = 1, ale już 0x88 - 0x89 = -1. Podobnie 0xAE - 0xA2 = 12 ale 0x89 - 0x85 = 4.

Spróbujmy w takim razie znaleźć wartość kodu zakładając, że chcemy uzyskać kolor ze zrzutu ekranu.
AF ^ 2E = 81
AE ^ 2F = 81
A2 ^ 29 = 8B

88 ^ 2E = A6
89 ^ 2F = A6
85 ^ 29 = AC

8D ^ 2E = A3
8C ^ 2F = A3
80 ^ 29 = A9

Wygląda na to, że ta sama wartość jest używana do XORowania całego sprajta (odległość Hamminga między wynikami 81-8B, A6-AC i A3-A9 to zawsze 2, co tłumaczy przekłamania związane z kompresją JPG i przyciemnianiem sprajtów w grze). Kod niestety nie jest zbliżony do żadnej wartości z 5 bajtów poprzedzających sprajt (zbliżony znowu w sensie odległości Hamminga), więc nie sądzę by któraś z wartości przed sprajtem była kodem. Nic też nie wskazuje na to, że kod zwiększa się o stałą wartość co sprajt.

Do analizy pliku wrócę niebawem. Jeśli ktoś ma jakieś uwagi, pomysły, albo chce pociągnąć to dalej, zapraszam.

//edyta
Już wiem jak to jest kodowane. Smiley Podpowiem, że ((20 ^ E3) ^ AF) == ((20 ^ 14) ^ 58) == ((20 ^ C1) ^ 8D).
« Ostatnia zmiana: Styczeń 03, 2010, 04:24:17 wysłane przez ConayR » Zapisane

On the Internet, nobody knows you're a dog
KriS
Full Member
***

wiadomości: 126


Zobacz profil WWW
« Odpowiedz #17 : Styczeń 06, 2010, 01:13:43 »

Do analizy pliku wrócę niebawem. Jeśli ktoś ma jakieś uwagi, pomysły, albo chce pociągnąć to dalej, zapraszam.

Zaciekawiłeś mnie swoim postem. Szczególnie rozwaliły mnie te wielokrotne xory i RLE - że się komuś chciało to pisać Smiley.


Trochę się pobawiłem i podaje pełny opis formatu pliku:

Nagłówek
2b - wersja pliku
256b - tablica do xorowania Smiley (packHeader)

Plik z obrazkiem
5b - nagłówek pliku (fileHeader)
Następnie jest strumień danych danego obrazka.

Nagłówek pliku z obrazkiem
1b - do xorowania
2b - typ kafla
1b - wysokość
1b - szerokość

Dekodowanie nagłówka obrazku
xorFileVal = ( packHeader[ fileHeader[0] ] ^ 0x1B ) ^ fileHeader[0]
imgWidth = fileHeader[3] ^ xorFileVal
imgHeight = fileHeader[4] ^ xorFileVal

Odczytywanie obrazka
Czytamy 3 bajty (RGB), dekodujemy analogicznie do szerokości i wysokości. Jeżeli RGB = 0xFF00FF to czytamy następny 1b i pomijamy odczytaną ilość pikseli (powinny one być ustawione na 0x00000000).
Zapisane

http://KriScg.blogspot.com
"Don't have any friends? Still a virgin? Programming is for you!"
ConayR
SuperHero Member
******

wiadomości: 1389


Cheers!


Zobacz profil
« Odpowiedz #18 : Styczeń 06, 2010, 01:39:00 »

O, i z miejsca mam mniej roboty. Cheesy

Kluczowe w tym wszystkim było znalezienie xorFileVal. Z ciekawości - jak do tego doszedłeś? Z wysokości i szerokości przykładowej grafiki znałem kilka wartości kodu, zamierzałem szukać czegoś w nagłówku (bo był dziwnie długi, przeszło ćwierć kilo bzdur) ale już mi się tamtej nocy nie chciało. W tą stronę szedłeś, czy zaczynałeś od nagłówka pliku?
Zapisane

On the Internet, nobody knows you're a dog
KriS
Full Member
***

wiadomości: 126


Zobacz profil WWW
« Odpowiedz #19 : Styczeń 06, 2010, 02:07:07 »

O, i z miejsca mam mniej roboty. Cheesy

Kluczowe w tym wszystkim było znalezienie xorFileVal. Z ciekawości - jak do tego doszedłeś? Z wysokości i szerokości przykładowej grafiki znałem kilka wartości kodu, zamierzałem szukać czegoś w nagłówku (bo był dziwnie długi, przeszło ćwierć kilo bzdur) ale już mi się tamtej nocy nie chciało. W tą stronę szedłeś, czy zaczynałeś od nagłówka pliku?

Na początku też kombinowałem na podstawie szerokości i wysokości. Następnie zauważyłem w krótszych sprajtach, że się powtarza pewien wzór (nawet słusznie założyłem, że to może być 0xFF00FF). No i na tyle starczyło moich pomysłów, więc po prostu odpaliłem disassemblera Smiley.
Zapisane

http://KriScg.blogspot.com
"Don't have any friends? Still a virgin? Programming is for you!"
ConayR
SuperHero Member
******

wiadomości: 1389


Cheers!


Zobacz profil
« Odpowiedz #20 : Styczeń 06, 2010, 02:15:29 »

No i na tyle starczyło moich pomysłów, więc po prostu odpaliłem disassemblera Smiley.
Grin To oszustwo. ;P Plik bez kompresji atakować od strony kodu? To nieuczciwe. ;]
Zapisane

On the Internet, nobody knows you're a dog
RedHot
Hero Member
*****

wiadomości: 532


LiekTehOrly ?


Zobacz profil
« Odpowiedz #21 : Luty 27, 2010, 03:47:38 »

Może odkopuje trochę temat , ale coś nie mogę wpaśc na rozw.

Generalnie próbowałem zaimplementować dekodowanie obrazka.  Ogólnie moja funkcja rysująca działa ok dla 3 pierwszych sprite'ów .
Po lewej każda składowa koloru XORowana, po prawej (w celach diagnostycznych) nie.





Oto kod
http://nopaste.gamedev.pl/?id=6372
« Ostatnia zmiana: Luty 27, 2010, 04:42:04 wysłane przez RedHot » Zapisane

OpenLayer 2.1 = good shit Cool
ConayR
SuperHero Member
******

wiadomości: 1389


Cheers!


Zobacz profil
« Odpowiedz #22 : Luty 27, 2010, 23:12:22 »

Bez patrzenia w kod, z obrazków widać, że źle liczysz offset kafla/rozmiar kafla. Zobacz, że od czwartego pojawiają się w pewnym momencie drastycznie zmiany kolorów (czwarty zaczyna się jako brązowy a później szara plama; drugi z trzeciego rzędu wyraźniej jest rozłożony na końcu jednego kafla i początku drugiego, niebieskiego). Przeanalizuj uważnie co się dzieje na koniec 3. i na początku 4. kafla. Może jakiś błąd off by one widoczny wyłącznie jeśli kafel kończy się skompresowanym ciągiem?
Zapisane

On the Internet, nobody knows you're a dog
KriS
Full Member
***

wiadomości: 126


Zobacz profil WWW
« Odpowiedz #23 : Luty 28, 2010, 00:34:08 »

Może odkopuje trochę temat , ale coś nie mogę wpaść na rozw.

Generalnie próbowałem zaimplementować dekodowanie obrazka.  Ogólnie moja funkcja rysująca działa ok dla 3 pierwszych sprite'ów .

Wygląda na to, że źle odczytujesz przezroczyste sprite. Napewno źle zapisałeś warunek if ( rgb == 0xFF00FF ). Wrzucam swój kod, może coś ci pomoże: http://nopaste.gamedev.pl/?id=6376.
Zapisane

http://KriScg.blogspot.com
"Don't have any friends? Still a virgin? Programming is for you!"
RedHot
Hero Member
*****

wiadomości: 532


LiekTehOrly ?


Zobacz profil
« Odpowiedz #24 : Luty 28, 2010, 19:39:20 »

Udało mi się wszystko ładnie skleić Smiley . Faktycznie błędy były w pixelach, które miały być pomijane. W sprawdzaniu koloru pojawił się też błąd związany z priorytetem operatorów (mianowicie  == i ^ ) .

Dodam tylko, że są jednak obrazki o większych rozmiarach tj. 64x64 i chyba 64x96.
Zapisane

OpenLayer 2.1 = good shit Cool
Strony: 1 [2]
  Drukuj  
 
Skocz do:  

Hosting: Polska Strefa - Ogłoszenia
Powered by SMF 1.1.7 | SMF © 2006, Simple Machines LLC