Cultures 1 - Edytor Map

W dniu wczorajszym opublikowany został na naszej stronie edytor map do gier które potocznie nazywamy razem Cultures 1, są to: Cultures: Discovery of Vinland, Cultures: The Revenge of the Rain God oraz Cultures Gold. Bynajmniej nie był to żart na prima aprilis, dlatego też post ten piszę dopiero dzień później.

Pobierz go tutaj.



Publikacja tego edytora jest dość istotna dla rozwoju mappingu. Dotychczas cała wiedza i praktyka dotyczące tworzenia map skupione były na odsłonach z serii Cultures osadzonych na silniku Cultures 2. Są to: Bramy Asgardu, Wyprawa na Północ, 8 Cud Świata oraz Saga. Wynika to z prostego faktu - na ten silnik od zamierzchłych początków XXI wieku istniały oficjalne ogólnodostępne edytory map autorstwa developerów gry. Każdy zatem kto miał dostęp do jednej z tych gier miał również możliwość po prostu odpalić go i stworzyć mapę. Wiem, że upraszczam tu całą sprawę, ponieważ rozwój mappingu w Culuresie 2 również przeżył istotne kamienie milowe jak m.in. złamanie w 2009 roku szyfru plików *.cif oraz uzyskanie dostępu do edytora wewnątrznego w roku 2017, które poszerzyły nam horyzonty co do jakości publikowanych map, nie mniej nie o tym dzisiaj.
Cultures 1 nigdy nie cieszył się w kontekście mappingu znaczącą popularnością, nie tylko ze względu na brak jakichkolwiek narzędzi do tworzenia map ze strony twórców gry, ale również z powodu melancholicznego stylu gry. Dlatego też przez ostatnie ćwierć wieku jego istnienia nie doczekaliśmy się absolutnie żadnej fanowskiej mapy wykonananej na tą część gry - zarówno na naszej polskiej stronie jak i w niemieckiej bazie map.
Z dniem wczorajszym problem braku narzędzi do tworzenia map w Culturesie 1 został rozwiązany - na naszej stronie opublikowany został w pełni funkcjonalny edytor map na te odsłony naszej ukochanej serii, które bazują na silniku pierwszego Culturesa. Od teraz istnieje możliwość tworzenia map nie tylko na Bramy Asgardu, Wyprawę na Północ, 8 Cud Świata czy Sagę, ale również na Odkrycia Vinlandii oraz Zemstę Boga Deszczu.

Jako osoba, która przez ostatni rok poświęciła znaczącą część swojego czasu wolnego na ukończenie tego projektu chciałbym opowiedzieć jak wyglądał on od wewnątrz - z mojej perspektywy. Po części może być to sugestia dla tych osób, które z wielkim zapałem sugerują wykonanie pełnego fanowskiego remake Culturesa nie będąc świadomym jak olbrzymiej skali byłby taki remake jak i również z innej strony miła opowieść dla tych którzy po prostu zainteresowani są tym z jakimi wyzwaniami musieliśmy się zmierzyć podczas całego przedsięwzięcia.

Pierwsze fantazje o edytorze do Culturesa 1 pojawiły się we wrześniu dwa lata temu. Z moim kompanem - o nicku Basssiiie - któremu niezmiernie wdzięczny jestem za całą późniejszą pomoc, dyskutowaliśmy dość powierzchniowo jak wyglądałoby tworzenie map do jedynki. Konkluzja była wówczas taka, że edytor byłby masywnym projektem na którego wówczas nie byłem ani gotowy ani zmotywowany.
Stan rzeczy uległ zmianie w okolicach marca zeszłego roku - pierwszy raz wówczas udało nam się zagrać multiplayer w Culturesa 1 pokaźną grupą, w skład której wchodziliśmy: ja, jakester, Chicken oraz Snoopyhr. Grało się nam bardzo fajnie. Pod koniec gry jakester powiedział - co do dzisiaj pamiętam klarownie - że o ile Cultures 1 ma dużo map wieloosobowych (co widzieliśmy wówczas wewnątrz gry), to żadna z nich nie jest w stylu Fortecy lub Nawałnicy, a fajnie by było gdyby taka mapa istniała, lub gdyby dało się ją jakoś stworzyć.
Myśl o tej wypowiedzi chodziła mi przez następne kilka dni lub tygodni po głowie. Co gdyby zrobić edytor do jedynki? Co gdyby zrobić fanowską mapę do jedynki? Jak byłoby to trudne?
Często jak myślę sobie o takich tematach to próbuję wcielić się w autorów gry i pomyśleć - jak ja, ze swoją wiedzą programistyczną, bym zaimplementował od strony plików gry to co widzę na ekranie? Jak trudne by to było? Moją chojraczą konkluzją było to, że.. no w sumie w grze jest teren, jest wysokość, są landscape i struktury - to wychodzą co najwyżej cztery tablice do wypakowania z informacji binarnych, nie wydaje się aż takie złe. Gdybym tylko wiedział jak bardzo byłem wtedy w błędzie... prawdopodbnie nigdy nie zacząłbym tego projektu, jednak wtedy jeszcze o tym nie wiedziałem. Widziałem dopiero czubek góry lodowej która mnie czeka.

