Cílem projektu Massiv bylo naprogramovat distribuovaný systém založený na architektuře klient-server, který by umožňoval herním vývojářům vytvářet tzv. "online (internetové) hry".
Společným znakem takovýchto her (označovaných jako MMO - massively multiplayer online hry) je perzistentní svět, ve kterém se pohybuje větší množství aktivně připojených hráčů, jejichž počet může jít řádově do tisíců. Svět je simulován 24 hodin denně na jednom nebo více serverech, hráči se k nim mohou kdykoliv připojit. Po odpojení hráče se jeho postava většinou dění ve světě neúčastní, ale zachovává si svoje vlastnosti a majetek.
Massiv systém poskytuje programové prostředky pro vytváření MMO her a objektový model pro distribuovanou simulaci odpovídajících světů.
MMO hry zažívají v posledních letech velký rozmach a objevuje se mnoho nových online her. Vývoj MMO hry je však velice náročný, protože dříve, než je možno vytvářet vlastní hru, je nutno naprogramovat základní jádro systému. Z charakteristik a požadavků MMO her však takový systém musí poskytovat velkou škálu služeb a pokrývat mnoho programových oblastí, a proto je vývoj takového systému náročný jak na vynaložené prostředky, tak na čas. Z těchto důvodů je vývoj MMO her velice složitý pro nezávislé či nevýdělečné vývojové týmy. Našim cílem bylo vytvořit systém pro tvorbu MMO her, který by byl dostupný pro obecnou komunitu vývojářů a byl by dostatečně obecný pro co nejvíce žánrů her.
Od začátku vývoje byl Massiv koncipován jako objektově orientovaný systém. Objekty se jeví jako vhodné řešení dané problematiky a téměř každý programátor je s objektovým přístupem dobře obeznámen.
Zde je uveden základní přehled charakteristik a služeb, které musí takový system splňovat a poskytovat. Jedná se současně o oblasti, které jsou pokryty systémem Massiv:
Velký počet hráčů a obsáhlost simulovaného světa vyžaduje, aby simulace byla distribuována na vícero počítačů (serverů) a aby libovolné objekty mohly v průběhu své existence mezi servery migrovat. K tomu je potřeba vytvořit vhodné prostředky pro komunikaci mezi objekty.
Jelikož k systému je možno se připojit z celého internetu, je nutno co nejlépe zabezpečit komunikaci mezi hráči a servery a také zabránit možným útokům ze strany klientů. Bezpečnost také zahrnuje vytvoření takových komunikačních protokolů, aby hráči nemohli (i nechtěně) povolenými akcemi narušit běh simulace či využít zjištěných informací ke svému obohacení (v rámci hry).
Hráči musí být schopni interagovat se světem v reálném čase.
Systém musí umět co nejrychleji prezentovat změny a akce v simulovaném světě tak, aby hráči měli co nejaktuálnější přehled o stavu simulace. Je nutno také oddělit prezentační data (data, která posílají servery hráčům) od vlastních simulačních dat nejen z důvodu co nejmenšího toku dat mezi servery a klientem, ale také z důvodu bezpečnosti (aby hráči nemohli z příchozích dat získávat informace o vnitřních pochodech probíhajících v simulaci).
Jelikož simulovaný svět běží 24 hodin denně, musí systém v jémkoli okamžiku umět vytvořit zálohu celé simulace tak, aby bylo možné obnovit stav simulace v případě pádu některého ze serverů či úmyslného zastavení z důvodu údržby. V ideálním případě by zálohování (archivace) světa měla být neviditelná z hlediska hráče.
S postupem času, kdy se vyvíjí a upravuje MMO hra, se samozřejmě mění již existující a přibývají nová data (grafika, textury, modely postav, ...), která je potřeba nějakým způsobem distribuovat hráčům tak, aby mohli klienti, přes které se hráči připojují, správně prezentovat stav simulace. To vyžaduje vytvořit sofistikovaný systém na správu a distribuci herních dat a to nejlépe tak, aby se klienti mohli připojit k simulaci s minimálním množstvím dat (bez nutnosti stahovat stovky megabytů) a další potřebná data stahovat až za běhu dle potřeby.
Je potřeba synchronizovat simulační čas jak mezi servery navzájem tak mezi servery a klienty.
Pro rovnoměrné zatížení serverů je potřeba vytvořit prostředky pro monitorování jejich zatížení a možnost automatického přesouvání určitých částí simulovaného světa na méně zatížené servery.
V oblasti MMO her je velice častá situace, kdy nezávislí vývojáři spravují určitou hru jen pro vlastní zábavu a tudíž bez jakýchkoli finančních prostředků. Pro takovéto vývojáře samozřejmě kompletní vývoj MMO hry pro svou složitost nepřipadá úvahu a proto většinou upravují již existující MMO hry. Projektem Massiv jsme se snažili poskytnout těmto vývojářům systém, který by splňoval výše uvedené požadavky.
Při navrhování Massivu jsme se zaměřili převážně na takovouto cílovou skupinu nezávislých vývojářů s vědomím, že pokud nějaká firma bude vytvářet MMO hru, dá spíše přednost vývoji vlastního systému, který si sama zaplatí, např. proto, aby měla nad výsledkem větší kontrolu.
Jelikož nezávislí vývojáři většinou nemají možnost provozovat simulaci světa na množině serverů běžících v privátní lokální síti, která by byla oddělena od internetu a umožňovala připojení k serverům jako k celku, rozhodli jsme se, že budeme přepokládat, že simulace poběží na serverech, které budou rozmístěny v různých částech internetu. To vyžadovalo rozšíření o níže uvedené požadavky na servery a tyto požadavky jsou současně jednou z hlavních oblastí, ve které se Massiv liší od jiných podobných systémů:
Je nutno zabezpečit komunikaci nejenom mezi servery a klienty, ale také komunikaci mezi servery navzájem.
Je nutno počítat s nezanedbatelným zpožděním na komunikačních kanálech mezi samotnými servery. Tento požadavek ovlivnil velkou řadu rozhodnutí týkajících se návrhu celého systému, především způsobů komunikace objektů mezi sebou.
Asi nejdůležitějším důsledkem je to, že se Massiv nesnaží za každou cenu distribuovanost před programátorem skrývat. Naopak, k optimálnímu využití systému Massiv by programátor měl plně využít ty vlastnosti Massivu, které mu umožňují provádět operace lokálně s minimální režií v porovnáním s běžnou aplikací běžící na jednom počítači. Mezi takové vlastnosti Massivu patří replikace (možnost pracovat s read-only kopiemi nelokálních objektů) a migrační resp. replikační skupiny (pomocí speciálních atributů ukazatelů lze zajistit, že odkazovaný objekt bude vždy lokální a lze s ním pracovat přímo).
Massiv lze rozdělit na dvě hlavní části, které získá vývojář, pokud se rozhodne tento systém využít:
První a hlavní část Massivu tvoří jádro celého systému, jehož funkčnost pokrývá všechny (výše zmíněné) oblasti potřebné k vytvoření vlastní MMO hry. Hlavní část jádra Massivu tvoří distribuovaný objektový systém, ve kterém se píše vlastní logika hry. Dále jádro obsahuje komponenty pro dynamické stahování herních dat, synchronizaci času, pomocné utility pro správu dat nebo konfiguraci jednotlivých serverů a mnoho dalšího.
Druhou částí Massivu je demo. Jedná se o ukázkovou distribuovanou aplikaci vytvořenou nad jádrem Massivu. Demo využívá všechny prostředky, které jádro Massivu poskytuje, a pomocí nich implementuje a ukazuje řešení základních situací a problémů, které musí vývojář při psaní distribuované hry řešit. Hlavním účelem dema je poskytnout potencionálním vývojářům základní odrazový můstek, kde mohou začít s vývojem vlastní hry a prezentovat všechny jádrem nabízené funkce a možnosti, jak je využít ve svůj prospěch.
V této kapitole je uvedeno, jak se vyvíjel návrh hlavních oblastí pokrytých jádrem Massivu, jak se měnil v průběhu projektu a případně proč bylo nutné provést některé změny od původní specifikace.
Distribuovaný objektový systém, ve kterém se provádí vlastní simulace světa, je vybudován nad C++. Jádro Massivu poskytuje základní hiearchii tříd a prostředky pro popis vlastních objektů tak, aby jádro rozumělo struktuře všech simulovaných objektů a mohlo je bez jejich vědomí přesunovat ze serveru na server či je automaticky zálohovat.
Při návrhu objektového modelu byly tři možnosti:
Vlastní jazyk jsme zavrhli okamžitě, protože implementace skriptovacího jazyka by sama o sobě vydala na samostatný projekt a nebylo by v našich silách něco takového zvládnout. Zvoleno bylo C++ jednak z důvodu efektivity generovaného kódu a také proto, že jsme se obávali, že modifikace některého z existujících skriptovacích jazyků tak, aby vyhoval distribuovanému charakteru Massivu, by byla příliš složitá a nedaly se odhadnout možné komplikace. Nevýhodou C++ se ukázala být doba kompilace a linkování, což však u takto velkých projektů není nic neočekávaného. Dalším problémem, na který jsme naráželi v průběhu vývoje, byla nedostatečná podpora C++ standardu, rozdílnost a nekompatibilita kompilátorů (především gcc 2.9* a msvc 6.0). Výhodou C++ je naopak to, že umožňuje jednoduše napojit objektový systém Massivu na jiné C++ knihovny.
Původní idea byla, aby každý simulační server udržoval konzistenci objektů jen na lokální úrovni. Tedy aby si každý server zálohoval svou část simulace relativně nezávisle na ostatních serverech a také se moc nestaral o případné pády jiných serverů. Část světa simulovaná neběžícími (spadlými) servery by prostě byla nedostupná, dokud adminstrátoři problém neodstraní. Kdykoliv by bylo možno spustit nový server z lokální zálohy (případně ze zálohy nadobro spadlého serveru) a připojit ho k již běžící simulaci.
Takové řešení by bylo vhodné, kdyby byl každý server zodpovědný za simulaci relativně nezávislé části světa. Komunikace mezi objekty z dvou různých částí a migrace objektů mezi částmi by byla velmi omezená. O rozdělení světa na nezávilé časti a distribuci těchto částí mezi servery by se starali designeři a administrátoři vlastní hry. Rozdistribuovanost objektů mezi servery by pak byla dána jejich geografickou pozicí.
Tento model jsem zavrhli, protože se nám zdál příliš omezující. Vlastní hra by musela být navržena tak, aby nevadilo, když jsou některé části světa nedostupné nebo když se stav některých častí světa změní "do minulosti", k čemuž dojde při každém načtení světa ze zálohy. Dle našeho názoru by se nejednalo o dostatečně obecný a "plnohodnotný" distribuovaný objektový systém.
Námi zvolený model dovoluje libovolným objektům volně migrovat mezi servery, a to jak "z vlastní vůle" (tak je například implementováno základní posílání asynchronních zpráv), tak automaticky systémem (vyvažování zátěže). Po analýze možných nekonzistencí vzniklých v důsledku pouštění serverů z nezávislých lokálních záloh se ukázalo, že by výsledný systém byl téměř nepoužitelný. Řešení potencionálních problémů by bylo příliš náročné a v mnoha případech dokonce nemožné.
Proto jsme se rozhodli zaručovat úplnou konzistenci simulovaného světa. To mimo jiné znamená, že archivace simulace probíhá koordinovaně na všech serverech a takto vytvořená záloha obsahuje konzistentní obraz celé simulace v době, kdy byla archivace započata. Nepříjemným důsledkem tohoto rozhodnutí je, že simulace nyní nemůže běžet, dokud nejsou nastartovány všechny servery a zastavení jednoho ze serverů vyžaduje zastavení celé simulace a opětovné spuštění z poslední zálohy. Abychom kompenzovali tuto nevýhodu, rozhodli jsme se naimplementovat archivaci tak, aby mohla probíhat souběžně se simulací. Díky tomu je archivace pro hráče nepostřehnutelná a lze ji provádět dostatečně často, čímž se minimalizuje dopad na hráče při případném pádu jednoho ze serverů. V tomto se Massiv rozchází s původní představou popsanou ve specifikaci projektu.
Prvotním problémem při návrhu Massivu bylo vymyslet způsob, jakým budou objekty v distribuované simulaci navzájem komunikovat. Vlastnosti komunikace však nesměly jít proti základním předpokladům o systému (interaktivnost, latence) a také bylo potřeba, aby s jejích pomocí šly řešit standardní situace v MMO hrách (komunikace hráčů se světem, předměty apod.). Vlastně se jednalo o poměrně klasický problém synchronizace mezi vzdálenými procesy s požadavky na interaktivnost, latence, archivaci apod.
Hned v počátečních fázích projektu jsem zavrhli synchronní RPC jako základní komunikační prostředek. Důvodů bylo hned několik - při velkých latencích se nám RPC zdálo jako neefektivní řešení, nechtěli jsem se pouštět do multithreadingu vlastní simulace, zamykání objektů a řešení problémů s tím spojených. Po promyšlení základních modelových situací se ukázalo, že takovýto model není ani úpně ideální a příliš moc pohodlí by programátorům nad systémem nepřinesl.
Při probírání výhod a nevýhod různých způsobů komunikace (mj. asynchronního RPC) jsme došli k následujícímu závěru: Pokud již máme objekty, které mohou migrovat mezi servery, a pokud dva objekty na jednom serveru mohou spolu komunikovat přímo prostředky zvoleného skriptovacího jazyka (v konečné implementaci pomocí volání metod v C++), proč vytvářet nějaký extra model pro jejich komunikaci? Tak vznikl základní komunikační model, který nerozlišuje mezi zprávou a objektem. Migrace objektů není adresována servery, ale identifikací jiných objektů. Po úspěšném doručení objektu systém zaručuje, že adresát migrace je lokální objekt a je ponecháno na migrujícím objektu, co pak provede, případně jak zareaguje v případě, když se jej doručit nepodaří (adresát migrace neexistuje).
Doručování objektů vyžadovalo implementaci protokolů na vyhledávání objektů v distribuované simulaci. Díky tomu, že adresát může sám také libovolně migrovat, není implementace těchto protokolů úplně triviální záležitostí. Používá se kombinace lokalizační cache (servery si pamatují, kde jsou objekty, se kterými se poslední dobou komunikovalo), sledování některých objektů servery, které tyto objekty vytvořily, a globálního hledání objektů.
V průběhu vývoje Massivu se ukázalo, že většina námi naimplementovaných objektů-zpráv má sémantiku asynchronního RPC. Proto byla podpora asynchronního RPC naimplementována přímo do systému. Později bylo základní RPC z různých důvodů postupně rozšiřováno a v současné verzi podporuje Massiv pestrou škálu možností komunikace mezi objekty: vyvolání asynchronního RPC lze načasovat na konkrétní dobu, lze sledovat průběh asynchronního RPC a zjistit jeho výsledek a nakonec přibyla i implementace synchronního RPC (a kooperativního multithreadingu - existuje více vláken, ale vždy běží jen jedno, ostatní čekají na dokončení volání) včetně podpory vyjímek. Nic z toho nebylo původně plánováno.
Aby jádro Massivu bylo schopno provádět automaticky migrace, archivace a replikace C++ objektů, potřebuje o každém objektu znát informace, které nejsou dostupné běžnými prostředky samotného jazyka. Původně jsme mysleli, že bude stačit, když programátor pro každou třídu napíše triviální strukturu, obsahující odkazy na data třídy (pravděpodobně něco jako pole member pointerů) a odkazy na obdobné struktury popisující předky třídy. Později požadavky na obsah těchto struktur vzrostly, a proto vznikl jednoduchý skript, generující vše potřebné pro práci s objekty Massivu z krátkých komentářů vepisovaných přímo do definice třídy v C++. Tak vznikl základ IDL (Interface Definition Language). Označení IDL zůstalo dodnes, i když přesnější by bylo něco jako ODL (Object Description Language).
Postupem času se IDL značně rošířilo a dnes se IDL popis tříd píše do vlastních souborů. IDL má podobnou syntax jako definice tříd C++, včetně namespaces apod. Popisuje dědičnost tříd (Massiv se dokáže vypořádat se složitými hierarchiemi včetně násobné virtuální dědičnosti), data tříd a metody, které lze volat pomocí RPC. Pro data, metody a samotné třídy lze specifikovat mnoho různých atributů, které určují jejich chování v systému.
Stále se ale jedná o popis tříd napsaných v C++, na rozdíl např. od Corby se z IDL negenerují třídy, ze kterých by programátor dědil a implementoval jejich metody. Massiv IDL kompilátor vytvoří z IDL souborů speciální třídy, které poskytují základní prostředky pro práci s instancemi jednotlivých objektů, jako je textová a binární serializace objektů, jejich automatické vytváření při migracích apod. Tyto třídy také poskytují introspekci objektů. Všechny informace vyextrahované z IDL jsou za běhu plně k dispozici. Díky tomu lze v Demu s objekty pracovat přímo z konzole, mimo jiné lze čist a měnit data objektů a volat pomocí RPC jejich metody.
Základní síťová vrstva příliš nerozlišuje jednotlivé druhy procesů zapojených do simulace, ať už se jedná o simulační servery, datové servery či klienty. Pro komunikaci se používají protokoly TCP a UDP (UDP především pro replikaci). Každý proces se při spojování musí autentifikovat pomocí RSA klíčů, vlastní komunikace je pak kódována symetrickou šifrou (blowfish).
Massiv rozlišuje několik druhů procesů, tzv. "nodů", které se mohou do simulace zapojit:
Servery tvoří základ celého systému. Každý server simuluje určitou část simulace, provádí archivace a stará se o replikace objektů.
Klienti jsou aplikace, pomocí nichž se mohou uživatelé připojovat do běžící simulace.
Tyto nody poskytují automatické stahování dat statické povahy, která jsou potřebná pro vlastní běh simulace a pro její vizualizaci na klientech. Datové servery se neúčastní vlastní simulace. Více viz. oddíl Data Manager.
V původní specifikaci jsme uvažovali několik dalších typů serverů. Jejich existence se ale nakonec ukázala jako neopodstatněná. Konkrétně se jedná o:
Účet každého hráče je reprezentován objektem a je archivován jako každý jiný objekt. Díky tomu, že se archivace provádí často a archiv je globálně konzistentní, není nutné účty spravovat a zálohovat speciálním způsobem. Zároveň díky efektivnímu swapování objektů na disk nehrozí, že by nepoužívané účty zbytečně zatěžovaly systém. S účty dále souvisí databáze nodů. Každý klient připojený do simulace je node a servery potřebují znát mj. veřejné klíče všech klientských nodů. Databáze všech nodů je implementována jako datový objekt spravovaný data managerem. Způsob, jakým se archivují zálohy simulačních serverů a datové objekty (vše běžné soubory), zavisí na administrátorech konkrétní hry.
Tento server měl zastávat různé funkce globálního rázu. V simulaci byla jeho funkce nahrazena speciálními objekty, které jsou dostupné přes naming service objekt, který pro danou hru existuje v jediné instanci po celou dobu trvání světa. Ostatní globální data (jako je databáze simulačních serverů) jsou spravována a distribuovávána datovými servery.
Servery tohoto typu jsou běžné u komerčních MMORPG. Slouží jako brána mezi klienty a servery simulujícími vlastní svět, tj. něco jako firewally. Protože Massiv počítá s tím, že simulační servery mohou být volně roztroušeny po světě, způsobovaly by takovéto brány pouze zbytečné zpoždění komunikace. Klienti v Massivu komunikují se simulačními servery přímo a při každém navázání spojení se musejí autentifikovat. Možnosti komunikace směrem od klientů k serverům jsou přesně specifikovány a při libovolném porušení pravidel je klient od simulace odpojen.
Tyto servery byly navrženy z toho důvodu, že základní zálohovaní objektů mělo být prováděno pouze lokálně. Ve výsledku tomu tak není.
Cílem replikace je udržovat na určitých nodech co nejaktuálnější kopie objektů určené výhradně pro čtení. Replikace byla navržena jako základní metoda přenášení prezentačních informací ze serverů na klienty a pro optimalizace čtení dat vzdálených (nelokálních) objektů na simulačních serverech.
Při implementaci replikace se vyskytla řada problémů, spojených především se snahou posílat co nejméně dat a přitom se vypořádat se situacemi, kdy objekty vznikají, zanikají, migrují mezi servery, spojují se do replikačních skupin a opět se rozpojují (replikační skupina je množina objektů, které se vždy replikují dohromady, a je určována speciálními vlastnostmi ukazatelů mezi objekty). Funkcionalitu replikací se nakonec podařilo naimplementovat podle původních představ.
Při vývoji MMO hry je jedním z problémů distribuce dat, jako jsou textury, 3D modely a podobně, zvláště mají-li se v průběhu existence herního světa objevovat data nová. Je potřeba nejenom dodat všechna data klientům tak, aby se mohli připojit, ale je také potřeba vytvořit systém, který by jednoduše umožňoval při změně dat tuto změnu propagovat na klienty. Standardní řešení této situace bývá to, že klient při každém spuštění stáhne nejaktuálnější data a teprvé poté se může připojit do vlastní simulace. V Massivu jsme se snažili o to, aby k připojení do simulace bylo potřeba pouze minimální množství dat a aby se aktuální data stahovala ke klientům až za běhu podle potřeby. Díky tomu se klienti s pomalým připojením k internetu mohou připojit k simulaci bez toho, aby museli dlouho a nákladně stahovat obrovské objemy dat.
Z důvodů efektivity není vhodné reprezentovat tato data jako objekty Massivu a používat například replikaci k jejich zasílání na klienty. To má smysl pouze u objektů, které se mohou často měnit.
O práci s datovými objekty se stará data manager, který je součástí jádra Massivu. Aby se klient mohl připojit k simulaci s neúplnou množinou dat, organizuje data manager všechna data do hiearchické struktury. V této struktuře má každý datový objekt svého předka, který jej může zastupovat, pokud klient nemá aktuální stav daného datového objektu. Díky tomu se klient může připojit k simulaci už v době, kdy vlastní pouze kořenové datové objekty z této hiearchie. Pokud klient potřebuje např. vykreslit nějaký model postavičky na obrazovku, ale nemá odpovídající datový model, použije na vykreslení nejbližšího předka tohoto datového objektu a současně začne stahovat aktuální verzi. Jakmile je nová verze k dispozici, klient použije novější verzi objektu.
Všechna data jsou poskytována datovými servery (též označovanými jako data service). Service node je proces, ke kterému se může připojit klient či server a může si od něj stáhnout libovolná data, která potřebuje. Administrátor mění data na master service nodu, který udržuje zmíněnou hiearchii datových objektů, která je následně využívána data managery klientů a serverů. Administrátor může měnit data za běhu simulace bez toho, aby se museli klienti znovu připojit či aby bylo nutno restartovat servery.
Z historických důvodů je kód, který naprogramuje programátor vytvářející nějakou hru nad Massivem, označován jako "lib" (od anglického library). V průběhu vývoje došlo k rozdělení objektů libu na dvě části. Client lib zahrnuje objekty, které klient potřebuje znát pro komunikaci se servery a pro prezentaci světa. Server lib zahrnuje všechny ostatní objekty, o kterých klientí node nic neví. Hlavním důvodem bylo, aby celá logika mohla zůstat skryta před klienty, a to jednak z důvodu bezpečnosti a také proto, aby server lib nemusel být distribuován ke všem klientům. Zatímco se server lib může změnit, klient se o tom nemusí vůbec dozvědět.
Demo je ukázková aplikace vytvořená nad jádrem Massivu. Demo využívá všechny prostředky, které jádro Massivu poskytuje, a pomocí nich implementuje a ukazuje řešení základních situací a problémů, které musí vývojář při psaní distribuované hry řešit. Hlavním účelem dema je poskytnout potencionálním vývojářům základní odrazový můstek, kde mohou začít s vývojem vlastní hry, a prezentovat všechny jádrem nabízené funkce a možnosti, jak je využít ve svůj prospěch.
Původní idea byla, že demo bude malá a jednoduchá ukázková RPG hra. Tato idea se ale ukázala hodně nadsazená. Ať je hra jednoduchá či složitá, množství věcí, které se musí naprogramovat, je velmi velké, a zvláště v případě, když se jedná o distribuovanou hru. Původní cíl, tedy napsat základ konkrétní hry ve stylu RPG, ve kterém by případně šlo po dokončení projektu pokračovat a vytvořit z něj hru se vším všudy, jsme brzy opustili.
Při psaní dema jsme se proto soustředili na dvě věci: Naimplementovat ty části MMO systému, které se pravděpodobně objeví v každé hře tohoto typu a nad tím vystavět jednoduchou pseudohru. S postupem prací vznikla z dema určitá ukázková aplikace, takový balík poznatků, principů a řešení problémů, které se pravděpodobně objeví, pokud by se někdo pokoušel vytvořit vlastní MMO hru; nikoliv hra samotná. Ač se jádro Massivu pokouší maximálně zjednodušit práci v distribuovaném prostředím, přeci jen je některé věci nutno řešit trochu jinak, než by se řešily v nedistribuovanén případě.
Všeobecně použitelná část dema mj. zahrnuje:
Speciální druh objektů, které existují vždy v právě jedné instanci na každém node (simulačním serveru nebo klientu). Slouží k přímé komunikaci s nody, především pak s klienty, jejichž objekty nejsou přímo adresovatelné.
Pro každý klientský node existuje právě jeden objekt vlastněný nějakým simulačním serverem, reprezentující hráčův účet. Klientský node smí komunikovat pouze se svým účtem a výhradně přes něj ovlivňuje dění ve světě. Pomocí klienta lze v demu automaticky vytvářet nové účty bez nutnosti zásahu administrátora.
Demo poskytuje hráčům konzoli, pomocí níž lze monitorovat a měnit dění ve světě. Většina kódu konzole není vázána na vlastní "hru" a lze bez větších změn použít v libovolném systému založeném na Massivu.
Demo rozlišuje dvě skupiny klientů. Některé operace, jako je přímá práce s objekty vlastněnými simulačními servery nebo editace terénů a entit, jsou povoleny pouze privilegovaným klientům.
Jsou k dispozici tradiční kontejnerové struktury, které neposkytuje přímo jádro Massivu, naimplementované pomocí objektů Massivu, jako spojový seznam a hashovací tabulka.
Ukázková hra implementuje:
Terén představuje povrch imaginární krajiny, po které se hráči a ostatní objekty pohybují. Terén je rozdělen na sektory, které tvoří základní migrační jednotku světa v demu - sektor a všechny související datové struktury včetně entit nacházejících se v něm jsou vždy vlastněné jedním serverem. Operace v rámci sektoru jsou tedy vždy lokální a velmi rychlé, stějně tak čtení dat ze sousedních sektorů (jejichž repliky jsou většinou k dispozici). Každý sektor je implementován jako objekt, který mimo jiné zahrnuje výškovou mapu. To znamená, že lze za běhu modifikovat výšku a druh povrchu terénu a klienti všechny provedené změny okamžitě díky replikaci objektů uvidí.
Objekty pohybující se po terénu, včetně postav hráčů, jsou označovány jako "entity". Je naimplementován jednoduchý kolizní systém mezi entitami a základní umělá inteligence samostatných entit. Mimo jiné slouží entity jako pěkná ukázka plánování událostí do budoucnosti pomocí asynchronního RPC.
Demo ukazuje, jak implementovat jednoduchý inventorář, který může obsahovat různé předměty. Předměty lze používat (např. vypít obsah lahvičky) či nasazovat (obléci boty postavičce).
Demo ukázkovým způsobem používá replikaci pro přenos stavu terénů a entit na připojené klienty. Replikuje se pouze ta část světa, která je "vidět" (blízké okolí hráče). Na klienty se přenáší pouze minimum dat nutných k prezentaci, což snižuje zatížení sítě a zabraňuje klientům v podvádění. Replikace se také používá k optimalizaci operací na simulačních serverech, například při hledání cest.
Klient se snaží predikovat pozice všech entit na základě předpokladu, že konají pohyb rovnoměrný přímočarý. Predikce výrazně zlepšuje výsledný dojem, ale není dokonalá a v praxi by asi bylo nutné naimplementovat predikci na základě znalosti logiky pohybu entit.
Pomocí editoru může administrátor přímo na klientu modifikovat výškovou mapu terénu, druh povrchu jednotlivých částí terénu, přidávat entity do simulovaného světa, měnit některé parametry entit a mazat entity.
Dále klient implementuje spoustu věcí, které nedemonstrují vlastní použití Massivu, ale jsou nutné pro jeho funkčnost. Sem patří mimo jiné poměrně mocný renderer používající OpenGL (i když samotná hra moc efektně nevypadá), GUI a podobně. Všechna data klienta (především textury a modely) jsou implementována jako datový objekt spravovaný data managerem. Díky tomu může být klient spuštěn s minimalními základními daty a vše potřebné se za běhu stáhne automaticky.
Jádro massivu lze zkompilovat a provozovat pod systémy Linux a Windows (předpokládají se ovšem alespoň Windows98). Na těchto platformách bylo také otestováno.
Přenos na jiné systémy by neměl být problém, všechny části kódu závislé na operačním systému jsou speciálně odlišeny od ostatního kódu a jejich úprava pro jiný systém, pakliže je možná, by měla být přímočará.
Dále je Massiv konstruován tak, aby jen s minimálními obtížemi mohl být zprovozněn na počítačích typu big endian (zjednodušeně - "nižší" byty vícebytových slov jsou uložena v paměti na vyšších adresách). Bez zásahů do kódu ovšem pravděpodobně na těchto systémech v současnosti fungovat nebude, protože jsme neměli možnost jej na nich testovat. Podporovány jsou tudíž pouze little endian systémy (tj. "nižší" byty vícebytových slov jsou uložena v paměti na nižších adresách), testována však byla pouze platforma x86.
Vlastní demo také funguje jak pod Linuxem tak pod Windows (s omezeními uvedenými výše).
Hardwarové požadavky shrnuje následující přehled:
Minimální hardwarová konfigurace:
Simulační server:
procesor Pentium II, Duron, Athlon nebo jiný kompatibilní procesor (alespoň 400Mhz)
32MB RAM
síťová karta
Klient:
procesor Pentium II, Duron, Athlon nebo jiný kompatibilní procesor (alespoň 400Mhz)
32MB RAM
grafická karta 2MB podporující 16 bitové barvy
síťová karta
Datový server:
procesor Pentium I, Duron, Athlon nebo jiný kompatibilní procesor (alespoň 60Mhz)
32MB RAM
síťová karta
Doporučená hardwarová konfigurace:
Simulační server:
procesor Pentium III, Duron, Athlon nebo jiný kompatibilní procesor (alespoň 1Ghz)
64MB RAM
síťová karta
Klient:
procesor Pentium III, Duron, Athlon nebo jiný kompatibilní procesor (alespoň 1Ghz)
64MB RAM
grafická karta s hardwarovou akcelerací OpenGL
síťová karta
Datový server:
procesor Pentium II, Duron, Athlon nebo jiný kompatibilní procesor (alespoň 300Mhz)
32MB RAM
síťová karta
Abstrakce doručování zpráv.
Objektový model byl navržen tak, aby smazal rozdíl mezi objektem
a zprávou. Jakákoli zpráva je současně také objekt a také jakýkoli
objekt může být poslán jako zpráva k nějakému jinému objektu.
To umožnilo jednotný systém při migracích objektů a doručování
zpráv. Současně se tím zjednodušila archivace simulovaného světa
(zprávy se jako jiné objekty také normálně archivují).
Asynchronní a synchronní RPC.
Původně se předpokládalo, že veškerá komunikace mezi simulovanými objekty
se bude řídit explicitně pomocí doručování jiných objektů, které budou
vytvářeny programátorem.
Do Massivu jsme ale nakonec přidali automatickou podporu pro
asynchronní a dokonce synchronní RPC (vzdálené volání metod).
Jak se ukázalo, byl to krok správným směrem a jednoduchost použití
RPC nakonec způsobilo, že se RPC využívá skoro všude a není nutno
využívat jiných prostředků pro komunikaci. Díky tomu, že je RPC vystavěno nad
migrací objektů, nebylo nutno posílání a archivaci RPC požadavků implementovat
speciálním způsobem.
Plné využití standardu C++.
Velkým přínosem se ukázalo využití prostředků C++, se kterými měli členové týmu
před započetím projektu pouze minimální praktické zkušenosti. Jedná se především
o vyjímky, templates, STL (Standard Template Library) pro základní datové struktury a
využití iostreamů pro vstup a výstup, včetně implementace vlastních tříd kompatibilních
s iostreamy pro práci s archívy. Využití STL knihovny bylo daleko větší, než se původně
předpokládalo.
Využití externích knihoven.
Pro implementaci síťové vrstvy, především šifrování, se jako velmi dobrá ukázala
knihovna CryptoPP. Portabilitě klienta značně pomohlo použití OpenGL pro 3D grafiku
a knihovny SDL.
Jednotná pravidla pro layout zdrojových souborů.
Již od počátku projektu byla stanovena striktní pravidla pro formátování, pojmenovávací
konvence a styl psaní zdrojových souborů, což se ukázalo jako dobré rozhodnutí a
poskytuje celému systému ucelený vzhled.
Doba vývoje.
Dlouhá doba vývoje byla způsobena několika faktory. Hlavním z nich byly
personální problémy s aktivitou některých členů týmu (forma projektu
a vztahy mezi členy týmu v rámci školy neumožňuje efektivní řízení
celého projektu, narozdíl od klasických postupů, které lze aplikovat
na vývoj projektů v rámci nějaké firmy, kde lze definovat vztah
nadřízený/podřízený a jsou k dispozici prostředky na ohodnocení
výkonů podle splnění či nesplnění zadaných úkolů). Dalším důvodem
pro dlouhou dobu vývoje byla příliš nadsazená a obsáhlá specifikace
projektu, ve které nebyly zohledněny reálné možnosti vývojářského
týmu v daném prostředí.
Nepřesný návrh.
Některé části systému nebyly přesně navrženy již v počátku
projektu. Kvůli tomu jejich implementace způsobila, že se musely
netriviálně upravovat již existující části kódu a změnily
se funkčnosti ostatních částí systému. Jiné části systému
pak byly zbytečně předimenzovány a poskytují více funkčnosti,
než se reálně využívá.
Feature creep.
Přestože specifikace byla již tak dost obsáhlá, nedokázali jsme se ubránit vlastní
megalomanii a výsledný produkt obsahuje spoustu kódu, se kterým se zpočátku vůbec
nepočítalo. Velká část se ukázala pro výsledek jako velmi užitečná (například
synchronní RPC s podporou vyjímek, lokální garbage collector), některé části jsou
ale více-méně zbytečné nebo nevyužité (především části dema psané v době, kdy jsme
z něj ještě chtěli mít pěknou malou zábavnou hru).
Ladění
Ladění distribuovaného systému se ukázalo jako velice náročné.
U takovéhoto systému lze jen ztěží použít klasické debugovací
prostředky poskytované kompilátorem. Proto se velmi často ladění
programu provádělo přes analýzu debugovacích hlášek a výpisů
jednotlivých serverů.
Srovnání Massivu s podobnými systémy nelze jednoduše provést. Hlavním důvodem je skutečnost, že jsme nenalezli žádný veřejně přístupný systém, který by poskytoval takové prostředky a byl podobně zaměřen jako Massiv. Existuje několik distribuovaných MMO her, ale jedná se pouze o komerční projekty a tudíž veškeré informace o tom, jak tyto hry interně fungují a nad jakými systémy byly vybudovány, jsou střeženy jako výrobní tajemství. Mimo tyto hry existuje také mnoho jiných her, které se jako MMO označují, ale jsou navrženy pouze pro jeden server a tedy je nelze s Massiv srovnávat.
Při hledání podobného systému jako je Massiv jsme narazili na systém Nevrax, na kterém lze ukázat rozdílnost přístupu k problematice MMO her. Nevrax je opensource projekt, který se prezentuje jako systém pro vytváření MMO aplikací (her).
Zatímco Massiv se zaměřuje primárně na distribuovaný objektový model, kde jednotlivé objekty mohou mezi servery migrovat, Nevrax nahlíží na distribuovanou simulaci jako skupinu procesů (nazývané služby), které jsou rozmístěny na vícero serverů. Např. můžeme mít proces, který se stará simulaci krajiny, jiný proces, který se stará o pohyb entit po krajině, proces pro synchronizaci času, zálohovací proces, atp. Nevrax s migrací těchto procesů nepočítá, místo toho ale může být funkčnost jedné služby duplikována na více serverech a tím také dochází k rozložení zátěže.
Nevrax poskytuje základní komunikační prostředky pro komunikaci mezi procesy založené na posílání zpráv. Podobně jako Massiv poskytuje pro programátora neviditelné vyhledávání objektů, poskytuje Nevrax základní proces pro vyhledávání běžících služeb (naming service), do které se registrují všechny běžící procesy.
Jak již bylo řečeno, Massiv počítá se servery, které mohou být umístěné v různých sítích. Nevrax je vybudován tak, že všechny servery jsou umístěny v jedné lokální síti.
Nevrax neposkytuje žádné prostředky pro replikaci dat. Tyto služby si musí programátor zařídit sám, buď úpravou existujících služeb nebo vytvořením nové replikační služby.
Nevrax podobně jako Massiv zpřístupňuje mnoho pomocných knihoven jako jsou knihovny pro logování, debugování, podpora vláken, knihovnu pro síťovou komunikaci a přenos dat, protokoly na komunikaci mezi servery a klienty a mnoho dalšího.
Zatímco nelze příliš srovnávat princip objektů v Massivu a princip služeb v Nevraxu, lze srovnat jejich vytváření. V Massivu programátor vytvoří objekty jako běžné C++ objekty a jádru Massivu oznamuje strukturu těchto objektů. V Nevraxu se služby implementují pomocí C++ dědičnosti. Nevrax poskytuje základní rozhraní, které musí každý proces splňovat, a programátor pak implementuje metody tohoto rozhraní.
Viz pozadavky komise: jmenny seznam, rozdeleni prace, dokumentace vyvojova a uzivatelska, specifikace platformy (HW, OS), installer, sources, utilities.