Dziesiątego kwietnia 2024 zdecydowałem się zacząć ten projekt - założyłem wówczas temat na forum zastępczym z naszego serwera Discord pt. "Cultures 1: Fan Made maps". Cel był prosty - zrozumieć kontent trzech plików używanych przez grę: *.map, *.cif oraz *.txt. Te dwa ostatnie były po prostu skryptami tekstowymi, czymś na temat czego wiele osób z naszej społeczności posiada wyrafinowaną wiedzę i nie zdawały być się one znaczącym wyzwaniem - zostawiliśmy je więc na koniec. Natomiast pliki *.map... tutaj leżało całe sedno problemu, zakurzony binarny format danych którego nikt nie ruszył przez ostatnie 25 lat, nikt nie miał pojęcia co się w nim kryje. Wiedzieliśmy tylko jedno - gdzieś wewnątrz niego muszą być zapisane informacje o tym co jest statyczne na mapie: o typie terenu, o wysokości terenu, o rozłożeniu elementów otoczenia i kilka innych drobiazgów.
Tutaj z pomocą przyszedł mi Basssiiie, był on jedyną osobą, która zainteresowana była całym tym projektem od samego początku, aż do samego końca. Wspierał mnie nie tylko od strony moralnej, ale równiez dysponował umiejętnością dekompilowania plików wykonywalnych - coś co ja jako wysokopoziomowy programista zawsze postrzegałem jak czarną magię. Jego pomysł był następujący: W Cultures 1 istnieją dwie mapy samouczkowe. Dzieją się one w dokładnie tej samej lokacji (jedna jest tak jakby kontynuacją drugiej). Różnice pomiędzy ich kontentem są znikome, w jednym miejscu pojawia się wioska indian a teren zmienia się marginalnie mało. Pomysł polegał na tym żeby porównać jakie różnice widzimy na mapach wewnątrz gry i przyłożyć to do tego jakie różnice pojedynczych bajtów widzimy w plikach gry.
Wyobraź sobie to tak drogi czytelniku: gdybyś dostał dwa zaszyfrowane listy, których treść była Ci uprzednio znana, o wiele łatwiej byłoby Ci analizować sam szyfr gdyby listy miały podobieństwa w swojej treści, a nie gdyby były oba zupełnie inne. Z tego powodu para bliźniaczych map samouczkowych miała znaczącą wartość, która nie była zawarta w żadnych innych o wiele bardziej wyrafinowanych mapach kampanijnych.
Po pierwszych kilku dniach pracy nad tym projektem konkluzja była jasna: Dane map używają algorytmu kompresji. Była to dokładnie mówiąc kompresja RLE. Jak nam los przyszczęścił, okazało się że jest to praktycznie identyczny algorytm kompresji którego używa się od dawna w formacie plików *.bmd. To zatem czego dokonaliśmy wówczas, polegało głównie na czytaniu dokumentacji Siguzy z roku 2013 i lekkim modyfikowaniu jego oryginalnego sposobu odczytywania plików graficznych. Po kilku próbach korekty różnych parametrów metodą prób i błędów trafiłem w sedno - przed moimi oczami ukazał się obrazek przedstawiający teren pierwszego samouczka. Byłem wtedy przeszczęśliwy. Na moje nieszczęście okazało się jednak że gra nie ma dwóch czy trzech tablic z danymi tak jak wówczas przewidywałem: tablic takich było aż dziewięć! I do tego trzy inne 'sekcje' danych które nie były kompresowalne - zdecydowanie więcej niż się spodziewałem.
W tym momencie zorientowałem się na jaką głęboką wodę się rzuciłem. Pliki *.map nie zawierały tylko i wyłącznie pierwotnych informacji które bezpośrednio widzi mapper gdy tworzy mapę, ale również masę informacji wtórnych. Na przykład: gra zamiast zapisywać jasność wierzchołków wynikającą z różnorodnego rozkładu wysokości zapisuje jasność terenu osobno od wysokości terenu. Jak się okazuje dla devów pewne dodatkowe informacje było łatwiej wcisnąć do pliku niż liczyć je na bierząco gdy uruchamiana jest mapa, a ilość takich wtórnych danych przekraczała moje najśmielsze oczekiwania, wtedy zobaczyłem jak głęboka jest góra lodowa w którą się wpakowałem.

Pracę przez kolejne miesiące podsumować można jednym zdaniem, wręcz w formie zadania matematycznego: Mając tylko pierwotne informacje o mapie (teren, wysokość, landscape) znajdź wszystkie wtórne informacje zapisywane przez plik mapy (m.in jasność, hitboxy landscape, nawodnienie gleby, granice kontynentów, sektory pathfindera).
W praktyce polegało to na szukaniu w stylu pattern-recognition jaki dokładnie algorytm kryje się pod wyprowadzeniem sekcji wtórnych z sekcji pierwotnych. Brzmi to może trywialnie, ale wcale tak nie jest. Wyobraźcie sobie że macie po jednej stronie parking z samochodami, a po drugiej stronie kontenery z surowymi metalami i plastkiami. Waszym zadaniem jest skonstruować uniwersalną instrukcję która jako input bierze ilość i typ surowych materiałów, a jako wyjście zwraca gotowy samochód. Nie brzmi to bynajmniej banalnie. Jeżeli ktoś z was kiedyś próbował rozwiązywać układy równań algebraicznych po prostu zgadując końcowe parametry i mozolnie sprawdzając czy się zgadzają, to zna to uczucie.
Za wszystkim tym oczywiście kryje się multum matematyki - nie tylko takiej szkolnej ale również rachunku różniczkowego, co do których z pewnością jestem przekonany że dałaby radę zanudzić lub zniesmaczyć niejednego czytelnika niezainteresowanego naukami ścisłymi. Pozwólcie zatem, że omówię tylko dwa fragmenty które najbardziej zapadły mi w pamięć: problem najciekawszy oraz problem najbardziej frustrujący. Ostrzegam że dwa kolejne paragrafy mogą być wysycone słownictwem matematycznym.

Algorytm wyprowadzenia jasności wierzchołków na bazie wysokości wierzchołków był moim zdaniem najciekawszym problemem. Pewnego razu bawiąc się w GIMPie bitmapami reprezentującymi wysokość wierzchołków mapy natrafiłem na coś co nazywa się emboss filter - zauważyłem wówczas, że uzyskany obraz po zastosowaniu takiego fitru bardzo przypomina mapę jasności terenu. Filtr ten można było opisać wizualnie jako pewien rodzaj skryptu wykrywającego krawędzie na obrazach. Zacząłem więc zastanawiać się nad tym głębiej, czy może mieć on coś więcej wspólnego z nieznanym mi jeszcze wówczas algorytmem? W tym momencie doznałem jednego z największych przypływów geniuszu jakiego nie miałem od długiego czasu. Kilka miesięcy przed całym tym projektem miałem na studiach kurs z optyki fizycznej. Połączyłem kropki - to czego mnie uczą na uczelni: delta diraca, konwolucja macierzy, filtry fazowe, całki, wszystko to zaczęło składac się w spójną całość jak można opisać jasność terenu na podstawie wysokości terenu - trzeba policzyć splot macierzy reprezentującej wysokość ze stałym jądrem przekształcenia algebraicznego i uzyskamy w ten sposób macierz reprezentującą jasność terenu. Wiem, brzmi to jak naukowa paplanina, ale wyobrazić możecie sobie to w duuuużym uproszczeniu jako pewien układ soczewek gdzie na wejściu dajemy wysokość wierzchołków na mapie jako 2D rozkład intensywność światła i na wyjściowym ekranie dostajemy rozkład światła reprezentujący jasność wierzchołków. Pozostał jednak jeden problem - wyznaczyć dokładne jądro przekształcenia algebraicznego, czyli dowiedzieć się jak dokładnie światło się zmienia w takim wyimaginowanym układzie optycznym. W tym celu zaprogramowałem własną konwolucyjną sieć neuronową której jedynym celem było przewidywać korelacje wysokości i światła. Tak, stworzyłem własne AI od zera którego jedynym celem było symulowanie słońca w Culturesie. Następnie grzebiąc w jego pamięci byłem w stanie wyciągnąć do prostrzej postaci to czego się wyuczył i zrobić z tego deterministyczny algorytm wykorzystujący w pewnym stopiu całkowianie.
Jeżeli kiedykolwiek będziesz wątpić w przydatność szkolnej matematyki, drogi czytelniku, wspomnij na edytor do Culturesa 1. Gdyby nie moja wiedza z matmy i fizyki którą wyniosłem aż z uczelni wyższej, to być może projekt ten nigdy by nie dobiegł końca.

Kolejnym problemem - tym razem najbardziej frustrującym - były zero-jedynkowe informacje o tym które krawędzie pomiędzy trójkątami terenu sa dostępne dla jednostek do chodzenia, a które nie. Jak pewnego razu zorientował się Basssiiie, jedna z tablic danych, która wydawała byc się stosunkowo prosta, okazała się być złożeniem ośmiu osobnych tablic (bajt ma osiem bitów - w dużym skrócie z tego to wynika), co praktycznie podwoiło nam liczbę problemów. Trzy z tych tablicy opisywały ww. dostępność krawędzi. Krawedź zdawała się być blokowana jeżeli była ona zbyt stroma lub gdy jeden z jej końców zamiast znajdować się na lądzie znajdował się w wodzie lub próżni. Stromość nie była tu problemem, choć wpadnięcie na pomysł że różnica wysokości może tu grać rolę to w pełności zasługa Basssiiie'go. Apogeum pojawiło się gdy warunek badający czy krawędź jest na lądzie nie zgadzał się nam z istniejącymi mapami. Frustracja moja osiągnęła wówczas swój szczyt, rozwiązanie tego problemu zajęło nam dwa lub trzy miesiące, a sama solucja była jak typowe bugi programistyczne których nikt nie widzi dopóki nie wpadnie na odpowiedni pomysł zastanawiając się po całej sytuacji jak mogło się tego nie widzieć od samego poczatku.
Drogi czytelniku, spróbuj wyobrazić sobie trójkątną siatkę terenu 2D - niektóre trójkąty to ląd, niektóre to woda. Wyobraź sobie że przez mapę taką płynie idealnie prosta rzeka o szerokości jednego trójkąta. Czy krawędzie ją przecinające są dostępne do chodzenia? No, gra mówi jasno że nie, nie możemy chodzić po wodzie niczym Jezus. A nasz program? Cóż, wierzchołek po lewej: dotyka lądu - jest git!, wierzchołek po prawej - dotyka lądu - jest git!, zatem da się przejść! Mam nadzieję że dostrzegacie komizm całej tej sytuacji. Dwa miesiące nam zajęło, że to czy krawędź jest w wodzie czy na lądzie nijak nie zależy od tego czy końce jego wierzchołków są lądem czy wodą. Brzmi to może abstrakcyjnie, ale zachęcam was żebyście podjeli wysiłek intelektualny przedstawienia sobie całej tej sytuacji w sposób geometyczny, wtedy jasno widać w jak głupi błąd webrneliśmy na aż prawie kwartał.

To tylko dwa fragmenty które zapadły mi najbardziej w pamięć. Problemów na porównywalnym poziomie zaawansowania matematycznego było może z 10-15. Kilka z nich rozwiązałem samodzielnie, kilka z nich samodzielnie rozwiązał Basssiiie, ale zdecydowaną większość rozwiązaliśmy wpółpracując. Warto również dodać że w jednym z takich problemów pomógł nam równiez Tyrannica, który co prawda nie dokonał programistycznych przełomów, ale zwizualizował nam dane o sektorach wykorzystywanych przez pathfinder, co pozwoliło nam od innej strony spojrzeć na jeden z zastałych problemów.

Ciekawą obserwacją na którą natknęliśmy się w trakcie całego tego projektu - o której uważam, że również warto wspomnieć - jest to że twórcy gry w trakcie tworzenia map zdecydowali się zmienić hitboxy niektórych elementów otoczenia. W Zemście Boga Deszczu posiadają one konsekwentnie taki kształt jaki jest zadeklarowany jest w plikach gry, natomiast w starszej odsłonie, tj. w Odkryciach Vinalndii, często kształty hitboxów z plików oraz z map się nie zgadzają. Czy daje to nam wgląd do procesu developerskiego? Czy możemy na podstawie tego wydedukować jak twórcy tworzyli mapy? Poniekąd tak, nie mniej są ty tylko ciekawostki i domniemania, nic praktycznego z tego nie wynika poza spekulacją że być może istnieje starsza zaginiona wersja Culturesa 1, która ma w plikach zadeklarowane stare kształty hitboxów.

Ostatnie z tych zagadnień, które dotyczyły algorytmów, rozwiązaliśmy dopiero pod koniec listopada. Pomijając czas sesji akademickiej i częściowo wakacji kiedy się wyłączyłem z projektu, można powiedzieć że było to bite pół roku pracy. Drodzy entuzjaści remake Culturesa, wyobraźcie sobie że samo odczytanie plików map (do zorganizowanej struktury programistycznej, jeszcze nie do wyświetlania!) to pół roku pracy dwóch osób tylko na to, żeby potencjalnie mieć kompatybilność wsteczną. Teraz wyobraźcie sobie że w plikach Culturesa są jeszcze save'y które są około 10-20 razy bardziej pojemne niż zwykłe pliki map + istnieje cała mechanika gameplay'u. Myślicie że ktoś będzie chciał poświęcić 5-10 lat żeby za darmo zrobić grę ryzykując pozwem o naruszenie praw autorskich? Cytując klasyka: "Nie wiem, choć się domyślam".

Po etapie rozbebeszenia całego formatu i uzyskaniu w Pythonie obiektowej interpretacji struktury binarnej plików *.map pozostał nam jeden rozdział tej wielomiesięcznej przygody - zaprogramowanie wizualiów edytora. Nad tą częścią pracowałem głównie samemu, nie mniej kto wie czy gdyby nie towarzystwo Basssiiie'go to starczyłoby mi motywacji. Jako że miałem już trochę wiedzy z game jamów jak robi się gry, to nie był to aż taki problem, nie mniej pierwszy raz musiałem zaprogramować renderowanie się oteksturowanych trójwymiarowych trójkątów, co dało mi trochę nowej wiedzy z programowania.
Pojawiło się również kilka problemów z plikami *.bmd oraz *.cdf. Te drugie to dość śmieszna historia. Jak zauważył Basssiiie, nie jest to klasyczny format plików który ma usystematyzowaną strukturę. Do plików *.cdf developerzy po prostu surowo wrzucili pre-generowane fragmenty pamięci gry, co wymusiło pisanie indywidualnego algorytmu na odczytanie każdego z tych plików z osobna - tutaj również kieruję dogłębne podziękowania do Basssiiie'go za pomoc.

Mógłbym pisać jeszcze więcej, ale wydaje mi się że tyle informacji starczy jako ogólny opis tego jak wyglądało to nad czym pracowaliśmy: dużo matmy, dużo matmy i jeszcze raz dużo matmy. Tyle matmy chyba wystarczy. ;)

Tak więc w ten sposób widzimy się tutaj - rok po rozpoczęciu projektu - na jego największym kamieniu milowym. Uważam że edytor ten to moje obecne opus magnum programistyczne. Jest to około 8100 linii kodu, to mniej więcej tyle co cztery gry razem wzięte, które od czasu do czasu programuję i wrzucam do neta.
Przypominam że zostały nam jeszcze do ogarnięcia pliki *.cif i *.txt które zawierają tekstowe skrypty do map. Wiem że w naszej społeczności jest sporo osób, które są biegłe w oskryptowywaniu map. Gorąco zachęcam was, żebyście wykorzystali tę wiedzę i spróbowali dołożyć cegiełkę dokumentując co nieco misji, poleceń AI czy innych rzeczy.
Pomimo tego pozostałego zadania chyba póki co - ze względu na życie prywatne - muszę dać sobie na wstrzymanie, jestem przekonany że najtrudniejsze jest już za nami i społeczność nasza ma wiele innych tęgich głów zdolnych do rozwiązania tego problemu. Mimo jego obecności oczywiście da się już w zupełności tworzyć mapy do gry, wiele osób uczyło się mappingu podglądając cudze skrypty w mapach, tak i teraz można zrobić z mapami developerów bez konieczności posiadania jeszcze pełnej dokumentacji co dokładnie za co odpowiada.

Mam nadzieję że narzędzie które skonstruowałem będzie przydatne dla fanów Culturesa 1 :D

Mikulus

Komentarze

#1 | StachuMMV dnia April 02 2025 21:25:45
POTĘŻNE gratulacje dla was i podziwiam waszą cierpliwość

Do cifów bym mógł się w sumie przyłączyć, niemniej zobaczę jak z czasem.

Dodaj komentarz

Zaloguj się, aby móc dodać komentarz.

Oceny

Tylko zarejestrowani użytkownicy mogą oceniać zawartość strony
Zaloguj się , żeby móc zagłosować.

Świetne! Świetne! 100% [1 głos]
Bardzo dobre Bardzo dobre 0% [0 głosów]
Dobre Dobre 0% [0 głosów]
Średnie Średnie 0% [0 głosów]
Słabe Słabe 0% [0 głosów]