Progettazione e Sviluppo di un Multiplayer Online Game su Reti Peer-to-Peer
Alma Mater Studiorum Universit`a degli Studi di Bologna Facolta` di Scienze Matematiche, Fisiche e Naturali Corso di Laurea in Scienze di Internet Tesi di Laurea in Laboratorio di Programmazione Internet
Alma Mater Studiorum Universit`a degli Studi di Bologna
Facolta` di Scienze Matematiche, Fisiche e Naturali
Corso di Laurea in Scienze di Internet
Tesi di Laurea in Laboratorio di Programmazione Internet
Create successful ePaper yourself
Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.
Alma Mater Stu<strong>di</strong>orum<br />
Università degli Stu<strong>di</strong> <strong>di</strong> Bologna<br />
Facoltà <strong>di</strong> Scienze Matematiche, Fisiche e Naturali<br />
Corso <strong>di</strong> Laurea in Scienze <strong>di</strong> Internet<br />
Tesi <strong>di</strong> Laurea in Labora<strong>to</strong>rio <strong>di</strong> Programmazione Internet<br />
<strong>Progettazione</strong> e <strong>Sviluppo</strong> <strong>di</strong> <strong>un</strong><br />
<strong>Multiplayer</strong> <strong>Online</strong> <strong>Game</strong> <strong>su</strong><br />
<strong>Reti</strong> <strong>Peer</strong>-<strong>to</strong>-<strong>Peer</strong><br />
Can<strong>di</strong>da<strong>to</strong>:<br />
Fabrizio Zagaglia<br />
Rela<strong>to</strong>re:<br />
Chiar.mo Prof. Stefano Ferretti<br />
Anno Accademico 2009/2010 - Sessione III
De<strong>di</strong>co questa tesi alla mia famiglia<br />
i
ii
In<strong>di</strong>ce<br />
Introduzione<br />
v<br />
1 Sta<strong>to</strong> dell’arte 1<br />
1.1 S<strong>to</strong>ria dei MOGs . . . . . . . . . . . . . . . . . . . . . . . . . 1<br />
1.2 Architetture <strong>di</strong>stribuite per il <strong>su</strong>ppor<strong>to</strong> ai MOGs . . . . . . . . 4<br />
1.3 Sincronizzazione Temporale . . . . . . . . . . . . . . . . . . . 7<br />
1.4 Tecnologie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14<br />
2 Architettura Software 17<br />
2.1 Problematiche . . . . . . . . . . . . . . . . . . . . . . . . . . . 17<br />
2.2 Layer NET . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21<br />
2.3 Layer P2P . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24<br />
2.3.1 Modulo Time . . . . . . . . . . . . . . . . . . . . . . . 28<br />
2.4 Modulo SharedComponents . . . . . . . . . . . . . . . . . . . 30<br />
2.5 Layer Logic . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35<br />
2.6 Layer View . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39<br />
2.7 Esempi pratici . . . . . . . . . . . . . . . . . . . . . . . . . . . 43<br />
2.7.1 Movimen<strong>to</strong> <strong>di</strong> oggetti . . . . . . . . . . . . . . . . . . . 44<br />
2.7.2 Collisione tra oggetti . . . . . . . . . . . . . . . . . . . 52<br />
2.7.3 Creazione e <strong>di</strong>struzione <strong>di</strong> oggetti . . . . . . . . . . . . 62<br />
2.7.4 Connessione e Disconnessione dei Player . . . . . . . . 64<br />
3 Implementazione 67<br />
3.1 Introduzione Generale . . . . . . . . . . . . . . . . . . . . . . 67<br />
iii
iv<br />
INDICE<br />
3.2 Layer NET . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69<br />
3.2.1 Commands . . . . . . . . . . . . . . . . . . . . . . . . 74<br />
3.3 Layer P2P . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77<br />
3.3.1 Modulo Time . . . . . . . . . . . . . . . . . . . . . . . 80<br />
3.4 Modulo SharedComponents . . . . . . . . . . . . . . . . . . . 80<br />
3.5 Layer Logic . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84<br />
3.6 Layer View . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87<br />
4 Analisi delle prestazioni 93<br />
5 Sviluppi futuri 99<br />
5.1 Anti-Cheating . . . . . . . . . . . . . . . . . . . . . . . . . . . 99<br />
5.1.1 Time Based Cheating . . . . . . . . . . . . . . . . . . . 104<br />
5.1.2 Space Based Cheating . . . . . . . . . . . . . . . . . . 105<br />
5.2 Ottimizzazione NET Layer . . . . . . . . . . . . . . . . . . . . 110<br />
5.3 Gestione utenti e MatchMaking . . . . . . . . . . . . . . . . . 112<br />
6 Conclusioni 117<br />
Ringraziamenti 125
Introduzione<br />
Astraendo da quelli che sono gli aspetti generali e multi<strong>di</strong>sciplinari che si<br />
possono in<strong>di</strong>viduare nel processo produttivo <strong>di</strong> <strong>un</strong> videogioco (si pensi agli<br />
elementi artistici, dalla grafica alla musica, o alla necessità <strong>di</strong> soli<strong>di</strong> sistemi<br />
economici e <strong>di</strong> marketing), dal p<strong>un</strong><strong>to</strong> <strong>di</strong> vista tecnico, tra le caratteristiche che<br />
contrad<strong>di</strong>stinguono maggiormente <strong>un</strong> software videolu<strong>di</strong>co, vi sono, da <strong>un</strong>a<br />
parte, la necessità <strong>di</strong> <strong>un</strong> feedback pressoché imme<strong>di</strong>a<strong>to</strong> alle azioni eseguite<br />
dal gioca<strong>to</strong>re, e, dall’altra, la forte interazione tra gli elementi che popolano<br />
l’ambiente <strong>di</strong> gioco.<br />
Questi aspetti implicano <strong>un</strong>a serie <strong>di</strong> problematiche che, nell’ambi<strong>to</strong> specifico<br />
dei giochi <strong>Multiplayer</strong> online, vengono in qualche modo amplificate:<br />
<strong>di</strong>ventano quin<strong>di</strong> necessarie soluzioni che, a livello <strong>di</strong> architettura hardware<br />
e software, <strong>di</strong>fferiscono da quelle richieste, ad esempio, da <strong>un</strong> videogioco Singleplayer.<br />
Un primo aspet<strong>to</strong> da analizzare è in<strong>di</strong>vidua<strong>to</strong> dalla scelta dell’architettura<br />
<strong>di</strong> rete, tipicamente tra il modello Client-Server ed il modello <strong>Peer</strong>-To-<strong>Peer</strong>.<br />
Entrambi hanno vantaggi e svantaggi e ri<strong>su</strong>ltano preferibili l’<strong>un</strong>o all’altro a<br />
seconda del contes<strong>to</strong>, <strong>di</strong>sponibilità hardware, tipologia e specifiche <strong>di</strong> gioco.<br />
Un sistema centralizza<strong>to</strong> Client-Server, da <strong>un</strong> la<strong>to</strong> sopperisce al problema<br />
<strong>di</strong> inconsistenza dei dati, dal momen<strong>to</strong> che è il Server stesso a mantenere lo<br />
sta<strong>to</strong> e a processare la logica <strong>di</strong> gioco, ma dall’altro ri<strong>su</strong>lta meno flessibile,<br />
v
vi CAPITOLO 0. INTRODUZIONE<br />
portabile e scalabile. Il Server inoltre rappresenta <strong>un</strong>o SPOF 1 .<br />
Con “consistenza” si intende la necessità <strong>di</strong> avere <strong>un</strong>o sta<strong>to</strong> <strong>di</strong> gioco defini<strong>to</strong><br />
da dati integri e valorizzati allo stesso modo <strong>su</strong> ogni singolo client, dove con<br />
“sta<strong>to</strong> <strong>di</strong> gioco” si intende <strong>un</strong>a rappresentazione, <strong>un</strong>a sorta <strong>di</strong> “istantanea”,<br />
dello sta<strong>to</strong> (posizione, rotazione, azioni, eventi, variabili, etc.) <strong>di</strong> ogni singolo<br />
elemen<strong>to</strong> presente nell’ambiente <strong>di</strong> gioco.<br />
In <strong>un</strong> sistema decentralizza<strong>to</strong> <strong>Peer</strong>-To-<strong>Peer</strong>, ogni nodo è paritetico e può<br />
f<strong>un</strong>gere quin<strong>di</strong> contemporaneamente sia da Client che da Server.<br />
Su ogni <strong>Peer</strong> è presente <strong>un</strong>a copia dello sta<strong>to</strong> <strong>di</strong> gioco, e nel caso <strong>di</strong> sistemi<br />
<strong>Peer</strong>-To-<strong>Peer</strong> “puri”, ogni <strong>Peer</strong> porterà avanti la logica <strong>di</strong> gioco basandosi<br />
<strong>su</strong>l proprio Data Layer, introducendo quin<strong>di</strong> problematiche <strong>di</strong> consistenza e<br />
sincronizzazione temporale.<br />
Senza ness<strong>un</strong> sistema <strong>di</strong> controllo, infatti, ogni <strong>Peer</strong>, specie in quelle situazioni<br />
ed in quegli eventi soggetti a processi alea<strong>to</strong>ri o notevolmente sensibili<br />
alla sincronizzazione temporale, può presentare <strong>un</strong>o sta<strong>to</strong> <strong>di</strong> gioco <strong>di</strong>fferente<br />
rispet<strong>to</strong> agli altri, e tale errore è destina<strong>to</strong> a propagarsi aggiornamen<strong>to</strong> dopo<br />
aggiornamen<strong>to</strong>, portando ad <strong>un</strong>a <strong>di</strong>vergenza dei ri<strong>su</strong>ltati potenzialmente<br />
mol<strong>to</strong> elevata (i.e. in <strong>un</strong> <strong>Peer</strong> la vit<strong>to</strong>ria è assegnata al Player A, mentre in<br />
<strong>un</strong> altro <strong>Peer</strong> la vit<strong>to</strong>ria è assegnata al Player B).<br />
Obiettivi <strong>di</strong> proget<strong>to</strong><br />
In questa tesi <strong>di</strong> proget<strong>to</strong> si é deciso <strong>di</strong> affrontare lo sviluppo <strong>di</strong> <strong>un</strong> videogioco<br />
<strong>Multiplayer</strong> basa<strong>to</strong> <strong>su</strong>ll’architettura <strong>Peer</strong>-<strong>to</strong>-<strong>Peer</strong>. La soluzione adottata,<br />
però, non è riconducibile al modello <strong>Peer</strong>-<strong>to</strong>-<strong>Peer</strong> “Puro”, in quan<strong>to</strong> i no<strong>di</strong><br />
non sono propriamente paritetici: ogni <strong>Peer</strong> infatti, pur conoscendo lo sta<strong>to</strong><br />
<strong>di</strong> gioco globale, ne gestirà <strong>di</strong>rettamente solo <strong>un</strong>a partizione, aggiornando <strong>di</strong><br />
1 Single point of failure, <strong>un</strong> generico elemen<strong>to</strong> il cui malf<strong>un</strong>zionamen<strong>to</strong> compromette<br />
l’intero sistema del quale fa parte.
vii<br />
fat<strong>to</strong> solo gli elementi <strong>di</strong> propria appartenenza.<br />
In ques<strong>to</strong> modo viene contenu<strong>to</strong> l’impat<strong>to</strong> del problema <strong>di</strong> consistenza,<br />
dal momen<strong>to</strong> che, desincronizzazioni temporali a parte, tutti gli stati <strong>di</strong> gioco<br />
convergeranno ad <strong>un</strong>o sta<strong>to</strong> virtualmente con<strong>di</strong>viso com<strong>un</strong>e. Rispet<strong>to</strong> al modello<br />
“Puro”, si è però anche più sensibili a problemi derivanti dal cheating 2<br />
e alla formazione <strong>di</strong> bottleneck at<strong>to</strong>rno all’insieme <strong>di</strong> dati gestiti da <strong>un</strong> <strong>Peer</strong><br />
poco performante. Il che significa l’eventuale implementazione <strong>di</strong> politiche<br />
<strong>di</strong> <strong>di</strong>stribuzione <strong>di</strong> calcolo mirate alla riduzione del contes<strong>to</strong> dei dati che appartengono<br />
ai no<strong>di</strong> computazionalmente più lenti o con maggiore latenza, in<br />
favore <strong>di</strong> quelli più performanti.<br />
Il gioco realizza<strong>to</strong> appartiene alla tipologia degli “Shooter 3D”, e prende<br />
sp<strong>un</strong><strong>to</strong>, sia dal p<strong>un</strong><strong>to</strong> <strong>di</strong> vista delle meccaniche <strong>di</strong> gioco che dal p<strong>un</strong><strong>to</strong> <strong>di</strong> vista<br />
dello stile grafico, da Spectre (si veda il capi<strong>to</strong>lo 1): ogni gioca<strong>to</strong>re controlla<br />
<strong>un</strong> proprio “Tank” ed è chiama<strong>to</strong> <strong>di</strong>struggere i “Tank” nemici controllati<br />
dagli altri gioca<strong>to</strong>ri.<br />
Nel prossimo capi<strong>to</strong>lo verranno introdotti quelli che sono i sistemi, le<br />
architetture e le tecnologie attualmente più utilizzate a seconda dei <strong>di</strong>versi<br />
contesti e delle <strong>di</strong>verse specifiche <strong>di</strong> gioco.<br />
Nei capi<strong>to</strong>li <strong>su</strong>ccessivi, invece, verranno analizzate nel dettaglio le fasi <strong>di</strong><br />
progettazione e le scelte implementative del proget<strong>to</strong> <strong>di</strong> tesi.<br />
2 Un sistema grazie al quale è possibile aggirare le regole <strong>di</strong> gioco traendone vantaggio
viii CAPITOLO 0. INTRODUZIONE<br />
Figura 1: Screenshots
Capi<strong>to</strong>lo 1<br />
Sta<strong>to</strong> dell’arte<br />
1.1 S<strong>to</strong>ria dei MOGs<br />
Il concet<strong>to</strong> <strong>di</strong> videogioco <strong>Multiplayer</strong> (<strong>Multiplayer</strong> <strong>Online</strong> <strong>Game</strong>, MOG)<br />
è muta<strong>to</strong> notevolmente nell’arco della <strong>su</strong>a evoluzione.<br />
Inizialmente era confina<strong>to</strong> ad <strong>un</strong>a rappresentazione testuale <strong>di</strong> wargames 1 ,<br />
gioca<strong>to</strong> via BBS 2 ed organizza<strong>to</strong> e gesti<strong>to</strong> da amministra<strong>to</strong>ri fisici che, manualmente,<br />
calcolavano lo sta<strong>to</strong> <strong>di</strong> gioco ri<strong>su</strong>ltante dalle richieste inoltrate<br />
dai gioca<strong>to</strong>ri, <strong>di</strong>stribuiti <strong>su</strong>l tut<strong>to</strong> il globo, ore o ad<strong>di</strong>rittura giorni prima.<br />
Pres<strong>to</strong> tale processo venne au<strong>to</strong>matizza<strong>to</strong>, dando via alla nascita dei<br />
MUD 3 .<br />
Parallelamente, se si estende il <strong>di</strong>scorso anche ai giochi “vi<strong>su</strong>ali” e realtime<br />
(in contrapposizione a quelli testuali), tale concet<strong>to</strong> è sta<strong>to</strong> dapprima<br />
1 Un gioco accostabile alla categoria dei giochi strategici, le cui regole sono mirate alla<br />
simulazione o alla rappresentazione <strong>di</strong> <strong>un</strong>o scenario <strong>di</strong> guerra, ed il cui scopo è in<strong>di</strong>vidua<strong>to</strong><br />
nella vit<strong>to</strong>ria <strong>di</strong> <strong>un</strong>a battaglia, raggi<strong>un</strong>ta attraverso determinate tattiche e strategie.<br />
2 Bulletin board system, <strong>un</strong> sistema software, utilizza<strong>to</strong> principalmente a cavallo tra gli<br />
anni ’80 e ’90, che permetteva <strong>di</strong> scambiare dati, da semplici messaggi <strong>di</strong> tes<strong>to</strong> ad interi<br />
file, attraverso la linea telefonica.<br />
3 Multi User D<strong>un</strong>geon, giochi <strong>di</strong> ruolo testuali multi-utente<br />
1
2 CAPITOLO 1. STATO DELL’ARTE<br />
confina<strong>to</strong> al singolo device fisico: due o più gioca<strong>to</strong>ri dovevano essere presenti<br />
fisicamente nella stanza per poter controllare il proprio personaggio e ricevere<br />
il feedback visivo e sonoro corrispondente alle proprie azioni. Si pensi<br />
ai Coin-op presenti nelle sale giochi, o allo stesso Pong, (Atari, 1972) che<br />
permetteva a due gioca<strong>to</strong>ri <strong>di</strong> sfidarsi (o cooperare) <strong>di</strong>rettamente <strong>su</strong>llo stesso<br />
device.<br />
La comparsa dei primi giochi <strong>Multiplayer</strong> online e real-time è da ricercare<br />
nell’ambi<strong>to</strong> <strong>un</strong>iversitario: Empire <strong>di</strong> John Daleske e Spasim <strong>di</strong> Jim Bowery<br />
sono tra i primi giochi multi-utente basati <strong>su</strong>l sitema PLATO. Si <strong>su</strong>sseguono,<br />
poi, numerose versioni <strong>di</strong> Empire ambientate nell’<strong>un</strong>iverso <strong>di</strong> Star Trek<br />
(Xtrek, Netrek, Decwars, WinTrek, etc.): queste si basavano <strong>su</strong>lla rappresentazione<br />
dello spazio bi<strong>di</strong>mensionale, in<strong>di</strong>vidua<strong>to</strong> da <strong>un</strong>a griglia nella quale era<br />
possibile spostare in tempo reale la propria nave nelle 8 <strong>di</strong>rezioni <strong>di</strong>sponibili.<br />
Particolarmente significativo dal p<strong>un</strong><strong>to</strong> <strong>di</strong> vista s<strong>to</strong>rico è sta<strong>to</strong> Maze War 4<br />
(1974), videogioco seminale che ha introdot<strong>to</strong> numerose <strong>di</strong>namiche <strong>di</strong> gameplay<br />
<strong>su</strong>ccessivamente riprese e tutt’ora presenti nella maggior parte dei ti<strong>to</strong>li<br />
videolu<strong>di</strong>ci o<strong>di</strong>erni. E’ considera<strong>to</strong> infatti il primo FPS 3D <strong>Multiplayer</strong>.<br />
L’avven<strong>to</strong> del Personal Computer incentivò la richiesta <strong>di</strong> <strong>un</strong> <strong>su</strong>ppor<strong>to</strong> al<br />
“NetPlay”, cioè <strong>un</strong>a modalità alternativa a quella classica Singleplayer, che<br />
consentisse <strong>di</strong> giocare in <strong>Multiplayer</strong> via LAN o Internet. Spectre (1991) per<br />
Apple Macin<strong>to</strong>sh fu tra i primi a dare cre<strong>di</strong><strong>to</strong> a tale richiesta, permettendo<br />
a 8 gioca<strong>to</strong>ri simultanei <strong>di</strong> scontrarsi in <strong>un</strong>’arena tri<strong>di</strong>mensionale vet<strong>to</strong>riale.<br />
Ma il p<strong>un</strong><strong>to</strong> <strong>di</strong> svolta più significativo è probabilmente rappresenta<strong>to</strong> da<br />
DooM (1993) <strong>di</strong> ID Software, che, grazie alla <strong>di</strong>stribuzione capillare <strong>di</strong> <strong>un</strong>a<br />
<strong>su</strong>a versione Shareware, <strong>di</strong>ventò popolare in brevissimo tempo. Concretizza<br />
alc<strong>un</strong>e idee legate al mutiplayer già presenti a livello embrionale in Maze War<br />
4 http://en.wikipe<strong>di</strong>a.org/wiki/Maze War
1.1. STORIA DEI MOGS 3<br />
e le fissa ad <strong>un</strong> nuovo standard qualitativo. Per <strong>di</strong>versi anni a seguire venne<br />
utilizza<strong>to</strong> come termine <strong>di</strong> paragone.<br />
E’ solo verso la fine degli anni ’90, parallelamente alla crescente <strong>di</strong>ffusione<br />
<strong>di</strong> Internet <strong>su</strong> larga scala, che iniziano a definirsi tipologie <strong>di</strong> gioco real-time<br />
esclusivamente orientate al <strong>Multiplayer</strong>: se qualche anno prima ques<strong>to</strong> aspet<strong>to</strong><br />
era spesso e volentieri relega<strong>to</strong> a rare modalità <strong>di</strong> gioco alternative a quella<br />
principale Singleplayer, da qui in poi entra prepotentemente tra le necessità<br />
più sentite dai gioca<strong>to</strong>ri PC, prima, e console poi.<br />
E’ il caso <strong>di</strong> FPS principalmente orientati al <strong>Multiplayer</strong> come Quake 3<br />
Arena (1999) <strong>di</strong> ID Software e Unreal Tournament (1999) <strong>di</strong> Epic <strong>Game</strong>s.<br />
In ques<strong>to</strong> periodo nasce ed inizia a prendere piede anche <strong>un</strong>o dei generi<br />
<strong>di</strong> gioco che ha caratterizza<strong>to</strong>, e monopolizza<strong>to</strong>, l’intero decennio ’00: è con<br />
Ultima <strong>Online</strong> (1997, Origin), infatti, che si inizia a parlare <strong>di</strong><br />
MMORPG 5 , <strong>di</strong> avatar e <strong>di</strong> mon<strong>di</strong> persistenti. L’apice del genere, in termini<br />
<strong>di</strong> popolarità (e quin<strong>di</strong> <strong>di</strong> ricavi economici) è sicuramente in<strong>di</strong>viduabile in<br />
World of Warcraft (2004, Blizzard).<br />
Tornano inoltre in auge tipologie <strong>di</strong> gioco più lente e visivamente astratte,<br />
in qualche modo <strong>di</strong>rettamente derivabili dalle prime forme testuali <strong>di</strong> wargame<br />
multigioca<strong>to</strong>re; videogiochi <strong>di</strong>rettamente giocabili da qualsiasi browser,<br />
che in parte ricalcano gli stilemi proposti dai MMORPG dal p<strong>un</strong><strong>to</strong> <strong>di</strong> vista<br />
delle meccaniche social e ad<strong>di</strong>ctive e che fanno della loro estrema accessibilità<br />
(basse richieste Hardware, ness<strong>un</strong> cos<strong>to</strong> d’ingresso o <strong>di</strong> abbonamen<strong>to</strong>)<br />
<strong>un</strong>o dei maggiori motivi <strong>di</strong> <strong>su</strong>ccesso. Tra questi si possono ricordare Ogame<br />
(<strong>Game</strong>forge, 2002), Travian (Travian <strong>Game</strong>s, 2005) e FarmVille (Zynga,<br />
2009). Quest’ultimo ha raggi<strong>un</strong><strong>to</strong> <strong>un</strong>’elevata popolarità utilizzando sinergica-<br />
5 <strong>Multiplayer</strong> <strong>Online</strong> Role-Playing <strong>Game</strong>, gioco <strong>di</strong> ruolo ambienta<strong>to</strong> <strong>su</strong> <strong>un</strong> mondo<br />
virtuale persistente
4 CAPITOLO 1. STATO DELL’ARTE<br />
mente la base d’utenza <strong>di</strong> Facebook come sistema <strong>di</strong> marketing e <strong>di</strong> <strong>di</strong>ffusione.<br />
1.2 Architetture <strong>di</strong>stribuite per il <strong>su</strong>ppor<strong>to</strong><br />
ai MOGs<br />
Tale eterogeneità non rende possibile l’affermarsi <strong>di</strong> soluzioni generiche<br />
ottimali per ogni tipologia <strong>di</strong> gioco, ogni tipo <strong>di</strong> architettura e <strong>di</strong> tecnologia: i<br />
requisiti ed i sistemi <strong>di</strong> sincronizzazione utilizzati per realizzare <strong>un</strong> RPG playby-post<br />
sono, ad esempio, notevolmente <strong>di</strong>fferenti rispet<strong>to</strong> a quelli utilizzati<br />
invece per sviluppare <strong>un</strong> FPS o <strong>un</strong> MMORPG.<br />
L’architettura Client-Server (Figura 1.1) in ambi<strong>to</strong> videolu<strong>di</strong>co è attualmente<br />
predominante: viene utilizzata in FPS <strong>Multiplayer</strong> come Quake o<br />
Unreal Tournament, o in MMORPG come Ultima <strong>Online</strong> o World of Warcraft.<br />
Nei primi la simulazione e l’aggiornamen<strong>to</strong> dello sta<strong>to</strong> <strong>di</strong> gioco sono<br />
a carico <strong>di</strong> <strong>un</strong> processo fisicamente esterno ai client. Poiché la durata delle<br />
partite <strong>di</strong> <strong>un</strong>o Shooter è piut<strong>to</strong>s<strong>to</strong> bassa (me<strong>di</strong>amente circa <strong>di</strong>eci minuti), e<br />
non è richies<strong>to</strong> ness<strong>un</strong> tipo <strong>di</strong> sistema <strong>di</strong> permanenza dei dati (se non a livello<br />
<strong>di</strong> statistiche esterne), i requisiti per “hostare” <strong>un</strong> server de<strong>di</strong>ca<strong>to</strong> sono tali<br />
da permettere la proliferazione <strong>di</strong> server non ufficiali gestiti <strong>di</strong>rettamente dai<br />
gioca<strong>to</strong>ri, sia in LAN che in Internet [Abrash 1996].<br />
Per quan<strong>to</strong> riguarda invece i generi <strong>di</strong> gioco ambientati in <strong>un</strong> mondo virtuale<br />
persistente, il numero <strong>di</strong> gioca<strong>to</strong>ri e <strong>di</strong> items da gestire a carico <strong>di</strong> ogni singolo<br />
server è notevolmente più al<strong>to</strong>, e dal momen<strong>to</strong> che il concet<strong>to</strong> <strong>di</strong> partita in<strong>di</strong>viduata<br />
da <strong>un</strong> inizio ed <strong>un</strong>a fine è assente, in favore <strong>di</strong> <strong>un</strong>’esperienza <strong>di</strong> gioco<br />
potenzialmente infinita, i requisiti Hardware per aggiornare e mantenere i<br />
dati relativi all’ambiente e alle entità che lo popolano sono tali da rendere<br />
necessaria l’esistenza <strong>di</strong> singoli server <strong>di</strong> gioco “ufficiali”.<br />
L’architettura <strong>Peer</strong>-To-<strong>Peer</strong> (Figura 1.2), anche se utilizzata in <strong>di</strong>versi<br />
ti<strong>to</strong>li, specialmente RTS (Warcraft II (Blizzard, 1995) o Demigod (Gas<br />
Powered <strong>Game</strong>s, 2009)), è invece meno <strong>di</strong>ffusa. Inoltre, mentre il modello
1.2. ARCHITETTURE DISTRIBUITE PER IL SUPPORTO AI<br />
MOGS 5<br />
Figura 1.1: Modello Client-Server: lo sta<strong>to</strong> <strong>di</strong> gioco comple<strong>to</strong> (esagono verde)<br />
è mantenu<strong>to</strong> e aggiorna<strong>to</strong> da <strong>un</strong> singolo Server centralizza<strong>to</strong>. Ogni Client<br />
è connesso esclusivamente al Server e mantiene <strong>un</strong>a propria visione dello<br />
sta<strong>to</strong> <strong>di</strong> gioco, tipicamente incompleta (quadra<strong>to</strong> verde), aggiornata grazie<br />
ai messaggi inviati, au<strong>to</strong>nomamente o come <strong>di</strong>retta conseguenza <strong>di</strong> <strong>un</strong> input<br />
esterno, dal Server (triangolo verde).
6 CAPITOLO 1. STATO DELL’ARTE<br />
Figura 1.2: Modello <strong>Peer</strong>-To-<strong>Peer</strong>: ogni <strong>Peer</strong>, connesso <strong>di</strong>rettamente o in<strong>di</strong>rettamente<br />
a tutti gli altri <strong>Peer</strong>, mantiene e aggiorna <strong>un</strong>a propria visione<br />
dello sta<strong>to</strong> <strong>di</strong> gioco comple<strong>to</strong> (esagono verde), secondo gli eventi ricevuti.
1.3. SINCRONIZZAZIONE TEMPORALE 7<br />
Client-Server segue <strong>un</strong>a serie <strong>di</strong> pattern architetturali ormai consolidati, rintracciabili<br />
nella maggior parte dei ti<strong>to</strong>li <strong>Multiplayer</strong>, ques<strong>to</strong> non accade per<br />
il modello <strong>Peer</strong>-To-<strong>Peer</strong>, che tendenzialmente vede approcci e scelte implementative<br />
<strong>di</strong>fferenti anche in tipologie <strong>di</strong> gioco relativamente simili.<br />
In Age of Empire, gioco strategico <strong>di</strong> Ensemble Stu<strong>di</strong>os (1997), è utilizzata<br />
<strong>un</strong>’architettura <strong>Peer</strong>-To-<strong>Peer</strong> ibrida, caratterizzata da <strong>un</strong> <strong>Peer</strong> appartente<br />
alla Membership, elet<strong>to</strong> “Host” che fa da “<strong>Game</strong> Master” e che si occupa<br />
<strong>di</strong> inizializzare la partita e gestire tutte le situazioni critiche e concorrenziali<br />
[Bettner 2001].<br />
Altri para<strong>di</strong>gmi ibri<strong>di</strong>, basati <strong>su</strong>l concet<strong>to</strong> <strong>di</strong> “regione” o <strong>di</strong> “area <strong>di</strong> interesse”,<br />
sono stati invece proposti per far fronte al problema <strong>di</strong> scalabilità<br />
in<strong>di</strong>vidua<strong>to</strong> nel modello Client-Server per quelle tipologie <strong>di</strong> gioco, come i<br />
MMOG, contrad<strong>di</strong>stinte da <strong>un</strong> eleva<strong>to</strong> numero <strong>di</strong> gioca<strong>to</strong>ri.<br />
Ad esempio in [Rhalibi 2005] viene <strong>di</strong>scussa <strong>un</strong>’architettura nella quale <strong>un</strong><br />
Server centrale controlla <strong>un</strong>a serie <strong>di</strong> “regioni” composte da singole reti <strong>Peer</strong>-<br />
To-<strong>Peer</strong> che fanno capo ad <strong>un</strong> proprio “Supernode”, e <strong>su</strong>d<strong>di</strong>vise in f<strong>un</strong>zione<br />
della loro posizione geografica all’interno dell’ambiente virtuale <strong>di</strong> gioco<br />
(Figura 1.3).<br />
In ultima analisi, i fat<strong>to</strong>ri che influenzano la scelta dell’architettura derivano<br />
da molteplici aspetti, dalla tipologia <strong>di</strong> gioco alla <strong>di</strong>sponibilità hardware.<br />
L’approccio <strong>Peer</strong>-To-<strong>Peer</strong> è tutt’ora meno <strong>di</strong>ffuso e standar<strong>di</strong>zza<strong>to</strong> rispet<strong>to</strong><br />
a quello centralizza<strong>to</strong> Client-Server, e spesso si presenta in veste “ibrida”,<br />
caratterizzata cioè da <strong>un</strong>a gerarchizzazione dei no<strong>di</strong> e dalla formazione <strong>di</strong><br />
“isole” centralizzate. Inoltre a <strong>su</strong>o <strong>su</strong>ppor<strong>to</strong>, tipicamente viene introdot<strong>to</strong> <strong>un</strong><br />
sistema Client-Server apposi<strong>to</strong> per la gestione delle lobby, il player <strong>di</strong>scovery<br />
ed il MatchMaking.<br />
1.3 Sincronizzazione Temporale<br />
In <strong>un</strong>’applicazione <strong>di</strong> rete non è possibile garantire la continua consistenza<br />
dei dati senza che vi sia <strong>un</strong>a qualche forma <strong>di</strong> sincronizzazione temporale:
8 CAPITOLO 1. STATO DELL’ARTE<br />
Figura 1.3: Modello ibrido propos<strong>to</strong> in [Rhalibi 2005] ed in [Luo 2010], e<br />
<strong>di</strong>scusso in [Due Billing 2006]
1.3. SINCRONIZZAZIONE TEMPORALE 9<br />
i dati che in<strong>di</strong>viduano lo sta<strong>to</strong> <strong>di</strong> <strong>un</strong> dominio, sono per definizione mutevoli,<br />
sono cioè destinati a cambiare valore nel corso del tempo.<br />
Senza <strong>un</strong>a corrispondenza tra <strong>un</strong> determina<strong>to</strong> da<strong>to</strong> e l’istante <strong>di</strong> tempo nel<br />
quale quest’ultimo as<strong>su</strong>me <strong>un</strong> determina<strong>to</strong> valore, l’informazione apportata<br />
perde <strong>di</strong> significa<strong>to</strong>.<br />
Nelle applicazioni real-time, tale aspet<strong>to</strong> è destina<strong>to</strong> ad avere <strong>un</strong> impat<strong>to</strong> considerevole,<br />
dal momen<strong>to</strong> che i cambi <strong>di</strong> sta<strong>to</strong> tipicamente avvengono con <strong>un</strong>a<br />
frequenza decisamente alta. Nell’ambi<strong>to</strong> videolu<strong>di</strong>co, inoltre, tra la sincronizzazione<br />
temporale e la sincronizzazione dello sta<strong>to</strong>, si instaura <strong>un</strong>a terza<br />
problematica: Il Cheating (si veda la sezione 5.1).<br />
Una situazione ideale <strong>di</strong> perfetta consistenza, nella quale ogni gioca<strong>to</strong>re vede<br />
esattamente lo stesso sta<strong>to</strong> <strong>di</strong> gioco globale allo stesso preciso istante <strong>di</strong> tempo<br />
assolu<strong>to</strong>, è fisiologicamente impossibile da realizzare causa latenza <strong>di</strong> rete.<br />
Per gestire la problematica <strong>di</strong> sincronizzazione è necessario valutare i termini<br />
<strong>di</strong> <strong>un</strong> compromesso tra la reattività <strong>di</strong> risposta e la consistenza ad <strong>un</strong><br />
determina<strong>to</strong> istante <strong>di</strong> tempo: <strong>un</strong> approccio “conservativo” è implementa<strong>to</strong><br />
in sistemi <strong>di</strong> sincronizzazione “S<strong>to</strong>p-And-Wait”, come il Lock-Step (Figura<br />
1.4) e la Bucket Synchronization (Figura 1.5), ed è caratterizza<strong>to</strong>, da <strong>un</strong>a<br />
parte da <strong>un</strong>a forte consistenza a livello temporale, poiché ogni azione viene<br />
processata solo quando questa è, teoricamente, conosciuta da tutti i <strong>Peer</strong><br />
appartenenti alla Membership, e, dall’altra, come <strong>di</strong>retta conseguenza, da <strong>un</strong><br />
tempo <strong>di</strong> reazione al<strong>to</strong>.<br />
Per ques<strong>to</strong> motivo, ques<strong>to</strong> genere <strong>di</strong> sincronizzazioni vengono utilizzate soprattut<strong>to</strong><br />
in quei giochi, come gli RTS, caratterizzati da <strong>un</strong> <strong>Game</strong>play relativamente<br />
len<strong>to</strong>.<br />
É possibile com<strong>un</strong>que sfruttarle anche in tipologie <strong>di</strong> gioco più “veloci”, attivandole<br />
solo in particolari contesti <strong>di</strong> concorrenza e all’interno della stessa<br />
area <strong>di</strong> interesse (ad esempio nella gestione <strong>di</strong> <strong>un</strong>a collisione tra due oggetti<br />
in avvicinamen<strong>to</strong>).
10 CAPITOLO 1. STATO DELL’ARTE<br />
Un approccio “ottimistico”, implementa<strong>to</strong> ad esempio della Time-Warp<br />
Synchronization, prevede invece <strong>un</strong>’ esecuzione degli eventi imme<strong>di</strong>ata: questi<br />
infatti saranno processati appena gi<strong>un</strong>ti a destinazione. Il vincolo temporale<br />
at<strong>to</strong> a garantire la consistenza, che nell’approccio “conservativo” è realizza<strong>to</strong><br />
me<strong>di</strong>ante fasi ed intervalli <strong>di</strong> tempo “bloccanti”, è qui invece rappresenta<strong>to</strong><br />
dal processo <strong>di</strong> “Roll-back”. Ad ogni even<strong>to</strong> viene infatti assegna<strong>to</strong> <strong>un</strong> Time-<br />
Stamp: quando <strong>un</strong> <strong>Peer</strong> riceve <strong>un</strong> even<strong>to</strong> contrassegna<strong>to</strong> da <strong>un</strong> TimeStamp<br />
meno recente rispet<strong>to</strong> a quello attuale, vengono prima cancellati tutti gli effetti<br />
scaturiti da eventi già processati riportanti <strong>un</strong> TimeStamp più recente,<br />
poi esegui<strong>to</strong> l’even<strong>to</strong> in questione, ed infine ri-processati quest’ultimi. Alc<strong>un</strong>i<br />
eventi possono però essere “correlati” tra loro: l’esistenza -o la non esistenza<strong>di</strong><br />
<strong>un</strong> even<strong>to</strong> “chiave” all’interno <strong>di</strong> <strong>un</strong>a “Correlation chain” può alterare o<br />
compromettere il significa<strong>to</strong> e la vali<strong>di</strong>tà degli eventi ad esso correlati: in<br />
altre parole, compromettere la consistenza dello sta<strong>to</strong> <strong>di</strong> gioco (Figura 1.6).<br />
Ques<strong>to</strong> tipo <strong>di</strong> sincronizzazioni permette <strong>di</strong> avere <strong>un</strong>a maggiore reattività <strong>di</strong><br />
interazione rispet<strong>to</strong> a quelle basate <strong>su</strong>ll’approccio “conservativo”, ma, per<br />
garantire l’esistenza <strong>di</strong> <strong>un</strong>a base dati <strong>su</strong>fficientemente ampia da permettere<br />
il recovery degli stati precedenti in fase <strong>di</strong> rollback, richiede tendenzialmente<br />
<strong>un</strong>a quantità <strong>di</strong> memoria più elevata.<br />
Per limitare ques<strong>to</strong> problema, si può intervenire eliminando gli eventi obsoleti,<br />
cioè quegli eventi, non correlati, ridondanti e sostituibili quin<strong>di</strong> da eventi<br />
più recenti che, partendo dal medesimo sta<strong>to</strong> iniziale, portano al medesimo<br />
sta<strong>to</strong> finale.
1.3. SINCRONIZZAZIONE TEMPORALE 11<br />
Figura 1.4: LockStep Synchronization. In ques<strong>to</strong> sistema <strong>di</strong> sincronizzazione,<br />
l’esecuzione degli eventi è volutamente ritardata. Un <strong>Peer</strong> non processerà<br />
ness<strong>un</strong> even<strong>to</strong> fino a quando tutti gli altri <strong>Peer</strong> appartenenti alla Membership<br />
non saranno “pronti” per passare allo step <strong>su</strong>ccessivo, ovvero fintan<strong>to</strong><br />
che non riceverà le loro intenzioni, sot<strong>to</strong>forma <strong>di</strong> even<strong>to</strong>. Lo si può associare<br />
ad <strong>un</strong> sistema a turni, nel quale ogni at<strong>to</strong>re è obbliga<strong>to</strong> ad eseguire la propria<br />
mossa (eventualmente nulla) prima <strong>di</strong> passare al turno <strong>su</strong>ccessivo.<br />
Per evitare che <strong>un</strong> <strong>Peer</strong> malevolo possa mo<strong>di</strong>ficare le proprie azioni in conseguenza<br />
alla ricezione degli eventi appartenenti agli altri <strong>Peer</strong>, ogni step viene<br />
<strong>di</strong>viso in due fasi: nella prima ogni <strong>Peer</strong> ann<strong>un</strong>cia <strong>un</strong>a propria “intenzione”,<br />
inviando, ad esempio, l’Hash dell’azione voluta a tutti gli altri <strong>Peer</strong> appartenenti<br />
alla Membership. L’“intenzione” non identifica <strong>un</strong>’azione, nel senso<br />
che dal <strong>su</strong>o valore non è possibile ricavare tramite inferenza la semantica<br />
dell’azione stessa. E’ solo nella seconda fase, infatti, che ogni <strong>Peer</strong> è tenu<strong>to</strong> a<br />
rivelare la propria azione, inviando, agli altri <strong>Peer</strong>, il relativo even<strong>to</strong>. Ques<strong>to</strong><br />
infine sarà esegui<strong>to</strong> solo se, applicando la f<strong>un</strong>zione inversa a quella utilizzata<br />
per ricavare l’“intenzione”, il valore ri<strong>su</strong>ltate sarà equivalente all’azione stessa.<br />
Rispet<strong>to</strong> alla Bucket Synchronization, ques<strong>to</strong> sistema da <strong>un</strong> la<strong>to</strong> argina<br />
il problema del Look Ahead Cheat (5.1), ma dall’altro ri<strong>su</strong>lta essere più sensibile<br />
alle variazioni <strong>di</strong> latezna (Jitter), poiché ogni step, ed ogni singola fase<br />
è in<strong>di</strong>viduata da <strong>un</strong> periodo <strong>di</strong> tempo variabile.
12 CAPITOLO 1. STATO DELL’ARTE<br />
Figura 1.5: Bucket Synchronization: nella Bucket Synchronization il tempo<br />
viene idealmente <strong>su</strong>d<strong>di</strong>viso in intervalli, “Bucket Intervals” (rettangoli grigi),<br />
<strong>di</strong> N millisecon<strong>di</strong> (rettangolo verde), calcolati in base al <strong>Peer</strong> più len<strong>to</strong>.<br />
Viene inoltre defini<strong>to</strong> <strong>un</strong> TimeSpan, “Delay” (rettangolo rosso), calcola<strong>to</strong> in<br />
base alla latenza più alta presente all’interno della Membership. Ogni <strong>Peer</strong><br />
assegna ad ogni singolo intervallo <strong>un</strong> “Bucket”, cioè <strong>un</strong> Buffer destina<strong>to</strong> a<br />
mantenere gli eventi in attesa <strong>di</strong> essere effettivamente eseguiti.<br />
Nell’intervallo I1, il <strong>Peer</strong> A genera <strong>un</strong> even<strong>to</strong> e lo invia <strong>di</strong> conseguenza agli<br />
altri <strong>Peer</strong> appartenenti alla Membership (<strong>Peer</strong> B). Localmente, però, tale<br />
even<strong>to</strong> non viene esegui<strong>to</strong> come conseguenza <strong>di</strong>retta della <strong>su</strong>a generazione:<br />
Verrà invece esegui<strong>to</strong> in I3, poiché quest’ultimo rappresenta il primo intervallo<br />
<strong>di</strong> tempo <strong>su</strong>ccessivo all’istante in<strong>di</strong>vidua<strong>to</strong> dalla somma temporale tra<br />
il momen<strong>to</strong> <strong>di</strong> generazione ed il periodo <strong>di</strong> “Delay”.<br />
Il <strong>Peer</strong> B, riceve l’even<strong>to</strong> in I2 ma, utilizzando il medesimo calcolo, sa che<br />
dovrà eseguirlo in I3. In entrambi i <strong>Peer</strong>, quin<strong>di</strong>, l’even<strong>to</strong> in questione verrà<br />
memorizza<strong>to</strong> nel Bucket relativo all’intervallo I3, e quin<strong>di</strong> esegui<strong>to</strong> a tempo<br />
debi<strong>to</strong>.
1.3. SINCRONIZZAZIONE TEMPORALE 13<br />
Figura 1.6: Time-Warp Synchronization: ogni even<strong>to</strong> è temporizza<strong>to</strong> tramite<br />
<strong>un</strong> TimeStamp e viene esegui<strong>to</strong> <strong>di</strong>rettamente al momen<strong>to</strong> della <strong>su</strong>a ricezione.<br />
Dal p<strong>un</strong><strong>to</strong> <strong>di</strong> vista del <strong>Peer</strong> B, la situazione mostrata in figura si configura<br />
nel modo seguente: Il <strong>Peer</strong> A genera <strong>un</strong> even<strong>to</strong> in TS 0, mentre il <strong>Peer</strong> C<br />
genera <strong>un</strong> even<strong>to</strong> in TS 2.<br />
In TS 4 l’even<strong>to</strong> <strong>di</strong> A gi<strong>un</strong>ge a B, e viene imme<strong>di</strong>atamente esegui<strong>to</strong>, mentre<br />
l’even<strong>to</strong> <strong>di</strong> C tarda ad arrivare.<br />
In TS 7 il <strong>Peer</strong> A invia <strong>un</strong> secondo even<strong>to</strong> che gi<strong>un</strong>ge a B in TS 8.<br />
Solo in TS 12 il <strong>Peer</strong> B riceve l’even<strong>to</strong> invia<strong>to</strong> da C in T 2.<br />
Il <strong>Peer</strong> B, però ha già esegui<strong>to</strong> il secondo even<strong>to</strong> proveniente da A (TS 7),<br />
quin<strong>di</strong> è costret<strong>to</strong> ad eseguire <strong>un</strong> Roll-back, poiché l’even<strong>to</strong> invia<strong>to</strong> dal <strong>Peer</strong> C<br />
deve essere esegui<strong>to</strong> prima, in quan<strong>to</strong> genera<strong>to</strong> ad <strong>un</strong> TimeStamp precedente.<br />
Elimina quin<strong>di</strong> gli effetti causati dal secondo messaggio <strong>di</strong> A me<strong>di</strong>ante <strong>un</strong><br />
“Anti-Message”, notifica<strong>to</strong> <strong>di</strong> conseguenza agli altri <strong>Peer</strong>. L’UnDo può essere<br />
implementa<strong>to</strong> ad esempio memorizzando lo sta<strong>to</strong> incrementale in <strong>un</strong>a “State<br />
queue”.
14 CAPITOLO 1. STATO DELL’ARTE<br />
1.4 Tecnologie<br />
Dal p<strong>un</strong><strong>to</strong> <strong>di</strong> vista dello sviluppo, il videogioco è <strong>un</strong> software complesso,<br />
e come tale si presta ad essere <strong>di</strong>viso in moduli separati, ogn<strong>un</strong>o de<strong>di</strong>ca<strong>to</strong> ad<br />
<strong>un</strong>a precisa f<strong>un</strong>zione.<br />
Escludendo il modulo che implementa le logiche <strong>di</strong> gioco, che è fisiologicamente<br />
<strong>di</strong>pendente dalle specifiche <strong>di</strong> gameplay, si possono in<strong>di</strong>viduare moduli,<br />
tipicamente generalizzabili, come il Renderer (o Engine 3D), utilizza<strong>to</strong> per<br />
<strong>di</strong>segnare <strong>su</strong> schermo gli oggetti tri<strong>di</strong>mensionali, l’Engine fisico, utilizza<strong>to</strong><br />
invece per simulare il movimen<strong>to</strong>, le collisioni e le relative risposte o l’Engine<br />
<strong>di</strong> rete (Networking Engine o “NetCode”), de<strong>di</strong>ca<strong>to</strong> alla connessione e alla<br />
sincronizzazione dello sta<strong>to</strong> <strong>di</strong> gioco.<br />
Dal momen<strong>to</strong> che le f<strong>un</strong>zioni <strong>su</strong>pportate da tali moduli sono piut<strong>to</strong>s<strong>to</strong> generiche<br />
e “gamelogic independent”, <strong>di</strong>versi Team e Software House rilasciano<br />
pubblicamente le versioni dei propri Engines, opport<strong>un</strong>amente aggiornati secondo<br />
gli ultimi standard qualitativi. In ques<strong>to</strong> modo è possibile sviluppare<br />
videogiochi astraendo da <strong>un</strong>a vasta gamma <strong>di</strong> aspetti inerenti al game development,<br />
evitando quin<strong>di</strong> <strong>di</strong> dover reimplementare complesse componenti<br />
software già esistenti, e risolverne le problematiche annesse.<br />
Per quan<strong>to</strong> riguarda gli Engines 3D, spesso questi sono accompagnati da<br />
mo<strong>to</strong>ri <strong>di</strong> gioco e Tools <strong>di</strong> <strong>su</strong>ppor<strong>to</strong>: attualmente a livello <strong>di</strong> software Open<br />
Source, gli Engines grafici più utilizzati sono Ogre3D 6 che si presenta come<br />
Renderer multipiattaforma basa<strong>to</strong> <strong>su</strong> <strong>un</strong>o scenegraph a no<strong>di</strong>, e Irrlicht 7 ,<br />
simile al primo quan<strong>to</strong> a features <strong>di</strong> base ma pre<strong>di</strong>spos<strong>to</strong> al <strong>su</strong>ppor<strong>to</strong> <strong>di</strong> caratteristiche<br />
tipiche <strong>di</strong> <strong>un</strong> <strong>Game</strong> Engine quali la gestione input, dell’au<strong>di</strong>o e<br />
della fisica.<br />
6 Object-Oriented Graphics Rendering Engine, http://www.ogre3d.org<br />
7 http://irrlicht.sourceforge.net
1.4. TECNOLOGIE 15<br />
In molte realtà, però, si mira alla realizzazione <strong>di</strong> mo<strong>to</strong>ri e <strong>to</strong>ols meno<br />
“general purpose” e più orientati a quelle che sono le features particolari richieste<br />
dalle specifiche <strong>di</strong> gioco. Tra questi ve ne sono alc<strong>un</strong>i appositamente<br />
sviluppati in modo da lasciare <strong>un</strong> grado <strong>di</strong> libertà tale da poter essere riutilizzati,<br />
<strong>su</strong>ccessivamente, per la realizzazione <strong>di</strong> nuovi ti<strong>to</strong>li, eventualmente<br />
anche sviluppati da terze parti. Tra questi vi sono l’id Tech <strong>di</strong> ID Software,<br />
famoso per essere sta<strong>to</strong> utilizza<strong>to</strong> come tecnologia <strong>di</strong> base per realizzare le<br />
serie <strong>di</strong> DooM e <strong>di</strong> Quake ed ormai gi<strong>un</strong><strong>to</strong> alla <strong>su</strong>a quinta versione, l’Unreal<br />
Technology, <strong>di</strong> Epic <strong>Game</strong>s, utilizza<strong>to</strong> invece per la serie Unreal e per numerosi<br />
altri ti<strong>to</strong>li per PC e console, ed il CryEngine, attualmente utilizza<strong>to</strong><br />
esclusivamente per la serie Crysis ma tecnicamente ancora all’avanguar<strong>di</strong>a.<br />
Da qualche anno, inoltre, è aumentata la richiesta <strong>di</strong> Middleware crossplatform<br />
a basso cos<strong>to</strong> che, oltre all’Engine 3D, offrano ambienti integranti<br />
E<strong>di</strong><strong>to</strong>rs, Tools, Engines <strong>di</strong> gioco, Engines fisici, <strong>su</strong>ppor<strong>to</strong> au<strong>di</strong>o e gestione<br />
degli input: Unity3D 8 ne è <strong>un</strong> esempio. Altrettan<strong>to</strong> vali<strong>di</strong> sono Shiva 3D 9<br />
e l’UDK 10 .<br />
Un <strong>di</strong>scorso analogo lo si può fare per quan<strong>to</strong> riguarda i moduli relativi<br />
alla gestione <strong>di</strong> rete:<br />
RakNet 11 è <strong>un</strong> <strong>Game</strong> Networking Engine crossplatform che oltre a features<br />
base a livello <strong>di</strong> com<strong>un</strong>icazione (NAT P<strong>un</strong>chthrough, or<strong>di</strong>namen<strong>to</strong> messaggi,<br />
serializzazione e generazione pacchetti) e a livello applicazione Object<br />
replication e chiamate remote, offre <strong>un</strong>a serie <strong>di</strong> f<strong>un</strong>zioni aggi<strong>un</strong>tive come la<br />
gestione utenti, gestione lobby, stanze e matchmaking. Supporta sia il modello<br />
Client-Server che quello <strong>Peer</strong>-To-<strong>Peer</strong>.<br />
8 http://<strong>un</strong>ity3d.com<br />
9 http://www.s<strong>to</strong>netrip.com<br />
10 Unreal Development Kit, http://www.udk.com<br />
11 http://www.jenkinssoftware.com
16 CAPITOLO 1. STATO DELL’ARTE<br />
SmartFoxServer 12 , è <strong>un</strong> ambiente integra<strong>to</strong> con caratteristiche simili a<br />
RakNet ma orientate maggiormente verso la semplificazione <strong>di</strong> utilizzo: la<strong>to</strong><br />
Server infatti <strong>di</strong>spone <strong>di</strong> <strong>un</strong>a notevole quantità <strong>di</strong> strumenti <strong>di</strong> amministrazione<br />
per la gestione utenti, mentre la<strong>to</strong> Client mette a <strong>di</strong>sposizione <strong>un</strong>a serie<br />
<strong>di</strong> API per migliorarne l’integrazione.<br />
Altre librerie invece omet<strong>to</strong>no appositamente alc<strong>un</strong>e features <strong>di</strong> più al<strong>to</strong><br />
livello, in favore <strong>di</strong> <strong>un</strong>a maggiore flessibilità <strong>di</strong> implementazione la<strong>to</strong> utente:<br />
Zoidcom 13 , ad esempio, fornisce sistemi <strong>di</strong> Object replication e sincronizzazione<br />
degli stati, ma non <strong>su</strong>pporta features legate alla gestione delle partite e<br />
dei gioca<strong>to</strong>ri. Enet 14 , invece, fornisce solamente <strong>un</strong> leggero ma robus<strong>to</strong> Layer<br />
<strong>di</strong> com<strong>un</strong>icazione basa<strong>to</strong> <strong>su</strong>l pro<strong>to</strong>collo UDP.<br />
12 http://www.smartfoxserver.com<br />
13 http://www.zoidcom.com<br />
14 http://enet.bespin.org
Capi<strong>to</strong>lo 2<br />
Architettura Software<br />
2.1 Problematiche<br />
L’esigenza <strong>di</strong> <strong>un</strong> elevata reattività <strong>di</strong> risposta (logica e visiva) ai coman<strong>di</strong><br />
del gioca<strong>to</strong>re è sentita in quantità <strong>di</strong>fferente a seconda della tipologia <strong>di</strong> gioco:<br />
In <strong>un</strong> gioco Arcade 1 , ad esempio, il Timespan 2 tra l’input “meccanico”<br />
dell’utente ed il relativo feedback visivo deve essere estremamente ridot<strong>to</strong> (si<br />
pensi al movimen<strong>to</strong> del personaggio controlla<strong>to</strong> dal gioca<strong>to</strong>re in <strong>un</strong> FPS 3 ),<br />
mentre in <strong>un</strong> gioco TBS 4 tut<strong>to</strong> ques<strong>to</strong> non è necessario, dal momen<strong>to</strong> che i<br />
coman<strong>di</strong> impartiti dal gioca<strong>to</strong>re verranno eseguiti solo alla fine <strong>di</strong> <strong>un</strong> turno<br />
che può durare anche <strong>di</strong>versi minuti.<br />
Queste <strong>di</strong>fferenze influenzano non solo il design degli algoritmi e delle<br />
strutture dati relativi alla logica specifica del gameplay 5 , ma anche alc<strong>un</strong>e<br />
scelte progettuali <strong>su</strong>l design del <strong>Game</strong> Engine 6 :<br />
1 Un videogioco caratterizza<strong>to</strong> da <strong>di</strong>namiche rapide, imme<strong>di</strong>ate, e con ridotte pretese <strong>di</strong><br />
realismo<br />
2 Lasso <strong>di</strong> tempo<br />
3 First-person shooter, Sparatut<strong>to</strong> in prima persona<br />
4 Turn-based strategy, Gioco strategico a turni<br />
5 Regole e <strong>di</strong>namiche logiche e d’interazione che contrad<strong>di</strong>stinguono il gioco<br />
6 Genericamente è inteso come l’insieme dei sistemi software che gestiscono il rendering,<br />
le animazioni, la logica, le collisioni, la scena, l’intelligenza artificiale, au<strong>di</strong>o, input ed il<br />
17
18 CAPITOLO 2. ARCHITETTURA SOFTWARE<br />
Riprendendo l’esempio precedente, e limitando il contes<strong>to</strong> ai soli giochi offline,<br />
al fine <strong>di</strong> realizzare <strong>un</strong> semplice gioco Arcade può non essere necessaria<br />
<strong>un</strong>a forte separazione tra il Layer logico (Business Layer) ed il Layer <strong>di</strong> vi<strong>su</strong>alizzazione<br />
(Presentation Layer): lo spostamen<strong>to</strong> <strong>di</strong> <strong>un</strong>o Sprite 7 che ne simula<br />
il movimen<strong>to</strong> <strong>su</strong> schermo, può essere realizza<strong>to</strong> mo<strong>di</strong>ficando <strong>di</strong>rettamente le<br />
variabili relative alla posizione <strong>di</strong> <strong>di</strong>segno dello stesso, come imme<strong>di</strong>ata conseguenza<br />
dell’input dell’utente.<br />
In <strong>un</strong> TBS, invece, i due Layer tendono ad essere <strong>di</strong>saccoppiati in modo<br />
naturale, portando il Layer <strong>di</strong> vi<strong>su</strong>alizzazione ad essere <strong>un</strong>a mera rappresentazione<br />
dei dati logici che, in ultima analisi, sono gli <strong>un</strong>ici deten<strong>to</strong>ri dello<br />
sta<strong>to</strong> attuale <strong>di</strong> gioco.<br />
Se però si estende l’esempio ampliandolo ai giochi online, allora anche per<br />
<strong>un</strong> gioco Arcade sarà opport<strong>un</strong>o seguire <strong>un</strong> pattern Three-tier 8 o MVC-like 9 ,<br />
dal momen<strong>to</strong> che avere <strong>un</strong> Layer logico separa<strong>to</strong> semplifica l’identificazione,<br />
la ricerca, l’accesso e quin<strong>di</strong> la sincronizzazione dello sta<strong>to</strong> <strong>di</strong> gioco. Non<br />
solo: In ques<strong>to</strong> contes<strong>to</strong> nascono problematiche relative alla latenza <strong>di</strong> rete,<br />
specialmente proprio in quelle tipologie <strong>di</strong> gioco che richiedono contemporaneamente<br />
massima reattività e massima consistenza.<br />
Idealmente, quin<strong>di</strong>, anche quelle azioni che normalmente, in architetture Singleplayer<br />
oriented, producono <strong>un</strong> feedback <strong>di</strong>ret<strong>to</strong>, come lo spostamen<strong>to</strong> <strong>di</strong><br />
<strong>un</strong> elemen<strong>to</strong> grafico in conseguenza ad <strong>un</strong>o specifico input, devono qui essere<br />
processate attraverso <strong>di</strong>versi Layer prima <strong>di</strong> essere eseguite, eventualmente<br />
anche con <strong>un</strong> apposi<strong>to</strong> ritardo introdot<strong>to</strong> volutamente da alc<strong>un</strong>i sistemi<br />
<strong>di</strong> sincronizzazione (si veda la sezione 4). Per alc<strong>un</strong>e tipologie <strong>di</strong> gameplay,<br />
però, tale ritardo finisce con l’impattare negativamente <strong>su</strong>ll’esperienza <strong>di</strong> gionetworking<br />
7 Un qualsiasi elemen<strong>to</strong> grafico, statico o <strong>di</strong>namico, che compone la scena <strong>di</strong> gioco<br />
8 Architettura software caratterizzata da tre moduli: Interfaccia Utente, Logica<br />
F<strong>un</strong>zionale e Dati<br />
9 Model-View-Controller, <strong>un</strong> pattern architetturale che vede separati i concetti <strong>di</strong> Model:<br />
il sistema <strong>di</strong> accesso ai dati, View: Il sistema <strong>di</strong> vi<strong>su</strong>alizzazione dati, ed il Controller: Il<br />
sistema <strong>di</strong> mo<strong>di</strong>fica dei dati
2.1. PROBLEMATICHE 19<br />
co, rendendo necessaria l’implementazione <strong>di</strong> sistemi <strong>di</strong> interpolazione e <strong>di</strong><br />
Pre<strong>di</strong>ction che ne attenuino gli effetti <strong>di</strong> latenza percepiti dall’utente (2.7.1).<br />
Laddove ques<strong>to</strong> non bastasse, è possibile, uscendo però dal design propos<strong>to</strong><br />
dalla pipeline illustrata precedentemente, parallelizzare tale esecuzione<br />
processandola imme<strong>di</strong>atamente in <strong>un</strong> contes<strong>to</strong> locale, e, <strong>su</strong>ccessivamente interpolandone<br />
gli effetti ri<strong>su</strong>ltanti dall’esecuzione remota.<br />
Astraendo dall’architettura <strong>di</strong> rete utilizzata, quello che si mira ad avere<br />
è <strong>un</strong>o sta<strong>to</strong> <strong>di</strong> gioco “con<strong>di</strong>viso” da tutti gli at<strong>to</strong>ri partecipanti alla rete:<br />
In <strong>un</strong> sistema Client-Server lo sta<strong>to</strong> <strong>di</strong> gioco è mantenu<strong>to</strong> dal Server, ma <strong>un</strong>a<br />
<strong>su</strong>a copia, tipicamente meno estesa e dettagliata, è presente com<strong>un</strong>que <strong>su</strong><br />
ogni singolo Client. Ques<strong>to</strong> accade specialmente in quelle tipologie <strong>di</strong> gioco<br />
che richiedono continui accessi al da<strong>to</strong>, poiché accedere <strong>di</strong>rettamente ai Layer<br />
Business (o Data) del Server sarebbe deleterio in termini <strong>di</strong> performance, <strong>di</strong><br />
sicurezza e, in ultima analisi, <strong>di</strong> design.<br />
A maggior ragione, in <strong>un</strong> sistema <strong>Peer</strong>-<strong>to</strong>-<strong>Peer</strong> lo sta<strong>to</strong> <strong>di</strong> gioco deve risiedere<br />
<strong>su</strong> ogni nodo, e ques<strong>to</strong> introduce problematiche <strong>di</strong> sincronizzazione dello sta<strong>to</strong><br />
<strong>di</strong> gioco, rendendo necessaria l’implementazione <strong>di</strong> politiche atte a garantirne<br />
la consistenza. Su ogni nodo infatti risiede <strong>un</strong>a copia dello sta<strong>to</strong> <strong>di</strong> gioco <strong>su</strong>l<br />
quale vengono operate mo<strong>di</strong>fiche in modo in<strong>di</strong>pendente a seconda degli eventi<br />
ricevuti da altri no<strong>di</strong> in relazione alla logica <strong>di</strong> gioco implementata.<br />
Se la politica <strong>di</strong> sincronizzazione adottata prevede la possibilità <strong>di</strong> eseguire<br />
dei Rollback, tale copià può anche essere mantenuta <strong>su</strong> più istanze, mirate<br />
a fornire <strong>un</strong>a sorta <strong>di</strong> backup dal quale attingere in caso <strong>di</strong> Rollback le informazioni<br />
necessarie a ripristinare lo sta<strong>to</strong> precedente (si veda Figura 1.6).<br />
Come anticipa<strong>to</strong> nell’introduzione, per l’implementazione del proget<strong>to</strong> <strong>di</strong><br />
tesi si è scel<strong>to</strong> <strong>di</strong> limitare l’inconsistenza utilizzando <strong>un</strong> approccio che sot<strong>to</strong><br />
alc<strong>un</strong>i aspetti si <strong>di</strong>scosta da <strong>un</strong>’architettura <strong>Peer</strong>-To-<strong>Peer</strong> “pura”.<br />
Il sistema <strong>di</strong> sincronizzazione utilizza<strong>to</strong> pre<strong>di</strong>lige <strong>un</strong>a politica più “State-<br />
Driven” che “Event-Driven”: Infatti ogni nodo non sarà perfettamente pa-
20 CAPITOLO 2. ARCHITETTURA SOFTWARE<br />
ritetico: manterrà <strong>un</strong>a <strong>su</strong>a visione del Data Layer, ma opererà solo <strong>su</strong> <strong>un</strong><br />
limita<strong>to</strong> numero <strong>di</strong> dati <strong>di</strong> <strong>su</strong>a appartenenza.<br />
Ques<strong>to</strong> approccio coinciderà con <strong>un</strong> Data Layer nel quale ogni singola<br />
informazione a<strong>to</strong>mica è <strong>di</strong> proprietà <strong>di</strong> <strong>un</strong> generico “Owner”, ed è quin<strong>di</strong><br />
vincolata da <strong>un</strong>a serie <strong>di</strong> regole che ne garantiscono i permessi esclusivi <strong>di</strong><br />
creazione, mo<strong>di</strong>fica e <strong>di</strong>struzione. Nella fattispecie l’Owner coinciderà con i<br />
concetti <strong>di</strong> Player e <strong>di</strong> <strong>Peer</strong>.<br />
Quest’ultimo è concretizza<strong>to</strong> nel Layer de<strong>di</strong>ca<strong>to</strong> alla gestione della Membership<br />
dei no<strong>di</strong> che partecipano alla rete. Oltre a garantire la mutua conoscenza<br />
tra i <strong>di</strong>versi <strong>Peer</strong>, astrae il Layer NET sot<strong>to</strong>stante, de<strong>di</strong>ca<strong>to</strong> alla com<strong>un</strong>icazione<br />
<strong>di</strong> rete vera e propria.<br />
Rias<strong>su</strong>mendo, il software sarà compos<strong>to</strong> da i seguenti Layer e Moduli:<br />
• Layer View (Presentation Layer): De<strong>di</strong>ca<strong>to</strong> alla rappresentazione vi<strong>su</strong>ale<br />
dello sta<strong>to</strong> logico. Oltre agli aspetti prettamente grafici, impropriamente<br />
include i moduli de<strong>di</strong>cati alla gestione della fisica, dell’au<strong>di</strong>o<br />
e degli input.<br />
• Layer Logic (Business Layer): De<strong>di</strong>ca<strong>to</strong> all’implementazione delle meccaniche<br />
<strong>di</strong> gioco. Sostanzialmente mo<strong>di</strong>fica il Layer Data a seconda<br />
degli Input che gi<strong>un</strong>gono dal Layer View facendo riferimen<strong>to</strong> alle regole<br />
<strong>di</strong> gioco.<br />
• Modulo SharedComponents (Data Layer e Consistenza): Mantiene lo<br />
sta<strong>to</strong> <strong>di</strong> gioco. Espone <strong>un</strong> Manager in grado <strong>di</strong> creare, mo<strong>di</strong>ficare e <strong>di</strong>struggere<br />
i propri componenti, e <strong>di</strong> mantenere <strong>un</strong>a copia dei componenti<br />
creati dai Manager appartenenti agli altri <strong>Peer</strong>.<br />
• Layer P2P (Membership): De<strong>di</strong>ca<strong>to</strong> alla gestione della Membership.<br />
Astrae l’interfaccia del Layer NET sot<strong>to</strong>stante.<br />
• Layer NET (Comm<strong>un</strong>ication): Espone <strong>un</strong>’interfaccia che consente la<br />
com<strong>un</strong>icazione tra N generici endpoints.
2.2. LAYER NET 21<br />
Questa separazione <strong>di</strong> Layer e le loro caratteristiche sono state progettate<br />
per avere <strong>un</strong> sistema il più possibile generico, modulare, e, specialmente nel<br />
Layer inferiori, “gamelogic independent”.<br />
La tipologia <strong>di</strong> gioco scelta per il proget<strong>to</strong> <strong>di</strong> tesi, è identificabile all’interno<br />
della categoria degli “Shooter <strong>Game</strong>s”, che presenta <strong>un</strong> <strong>Game</strong>play dalle<br />
logiche relativamente semplici ed in<strong>di</strong>viduate da <strong>un</strong>a serie <strong>di</strong> elementi caratteristici<br />
del genere: La triade <strong>di</strong> elementi fondamentali <strong>di</strong> <strong>un</strong>o “Shooter” è<br />
formata dal concet<strong>to</strong> <strong>di</strong> “Protagonista”, che può essere sia <strong>un</strong> elemen<strong>to</strong> antropomorfo<br />
(<strong>un</strong> solda<strong>to</strong>) che <strong>un</strong> elemen<strong>to</strong> meccanico (<strong>un</strong>a navetta spaziale)<br />
controlla<strong>to</strong> <strong>di</strong>rettamente dal gioca<strong>to</strong>re; dal concet<strong>to</strong> <strong>di</strong> “Nemico”, che può essere<br />
<strong>un</strong> elemen<strong>to</strong> controlla<strong>to</strong> dalla CPU o <strong>di</strong>rettamente da <strong>un</strong> altro gioca<strong>to</strong>re,<br />
e da <strong>un</strong>’entità in grado <strong>di</strong> apportare danno al “Nemico” conseguentemente<br />
ad <strong>un</strong>a azione ad opera del “Protagonista”, o viceversa.<br />
La scelta è ricaduta <strong>su</strong> ques<strong>to</strong> genere <strong>di</strong> gioco poiché, nella <strong>su</strong>a semplicità,<br />
presenta implicitamente tutta <strong>un</strong>a serie <strong>di</strong> problematiche com<strong>un</strong>i alla<br />
maggior parte delle tipologie <strong>di</strong> gioco, ovvero la creazione e <strong>di</strong>struzione <strong>di</strong><br />
oggetti grafici, la gestione del loro spostamen<strong>to</strong> e delle eventuali collisioni.<br />
Di segui<strong>to</strong> verrà analizza<strong>to</strong> ogni singolo Layer nel dettaglio, lasciando<br />
però gli aspetti prettamente implementativi al prossimo capi<strong>to</strong>lo.<br />
2.2 Layer NET<br />
Ques<strong>to</strong> modulo è necessario per fornire <strong>un</strong>a astrazione <strong>di</strong> quella che è la<br />
com<strong>un</strong>icazione <strong>di</strong> rete a più basso livello. Quest’ultima infatti può <strong>di</strong>fferire<br />
mol<strong>to</strong> da implementazione a implementazione, a partire dal pro<strong>to</strong>collo <strong>di</strong><br />
com<strong>un</strong>icazione fino alla struttura dei singoli pacchetti, mentre i Layer sovrastanti<br />
necessitano <strong>di</strong> <strong>un</strong>’interfaccia astratta e trasparente in ques<strong>to</strong> senso. A<br />
ques<strong>to</strong> proposi<strong>to</strong>, il Layer espone, tramite <strong>un</strong>’interfaccia, i concetti <strong>di</strong> “Node”
22 CAPITOLO 2. ARCHITETTURA SOFTWARE<br />
e <strong>di</strong> “Link”. Un “Node” è sostanzialmente <strong>un</strong> endpoint <strong>di</strong> com<strong>un</strong>icazione,<br />
mentre <strong>un</strong> “Link” è <strong>un</strong>a rappresentazione del canale ci com<strong>un</strong>icazione tra<br />
due endpoints.<br />
In <strong>un</strong> contes<strong>to</strong> <strong>Peer</strong>-To-<strong>Peer</strong> forma<strong>to</strong> da N no<strong>di</strong>, significa che ogni “Node”<br />
possiede N-1 “Link”, <strong>un</strong>o per ogni nodo appartenente alla rete (escluso se<br />
stesso).<br />
Da <strong>un</strong> p<strong>un</strong><strong>to</strong> <strong>di</strong> vista più vicino all’implementazione vera e propria, sia il<br />
“Node” che il “Link” sono considerati “NetElement”, ovvero elementi identificabili<br />
tramite <strong>un</strong> “NetID”, costrui<strong>to</strong> in base all’in<strong>di</strong>rizzo IP e alla porta<br />
<strong>di</strong> ascol<strong>to</strong>.<br />
Quando si vuole connettere <strong>un</strong> nodo A ad <strong>un</strong> nodo B in ascol<strong>to</strong>, in A viene<br />
crea<strong>to</strong> <strong>un</strong> Link identifica<strong>to</strong> dal NetID <strong>di</strong> B. Quando B riceve la richiesta<br />
<strong>di</strong> connessione, può ricavare l’in<strong>di</strong>rizzo IP <strong>di</strong> A, ma non la porta <strong>su</strong>lla quale<br />
sta ascoltando.<br />
Inizia quin<strong>di</strong> <strong>un</strong>a fase <strong>di</strong> Handshaking, eseguita a livello applicazione, nella<br />
quale i due no<strong>di</strong> si scambiano i propri NetID, identificando gli at<strong>to</strong>ri e consolidando<br />
così la connessione.<br />
La fase <strong>di</strong> Handshaking inizia appena <strong>un</strong> nodo (A) riceve la connessione <strong>di</strong><br />
<strong>un</strong> secondo nodo (B).<br />
Il primo step vede A inviare il comando NET “HandShakeBegin” a B.<br />
Quando B riceve tale comando, risponderà inviando ad A il comando NET<br />
“HandShakeResponse” contenente il proprio NetID.<br />
L’ultimo step vede infine A confermare a B l’avvenu<strong>to</strong> riconoscimen<strong>to</strong> tramite<br />
il comando NET “HandShakeEnd”.<br />
Una volta terminata questa fase (Figura 2.1), entrambi i no<strong>di</strong> possono iniziare<br />
a scambiarsi i messaggi inoltrati dai rispettivi Layer <strong>su</strong>periori.
2.2. LAYER NET 23<br />
Figura 2.1: Fase <strong>di</strong> connessione tra due no<strong>di</strong> e relativo Handshaking, esegui<strong>to</strong><br />
all’interno del Layer NET
24 CAPITOLO 2. ARCHITETTURA SOFTWARE<br />
2.3 Layer P2P<br />
Una prima f<strong>un</strong>zione <strong>di</strong> ques<strong>to</strong> Layer è quello <strong>di</strong> astrarre quello sot<strong>to</strong>stante<br />
con <strong>un</strong>a serie <strong>di</strong> f<strong>un</strong>zioni <strong>di</strong> al<strong>to</strong> livello che permet<strong>to</strong>no la com<strong>un</strong>icazione tra<br />
i no<strong>di</strong> secondo <strong>un</strong>a logica <strong>Peer</strong>-To-<strong>Peer</strong> senza conoscerne la specifica implementazione.<br />
Ad esempio la f<strong>un</strong>zione “BroadCast(messaggio)” si preoccuperà<br />
<strong>di</strong> inviare lo stesso messaggio, attraverso il Layer NET, a tutti i <strong>Peer</strong> conosciuti.<br />
La seconda f<strong>un</strong>zione <strong>di</strong> ques<strong>to</strong> Layer è quella <strong>di</strong> garantire la conoscenza reciproca<br />
tra i <strong>di</strong>versi <strong>Peer</strong>: ogni <strong>Peer</strong> infatti contiene <strong>un</strong>a lista <strong>di</strong> ’NetID’ relativi<br />
ai <strong>Peer</strong> con i quali ri<strong>su</strong>lta già connesso.<br />
Supponendo <strong>di</strong> avere 5 <strong>Peer</strong>, A, B ,C , D ed E, e che siano già connessi<br />
tra loro secondo lo schema seguente (Figura 2.2): (A-B) , (C-D) , E<br />
Figura 2.2: Organizzazione delle connessioni all’istante T1<br />
• Il <strong>Peer</strong> A ha nella <strong>su</strong>a lista <strong>di</strong> <strong>Peer</strong> conosciuti il NetID <strong>di</strong> B (ed il<br />
proprio)<br />
• Il <strong>Peer</strong> B ha nella <strong>su</strong>a lista <strong>di</strong> <strong>Peer</strong> conosciuti il NetID <strong>di</strong> A (ed il<br />
proprio)<br />
• Il <strong>Peer</strong> C ha nella <strong>su</strong>a lista <strong>di</strong> <strong>Peer</strong> conosciuti il NetID <strong>di</strong> D (ed il<br />
proprio)<br />
• Il <strong>Peer</strong> D ha nella <strong>su</strong>a lista <strong>di</strong> <strong>Peer</strong> conosciuti il NetID <strong>di</strong> C (ed il<br />
proprio)
2.3. LAYER P2P 25<br />
• Il <strong>Peer</strong> E ha nella <strong>su</strong>a lista <strong>di</strong> <strong>Peer</strong> conosciuti solo il proprio NetID<br />
Quando E si connette al <strong>Peer</strong> D, teoricamente entrerebbe a far parte della<br />
rete formata dai <strong>Peer</strong> C,D ed E. Ma E non è a corrente dell’esistenza del<br />
<strong>Peer</strong> C, e viceversa, C non è a corrente dell’esistenza <strong>di</strong> E.<br />
Per ovviare a ques<strong>to</strong> problema, <strong>un</strong>a volta terminata la fase <strong>di</strong> HandShaking<br />
(a carico del Layer NET) tra i rispettivi no<strong>di</strong> <strong>di</strong> D ed E, viene avviata <strong>un</strong>a<br />
seconda fase a carico del Layer P2P, nella quale i <strong>Peer</strong> appena connessi, si<br />
scambiano tutti i NetID <strong>di</strong> loro conoscenza. In ques<strong>to</strong> modo grazie a D, C<br />
conoscerà E, vi si connetterà, e <strong>di</strong> conseguenza E conoscerà D, chiudendo <strong>di</strong><br />
fat<strong>to</strong> la sot<strong>to</strong>rete (C-D-E) (Figura 2.3).<br />
Figura 2.3: Organizzazione delle connessioni all’istante T2<br />
Quando C si connette a B, B notificherà l’esistenza <strong>di</strong> C ad A che vi si<br />
connetterà a <strong>su</strong>a volta. Allo stesso modo, C riferirà a D ed E dell’esistenza<br />
<strong>di</strong> B e quin<strong>di</strong> <strong>di</strong> A. Infine D ed E si connetteranno entrambi ad A e B<br />
(Figura 2.4).<br />
Figura 2.4: Organizzazione delle connessioni all’istante T3<br />
In (Figura 2.5) sono mostrate le fasi <strong>di</strong> connessione tra due <strong>Peer</strong>, sia del<br />
Layer NET che del Layer P2P A e B.
26 CAPITOLO 2. ARCHITETTURA SOFTWARE<br />
Figura 2.5: Fasi preliminari <strong>di</strong> connessione tra due <strong>Peer</strong><br />
Ad <strong>un</strong> istante T0, il <strong>Peer</strong> B si connette al <strong>Peer</strong> A.<br />
All’istante imme<strong>di</strong>atamente <strong>su</strong>ccessivo, nel contes<strong>to</strong> dell Layer NET, avviene<br />
la fase <strong>di</strong> HandShaking.<br />
Quando questa termina, nel contes<strong>to</strong> del Layer P2P, si attiva la fase <strong>di</strong> interscambio<br />
dei NetID conosciuti. In ques<strong>to</strong> caso B conosce solo B (se stesso)<br />
ed A conosce solo A (se stesso).<br />
B invierà quin<strong>di</strong> ad A il comando P2P “Add<strong>Peer</strong>” parametrizza<strong>to</strong> con il<br />
proprio NetID. A farà lo stesso, inviando a B il comando P2P “Add<strong>Peer</strong>”<br />
parametrizza<strong>to</strong> con il proprio NetID.<br />
Quando A riceverà il comando P2P “Add<strong>Peer</strong>” contenente il NetID <strong>di</strong> B,<br />
controllerà che ques<strong>to</strong> non sia già presente nella propria lista dei <strong>Peer</strong> conosciuti:<br />
nel caso non sia effettivamente presente, aprirà au<strong>to</strong>maticamente <strong>un</strong>a<br />
connessione verso il NetID appena ricevu<strong>to</strong>.<br />
Non è ques<strong>to</strong> il caso, dal momen<strong>to</strong> che i <strong>Peer</strong> sono solo due, ed entrambi si<br />
conoscono a vicenda <strong>di</strong>rettamente dalla fase <strong>di</strong> HandShaking.
2.3. LAYER P2P 27<br />
Se però nell’esempio viene introdotta <strong>un</strong>a seconda sot<strong>to</strong>rete formata dai <strong>Peer</strong><br />
C e D (Figura 2.6), questa fase as<strong>su</strong>me maggior concretezza: in T1, il <strong>Peer</strong><br />
C si connette al <strong>Peer</strong> B, ed in T2 viene attivata la fase <strong>di</strong> scambio NetID,<br />
implementata tramite il comando P2P “Add<strong>Peer</strong>” (freccia in arancione):<br />
Figura 2.6: Fasi preliminari <strong>di</strong> connessione tra due sot<strong>to</strong>reti composte<br />
ciasc<strong>un</strong>a da due <strong>Peer</strong><br />
Il <strong>Peer</strong> C ha, nella lista <strong>di</strong> <strong>Peer</strong> conosciuti, se stesso ed il <strong>Peer</strong> D. Pertan<strong>to</strong><br />
invierà a B due coman<strong>di</strong> P2P “Add<strong>Peer</strong>”; il primo parametrizza<strong>to</strong> con il<br />
proprio NetID, ed il secondo parametrizza<strong>to</strong> con il NetID <strong>di</strong> D.<br />
Quando il primo comando “Add<strong>Peer</strong>” gi<strong>un</strong>gerà al <strong>Peer</strong> B, quest’ultimo controllerà<br />
che il NetID contenu<strong>to</strong> come parametro del comando stesso, non sia
28 CAPITOLO 2. ARCHITETTURA SOFTWARE<br />
già presente nella propria lista <strong>di</strong> <strong>Peer</strong> conosciuti.<br />
In ques<strong>to</strong> caso B è già a conoscenza dell’esistenza <strong>di</strong> C, dal momen<strong>to</strong> che la<br />
connessione è avvenuta proprio tra B e C.<br />
Quando però arriva il secondo comando “Add<strong>Peer</strong>”, parametrizza<strong>to</strong> con il<br />
NetID <strong>di</strong> D, il <strong>Peer</strong> B, controllando nella propria lista <strong>di</strong> <strong>Peer</strong> conosciuti, si<br />
accorge <strong>di</strong> non conoscere il <strong>Peer</strong> identifica<strong>to</strong> dal NetID <strong>di</strong> D. A ques<strong>to</strong> p<strong>un</strong><strong>to</strong>,<br />
quin<strong>di</strong>, Il <strong>Peer</strong> B si connetterà al NetID <strong>di</strong> D per includerlo tra i propri <strong>Peer</strong><br />
conosciuti.<br />
Si attiva quin<strong>di</strong> <strong>un</strong>a propagazione “a catena” che terminerà solo <strong>un</strong>a volta<br />
che tutte le liste <strong>di</strong> <strong>Peer</strong> conosciuti coincideranno tra loro.<br />
2.3.1 Modulo Time<br />
All’interno del Layer P2P, è presente <strong>un</strong> sot<strong>to</strong>-modulo che si occupa della<br />
gestione del Timing, mira<strong>to</strong> a garantire <strong>un</strong>a visione temporale con<strong>di</strong>visa.<br />
Una volta terminata la fase <strong>di</strong> consolidamen<strong>to</strong> della Membership, inizia<br />
<strong>un</strong>a fase parallela e prol<strong>un</strong>gata nel tempo: ogni <strong>Peer</strong> notificherà a tutti gli<br />
altri <strong>Peer</strong> conosciuti, quello che è il valore del proprio TimeStamp <strong>di</strong> sistema<br />
attraverso il comando TimeSync.<br />
Quando <strong>un</strong> <strong>Peer</strong> A riceverà <strong>un</strong> comando TimeSync da <strong>un</strong> <strong>Peer</strong> B, calcolerà<br />
il delta tra il TimeStamp in esso contenu<strong>to</strong> ed il proprio, e lo memorizzerà<br />
in <strong>un</strong>’apposita lista in<strong>di</strong>cizzata per NetID. Il valore del delta deve inoltre<br />
comprendere <strong>un</strong> TimeSpan che compensi il fat<strong>to</strong>re Lag: viene infatti aggi<strong>un</strong><strong>to</strong><br />
<strong>un</strong> lasso temporale calcola<strong>to</strong> in base al tempo <strong>di</strong> latenza tra la richiesta<br />
TimeSync e la relativa risposta.<br />
Dal momen<strong>to</strong> che questa fase viene reiterata (dopo <strong>un</strong> determina<strong>to</strong> periodo<br />
<strong>di</strong> tempo viene infatti esegui<strong>to</strong> nuovamente <strong>un</strong> BroadCast <strong>di</strong> TimeSync),<br />
ogni <strong>Peer</strong> conoscerà con <strong>un</strong>a <strong>di</strong>screta precisione il fat<strong>to</strong>re <strong>di</strong> conversione del<br />
TimeSpan <strong>di</strong> tutti gli altri <strong>Peer</strong>, rispet<strong>to</strong> al proprio.
2.3. LAYER P2P 29<br />
Ques<strong>to</strong> modulo, quin<strong>di</strong>, permette <strong>di</strong> convertire in maniera del tut<strong>to</strong> trasparente<br />
il TimeStamp del mittente, che viene appeso a tutti i coman<strong>di</strong> del Layer<br />
Logic, utilizzando come base <strong>di</strong> conversione il proprio TimeStamp.<br />
Non vi è quin<strong>di</strong> <strong>un</strong> sistema <strong>di</strong> Master Clock assolu<strong>to</strong>, associa<strong>to</strong> ad <strong>un</strong> <strong>Peer</strong><br />
elet<strong>to</strong> tale, ad <strong>un</strong>a risorsa esterna alla Membership od <strong>un</strong> sistema centralizza<strong>to</strong><br />
Client-Server, come accade per il più accura<strong>to</strong> NTP 10 , ma <strong>un</strong> sistema<br />
basa<strong>to</strong> <strong>su</strong>lla conversione <strong>di</strong> TimeSpan relativi, simile a quan<strong>to</strong> avviene nella<br />
la conversione <strong>di</strong> orari provenienti da fusi orari <strong>di</strong>fferenti (Figura 2.7 e<br />
Figura 2.8).<br />
Figura 2.7: I <strong>Peer</strong> A e B inviano il proprio TimeStamp a C, che ne memorizza<br />
il TimeSpan rispet<strong>to</strong> al proprio<br />
Ques<strong>to</strong> sistema ri<strong>su</strong>lta essere sogget<strong>to</strong> a problemi derivanti dalla variazione<br />
<strong>di</strong> latenza (Jitter) tra i <strong>di</strong>versi <strong>Peer</strong>: i delta sono infatti destinati a <strong>su</strong>bire<br />
oscillazioni ad ogni aggiornamen<strong>to</strong>, rendendo la stima temporale piut<strong>to</strong>s<strong>to</strong><br />
approssimativa.<br />
L’accuratezza richiesta nelle applicazioni real-time, specialmente nelle situazioni<br />
concorrenziali, viene qui mitigata dal sistema implementa<strong>to</strong> nel Modulo<br />
SharedComponents (sezione 2.4): Grazie a quest’ultimo non si possono presentare<br />
casi <strong>di</strong> inconsistenza dello sta<strong>to</strong> <strong>di</strong> gioco dovuti al margine <strong>di</strong> errore<br />
10 Network Time Pro<strong>to</strong>col
30 CAPITOLO 2. ARCHITETTURA SOFTWARE<br />
Figura 2.8: Quando arriva <strong>un</strong> comando o <strong>un</strong> even<strong>to</strong> temporizza<strong>to</strong> dal <strong>Peer</strong><br />
A secondo il <strong>su</strong>o sistema <strong>di</strong> riferimen<strong>to</strong>, al <strong>Peer</strong> C, quest’ultimo converte il<br />
TimeStamp secondo il delta precedentemente memorizza<strong>to</strong><br />
temporale relativamente eleva<strong>to</strong>, poichè situazioni temporalmente sensibili<br />
(ad esempio <strong>un</strong>a collisione con <strong>un</strong> proiettile) per le quali due peer mo<strong>di</strong>ficano<br />
la stessa risorsa sono opport<strong>un</strong>amente vincolate dal modulo in questione:<br />
l’assenza <strong>di</strong> <strong>un</strong> qualche tipo <strong>di</strong> sincronizzazione temporale (4), anche se non<br />
impatta <strong>su</strong>lla consistenza dello sta<strong>to</strong> <strong>di</strong> gioco, tende a penalizzare notevolmente<br />
l’esperienza <strong>di</strong> gioco dei <strong>Peer</strong> con alta latenza (si veda Figura 2.28 ed<br />
il capi<strong>to</strong>lo 4).<br />
2.4 Modulo SharedComponents<br />
Ques<strong>to</strong> modulo fornisce la base per il Data Layer, ed è completamente<br />
<strong>di</strong>saccoppia<strong>to</strong> dai Layer precedenti (NET e P2P): si presenta come <strong>un</strong> piccolo<br />
Framework de<strong>di</strong>ca<strong>to</strong> alla rappresentazione <strong>di</strong> <strong>un</strong>a sorta <strong>di</strong> “memoria” <strong>di</strong> al<strong>to</strong><br />
livello <strong>su</strong>lla quale memorizzare lo sta<strong>to</strong> <strong>di</strong> gioco (Figura 2.9), riprendendo in<br />
parte l’idea delle Distributed Hash Table (DHT).<br />
Si basa <strong>su</strong>l concet<strong>to</strong> <strong>di</strong> componente, inteso come il minimo elemen<strong>to</strong> in<br />
grado <strong>di</strong> apportare informazione <strong>su</strong>llo sta<strong>to</strong> <strong>di</strong> gioco:
2.4. MODULO SHAREDCOMPONENTS 31<br />
Il p<strong>un</strong>teggio <strong>di</strong> <strong>un</strong> gioca<strong>to</strong>re, ad esempio, può essere vis<strong>to</strong> come <strong>un</strong> componente,<br />
così come la posizione del <strong>su</strong>o personaggio all’interno dell’ambiente <strong>di</strong><br />
gioco.<br />
La stessa posizione, a <strong>su</strong>a volta è composta da 3 sot<strong>to</strong>-componenti (X, Y e<br />
Z ) secondo il Composite Pattern 11<br />
I componenti che riescono a rappresentare informazioni a<strong>to</strong>miche, senza<br />
doversi appoggiare a sot<strong>to</strong>-componenti, sono da considerarsi “leaf”, e sono<br />
tipicamente quei componenti che emulano variabili Value Type (ad esempio<br />
il componenti “Int” , “Float” o “String”).<br />
Tutti gli altri componenti (come app<strong>un</strong><strong>to</strong> la posizione del personaggio, che<br />
sarà concretizzata da <strong>un</strong> componente <strong>di</strong> tipo “Vec<strong>to</strong>r3”) sono aggregati, <strong>di</strong>retti<br />
o in<strong>di</strong>retti, <strong>di</strong> quest’ultimi.<br />
Ogni componente soggiace a precise regole che ne consen<strong>to</strong>no <strong>un</strong>a facile<br />
gestione non solo all’interno del modulo stesso, ma specialmente se quest’ultimo<br />
viene utilizza<strong>to</strong> come Data Layer all’interno <strong>di</strong> <strong>un</strong>’applicazione <strong>di</strong><br />
rete:<br />
• Ogni componente (parent) può essere compos<strong>to</strong> da altri componenti<br />
(child)<br />
• Ogni componente deve essere genera<strong>to</strong> da <strong>un</strong> apposi<strong>to</strong> Fac<strong>to</strong>ry 12 (identifica<strong>to</strong><br />
da <strong>un</strong> nome), e non può essere istanzia<strong>to</strong> in modo in<strong>di</strong>pendente.<br />
• Ogni componente è identifica<strong>to</strong> da <strong>un</strong> ID “globale” genera<strong>to</strong> dallo stesso<br />
Fac<strong>to</strong>ry al momen<strong>to</strong> della creazione.<br />
11 Uno dei Pattern fondamentali defini<strong>to</strong> dalla gang of four caratterizza<strong>to</strong> dalla definizione<br />
<strong>di</strong> <strong>un</strong> ogget<strong>to</strong> me<strong>di</strong>ante la composizione <strong>di</strong> altri oggetti (a formare <strong>un</strong>a struttura ad<br />
albero).<br />
12 Secondo l’omonimo pattern creazionale, con Fac<strong>to</strong>ry si intende <strong>un</strong> elemen<strong>to</strong> che<br />
incap<strong>su</strong>la al <strong>su</strong>o interno i processi coinvolti nella creazione <strong>di</strong> oggetti.
32 CAPITOLO 2. ARCHITETTURA SOFTWARE<br />
• Ogni componente può avere <strong>un</strong> ID “locale”, se child <strong>di</strong> <strong>un</strong> parent, che<br />
ne identifica la chiave con la quale il parent accederà al child.<br />
• Ogni componente appartiene ad <strong>un</strong> “Type” che ne identifica il tipo<br />
(“Int”, “Float” ,“String” , “Vec<strong>to</strong>r3” , “Object3D”, etc)<br />
• Ogni componente ha <strong>un</strong> valore serializzabile.<br />
• Ogni componente è caratterizza<strong>to</strong> da <strong>un</strong> TimeStamp <strong>di</strong> creazione/mo<strong>di</strong>fica<br />
In ques<strong>to</strong> modo è possibile modellare qualsiasi tipo <strong>di</strong> informazione, non<br />
solo dati relativi agli elementi <strong>di</strong> gioco, ma anche eventi, messaggi e sot<strong>to</strong>stati,<br />
ed identificarla quin<strong>di</strong> <strong>un</strong>ivocamente.<br />
Figura 2.9: Schema dei concetti esposti dal modulo SharedCompontes. I<br />
componenti verde chiaro rappresentano i componenti generati dal Fac<strong>to</strong>ry A,<br />
mentre i componenti verde scuro quelli generati da altri Fac<strong>to</strong>ry.<br />
Il Fac<strong>to</strong>ry <strong>di</strong>spone <strong>di</strong> <strong>di</strong>versi sistemi <strong>di</strong> creazione <strong>di</strong> Componenti:<br />
Il primo, quello <strong>di</strong>ret<strong>to</strong>, istanzia <strong>un</strong> ogget<strong>to</strong> componente e lo “marchia” come
2.4. MODULO SHAREDCOMPONENTS 33<br />
appartenente al proprio Manager. Ques<strong>to</strong> sistema viene utilizza<strong>to</strong> quando da<br />
<strong>un</strong> Layer esterno si vuole creare <strong>un</strong> nuovo componente all’interno del proprio<br />
contes<strong>to</strong>, specificandone solo il tipo ed eventualmente il valore <strong>di</strong> default.<br />
Il secondo invece viene utilizza<strong>to</strong> per istanziare “copie” <strong>di</strong> componenti appartenenti<br />
ad altri Fac<strong>to</strong>ry, eventualmente associati ad altri <strong>Peer</strong> (associazione<br />
che verrà implementata nel prossimo Layer Logic): il componente così crea<strong>to</strong><br />
non sarà <strong>di</strong> proprietà del Fac<strong>to</strong>ry, e non sarà “marchia<strong>to</strong>” come tale, dal<br />
momen<strong>to</strong> che possiede già l’identificativo assegna<strong>to</strong>gli dal Fac<strong>to</strong>ry originale.<br />
Il terzo permette <strong>di</strong> aggi<strong>un</strong>gere <strong>un</strong> generico componente come “sot<strong>to</strong>-componente”<br />
<strong>di</strong> <strong>un</strong> componente già esistente all’interno del contes<strong>to</strong>.<br />
E’ importante notare quin<strong>di</strong> come, all’interno del modulo SharedComponents,<br />
la lista dei componenti non sia popolata necessariamente da componenti<br />
generati dal “proprio” Fac<strong>to</strong>ry.<br />
Se ad esempio si vogliono modellare le informazioni che caratterizzano <strong>un</strong><br />
ogget<strong>to</strong> tri<strong>di</strong>mensionale, si possono utilizzare i seguenti componenti secondo<br />
la gerarchia proposta in Figura 2.10:<br />
Il componente <strong>di</strong> tipo Object3D è caratterizza<strong>to</strong> da due sot<strong>to</strong>-componenti,<br />
rispettivamente identificati dal LocalID “Position” e “Rotation” (non è sta<strong>to</strong><br />
inseri<strong>to</strong> <strong>un</strong> componente relativo al valore <strong>di</strong> Scaling dell’ogget<strong>to</strong> perché è <strong>un</strong><br />
parametro lega<strong>to</strong> maggiormente al Layer VIEW ed eventualmente può essere<br />
com<strong>un</strong>que incluso estendendo ques<strong>to</strong> componente). Entrambi sono componenti<br />
<strong>di</strong> tipo Vec<strong>to</strong>r3 che, come illustra<strong>to</strong> precedentemente, è compos<strong>to</strong> a <strong>su</strong>a<br />
volta dai componenti <strong>di</strong> tipo Float, “X ”,“Y ” e“Z ”.<br />
Un componente non “leaf” viene considera<strong>to</strong> “ready” solo quando tutti<br />
i <strong>su</strong>oi componenti sono stati istanziati e ri<strong>su</strong>ltano “ready” a loro volta: <strong>un</strong><br />
Object3D, quin<strong>di</strong>, non sarà considera<strong>to</strong> “ready” fintan<strong>to</strong> che non lo saranno<br />
i <strong>su</strong>oi due Vec<strong>to</strong>r3 “Position” e “Rotation”;
34 CAPITOLO 2. ARCHITETTURA SOFTWARE<br />
Figura 2.10: tassonomia dei sot<strong>to</strong>-componenti che, aggregati, realizzano <strong>un</strong><br />
componente <strong>di</strong> tipo Object3D<br />
Questa “frammentazione” dell’informazione ri<strong>su</strong>lta mol<strong>to</strong> comoda specialmente<br />
se la si pensa contestualizzata all’interno <strong>di</strong> <strong>un</strong>’applicazione <strong>di</strong> rete,<br />
come emergerà nel prossimo capi<strong>to</strong>lo.<br />
I coman<strong>di</strong> principali a carico <strong>di</strong> ques<strong>to</strong> Layer sono:<br />
• CreateComponent: Crea <strong>un</strong> componente tramite il Fac<strong>to</strong>ry utilizzando<br />
il sistema <strong>di</strong> “copia” <strong>di</strong> componenti appartenenti ad altri Fac<strong>to</strong>ry, in<br />
quan<strong>to</strong> si pre<strong>su</strong>me che, dal momen<strong>to</strong> che tale comando è gi<strong>un</strong><strong>to</strong> da<br />
<strong>un</strong>’altro contes<strong>to</strong>, il componente da creare appartenga a quest’ultimo.<br />
• UpdateComponent: Aggiorna <strong>un</strong> componente secondo il valore serializza<strong>to</strong><br />
contenu<strong>to</strong> come parametro<br />
• DestroyComponent: Distrugge <strong>un</strong> componente.<br />
• ActivateComponent: Attiva, cioè mo<strong>di</strong>fica l’attribu<strong>to</strong> “ready” <strong>di</strong> <strong>un</strong><br />
componente.
2.5. LAYER LOGIC 35<br />
È presente, inoltre, <strong>un</strong> sistema <strong>di</strong> Messaging tra i <strong>di</strong>versi componenti:<br />
ogni componente infatti può implementare il me<strong>to</strong>do ExecMessage(), e, a<br />
seconda <strong>di</strong> quan<strong>to</strong> riporta<strong>to</strong> come parametro, comportarsi <strong>di</strong> conseguenza.<br />
2.5 Layer Logic<br />
In ques<strong>to</strong> Layer prende forma il contes<strong>to</strong> logico: legando il concet<strong>to</strong> <strong>di</strong><br />
<strong>Peer</strong> espos<strong>to</strong> dal Layer P2P con il Fac<strong>to</strong>ry del DataLayer espos<strong>to</strong> dal modulo<br />
SharedComponents nasce l’idea <strong>di</strong> <strong>un</strong> contes<strong>to</strong> <strong>di</strong> dati appartenenti al singolo<br />
<strong>Peer</strong>.<br />
Ogni componente crea<strong>to</strong> <strong>di</strong>rettamente dal Fac<strong>to</strong>ry ri<strong>su</strong>lterà “lega<strong>to</strong>” al relativo<br />
<strong>Peer</strong>, e <strong>di</strong> conseguenza potrà essere mo<strong>di</strong>fica<strong>to</strong> o <strong>di</strong>strut<strong>to</strong> solo da<br />
quest’ultimo.<br />
A ques<strong>to</strong> Layer, inoltre, è delegata <strong>un</strong>’altra f<strong>un</strong>zione fondamentale, senza<br />
la quale l’utilità del modulo P2P e del modulo SharedComponents sarebbe fine<br />
a se stessa: rimane in ascol<strong>to</strong> delle notifiche (creazione/mo<strong>di</strong>fica/<strong>di</strong>struzione<br />
componenti) in uscita dal modulo SharedComponents, preoccupandosi poi <strong>di</strong><br />
inoltrarle al Layer P2P che, me<strong>di</strong>ante il Layer NET, le segnalerà a <strong>su</strong>a volta<br />
a tutti i <strong>Peer</strong> conosciuti.<br />
Ques<strong>to</strong> porta sostanzialmente ad avere lo stesso DataLayer (cioè popola<strong>to</strong><br />
dagli gli stessi componenti) <strong>su</strong> ogni <strong>Peer</strong>, e le regole che definiscono i permessi<br />
<strong>di</strong> creazione/mo<strong>di</strong>fica/<strong>di</strong>struzione garantiscono la consistenza, dal momen<strong>to</strong><br />
che ogni componente può cambiare <strong>di</strong> sta<strong>to</strong> solo tramite il <strong>su</strong>o <strong>Peer</strong> ’Owner’.<br />
Quando <strong>un</strong> <strong>Peer</strong> A si connette ad <strong>un</strong> <strong>Peer</strong> B, dopo le fasi <strong>di</strong> HandShaking<br />
(Layer NET) e <strong>di</strong> scambio NetID (Layer P2P), A invierà preventivamente a<br />
B i componenti serializzati <strong>di</strong> <strong>su</strong>a proprietà presenti nel proprio SharedComponents,<br />
e B farà lo stesso.<br />
Quando i componenti serializzati <strong>di</strong> A arrivano a B, il Fac<strong>to</strong>ry <strong>di</strong> quest’ultimo<br />
creerà <strong>di</strong> fat<strong>to</strong> <strong>un</strong>a “copia” del Data Layer <strong>di</strong> A (Object Replication).
36 CAPITOLO 2. ARCHITETTURA SOFTWARE<br />
Figura 2.11: Due Player che non si sono ancora connessi tra loro. Notare<br />
come il Layer Logic utilizzi il Layer P2P ed il modulo SharedComponents<br />
per concretizzare il “contes<strong>to</strong>” logico. Notare inoltre come il contenu<strong>to</strong> del<br />
Data Layer sia <strong>di</strong>fferente tra i due Player.<br />
Figura 2.12: Layer NET: I due Player si connet<strong>to</strong>no e avviano la fase <strong>di</strong><br />
HandShaking.<br />
Figura 2.13: Layer P2P: I due Player si scambiano i NetID conosciuti.
2.5. LAYER LOGIC 37<br />
Figura 2.14: Layer Logic: I due Player si scambiano il contenu<strong>to</strong> corrente dei<br />
propri Data Layer. Notare come, conclusa questa fase, il contenu<strong>to</strong> dei due<br />
Data Layer ri<strong>su</strong>lti identico.<br />
Una volta che i due Player si sono scambiati il contenu<strong>to</strong> dei rispettivi<br />
Data Layer, sono pronti per inviarsi messaggi relativi alla logica <strong>di</strong> gioco.<br />
Ad esempio, quando il personaggio controlla<strong>to</strong> dal Player A, connesso ad<br />
<strong>un</strong> Player B, spara <strong>un</strong> proiettile, crea <strong>di</strong> fat<strong>to</strong> <strong>un</strong> componente logico <strong>di</strong> tipo<br />
“Bullet”. Il componente “Bullet” estende MovingObject3D, che a <strong>su</strong>a volta<br />
estende il componente Object3D.<br />
MovingObject3D ha gli stessi sot<strong>to</strong>-componenti <strong>di</strong> Object3D (Vec<strong>to</strong>r3 Position<br />
e Vec<strong>to</strong>r3 Rotation), con l’aggi<strong>un</strong>ta <strong>di</strong> altri due nuovi sot<strong>to</strong>-componenti:<br />
Un Vec<strong>to</strong>r3 NextPosition ed <strong>un</strong> String NextTimeStamp. Il primo (NextPosition)<br />
in<strong>di</strong>ca la posizione dell’ogget<strong>to</strong> 3D attesa per l’istante <strong>di</strong> tempo espresso<br />
dal secondo (NextTimeStamp).<br />
La nuova istanza del componente <strong>di</strong> tipo Bullet viene creata all’interno del<br />
contes<strong>to</strong> logico <strong>di</strong> A, attraverso il <strong>su</strong>o Fac<strong>to</strong>ry e deposita<strong>to</strong> nel proprio Data<br />
Layer.<br />
In ques<strong>to</strong> momen<strong>to</strong> i Data Layer <strong>di</strong> A e B sono desincronizzati, dal momen<strong>to</strong><br />
che l’istanza del componente Bullet è presente solo nel Data Layer <strong>di</strong> A.<br />
Quando avviene <strong>un</strong>a creazione <strong>di</strong>retta <strong>di</strong> ques<strong>to</strong> tipo, il modulo SharedComponents<br />
notifica ai Layer in ascol<strong>to</strong> (il Layer Logic, ad esempio) l’avvenuta<br />
creazione del nuovo componente.
38 CAPITOLO 2. ARCHITETTURA SOFTWARE<br />
Il Layer Logic quin<strong>di</strong> esegue <strong>un</strong> BroadCast esteso a tutti i <strong>Peer</strong> conosciuti<br />
inviando il comando CreateComponent appositamente parametrizza<strong>to</strong> per la<br />
descrizione del componente Bullet.<br />
Ogni comando <strong>di</strong> ques<strong>to</strong> Layer viene marca<strong>to</strong> con l’attuale TimeStamp<br />
espos<strong>to</strong> dal sot<strong>to</strong>-modulo Time del Layer P2P.<br />
In ques<strong>to</strong> modo si possono implementare controlli basati <strong>su</strong>l tempo: quando<br />
<strong>un</strong> comando gesti<strong>to</strong> dal Layer Logic viene ricevu<strong>to</strong> da <strong>un</strong> Nodo, ques<strong>to</strong> viene<br />
inseri<strong>to</strong> in <strong>un</strong>a lista <strong>di</strong> esecuzione, ed esegui<strong>to</strong> solo all’iterazione <strong>su</strong>ccessiva, o,<br />
nel caso <strong>di</strong> coman<strong>di</strong> esplicitamente temporizzati, solo quando il TimeStamp<br />
del <strong>Peer</strong> destinatario sarà maggiore o uguale a quello presente all’interno del<br />
comando stesso (opport<strong>un</strong>amente converti<strong>to</strong> in modo au<strong>to</strong>matico dal sot<strong>to</strong>modulo<br />
Time del Layer P2P).<br />
Ques<strong>to</strong> tipo <strong>di</strong> controlli viene effettua<strong>to</strong> in <strong>un</strong> sot<strong>to</strong>-modulo compos<strong>to</strong> da<br />
<strong>un</strong>a serie <strong>di</strong> Filtri che intervengono tra la ricezione del comando e la <strong>su</strong>a<br />
esecuzione. Uno <strong>di</strong> questi filtri controlla l’Obsolescence dei coman<strong>di</strong> UpdateComponent:<br />
Può capitare infatti <strong>di</strong> ricevere due messaggi UpdateComponent <strong>di</strong> <strong>un</strong>o stesso<br />
componente riportanti valori <strong>di</strong>fferenti. In ques<strong>to</strong> caso viene confronta<strong>to</strong><br />
il TimeStamp che accompagna entrambi i messaggi, ed elimina<strong>to</strong> l’Update-<br />
Component temporalmente più vecchio.<br />
Escludendo situazioni <strong>di</strong> estrema congestione, si tratta com<strong>un</strong>que <strong>di</strong> <strong>un</strong>’evenienza<br />
abbastanza rara, in quan<strong>to</strong> due UpdateComponent <strong>di</strong> <strong>un</strong>o stesso<br />
componente possono essere inviati solo dal medesimo <strong>Peer</strong>, e quest’ultimo tipicamente<br />
effettua aggiornamenti <strong>di</strong> componente con <strong>un</strong>a frequenza più bassa<br />
rispet<strong>to</strong> a quella <strong>di</strong> esecuzione.<br />
Ques<strong>to</strong> Layer inoltre mette a <strong>di</strong>sposizione <strong>un</strong>’interfaccia che permette <strong>di</strong><br />
inviare messaggi sia ai propri componenti che a quelli appartenenti agli altri<br />
<strong>Peer</strong>, utilizzando il sistema <strong>di</strong> Messaging del modulo SharedComponents.
2.6. LAYER VIEW 39<br />
2.6 Layer View<br />
A causa <strong>di</strong> alc<strong>un</strong>e scelte implementative, esposte nel prossimo capi<strong>to</strong>lo,<br />
il Layer View si presenta come <strong>un</strong> insieme <strong>di</strong> moduli che gestiscono i <strong>di</strong>versi<br />
aspetti <strong>di</strong> gioco non ancora affrontati nei Layer sot<strong>to</strong>stanti.<br />
Qui risiede il sot<strong>to</strong>-modulo Renderer, fondamentale per la rappresentazione<br />
e vi<strong>su</strong>alizzazione dello sta<strong>to</strong> <strong>di</strong> gioco; ma vi si possono anche trovare<br />
sot<strong>to</strong>-moduli non prettamente de<strong>di</strong>cati all’aspet<strong>to</strong> visivo: il modulo Au<strong>di</strong>o,<br />
il modulo che gestisce l’Input utente, il modulo che gestisce i movimenti, le<br />
animazioni, la fisica e le collisioni.<br />
Si tratta <strong>di</strong> <strong>un</strong>o stra<strong>to</strong> piut<strong>to</strong>s<strong>to</strong> eterogeneo, quin<strong>di</strong>, che deve il <strong>su</strong>o nome più<br />
alle similitu<strong>di</strong>ni con il Layer View del pattern MVC, che alla <strong>su</strong>a f<strong>un</strong>zione<br />
vera e propria.<br />
Così come il Layer Logic introduceva il concet<strong>to</strong> <strong>di</strong> “Contes<strong>to</strong> logico”, ques<strong>to</strong><br />
Layer introduce il concet<strong>to</strong> <strong>di</strong> “Contes<strong>to</strong> vi<strong>su</strong>ale” concretizza<strong>to</strong> in quello che,<br />
nell’architettura <strong>di</strong> <strong>un</strong> <strong>Game</strong> Engine, viene com<strong>un</strong>emente chiama<strong>to</strong> Scene-<br />
Graph.<br />
Con SceneGraph si intende quella struttura dati che contiene i riferimenti a<br />
tutti gli elementi grafici presenti nell’ambiente <strong>di</strong> gioco (Scene).<br />
Può anche essere implementata come Array o Plain List, ma tipicamente viene<br />
realizzata me<strong>di</strong>ante <strong>un</strong>a struttura ad albero, dal momen<strong>to</strong> che, quest’ultima,<br />
<strong>to</strong>rna particolarmente comoda per la propagazione delle trasformazioni<br />
geometriche per tutti quegli elementi grafici che in qualche modo sono legati<br />
tra loro da <strong>un</strong>a precisa gerarchia.<br />
Ques<strong>to</strong> tipo <strong>di</strong> struttura, inoltre, è perfetta per au<strong>to</strong>matizzare il processo<br />
<strong>di</strong> sincronizzazione tra il DataLayer, espos<strong>to</strong> dal Layer Logic, ed il Layer<br />
View.<br />
Tale processo “legge” il contenu<strong>to</strong> del Data Layer e ci costruisce sopra la<br />
scena 3D a seconda dei componenti presenti in esso.<br />
Chiaramente non tutti i componenti si possono convertire au<strong>to</strong>maticamente<br />
in oggetti grafici. Un componente <strong>di</strong> tipo Int, ad esempio, non può
40 CAPITOLO 2. ARCHITETTURA SOFTWARE<br />
essere converti<strong>to</strong> <strong>di</strong>rettamente, dal momen<strong>to</strong> che si tratta <strong>di</strong> <strong>un</strong> tipo <strong>di</strong> variabile<br />
troppo generico, e non è possibile quin<strong>di</strong> accostarlo sempre ad <strong>un</strong> <strong>un</strong>ico<br />
tipo <strong>di</strong> elemen<strong>to</strong> grafico: in <strong>un</strong> FPS, sia il valore dell’HP 13 che il numero <strong>di</strong><br />
m<strong>un</strong>izioni <strong>di</strong>sponibili sono rappresentati nel Data Layer attraverso componenti<br />
<strong>di</strong> tipo Int, ma a livello grafico possono essere vi<strong>su</strong>alizzati in maniera<br />
del tut<strong>to</strong> <strong>di</strong>fferente tra loro.<br />
Quin<strong>di</strong>, per ques<strong>to</strong> tipo <strong>di</strong> componenti, è necessario creare manualmente gli<br />
elementi vi<strong>su</strong>ali ed implementare <strong>un</strong>a logica <strong>di</strong> sincronizzazione con il rispettivo<br />
componente del Data Layer (<strong>di</strong> soli<strong>to</strong> me<strong>di</strong>ante sistemi che utilizzano<br />
l’Observer Pattern).<br />
Esis<strong>to</strong>no però alc<strong>un</strong>i componenti che possono essere inseriti in <strong>un</strong> logica<br />
<strong>di</strong> au<strong>to</strong>mazione <strong>di</strong> tale processo. È il caso dei componenti <strong>di</strong> tipo Object3D<br />
e dei <strong>su</strong>oi derivati.<br />
Un componente <strong>di</strong> tipo Object3D verrà trasforma<strong>to</strong> in <strong>un</strong> ogget<strong>to</strong> grafico<br />
<strong>di</strong> tipo Object3D. Allo stesso modo <strong>un</strong> componente <strong>di</strong> tipo Bullet (si veda<br />
esempi precedenti) verrà trasforma<strong>to</strong> in <strong>un</strong> ogget<strong>to</strong> grafico <strong>di</strong> tipo Bullet.<br />
In generale ogni componente tagga<strong>to</strong>, a livello <strong>di</strong> definizione <strong>di</strong> classe, con<br />
il tag “View”, quando esiste <strong>un</strong>a corrispondenza 1-a-1 tra componente Data<br />
Layer e classe View, soggiace a ques<strong>to</strong> tipo <strong>di</strong> au<strong>to</strong>matismo: basterà infatti<br />
creare <strong>un</strong> componente logico per vederlo apparire <strong>su</strong> schermo all’iterazione<br />
<strong>su</strong>ccessiva (Figura 2.15).<br />
Il Layer View non si limita solo a rappresentare il contenu<strong>to</strong> del Layer<br />
Logic e del Data Layer, operando quin<strong>di</strong> in sola lettura, ma, anzi, è da qui<br />
che tipicamente vengono lanciate le operazioni <strong>di</strong> scrittura e aggiornamen<strong>to</strong><br />
dei componenti logici:<br />
Ad ogni elemen<strong>to</strong> grafico genera<strong>to</strong> au<strong>to</strong>maticamente dal contes<strong>to</strong> vi<strong>su</strong>ale, viene<br />
“applicata” <strong>un</strong>’istanza <strong>di</strong> <strong>un</strong>a classe, estesa da “ComponentScript” che ne<br />
definisce il comportamen<strong>to</strong>.<br />
13 Health Point, p<strong>un</strong>ti vita / p<strong>un</strong>ti ferita. Unità <strong>di</strong> mi<strong>su</strong>ra che rappresenta lo sta<strong>to</strong> <strong>di</strong><br />
salute o il danno <strong>su</strong>bi<strong>to</strong> dal protagonista in molte tipologie <strong>di</strong> gioco
2.6. LAYER VIEW 41<br />
Figura 2.15: Il contes<strong>to</strong> vi<strong>su</strong>ale istanzia au<strong>to</strong>maticamente elementi grafici in<br />
relazione ai componenti presenti nel Data Layer
42 CAPITOLO 2. ARCHITETTURA SOFTWARE<br />
“ComponentScript” è <strong>un</strong>a classe base per l’implementazione della logica e<br />
delle <strong>di</strong>namiche <strong>di</strong> aggiornamen<strong>to</strong> dei componenti; a <strong>su</strong>a volta ere<strong>di</strong>ta dalla<br />
classe Behavior, e permette <strong>di</strong> definire le classiche fasi <strong>di</strong> “Inizializzazione”,<br />
“Aggiornamen<strong>to</strong>” e “Distruzione”. La <strong>su</strong>a peculiarità è quella <strong>di</strong> consentire<br />
<strong>un</strong>a separazione formale <strong>di</strong> quelle quelle che sono le azioni e gli aggiornamenti<br />
da eseguire in ogni singola fase a seconda che si tratti <strong>di</strong> <strong>un</strong> componente<br />
appartenente al proprio <strong>Peer</strong> o meno.<br />
Ad ogni “ComponentScript” viene associa<strong>to</strong> il GlobalID del componente <strong>di</strong><br />
cui si vuole definirne la logica <strong>di</strong> aggiornamen<strong>to</strong>.<br />
Ad esempio, Il componente logico <strong>di</strong> tipo “Character” (esteso da “Object3D”)<br />
identifica lo sta<strong>to</strong> del personaggio comanda<strong>to</strong> dal gioca<strong>to</strong>re. Ques<strong>to</strong><br />
viene tradot<strong>to</strong> au<strong>to</strong>maticamente nel rispettivo elemen<strong>to</strong> grafico, ma le<br />
politiche <strong>di</strong> aggiornamen<strong>to</strong> e sincronizzazione vengono definite dalla classe<br />
“CharacterScript”, estesa app<strong>un</strong><strong>to</strong> da “ComponentScript”.<br />
Qui, a seconda della proprietà del componente, CharacterScript esegue due<br />
me<strong>to</strong><strong>di</strong> <strong>di</strong>stinti. Per la fase <strong>di</strong> Update, ad esempio, il <strong>Peer</strong> “Owner” eseguirà<br />
il me<strong>to</strong>do “Update Writer”, mentre tutti gli altri eseguiranno il me<strong>to</strong>do “Update<br />
Reader”.<br />
Siano <strong>Peer</strong> “A” e <strong>Peer</strong> “B” due <strong>Peer</strong> connessi e sincronizzati a livello <strong>di</strong><br />
Data Layer, e sia il componente “A 12 ” <strong>di</strong> tipo “Character” il componente<br />
che identifica lo sta<strong>to</strong> relativo al personaggio controlla<strong>to</strong> dal Player “A”, il<br />
“ComponentScript” applica<strong>to</strong> alla relativa istanza grafica si dovrà comportare<br />
in modo <strong>di</strong>fferente nel contes<strong>to</strong> View dei due <strong>Peer</strong>.<br />
Su <strong>Peer</strong> “A”, infatti, dovrà aggiornare le coor<strong>di</strong>nate dell’ogget<strong>to</strong> 3D a seconda<br />
degli input del gioca<strong>to</strong>re (ad esempio, <strong>su</strong> pressione dei tasti <strong>di</strong>rezionali, o<br />
W-A-S-D, verrà mosso l’ogget<strong>to</strong>), e, a intervalli <strong>di</strong> tempo prefissati, scrivere<br />
le <strong>su</strong>e attuali coor<strong>di</strong>nate all’interno del rispettivo componente logico.<br />
Su <strong>Peer</strong> “B”, invece, dovrà leggere il valore delle coor<strong>di</strong>nate valorizzate nel rispettivo<br />
componente logico, ed interpolarle con le coor<strong>di</strong>nate dell’ogget<strong>to</strong>3D<br />
del contes<strong>to</strong> View (Figura 2.16).
2.7. ESEMPI PRATICI 43<br />
Figura 2.16: Il contes<strong>to</strong> vi<strong>su</strong>ale istanzia au<strong>to</strong>maticamente elementi grafici in<br />
relazione ai componenti presenti nel Data Layer<br />
L’aggiornamen<strong>to</strong> delle coor<strong>di</strong>nate del componente <strong>di</strong> tipo “Character”<br />
può essere effettua<strong>to</strong> in <strong>di</strong>versi mo<strong>di</strong>. Come evidenzia<strong>to</strong> nel capi<strong>to</strong>lo relativo<br />
al modulo SharedComponents, è possibile mo<strong>di</strong>ficare l’intero componente<br />
compos<strong>to</strong>, alc<strong>un</strong>i <strong>su</strong>oi sot<strong>to</strong>-componenti, o ad<strong>di</strong>rittura ogni singolo componente<br />
“leaf”: ad esempio, se il Character grafico si muove l<strong>un</strong>go la sola asse<br />
X, invece <strong>di</strong> aggiornare l’intero componente, conviene aggiornare il singolo<br />
componente “X” appartenente al <strong>su</strong>o sot<strong>to</strong>-componente “Position”.<br />
Allo stesso modo, se il Character grafico si muove senza ruotare, conviene<br />
aggiornare solo “Position” piut<strong>to</strong>s<strong>to</strong> che l’intero componente relativo al<br />
Character.<br />
2.7 Esempi pratici<br />
Al fine <strong>di</strong> completare la <strong>di</strong>ssertazione <strong>su</strong>ll’architettura software implementata,<br />
<strong>di</strong> segui<strong>to</strong> verranno proposti <strong>un</strong>a serie <strong>di</strong> casi che affrontano i problemi<br />
più com<strong>un</strong>i che ne derivano, e la relativa la soluzione adottata prendendo in<br />
esame ogni singolo Layer.
44 CAPITOLO 2. ARCHITETTURA SOFTWARE<br />
2.7.1 Movimen<strong>to</strong> <strong>di</strong> oggetti<br />
Il movimen<strong>to</strong> <strong>di</strong> elementi grafici in f<strong>un</strong>zione <strong>di</strong> <strong>un</strong> input utente è <strong>un</strong>o degli<br />
aspetti che contrad<strong>di</strong>stingue le applicazioni multime<strong>di</strong>ali interattive e, nella<br />
fattispecie, i videogiochi.<br />
Per ques<strong>to</strong> motivo è nata l’esigenza <strong>di</strong> estendere il componente “Object3D”,<br />
che <strong>di</strong> fat<strong>to</strong> è <strong>su</strong>fficiente per modellare le informazioni che caratterizzano<br />
oggetti 3D “statici”, in <strong>un</strong> apposi<strong>to</strong> componente “MovingObject3D” che consentisse<br />
la descrizione <strong>di</strong> <strong>un</strong> ogget<strong>to</strong> in movimen<strong>to</strong>.<br />
Ques<strong>to</strong> componente, come precedentemente illustra<strong>to</strong> nella sezione 2.5,<br />
è compos<strong>to</strong> dagli stessi sot<strong>to</strong>-componenti <strong>di</strong> “Object3D”, ma introduce due<br />
nuovi sot<strong>to</strong>-componenti: <strong>un</strong> componente <strong>di</strong> tipo Vec<strong>to</strong>r3 con LocalID “Next-<br />
Position” ed <strong>un</strong> componente <strong>di</strong> tipo String con LocalID “NextTimeStamp”.<br />
Il primo in<strong>di</strong>ca la posizione che as<strong>su</strong>merà l’ogget<strong>to</strong> all’istante <strong>di</strong> tempo in<strong>di</strong>ca<strong>to</strong><br />
dal secondo.<br />
E’ importante sot<strong>to</strong>lineare come, nel Layer View e nel Layer Logic (e Data<br />
Layer), le coor<strong>di</strong>nate della posizione <strong>di</strong> <strong>un</strong> ogget<strong>to</strong> in movimen<strong>to</strong> vengano<br />
campionate utilizzando intervalli <strong>di</strong> tempo <strong>di</strong>fferenti: nel Layer View si deve<br />
garantire l’illusione <strong>di</strong> movimen<strong>to</strong> “continuo”, e ques<strong>to</strong> avviene aggiornando<br />
ad ogni iterazione le coor<strong>di</strong>nate secondo <strong>un</strong> vet<strong>to</strong>re <strong>di</strong> “offset” calcola<strong>to</strong> in<br />
f<strong>un</strong>zione della velocità e del tempo trascorso tra il “frame” attuale e quello<br />
precedente. In quei casi in cui la velocità <strong>di</strong> movimen<strong>to</strong> è talmente alta da<br />
non consentire l’illusione <strong>di</strong> movimen<strong>to</strong>, spesso si interviene con effetti “Post<br />
Processing” quali l’“Onion Skinning” ed il “Motion Blur”.<br />
Nel Layer Logic invece la frequenza <strong>di</strong> aggiornamen<strong>to</strong> delle coor<strong>di</strong>nate<br />
può essere notevolmente più bassa, poiché le informazioni presenti nel Data<br />
Layer devono essere le minime in<strong>di</strong>spensabili a garantire la corretta interpretazione<br />
dello sta<strong>to</strong> <strong>di</strong> gioco <strong>su</strong> ogni <strong>Peer</strong>, astraendo, da <strong>un</strong>a parte, da quelle<br />
informazioni grafiche e decorative che non apportano cambiamenti sostanziali<br />
allo sta<strong>to</strong> <strong>di</strong> gioco, cercando, laddove possibile, <strong>di</strong> mantenere <strong>un</strong>a bassa
2.7. ESEMPI PRATICI 45<br />
frequenza <strong>di</strong> aggiornamen<strong>to</strong> (cioè intervalli <strong>di</strong> campionamen<strong>to</strong> relativamente<br />
l<strong>un</strong>ghi) dal momen<strong>to</strong> che questi devono essere ogni volta propagati <strong>su</strong> tutta<br />
la rete <strong>Peer</strong>-To-<strong>Peer</strong>, e dall’altra, da quelle informazioni che in qualche modo<br />
possono essere ricavate me<strong>di</strong>ante inferenza <strong>su</strong>lle informazioni presenti nel<br />
proprio Data Layer.<br />
Qui entrano in gioco sistemi <strong>di</strong> “pre<strong>di</strong>ction” e <strong>di</strong> interpolazione della posizione:<br />
il primo viene com<strong>un</strong>emente realizza<strong>to</strong> me<strong>di</strong>ante “Dead Reckoning”,<br />
cioè <strong>un</strong> algoritmo grazie al quale, utilizzando informazioni quali velocità e<br />
accelerazione, è possibile stimare la posizione che as<strong>su</strong>merà l’ogget<strong>to</strong> preso in<br />
esame al prossimo istante <strong>di</strong> tempo, conoscendo la posizione attuale o, ancora,<br />
stimare la posizione attuale conoscendo quella relativa all’istante <strong>di</strong> tempo<br />
precedente. Inversamente, è possibile ricavare la velocità <strong>di</strong> spostamen<strong>to</strong> (e<br />
quin<strong>di</strong> ogni singolo step da applicare la<strong>to</strong> View) se si è a conoscenza della<br />
posizione attuale e della posizione prevista ad <strong>un</strong> preciso prossimo istante <strong>di</strong><br />
tempo.<br />
Se si hanno a <strong>di</strong>sposizione questi dati è possibile applicarvi <strong>un</strong>’interpolazione<br />
in modo da ricavare gli step interme<strong>di</strong> tra la posizione all’istante <strong>di</strong><br />
tempo “Tn” e la posizione all’istante <strong>di</strong> tempo “Tn+1 ”. Questi step saranno<br />
più o meno ampi a seconda della velocità <strong>di</strong> spostamen<strong>to</strong> e dei millisecon<strong>di</strong><br />
trascorsi tra l’iterazione attuale e quella precedente.<br />
Le interpolazioni che vengono com<strong>un</strong>emente applicate sono l’interpolazione<br />
lineare e l’interpolazione spline. Per la prima sono <strong>su</strong>fficienti le informazioni<br />
che abbiamo deciso <strong>di</strong> includere nel componente MovingObject3D, anche se<br />
il ri<strong>su</strong>lta<strong>to</strong> non sempre sarà esteticamente apprezzabile , dal momen<strong>to</strong> che<br />
all’interno dello stesso intervallo il movimen<strong>to</strong> ri<strong>su</strong>lterà fluido, ma tra <strong>un</strong> intervallo<br />
e l’altro possono palesarsi repentini cambi <strong>di</strong> <strong>di</strong>rezione.<br />
Il secondo invece riduce ques<strong>to</strong> problema, ma necessita <strong>di</strong> maggiori informazioni<br />
(più p<strong>un</strong>ti interpolanti) e, in particolari tipi <strong>di</strong> movimen<strong>to</strong>, può presentare<br />
forti oscillazioni (fenomeno <strong>di</strong> Gibbs), <strong>di</strong>scostandosi quin<strong>di</strong> da quello<br />
che era il movimen<strong>to</strong> originale. Nel proget<strong>to</strong> <strong>di</strong> tesi si è scel<strong>to</strong> <strong>di</strong> utilizzare
46 CAPITOLO 2. ARCHITETTURA SOFTWARE<br />
l’interpolazione lineare.<br />
Per ridurre ulteriormente artefatti <strong>di</strong> ques<strong>to</strong> tipo, tale processo va esteso anche<br />
alla rotazione, utilizzando algoritmi interpolanti stu<strong>di</strong>ati appositamente<br />
per le rotazioni, come l’interpolazione sferica.<br />
Grazie al “Dead Reckoning”, quin<strong>di</strong>, si riduce la richiesta <strong>di</strong> banda per la<br />
notifica dei movimenti, ma contemporaneamente, dal momen<strong>to</strong> l’interpolazione<br />
viene effettuata dal Layer View <strong>di</strong> ogni singolo <strong>Peer</strong> in modo in<strong>di</strong>pendente,<br />
non viene garantita la consistenza dello sta<strong>to</strong> <strong>di</strong> gioco durante l’intera azione<br />
<strong>di</strong> movimen<strong>to</strong>, salvo la sincronizzazione apportata implicitamente dalla notifica<br />
dei singoli intervalli <strong>di</strong> tempo.<br />
Sorgono però i seguenti problemi:<br />
Quando <strong>un</strong> <strong>Peer</strong> “A” effettua il movimen<strong>to</strong> <strong>di</strong> <strong>un</strong> ogget<strong>to</strong> <strong>di</strong> <strong>su</strong>a appartenenza,<br />
<strong>di</strong>rettamente a carico del Layer View, ed invia, a precisi intervalli <strong>di</strong><br />
tempo, l’aggiornamen<strong>to</strong> del relativo componente logico al <strong>Peer</strong> “B” a lui connesso,<br />
<strong>su</strong>bentra <strong>un</strong> problema causa<strong>to</strong> dall’eventuale “Lag” tra “A” e “B”.<br />
L’aggiornamen<strong>to</strong> dello sta<strong>to</strong> del componente logico relativo all’ogget<strong>to</strong> in<br />
movimen<strong>to</strong>, arriverà a “B” dopo <strong>un</strong> cer<strong>to</strong> numero <strong>di</strong> millisecon<strong>di</strong> “N ”: significa<br />
che “B” inizierà il processo <strong>di</strong> movimen<strong>to</strong>, e quin<strong>di</strong> <strong>di</strong> interpolazione e<br />
“Dead Reckoning”, quando l’ogget<strong>to</strong> in “A” si è già sposta<strong>to</strong> <strong>di</strong> <strong>un</strong> vet<strong>to</strong>re<br />
pari alla velocità al millisecondo, moltiplicata per “N ”. Essendo com<strong>un</strong>e per<br />
entrambi il p<strong>un</strong><strong>to</strong> d’arrivo al medesimo istante <strong>di</strong> tempo, l’ogget<strong>to</strong> in “B”<br />
sarà costret<strong>to</strong> a muoversi più velocemente rispet<strong>to</strong> ad “A” per recuperare il<br />
ritardo accumula<strong>to</strong> con il Lag (Figura 2.17).<br />
Un altro problema frequente è caratterizza<strong>to</strong> da <strong>un</strong> fasti<strong>di</strong>oso effet<strong>to</strong> visivo<br />
che vede l’improvviso riposizionamen<strong>to</strong> dell’ogget<strong>to</strong> tra <strong>un</strong> istante <strong>di</strong><br />
aggiornamen<strong>to</strong> e quello <strong>su</strong>ccessivo, quando la posizione <strong>di</strong> destinazione prevista<br />
<strong>di</strong>fferisce da quella reale. Errori <strong>di</strong> arro<strong>to</strong>ndamen<strong>to</strong>, fat<strong>to</strong>ri non previsti<br />
(collisioni, attri<strong>to</strong>, etc) e desincronizzazioni temporali portano a ques<strong>to</strong> tipo<br />
<strong>di</strong> “Jumping” o <strong>di</strong> “Warping” (Figura 2.18 e Figura 2.19).<br />
Quando la <strong>di</strong>fferenza tra il p<strong>un</strong><strong>to</strong> <strong>di</strong> destinazione previs<strong>to</strong> e quello reale
2.7. ESEMPI PRATICI 47<br />
Figura 2.17: A T0 entrambi i <strong>Peer</strong> detengono <strong>un</strong>o sta<strong>to</strong> sincronizza<strong>to</strong>, e<br />
l’ogget<strong>to</strong> (sfera arancione) si trova alla medesima posizione.<br />
A T1 nel <strong>Peer</strong> A l’ogget<strong>to</strong> iniza a muoversi, ed invia la relativa notifica al<br />
<strong>Peer</strong> B.<br />
A T2 arriva la notifica al <strong>Peer</strong> B, che inizierà il proprio processo <strong>di</strong> movimen<strong>to</strong>.<br />
A T3 l’ogget<strong>to</strong> in A si trova più avanti rispet<strong>to</strong> alla controparte in B.<br />
A T4 l’ogget<strong>to</strong> in B deve muoversi più velocemente rispet<strong>to</strong> alla controparte<br />
in A, per compensare il ritardo.<br />
A T5 l’ogget<strong>to</strong> in A ha quasi raggi<strong>un</strong><strong>to</strong> il p<strong>un</strong><strong>to</strong> <strong>di</strong> destinazione.<br />
A T6, che coincide con l’istante <strong>di</strong> tempo previs<strong>to</strong> nella notifica <strong>di</strong> movimen<strong>to</strong>,<br />
entrambi gli oggetti sono gi<strong>un</strong>ti a destinazione.
48 CAPITOLO 2. ARCHITETTURA SOFTWARE<br />
Figura 2.18: Ad ogni “istantanea” dello sta<strong>to</strong> dell’ogget<strong>to</strong> si presenta <strong>un</strong>a <strong>di</strong>fferenza<br />
<strong>di</strong> posizione (Jump) tra quella prevista come p<strong>un</strong><strong>to</strong> <strong>di</strong> destinazione<br />
nella istantanea precedente e quella riportata come p<strong>un</strong><strong>to</strong> <strong>di</strong> partenza nell’istantanea<br />
<strong>su</strong>ccessiva. Le frecce ver<strong>di</strong> in<strong>di</strong>cano la <strong>di</strong>rezione, le sfere arancioni<br />
solide in<strong>di</strong>cano il p<strong>un</strong><strong>to</strong> <strong>di</strong> partenza mentre quelle semitrasparenti in<strong>di</strong>cano<br />
il p<strong>un</strong><strong>to</strong> <strong>di</strong> destinazione. I p<strong>un</strong>ti blu rappresentano gli step effettuati<br />
dall’ogget<strong>to</strong> grafico vero e proprio.
2.7. ESEMPI PRATICI 49<br />
Figura 2.19: Una soluzione potrebbe essere quella <strong>di</strong> ignorare il p<strong>un</strong><strong>to</strong> <strong>di</strong> partenza<br />
dell’istantanea <strong>su</strong>ccessiva quando la <strong>di</strong>stanza tra ques<strong>to</strong> ed il p<strong>un</strong><strong>to</strong> <strong>di</strong><br />
destinazione dell’istantanea precedente è al <strong>di</strong> sot<strong>to</strong> <strong>di</strong> <strong>un</strong>a certa soglia. Dal<br />
momen<strong>to</strong> che l’ogget<strong>to</strong> è in movimen<strong>to</strong> e lo sarà anche nella prossima istantanea,<br />
si può evitare <strong>di</strong> riposizionarlo <strong>su</strong>l p<strong>un</strong><strong>to</strong> <strong>di</strong> partenza, che causerebbe<br />
antiestetici artefatti <strong>di</strong> Warping, lasciando continuare la <strong>su</strong>a corsa verso il<br />
prossimo p<strong>un</strong><strong>to</strong> <strong>di</strong> destinazione, calcolata rispet<strong>to</strong> la <strong>su</strong>a attuale posizione.
50 CAPITOLO 2. ARCHITETTURA SOFTWARE<br />
è troppo elevata, ri<strong>su</strong>lta <strong>di</strong>fficile compensare l’offset <strong>di</strong> spostamen<strong>to</strong>, e contemporaneamente<br />
garantire <strong>un</strong> movimen<strong>to</strong> naturale e continuo.<br />
Una soluzione è quella <strong>di</strong> intervenire <strong>su</strong>lla frequenza <strong>di</strong> sincronizzazione, eseguendo<br />
aggiornamenti <strong>su</strong>l DataLayer (quin<strong>di</strong> propagati au<strong>to</strong>maticamente <strong>su</strong><br />
tutti i <strong>Peer</strong> connessi) “eccezionali”, fuori cioè dalla logica <strong>di</strong> aggiornamen<strong>to</strong><br />
perio<strong>di</strong>co ad intervalli <strong>di</strong> tempo prefissati.<br />
Ques<strong>to</strong> genere <strong>di</strong> aggiornamenti “forzati” viene attua<strong>to</strong> in quelle situazioni<br />
critiche nelle quali la probabilità che il p<strong>un</strong><strong>to</strong> <strong>di</strong> destinazione previs<strong>to</strong><br />
nell’istantanea precedente sia <strong>di</strong>verso da quello che si va a prefigurare è mol<strong>to</strong><br />
elevata: cambi repentini <strong>di</strong> <strong>di</strong>rezione, cambiamenti <strong>di</strong> velocità, previsioni <strong>di</strong><br />
eventuali collisioni imminenti, o lo s<strong>to</strong>p improvviso dell’ogget<strong>to</strong> in questione,<br />
ricadono nella casistica delle situazioni critiche più com<strong>un</strong>i (Figura 2.20 e<br />
Figura 2.21).<br />
Figura 2.20: Anche se si evita <strong>di</strong> riposizionare l’ogget<strong>to</strong> in movimen<strong>to</strong> nella<br />
posizione <strong>di</strong> partenza proposta dall’istantanea <strong>di</strong> turno, quando la <strong>di</strong>fferenza<br />
è troppo elevata tra questa e quella <strong>di</strong> destinazione prevista nell’istantanea<br />
precedente, ri<strong>su</strong>lta <strong>di</strong>fficile mantenere il movimen<strong>to</strong> costante e continuo.
2.7. ESEMPI PRATICI 51<br />
Figura 2.21: Una soluzione può essere quella <strong>di</strong> broadcastare <strong>un</strong>a o più istantanee<br />
ausiliarie in quelle situazioni critiche nelle quali è mol<strong>to</strong> probabile che<br />
la destinazione prevista non sia più valida.<br />
Ques<strong>to</strong> tipo <strong>di</strong> soluzioni si basano però <strong>su</strong>ll’ass<strong>un</strong>zione che il l’ogget<strong>to</strong><br />
in questione sia in movimen<strong>to</strong> e rimanga tale: quando l’ogget<strong>to</strong> termina il<br />
proprio movimen<strong>to</strong>, passando dallo sta<strong>to</strong> “Moving” a quello <strong>di</strong> “S<strong>to</strong>pped”, il<br />
palesarsi <strong>di</strong> artefatti <strong>di</strong> minore entità è inevitabile, dal momen<strong>to</strong> che la posizione<br />
riportata in <strong>un</strong>’istantanea <strong>di</strong> <strong>un</strong> ogget<strong>to</strong> ormai fermo non può essere<br />
ignorata, poiché rappresenta l’attuale sta<strong>to</strong> dell’ogget<strong>to</strong> e ques<strong>to</strong> può anche<br />
non <strong>su</strong>bire più mo<strong>di</strong>fiche fino a fine partita: se non si riposizionasse l’ogget<strong>to</strong><br />
alle coor<strong>di</strong>nate specificate come p<strong>un</strong><strong>to</strong> <strong>di</strong> partenza, ques<strong>to</strong> rimarrebbe fermo<br />
in <strong>un</strong>a posizione che, visti i problemi sopra elencati, probabilmente <strong>di</strong>fferirebbe<br />
da quan<strong>to</strong> riporta<strong>to</strong> nel DataLayer del <strong>Peer</strong> “Owner”.<br />
Rias<strong>su</strong>mendo, da<strong>to</strong> <strong>un</strong> ogget<strong>to</strong> 3D non statico, ques<strong>to</strong> viene mosso nel<br />
contes<strong>to</strong> View dal <strong>su</strong>o <strong>Peer</strong> “Owner”; il relativo “ComponentScript” aggiornerà<br />
perio<strong>di</strong>camente il componente logico del Data Layer a cui è associa<strong>to</strong>.<br />
Di conseguenza i <strong>Peer</strong> “non Owner” appartenenti alla Membership riceveran-
52 CAPITOLO 2. ARCHITETTURA SOFTWARE<br />
no <strong>un</strong> aggiornamen<strong>to</strong> perio<strong>di</strong>co che mo<strong>di</strong>ficherà au<strong>to</strong>maticamente lo sta<strong>to</strong> dei<br />
componenti <strong>su</strong>i loro Data Layer. Ques<strong>to</strong> si ripercuoterà <strong>su</strong>i rispettivi Layer<br />
View, che, attraverso i “ComponentScript” associati ai rispettivi oggetti grafici,<br />
ne mo<strong>di</strong>ficheranno le coor<strong>di</strong>nate secondo <strong>un</strong>a politica <strong>di</strong> Dead Reckoning<br />
(Figura 2.22).<br />
2.7.2 Collisione tra oggetti<br />
La collisione tra elementi grafici è <strong>un</strong> altro aspet<strong>to</strong> caratteristico delle<br />
<strong>di</strong>namiche presenti nei videogiochi. Non solo, è anche <strong>un</strong>o degli aspetti più<br />
sensibili e influenti <strong>su</strong>l flusso <strong>di</strong> gioco, poiché questi possono rappresentare<br />
<strong>un</strong>a <strong>di</strong>scriminante tra la vit<strong>to</strong>ria e la sconfitta <strong>di</strong> <strong>un</strong>a partita.<br />
Ogni collisione è tipicamente composta da due fasi:“Detection” e “Response”.<br />
La prima fase si occupa <strong>di</strong> testare la presenza <strong>di</strong> eventuali collisioni tra i<br />
<strong>di</strong>versi oggetti che compongono la scena 3D, mentre la seconda si occupa <strong>di</strong><br />
calcolare la risposta, in termini <strong>di</strong> movimen<strong>to</strong> e rotazione, che tali oggetti<br />
devono compiere a segui<strong>to</strong> <strong>di</strong> <strong>un</strong>a collisione.<br />
La “Collision Detection” solitamente opera <strong>su</strong> <strong>un</strong>’approssimazione <strong>di</strong> quelli<br />
che sono i volumi occupati dalla geometria degli oggetti 3D, e solo raramente<br />
<strong>di</strong>rettamente <strong>su</strong>lla geometria poligonale dei singoli modelli.<br />
Tra le approssimazioni più com<strong>un</strong>i vi sono le collisioni “Sphere-Sphere”,“Sphere-<br />
Box” e “Box-Box”.<br />
La “Sphere-Sphere” è tendenzialmente la meno precisa ma anche la più semplice<br />
da realizzare e computazionalmente meno cos<strong>to</strong>sa. È implementata me<strong>di</strong>ante<br />
<strong>un</strong> test <strong>su</strong>lla <strong>di</strong>stanza tri<strong>di</strong>mensionale tra i due oggetti (Figura 2.23).<br />
“Sphere-Box”, invece, prevede <strong>un</strong> test <strong>di</strong> intersezione tra <strong>un</strong>a sfera ed <strong>un</strong><br />
“Bo<strong>un</strong><strong>di</strong>ngBox”, cioè <strong>un</strong>’approssimazione del volume del modello tri<strong>di</strong>mensionale<br />
in <strong>un</strong> parallelepipedo, calcola<strong>to</strong> in base ai vertici estremi del modello<br />
stesso per ogni asse. Se il test viene esegui<strong>to</strong> <strong>su</strong> <strong>un</strong> “Axis-Aligned Bo<strong>un</strong><strong>di</strong>ng<br />
Box” (AABB, ovvero <strong>un</strong> Bo<strong>un</strong><strong>di</strong>ngBox non orienta<strong>to</strong>) continua ad essere poco<br />
cos<strong>to</strong>so e <strong>di</strong> semplice implementazione (Figura 2.24).
2.7. ESEMPI PRATICI 53<br />
Figura 2.22: T0: Il Player A, l’“Owner” sposta l’ogget<strong>to</strong> <strong>di</strong>rettamente a livello<br />
View, e tramite il relativo ComponentScript stima la prossima posizione.<br />
Di conseguenza aggiorna il rispettivo componente <strong>di</strong> tipo “MovingObject3D”<br />
T1: Au<strong>to</strong>maticamente viene propaga<strong>to</strong> l’aggiornamen<strong>to</strong> al Player B.<br />
T2: Il ComponentScript in B applica il Dead Reckoning <strong>su</strong>l valore riporta<strong>to</strong><br />
nel componente appena aggiorna<strong>to</strong>.
54 CAPITOLO 2. ARCHITETTURA SOFTWARE<br />
La “Box-Box” invece testa l’intersezione tra due “Bo<strong>un</strong><strong>di</strong>ngBox” (Figura 2.25).<br />
Figura 2.23: Sphere-Sphere<br />
Figura 2.24: Sphere-Box<br />
Esis<strong>to</strong>no inoltre altri tipi <strong>di</strong> approssimazione che introducono nuovi volumi<br />
geometrici come il “Cylinder” (anch’esso poco cos<strong>to</strong>so), o <strong>un</strong>a composizione<br />
<strong>di</strong> tali (Con due “Sphere” ed <strong>un</strong> “Cylinder” sia ha <strong>un</strong>a “Cap<strong>su</strong>le”, particolarmente<br />
in<strong>di</strong>cata per la rappresentazione <strong>di</strong> oggetti antropomorfi).<br />
La “Collision Response” viene eseguita utilizzando i dati ricavati nel processo<br />
<strong>di</strong> “Collision Detection”: oltre ad informazioni geometriche <strong>di</strong> base,<br />
come le coor<strong>di</strong>nate del p<strong>un</strong><strong>to</strong> <strong>di</strong> intersezione, la <strong>su</strong>rface od il poligono colpi<strong>to</strong><br />
ed il <strong>su</strong>o vet<strong>to</strong>re normale, possono essere utilizzate informazioni aggi<strong>un</strong>tive
2.7. ESEMPI PRATICI 55<br />
Figura 2.25: Box-Box<br />
utilizzate dall’Engine fisico, come il tipo <strong>di</strong> materiale colpi<strong>to</strong>, la “Bo<strong>un</strong>ciness”,<br />
la <strong>su</strong>a “Densità’ e la massa degli oggetti coinvolti nella collisione.<br />
Ci sono poi <strong>un</strong>a serie <strong>di</strong> ottimizzazioni che operano <strong>su</strong>i dati presenti nello<br />
“SceneGraph”, atte ad evitare che vengano eseguiti test <strong>di</strong> “Collision Detection”<br />
inutilmente e tra tutti gli oggetti, anche quando la <strong>di</strong>stanza tra questi è<br />
notevole: spesso infatti viene esegui<strong>to</strong> <strong>un</strong> test mol<strong>to</strong> approssima<strong>to</strong> me<strong>di</strong>ante<br />
<strong>un</strong> “Sphere-Sphere” massimizza<strong>to</strong>, che “filtra” e raggruppa quegli oggetti che<br />
si trovano in prossimità reciproca, applicando quin<strong>di</strong> “Collision Detections”<br />
più precise solo a quest’ultimi.<br />
Nel caso <strong>di</strong> gran<strong>di</strong> spazi, inoltre, si tende a razionalizzare preventivamente la<br />
scena <strong>di</strong> gioco in strutture apposite come il “QuadTree”, che partizionano lo<br />
spazio in quadranti ricorsivi.<br />
Dal p<strong>un</strong><strong>to</strong> <strong>di</strong> vista implementativo, entrambe le fasi verranno gestite dall’“Engine<br />
fisico” presente nel Layer View. Ciò significa che, così come avviene per il<br />
movimen<strong>to</strong>, chi controlla ed eventualmente mo<strong>di</strong>fica la posizione dei singoli<br />
oggetti 3D risidede nel Layer View dei loro rispettivi <strong>Peer</strong> “Owner”.<br />
Siano due oggetti tri<strong>di</strong>mensionali, “Ogget<strong>to</strong> A” ed “Ogget<strong>to</strong> B” in collisione,<br />
appartenenti rispettivamente al <strong>Peer</strong> “A” e al <strong>Peer</strong> “B”, la “Collision<br />
Detection” verrà eseguita allo stesso modo in entrambi i <strong>Peer</strong>, ma il “Colli-
56 CAPITOLO 2. ARCHITETTURA SOFTWARE<br />
sion Response” <strong>su</strong> “Ogget<strong>to</strong> A” verrà gesti<strong>to</strong> esclusivamente dal <strong>Peer</strong> “A”,<br />
e, viceversa il “Collision Response” <strong>su</strong> “Ogget<strong>to</strong> B” verrà gesti<strong>to</strong> esclusivamente<br />
dal <strong>Peer</strong> “B”. Gli effetti delle “Collision Responses” <strong>su</strong>i componenti<br />
logici coinvolti, verranno poi imme<strong>di</strong>atamente inoltrati agli altri <strong>Peer</strong>, che<br />
sposteranno infine i rispettivi oggetti View <strong>di</strong> conseguenza.<br />
Esis<strong>to</strong>no però contesti nei quali la “Collision Response” non in<strong>di</strong>vidua<br />
<strong>un</strong>a risposta “fisica”, cioè trasformazioni <strong>di</strong> ro<strong>to</strong>traslazioneil il cui aggiornamen<strong>to</strong><br />
è a carico <strong>di</strong> MovingObjectScript, bensì in<strong>di</strong>vidua variazioni logiche<br />
che impattano <strong>su</strong>lle <strong>di</strong>namiche <strong>di</strong> gioco e <strong>su</strong>l valore <strong>di</strong> specifici componenti<br />
del Data Layer. Si pensi ad esempio alla collisione tra <strong>un</strong> Bullet ed <strong>un</strong> Character,<br />
o ancora tra <strong>un</strong> Character ed <strong>un</strong> “HealthPack”. Nel primo caso il<br />
Bullet non deve <strong>su</strong>bire <strong>un</strong>a risposta fisica, rimbalzare o deviare traiet<strong>to</strong>ria,<br />
ma <strong>di</strong>struggersi e decrementare i P<strong>un</strong>ti vita del Character colpi<strong>to</strong>; viceversa,<br />
nel secondo caso invece l’“HealthPack” deve <strong>di</strong>struggersi e incrementare<br />
i P<strong>un</strong>ti vita del Character colpi<strong>to</strong>.<br />
In entrambi i casi viene utilizza<strong>to</strong> il sistema <strong>di</strong> Messaging per la notifica<br />
della collisione: Poiché il componente che rappresenta i P<strong>un</strong>ti vita <strong>di</strong> <strong>un</strong><br />
Character può essere mo<strong>di</strong>fica<strong>to</strong> esclusivamente dal proprio Player “Owner”,<br />
mentre il Bullet (o l’HealthPack) tipicamente appartengono ad <strong>un</strong> Player <strong>di</strong>fferente,<br />
e dal momen<strong>to</strong> che si è scel<strong>to</strong> <strong>di</strong> gestire il “Collision Detection” tra<br />
oggetti <strong>di</strong> tipo Bullet e Characater solo all’interno ComponentScript associa<strong>to</strong><br />
agli oggetti del primo tipo, quest’ultimo deve “informare” dell’avvenuta<br />
collisione il Characater coinvol<strong>to</strong>, che, <strong>di</strong> conseguenza decrementerà il proprio<br />
sot<strong>to</strong>-componente de<strong>di</strong>ca<strong>to</strong> ai P<strong>un</strong>ti vita (Figura 2.27).<br />
Analogamente al movimen<strong>to</strong>, anche per quan<strong>to</strong> riguarda le collisioni esis<strong>to</strong>no<br />
dei problemi dovuti al Lag, arro<strong>to</strong>ndamenti dei valori interpolanti e<br />
alla frequenza <strong>di</strong> aggiornamen<strong>to</strong> dell’Engine fisico (Tick). Anzi, in qualche<br />
modo, quest’ultimi vengono proprio amplificati dall’instabilità degli algoritmi<br />
<strong>di</strong> interpolazione utilizzati nel processo <strong>di</strong> movimen<strong>to</strong>, e alla loro, seppur<br />
minima, <strong>di</strong>fferenza tra <strong>Peer</strong> e <strong>Peer</strong>.
2.7. ESEMPI PRATICI 57<br />
Figura 2.26: In T0 il Player A sposta il <strong>su</strong>o personaggio in <strong>di</strong>rezione del<br />
personaggio appartenente al Player B, e, viceversa, il Player B muove il <strong>su</strong>o<br />
personaggio verso il personaggio del Player A.<br />
In T1 Viene attutata la sincronizzazione del DataLayer, e <strong>di</strong> conseguenza<br />
ogn<strong>un</strong>o dei due Player, eseguirà, nel proprio LayerView, me<strong>di</strong>ante Dead Reckoning,<br />
il movimen<strong>to</strong> del personaggio appartenente all’altro <strong>Peer</strong>. Entrambi<br />
gli Engine fisici rileveranno <strong>un</strong>a collisione e, in T2, come risposta muoveranno<br />
i rispettivi personaggi nel verso oppos<strong>to</strong>.
58 CAPITOLO 2. ARCHITETTURA SOFTWARE<br />
Figura 2.27: Il Layer View del Player A rileva <strong>un</strong>a collisione tra il proprio<br />
Bullet ed il Character appartenente al Player B. Come “Collision Response”<br />
logico, viene invia<strong>to</strong> <strong>un</strong> messaggio al componente del DataLayer che rappresenta<br />
il Character del Player B. Una volta ricevu<strong>to</strong>, all’interno del <strong>su</strong>o<br />
me<strong>to</strong>do ExecMessage(), verrà decrementa<strong>to</strong> il valore del sot<strong>to</strong>-componente<br />
HealthPoint <strong>di</strong> N p<strong>un</strong>ti, a seconda del tipo <strong>di</strong> Bullet.<br />
Tale mo<strong>di</strong>fica verrà notificata au<strong>to</strong>maticamente al Player A.<br />
Notare come Il Player A avrebbe com<strong>un</strong>que potu<strong>to</strong> inviare il messaggio anche<br />
alla propria copia del componente relativo al Character <strong>di</strong> B: il ri<strong>su</strong>lta<strong>to</strong><br />
sarebbe sta<strong>to</strong> imme<strong>di</strong>a<strong>to</strong>, ed il <strong>su</strong>ccessivo aggiornamen<strong>to</strong> proveniente da B<br />
ne avrebbe semplicemente sovrascrit<strong>to</strong> il valore senza mo<strong>di</strong>ficarne lo sta<strong>to</strong><br />
<strong>di</strong> gioco. (Entrambi infatti avrebbero riporta<strong>to</strong> lo stesso valore <strong>di</strong> HP decrementa<strong>to</strong>).<br />
Una <strong>di</strong>fferenza <strong>di</strong> valore, in ques<strong>to</strong> senso, potrebbe essere <strong>un</strong><br />
campanello d’allarme per <strong>un</strong> eventuale sistema Anti-Cheating.
2.7. ESEMPI PRATICI 59<br />
Può capitare infatti che <strong>un</strong> Bullet <strong>di</strong> <strong>un</strong> Player non rilevi la collisione con <strong>un</strong><br />
Character in movimen<strong>to</strong> appartenente ad <strong>un</strong> altro Player perchè <strong>un</strong>o dei due<br />
(o entrambi) sono soggetti ad <strong>un</strong>’elevata latenza a tal p<strong>un</strong><strong>to</strong> che le notifiche<br />
dei rispettivi movimenti vengano ricevute con <strong>un</strong> sincronizzazione temporale<br />
tale da bypassare la Collision Detection tra il Bullet ed il Character. O<br />
viceversa, che venga rilevata <strong>un</strong>a collisione con <strong>un</strong> Character che in realtà si<br />
trova già fuori portata <strong>di</strong> tiro.<br />
Facendo riferimen<strong>to</strong> alla Figura 2.28, si possono in<strong>di</strong>viduare alc<strong>un</strong>i problemi<br />
com<strong>un</strong>i: Il Player A ha <strong>un</strong> Lag relativamente basso (60ms), contrariamente<br />
a B e C che hanno <strong>un</strong> Lag relativamente al<strong>to</strong> (rispettivamente 120ms<br />
e 240ms).<br />
In T1 il Player A spara <strong>un</strong> Bullet. In ques<strong>to</strong> istante il proiettile è presente<br />
solamente nel Data Layer e Layer View del <strong>Peer</strong> A.<br />
In T2 il Player B riceve la notifica <strong>di</strong> creazione Bullet, e conseguentemente<br />
crea la propria copia del componente logico, e quin<strong>di</strong> il relativo ogget<strong>to</strong><br />
grafico nel proprio Layer View. Inoltre inizia a muovere il proprio Character<br />
nella <strong>di</strong>rezione del Bullet <strong>di</strong> A. Nel frattempo in A il proiettile si è mosso <strong>di</strong><br />
qualche step. Il Player C, invece, è ancora fermo allo sta<strong>to</strong> <strong>di</strong> gioco <strong>di</strong> T0.<br />
In T3 il Bullet <strong>di</strong> A ed il Character <strong>di</strong> B continuano la propria corsa, mentre<br />
in C è finalmente gi<strong>un</strong>ta la notifica <strong>di</strong> creazione Bullet.<br />
In T4, nel Layer View del Player B, si palesa <strong>un</strong>a collisione tra il Bullet <strong>di</strong> A<br />
ed il Character <strong>di</strong> B. Cosa che invece non avviene nel Layer View del Player<br />
A, poiché il movimen<strong>to</strong> <strong>di</strong> B è in ritardo <strong>di</strong> qualche step. Dal momen<strong>to</strong> che,<br />
per <strong>un</strong>a scelta implementativa, è il ComponentScript dell’Owner del Bullet<br />
ad effettuare la Collision Detection, cioè A, tale collisione viene ignorata e<br />
non ha ripercussioni quin<strong>di</strong> <strong>su</strong>llo sta<strong>to</strong> <strong>di</strong> gioco.<br />
Il Player C inizia a muovere il proprio Character, ma tale informazione per<br />
il momen<strong>to</strong> rimane confinata al <strong>su</strong>o <strong>Peer</strong>.<br />
In T5 è C a rilevare <strong>un</strong>a collisione tra il Bullet <strong>di</strong> A ed il Character <strong>di</strong> B, ma<br />
per gli stessi motivi elencati nel precedente p<strong>un</strong><strong>to</strong>, ciò non ha ripercussioni
60 CAPITOLO 2. ARCHITETTURA SOFTWARE<br />
<strong>su</strong>llo sta<strong>to</strong> <strong>di</strong> gioco. Intan<strong>to</strong> C continua ad allontanarsi dalla rotta <strong>di</strong> collisione<br />
del Bullet, ma tale movimen<strong>to</strong> continua ad essere notifica<strong>to</strong> in ritardo<br />
agli altri Player.<br />
In T6, A rileva finalmente <strong>un</strong>a collisione, tra il proprio Bullet ed il Character<br />
<strong>di</strong> C. In realtà il Character <strong>di</strong> C si è già allontana<strong>to</strong> da tempo dalla rotta del<br />
Bullet, ma A, basandosi <strong>su</strong>l proprio DataLayer, crede ancora che il Player C<br />
si trovi alla posizione <strong>di</strong> partenza. Il Player A quin<strong>di</strong> invia il messaggio <strong>di</strong><br />
collisione al componente relativo al Character <strong>di</strong> C.<br />
In T8, il Character <strong>di</strong> C riceve il messaggio <strong>di</strong> A e si decrementa i propri<br />
P<strong>un</strong>ti vita.<br />
In T9 ed in T10, la propagazione <strong>di</strong> tale mo<strong>di</strong>fica raggi<strong>un</strong>ge infine sia il Player<br />
A che il PlayerB<br />
L’esempio, volutamente amplifica<strong>to</strong>, mostra come, in caso <strong>di</strong> prestazioni<br />
<strong>di</strong> rete non ottimali, la desincronizzazione “percepita” possa deteriorare<br />
notevolmente l’esperienza <strong>di</strong> gioco (il Player C si vede sottrarre dei P<strong>un</strong>ti<br />
vita, nonostante, dal <strong>su</strong>o p<strong>un</strong><strong>to</strong> <strong>di</strong> vista, abbia schiva<strong>to</strong> abbontantemente il<br />
proiettile <strong>di</strong> A). In <strong>un</strong> contes<strong>to</strong> più realistico, il rappor<strong>to</strong> tra gli spazi <strong>di</strong> movimen<strong>to</strong>,<br />
la frequenza <strong>di</strong> aggiornamen<strong>to</strong> ed il Lag è minore, rendendo l’impat<strong>to</strong><br />
<strong>di</strong> ques<strong>to</strong> genere <strong>di</strong> desincronizzazioni piut<strong>to</strong>s<strong>to</strong> ri<strong>di</strong>mensiona<strong>to</strong>.<br />
È importante notare però come, nell’ultimo istante temporale presenta<strong>to</strong> nell’esempio,<br />
lo sta<strong>to</strong> <strong>di</strong> gioco sia perfettamente sincronizza<strong>to</strong> in tutti i tre <strong>Peer</strong>.<br />
In <strong>un</strong> First Person Shooter solitamente si possono <strong>di</strong>stinguere due tipi<br />
<strong>di</strong> Bullet: quello “fisico”, tipicamente più len<strong>to</strong> e quin<strong>di</strong> schivabile, e quello<br />
det<strong>to</strong> “HitScan”, che non implica la creazione <strong>di</strong> <strong>un</strong> apposi<strong>to</strong> ogget<strong>to</strong> 3D e<br />
relativa “Collision Detection”: viene infatti testata <strong>di</strong>rettamente l’intersezione<br />
tra il vet<strong>to</strong>re “Ray”, le cui coor<strong>di</strong>nate coincidono con le coor<strong>di</strong>nate del<br />
mouse (con la dovuta conversione da ScreenSpace (2D) a WorldSpace (3D)<br />
ed il cui verso coincide con la profon<strong>di</strong>tà in<strong>di</strong>viduata dalla rotazione della<br />
telecamera, e gli oggetti <strong>di</strong> tipo Character (od <strong>un</strong>a approssimazione del loro<br />
volume geometrico).
2.7. ESEMPI PRATICI 61<br />
Figura 2.28: Problematiche relative alla collisione tra oggetti in <strong>un</strong> contes<strong>to</strong><br />
caratterizza<strong>to</strong> da <strong>un</strong>a <strong>un</strong>’elevata latenza
62 CAPITOLO 2. ARCHITETTURA SOFTWARE<br />
Quando si verifica <strong>un</strong>’intersezione tra <strong>un</strong> “Ray” ed <strong>un</strong> Character, e quest’ultimo<br />
si trova in testa alla lista degli oggetti intersecati (<strong>un</strong> “Ray”, può<br />
intersecare, infatti, più oggetti contemporaneamente, or<strong>di</strong>nati in <strong>un</strong>a lista<br />
dal più vicino al più lontano), il <strong>Peer</strong> che ha esegui<strong>to</strong> l’“HitScan”, invierà <strong>un</strong><br />
messaggio al componente relativo al Character colpi<strong>to</strong>, che <strong>di</strong> conseguenza<br />
decrementerà i propri “P<strong>un</strong>ti vita”.<br />
2.7.3 Creazione e <strong>di</strong>struzione <strong>di</strong> oggetti<br />
Come illustra<strong>to</strong> nelle sezioni 2.4 e 2.6, la creazione <strong>di</strong> <strong>un</strong> elemen<strong>to</strong> grafico<br />
che apporta informazione allo sta<strong>to</strong> <strong>di</strong> gioco, come può essere <strong>un</strong> ogget<strong>to</strong> 3D,<br />
viene concretizzata, istanziando il componente vi<strong>su</strong>ale au<strong>to</strong>maticamente dal<br />
View Context del Layer View, basandosi <strong>su</strong>i componenti presenti nel Data<br />
Layer.<br />
Per quegli oggetti grafici che devono essere “con<strong>di</strong>visi”, cioè presenti in tutti<br />
i <strong>Peer</strong> appartenenti alla Membership, è imperativo, quin<strong>di</strong>, passare per il Data<br />
Layer, istanziando il componente logico, piut<strong>to</strong>s<strong>to</strong> che creare <strong>di</strong>rettamente<br />
l’ogget<strong>to</strong> 3D.<br />
Per esempio, se si vuole creare <strong>un</strong> Bullet tri<strong>di</strong>mensionale, sarà <strong>su</strong>fficiente<br />
creare <strong>un</strong> componente <strong>di</strong> tipo Bullet opport<strong>un</strong>amente inizializza<strong>to</strong> (coor<strong>di</strong>nate<br />
e rotazione devono coincidere con quella del Character che “spara” il<br />
Bullet).<br />
Analogamente, per <strong>di</strong>struggere <strong>un</strong> ogget<strong>to</strong> 3D, invece <strong>di</strong> eliminare <strong>di</strong>rettamente<br />
l’istanza grafica, è necessario rimuovere il relativo componente dal<br />
DataLayer.<br />
Eliminando solamente l’istanza grafica, infatti, ne verrebbe istanziata <strong>un</strong>a<br />
nuova copia, au<strong>to</strong>maticamente all’iterazione <strong>su</strong>ccessiva, dal momen<strong>to</strong> che il<br />
componente logico ri<strong>su</strong>lta ancora presente nel Data Layer.<br />
Ogni creazione e <strong>di</strong>struzione <strong>di</strong> <strong>un</strong> componente, come illustra<strong>to</strong> nella sezione<br />
2.4, viene propagata all’intera Membership attraverso i coman<strong>di</strong> “Create-
2.7. ESEMPI PRATICI 63<br />
Component” e “DestroyComponent”. Se il tipo <strong>di</strong> componente è <strong>un</strong> aggrega<strong>to</strong><br />
<strong>di</strong> sot<strong>to</strong>-componenti, allora saranno inoltrati tanti coman<strong>di</strong> “CreateComponent”<br />
e “DestroyComponent” quanti sono i sot<strong>to</strong>-componenti.<br />
Gli elementi presenti nell’ambiente tri<strong>di</strong>mensionale con<strong>di</strong>viso, a seconda delle<br />
loro caratteristiche e della loro f<strong>un</strong>zione, si possono raggruppare nei seguenti<br />
insiemi:<br />
• Elementi <strong>di</strong> scena: sono quegli elementi “statici” che non apportano informazione<br />
a livello <strong>di</strong> sta<strong>to</strong> <strong>di</strong> gioco. Tipicamente Arene (o mappe) 14 ,<br />
stanze, corridoi, o altri oggetti prettamente decorativi rientrano in questa<br />
tipologia <strong>di</strong> elementi, che non vengono istanziati conseguentemente<br />
ad <strong>un</strong> even<strong>to</strong> contestualizza<strong>to</strong> a livello logico o <strong>di</strong> rete, ma son presenti<br />
<strong>di</strong>rettamente nel Layer View, in<strong>di</strong>pendentemente dallo sta<strong>to</strong> del <strong>Peer</strong><br />
sot<strong>to</strong>stante.<br />
• Elementi attivi: sono quegli elementi “<strong>di</strong>namici” che, con la loro presenza<br />
alterano lo sta<strong>to</strong> <strong>di</strong> gioco: characters, Bullets, HealthPacks, ad<br />
esempio, rientrano in questa tipologia.<br />
Tra gli elementi attivi si può operare <strong>un</strong>’ulteriore <strong>di</strong>stinzione. Alc<strong>un</strong>i <strong>di</strong> questi<br />
elementi, infatti, “appartengono” in modo naturale ad <strong>un</strong> <strong>Peer</strong>: il Character<br />
del Player A è chiaramente <strong>di</strong> proprietà del rispettivo <strong>Peer</strong>. Analogamente<br />
<strong>un</strong> Bullet spara<strong>to</strong> da <strong>un</strong> Character del Player B apparterrà al <strong>Peer</strong> B. Altri<br />
elementi però sfuggono a questa regola. Si pensi agli HealthPack: a quale<br />
<strong>Peer</strong> appartengono? O, in altre parole, a quale Fac<strong>to</strong>ry è delegata la loro<br />
creazione?<br />
Per ques<strong>to</strong> tipo <strong>di</strong> elementi si è pensa<strong>to</strong> <strong>di</strong> agire nel seguente modo: <strong>su</strong>lla<br />
mappa “statica” (appartenente quin<strong>di</strong> alla categoria degli elementi <strong>di</strong> scena)<br />
vengono inseriti N PlaceHolder, cioè p<strong>un</strong>ti astratti che al momen<strong>to</strong> della<br />
realizzazione della mappa non contengono ness<strong>un</strong> ogget<strong>to</strong> in particoare, ma<br />
identificano com<strong>un</strong>que <strong>un</strong>a posizione eventualmente occupabile in r<strong>un</strong>time.<br />
14 Gli ambienti nei quali si svolgono le partite <strong>di</strong> <strong>un</strong> FPS
64 CAPITOLO 2. ARCHITETTURA SOFTWARE<br />
Questi PlaceHolder sono anch’essi elementi <strong>di</strong> scena dal momen<strong>to</strong> che caratterizzano<br />
la mappa <strong>di</strong> gioco (come colonne, p<strong>un</strong>ti luce, ostacoli, etc), e sono<br />
quin<strong>di</strong> caricati contestualmente al loa<strong>di</strong>ng della mappa (che viene eseguita<br />
in modo del tut<strong>to</strong> in<strong>di</strong>pendente da <strong>un</strong> <strong>di</strong>scorso <strong>di</strong> rete).<br />
Quando inizia <strong>un</strong>a partita, ogni <strong>Peer</strong> “occupa”, preventivamente, N/(Numero<br />
<strong>di</strong> <strong>Peer</strong>) PlaceHolder con <strong>un</strong> componente <strong>di</strong> tipo HealthPackGenera<strong>to</strong>r (ere<strong>di</strong>ta<strong>to</strong><br />
da Object3D). Il criterio (necessariamente con<strong>di</strong>viso) utilizza<strong>to</strong> per la<br />
<strong>di</strong>stribuzione e l’assegnazione dei PlaceHolder ai <strong>di</strong>versi <strong>Peer</strong> può essere realizza<strong>to</strong><br />
me<strong>di</strong>ante politiche basate <strong>su</strong>l NetID, o qual<strong>un</strong>que altra informazione<br />
che contrad<strong>di</strong>stingue ogni singolo <strong>Peer</strong>, evitando quin<strong>di</strong> f<strong>un</strong>zioni alea<strong>to</strong>rie.<br />
Ogni HealthPackGenera<strong>to</strong>r si occuperà <strong>di</strong> istanziare perio<strong>di</strong>camente, laddove<br />
non già presente, <strong>un</strong> componente <strong>di</strong> tipo HealthPack alle stesse coor<strong>di</strong>nate<br />
del relativo PlaceHolder.<br />
Ques<strong>to</strong> significa che ogni Player “possiede” <strong>un</strong> determina<strong>to</strong> numero <strong>di</strong><br />
HealthPack e ne gestisce quin<strong>di</strong> anche le collisioni con i Character degli altri<br />
Player (Figura 2.29).<br />
2.7.4 Connessione e Disconnessione dei Player<br />
Nelle sezioni precedenti è sta<strong>to</strong> evidenzia<strong>to</strong> come ogni informazione a<strong>to</strong>mica<br />
appartenga ad <strong>un</strong> determina<strong>to</strong> <strong>Peer</strong>.<br />
Ques<strong>to</strong> risolve, da <strong>un</strong>a parte, il problema della consistenza dello sta<strong>to</strong> <strong>di</strong> gioco,<br />
ma dall’altra introduce alc<strong>un</strong>e problematiche dovute all’importanza <strong>di</strong><br />
ogni singolo <strong>Peer</strong>, al p<strong>un</strong><strong>to</strong> da poter essere considerati degli SPOF.<br />
Quando <strong>un</strong> <strong>Peer</strong> si <strong>di</strong>sconnette od esce dalla Membership, gli effetti della<br />
logica <strong>di</strong> aggiornamen<strong>to</strong> dei componenti <strong>di</strong> <strong>su</strong>a appartenenza non viene più<br />
propagata agli altri <strong>Peer</strong>. Per alc<strong>un</strong>i tipi <strong>di</strong> componenti, inoltre, può essere<br />
necessario <strong>di</strong>struggerne le istanze quando il <strong>Peer</strong> owner non è più raggi<strong>un</strong>gibile.<br />
Non esiste <strong>un</strong>a regola generale, ma è possibile definirne <strong>un</strong>a per ogni tipo
2.7. ESEMPI PRATICI 65<br />
Figura 2.29: Arena e PlaceHolder sono elementi <strong>di</strong> scena, mentre HealthPack-<br />
Genera<strong>to</strong>r, HealthPack e Character sono elementi attivi. Alc<strong>un</strong>i <strong>di</strong> questi<br />
appartengono al Player A ed altri al Player B.<br />
<strong>di</strong> componente: gli HealthPack e i Bullet, ad esempio, non possono essere<br />
<strong>di</strong>strutti, e devono continuare ad essere aggiornati. Il Character, invece, generalmente<br />
viene <strong>di</strong>strut<strong>to</strong>.<br />
Sorge quin<strong>di</strong> <strong>un</strong> problema lega<strong>to</strong> all’aggiornamen<strong>to</strong> <strong>di</strong> quei componenti<br />
il cui <strong>Peer</strong> non è più presente all’interno della Membership. Una soluzione<br />
potrebbe essere quella <strong>di</strong> forzare il cambio <strong>di</strong> proprietà dal <strong>Peer</strong> <strong>di</strong>sconnesso<br />
ad <strong>un</strong> <strong>Peer</strong> ancora connesso.<br />
Il Modulo SharedComponents, in casi eccezionali, permette <strong>di</strong> delegare la<br />
proprietà <strong>di</strong> <strong>un</strong> componente come se fosse sta<strong>to</strong> genera<strong>to</strong> da <strong>un</strong>’altro Fac<strong>to</strong>ry.<br />
Il <strong>Peer</strong> che ne acquisisce la proprietà <strong>di</strong>venta il <strong>su</strong>o nuovo “Owner” e<br />
deve notificare tale passaggio a tutti gli altri <strong>Peer</strong> ancora connessi.<br />
Per decidere a quale <strong>Peer</strong> cedere la proprietà, analagomente a quan<strong>to</strong> <strong>su</strong>ccede<br />
per la creazione degli HealthPack, l’utilizzo <strong>di</strong> <strong>un</strong>a f<strong>un</strong>zione alea<strong>to</strong>ria<br />
è sconsigliabile. Così come è sconsigliabile eseguire <strong>un</strong> Polling N-a-N: ogni<br />
<strong>Peer</strong> esegue <strong>un</strong> Polling <strong>di</strong> check <strong>su</strong>l <strong>Peer</strong> temporalmente connesso dopo <strong>di</strong>
66 CAPITOLO 2. ARCHITETTURA SOFTWARE<br />
lui, e nel caso quest’ultimo non sia più raggi<strong>un</strong>gibile si appropria dei <strong>su</strong>oi<br />
componenti. Se l’or<strong>di</strong>ne <strong>di</strong> connessione è: Player A, Player B, Player C e<br />
Player D, quin<strong>di</strong>, Player A esegue <strong>un</strong> Polling <strong>su</strong>l Player B, il Player B <strong>su</strong>l<br />
Player C, il Player C <strong>su</strong>l Player D ed infine il Player D <strong>su</strong>l Player A. Ogni<br />
<strong>Peer</strong> com<strong>un</strong>que, a livello <strong>di</strong> implementazione del modulo NET, riceve <strong>un</strong>a<br />
notifica alla <strong>di</strong>sconnessione <strong>di</strong> nodo: se sia il Player B che il Player C si <strong>di</strong>sconnet<strong>to</strong>no<br />
contemporaneamente, prima che Player B sia riusci<strong>to</strong> quin<strong>di</strong> a<br />
notificare agli altri <strong>Peer</strong> l’avvenuta acquisizione dei componenti <strong>di</strong> Player C,<br />
Player A, sapendo che sia B che C non sono più presenti nella Membership,<br />
acquisisce i componenti appartenenti al Player B e quin<strong>di</strong> quelli appartenenti<br />
al Player C.
Capi<strong>to</strong>lo 3<br />
Implementazione<br />
Di segui<strong>to</strong>, dopo <strong>un</strong>’introduzione generale, verranno illustrate le problematiche<br />
e le soluzioni implementative che sono state in<strong>di</strong>viduate e concretizzate<br />
all’interno <strong>di</strong> ogni singolo Layer.<br />
3.1 Introduzione Generale<br />
L’implementazione software rispecchia la <strong>su</strong>d<strong>di</strong>visione dell’architettura<br />
presentata nel capi<strong>to</strong>lo 2 (Figura 3.1): Tutti i Layer ed i Moduli, ad esclusione<br />
del Layer View, sono <strong>di</strong>sponibili come DLL 1 e realizzati in modo da<br />
minimizzare le <strong>di</strong>pendenze.<br />
Quest’ultime sono, infatti, riscontrabili esclusivamente nei legami tra <strong>un</strong><br />
Layer <strong>su</strong>periore e quello inferiore, e non viceversa.<br />
Per la realizzazione <strong>di</strong> tali legami, inoltre, si é scel<strong>to</strong> da <strong>un</strong>a parte <strong>di</strong> esporre<br />
Interfacce piut<strong>to</strong>s<strong>to</strong> che Classi specifiche, e dall’altra <strong>di</strong> seguire, laddove<br />
possibile ed effettivamente conveniente, l’Observer Pattern, poiché induce <strong>un</strong><br />
maggiore <strong>di</strong>saccoppiamen<strong>to</strong> tra i <strong>di</strong>versi Layer.<br />
Si é inoltre cerca<strong>to</strong> <strong>di</strong> evitare l’utilizzo <strong>di</strong> me<strong>to</strong><strong>di</strong> e membri statici, rendendo<br />
1 Dynamic-Link Library, libreria software che viene caricata <strong>di</strong>namicamente in fase <strong>di</strong><br />
esecuzione<br />
67
68 CAPITOLO 3. IMPLEMENTAZIONE<br />
possibile l’esecuzione <strong>di</strong> più <strong>Peer</strong> all’interno dello stesso programma. Ciò ha<br />
facilita<strong>to</strong> i processo <strong>di</strong> debugging dei Layer logici e <strong>di</strong> rete.<br />
I <strong>di</strong>versi Layer con<strong>di</strong>vidono alc<strong>un</strong>i elementi <strong>di</strong> natura strutturale: ad esempio<br />
il Layer Net, il Layer P2P ed modulo SharedComponents concretizzano<br />
il concet<strong>to</strong> <strong>di</strong> “comando” nel medesimo modo (utilizzando lo stesso tipo <strong>di</strong><br />
interfacce e presentando implementazioni simili).<br />
Per quan<strong>to</strong> concerne le tecnologie ed i linguaggi <strong>di</strong> programmazione utilizzati,<br />
<strong>un</strong>o dei fat<strong>to</strong>ri che ne hanno vincola<strong>to</strong> la scelta, risiede nel Layer View.<br />
Il Layer View infatti é compos<strong>to</strong> da moduli piut<strong>to</strong>s<strong>to</strong> complessi, le cui f<strong>un</strong>zioni<br />
e<strong>su</strong>lano da quelle che sono le tematiche del proget<strong>to</strong> <strong>di</strong> tesi.<br />
Era necessario in<strong>di</strong>viduare <strong>un</strong> Framework od <strong>un</strong> Engine che offrisse il<br />
maggior numero <strong>di</strong> f<strong>un</strong>zionalità richieste dalle specifiche del Layer View e,<br />
contemporaneamente, permettesse in breve tempo l’integrazione con i Layer<br />
sot<strong>to</strong>stanti.<br />
La scelta é ricaduta <strong>su</strong> Unity3D 2 .<br />
Unity3D si presenta come <strong>un</strong> ambiente integra<strong>to</strong> che mette a <strong>di</strong>sposizione <strong>un</strong><br />
Renderer 3D, <strong>un</strong>o SceneGraph particolarmente modulare, <strong>un</strong> Engine fisico<br />
per la gestione dei movimenti e delle collisioni nonché sistemi per la gestione<br />
degli input ed il <strong>su</strong>ppor<strong>to</strong> au<strong>di</strong>o.<br />
Tra le caratteristiche peculiari <strong>di</strong> Unity3D vi sono il cos<strong>to</strong> (gratui<strong>to</strong> per<br />
applicazioni non commerciali), l’E<strong>di</strong><strong>to</strong>r WYSIWYG, che consente <strong>un</strong>a rapida<br />
definizione della scena tri<strong>di</strong>mensionale, e la possibilità <strong>di</strong> convertire il proget<strong>to</strong><br />
<strong>su</strong> <strong>di</strong>verse piattaforme.<br />
Per quan<strong>to</strong> riguarda la programmazione, Unity3D <strong>su</strong>pporta l’utilizzo del<br />
linguaggio C#, e mette a <strong>di</strong>sposizione <strong>un</strong> sistema semplifica<strong>to</strong> <strong>di</strong> “scripting”<br />
2 www.<strong>un</strong>ity3d.com
3.2. LAYER NET 69<br />
basa<strong>to</strong> <strong>su</strong>l concet<strong>to</strong> <strong>di</strong> Behaviour (che definisce parte della logica <strong>di</strong> ogni<br />
singolo ogget<strong>to</strong> grafico), consentendo com<strong>un</strong>que l’utilizzo <strong>di</strong> para<strong>di</strong>gmi ed<br />
approcci più classici.<br />
Per ridurre al minimo problematiche d’integrazione si é scel<strong>to</strong>, quin<strong>di</strong>, <strong>di</strong><br />
procedere con l’utilizzo del linguaggiio C# anche per l’implementazione dei<br />
Layer sot<strong>to</strong>stanti.<br />
Figura 3.1: Il Layer NET (de<strong>di</strong>ca<strong>to</strong> alla com<strong>un</strong>icazione) è implementa<strong>to</strong> nel<br />
file NET.DLL;<br />
Il Layer P2P (de<strong>di</strong>ca<strong>to</strong> alla gestione della Membership) è implementa<strong>to</strong> nel<br />
file P2P.DLL;<br />
Il Modulo SharedComponents (utilizza<strong>to</strong> come Data Layer) è implementa<strong>to</strong><br />
nel file SharedComponents.DLL;<br />
Il Layer Logic è implementa<strong>to</strong> nel file Logic.DLL, mentre il Layer View fa da<br />
EntryPoint e coincide con l’eseguibile dell’applicazione.<br />
3.2 Layer NET<br />
Il Layer NET presenta, ad <strong>un</strong> primo livello, alc<strong>un</strong>e classi <strong>di</strong> servizio, che<br />
per lo più espongono proprietà e me<strong>to</strong><strong>di</strong> statici:
70 CAPITOLO 3. IMPLEMENTAZIONE<br />
Figura 3.2: Diagramma delle Classi - Layer NET
3.2. LAYER NET 71<br />
• Le classi Setup e Constants fanno da conteni<strong>to</strong>re a tutti i parametri<br />
<strong>di</strong> configurazione del Layer. Ad esempio sono qui definiti i nomi delle<br />
classi che implementeranno le interfacce INet e ILink, i millisecon<strong>di</strong> <strong>di</strong><br />
attesa dei Thread <strong>di</strong> lettura e scrittura <strong>di</strong> <strong>un</strong> Link, e la <strong>di</strong>mensione<br />
della finestra TCP (nel caso sia utilizza<strong>to</strong> ques<strong>to</strong> pro<strong>to</strong>collo). Come<br />
prima implementazione, tali valori sono inizializzati <strong>di</strong>rettamente all’interno<br />
del co<strong>di</strong>ce, ma come sviluppo futuro è previs<strong>to</strong> l’utilizzo <strong>di</strong> file<br />
<strong>di</strong> configurazione esterni.<br />
• La classe Delegates raccoglie la definizione <strong>di</strong> tutti i Delegates, ovvero<br />
tipi <strong>di</strong> da<strong>to</strong> necessari a formalizzare la natura dei me<strong>to</strong><strong>di</strong> anonimi<br />
utilizzati per l’implementazione degli Eventi e dell’Observer Pattern in<br />
generale, <strong>su</strong>i quali si basa la com<strong>un</strong>icazione da ques<strong>to</strong> Layer verso i<br />
Layer <strong>su</strong>periori.<br />
• La classe Utils raccoglie <strong>un</strong>a serie <strong>di</strong> me<strong>to</strong><strong>di</strong> ausiliari e <strong>di</strong> utilità generale.<br />
Ad esempio qui risiedono i me<strong>to</strong><strong>di</strong> <strong>di</strong> conversione tra IP Address,<br />
Port e NetID.<br />
• La classe Fac<strong>to</strong>ry permette, attraverso il principio IoC 3 <strong>di</strong> istanziare<br />
oggetti concreti <strong>di</strong> INode e ILink astraendo dalla loro implementazione.<br />
Sono poi definite le interfacce esposte ai Layer <strong>su</strong>periori:<br />
• INode: Identifica <strong>un</strong> nodo <strong>di</strong> rete. Al <strong>su</strong>o interno è presente <strong>un</strong> lista<br />
<strong>di</strong> ILink, che vengono istanziati <strong>su</strong>lla chiamata del me<strong>to</strong>do ConnectTo(<br />
string ipAddress, int port).<br />
Il me<strong>to</strong>do SetNewIdentifierOfLink(ILink link, String newIdentifier) consente<br />
<strong>di</strong> cambiare l’identificativo <strong>di</strong> <strong>un</strong> link.<br />
Sono inoltre esposti <strong>un</strong>a serie <strong>di</strong> me<strong>to</strong><strong>di</strong> che permet<strong>to</strong>no ai Layer <strong>su</strong>periori<br />
<strong>di</strong> registrarsi ad alc<strong>un</strong>i eventi <strong>di</strong>spacciati dal singolo nodo: ad<br />
esempio quando <strong>un</strong> ILink presente nella lista riceve <strong>un</strong> messaggio, viene<br />
lancia<strong>to</strong> il me<strong>to</strong>do delega<strong>to</strong> che si era registra<strong>to</strong> all’even<strong>to</strong> OnRead.<br />
3 Inversion of control, <strong>un</strong> pattern grazie al quale è possibile delegare ad <strong>un</strong>a terza entità<br />
la creazione <strong>di</strong> <strong>un</strong> preciso ogget<strong>to</strong> in<strong>di</strong>candone, ad esempio, solamente l’interfaccia
72 CAPITOLO 3. IMPLEMENTAZIONE<br />
• ILink: identifica <strong>un</strong> canale <strong>di</strong> rete. Attraverso i me<strong>to</strong><strong>di</strong> Read() e Write()<br />
è possibile ascoltare ed inviare messaggi all’endpoint associa<strong>to</strong> all’ILink<br />
in questione.<br />
Figura 3.3: Interfacce NET<br />
Tali interfacce sono state concretizzate attraverso due classi: TCPNode e<br />
TPCLink. Il pro<strong>to</strong>collo <strong>di</strong> rete utilizza<strong>to</strong> come prima implementazione è infatti<br />
il TCP/IP. Applicazioni interattive come i videogiochi, spesso richiedono<br />
<strong>un</strong> frequente e rapido scambio <strong>di</strong> informazioni. Il pro<strong>to</strong>collo UDP potrebbe<br />
essere consigliabile in ques<strong>to</strong> senso, poiché è Message-Oriented invece che<br />
Stream-Oriented, e per ogni pacchet<strong>to</strong> invia<strong>to</strong> non deve aspettare <strong>un</strong> messaggio<br />
<strong>di</strong> ri<strong>to</strong>rno; d’altro can<strong>to</strong>, però, per evitare problemi <strong>di</strong> consistenza,<br />
ri<strong>su</strong>ltano necessari sistemi che garantiscono maggiore sicurezza e affidabilità<br />
in termini controllo <strong>di</strong> congestione, Ack <strong>di</strong> ricezione ed il mantenimen<strong>to</strong><br />
dell’or<strong>di</strong>ne <strong>di</strong> invio dei pacchetti. Inoltre per l’in<strong>di</strong>viduazione <strong>di</strong> <strong>un</strong>a Membership<br />
può ri<strong>su</strong>ltare più comodo <strong>un</strong> pro<strong>to</strong>collo Connection-oriented poiché<br />
la connessione e la <strong>di</strong>sconnessione <strong>di</strong> no<strong>di</strong> all’interno della rete vengono gestiti<br />
<strong>di</strong>rettamente dal sistema, rendendo <strong>su</strong>perflua <strong>un</strong>’emulazione logica la<strong>to</strong><br />
applicazione: esis<strong>to</strong>no infatti implementazioni UDP “Reliable”, anche appositamente<br />
mirate ai videogiochi (si veda Raknet 4 ), che, la<strong>to</strong> applicazione,<br />
4 http://www.jenkinssoftware.com
3.2. LAYER NET 73<br />
fanno fronte a ques<strong>to</strong> tipo <strong>di</strong> problematiche. Dal momen<strong>to</strong> che il Layer NET<br />
com<strong>un</strong>ica con il Layer de<strong>di</strong>ca<strong>to</strong> alla gestione della Membership attraverso interfacce<br />
agnostiche rispet<strong>to</strong> al pro<strong>to</strong>collo utilizza<strong>to</strong>, si è scel<strong>to</strong>, in prima istanza,<br />
<strong>di</strong> appoggiarsi al pro<strong>to</strong>collo TCP/IP. Questa scelta non ri<strong>su</strong>lta com<strong>un</strong>que<br />
vincolante, e sarà possibile, in futuro, <strong>su</strong>pportare <strong>un</strong>’implementazione esclusivamente<br />
UDP, od eventualmente ibrida, senza dover mo<strong>di</strong>ficare le interfacce<br />
dei Layer sovrastanti. E’ importante sot<strong>to</strong>lineare però come l’introduzione<br />
del <strong>su</strong>ppor<strong>to</strong> al pro<strong>to</strong>collo UDP renda necessario <strong>un</strong> sistema <strong>di</strong> or<strong>di</strong>namen<strong>to</strong><br />
dei pacchetti ricevuti, non richies<strong>to</strong> invece nell’attuale implementazione.<br />
Figura 3.4: Classi principali - Layer TCP<br />
• TCPNode: Concretizza l’interfaccia INode basandosi <strong>su</strong>l pro<strong>to</strong>collo<br />
TCP. Per rimanere in ascol<strong>to</strong> <strong>di</strong> connessioni esterne, viene utilizza<strong>to</strong><br />
<strong>un</strong> ogget<strong>to</strong> della classe TcpListener del FrameWork .NET.<br />
Quando si vuole connettere <strong>un</strong> TCPNode A ad <strong>un</strong> TCPNode B, <strong>su</strong>l<br />
primo viene chiama<strong>to</strong> il me<strong>to</strong>do ConnectTo(’B’) che creerà au<strong>to</strong>maticamente<br />
<strong>un</strong> TCPLink verso B, mentre <strong>su</strong>l secondo, quando sarà ri-
74 CAPITOLO 3. IMPLEMENTAZIONE<br />
levata la connessione da parte <strong>di</strong> A, verrà crea<strong>to</strong> <strong>un</strong> TCPLink verso<br />
quest’ultimo.<br />
• TCPLink: Concretizza l’interfaccia ILink basandosi <strong>su</strong>l pro<strong>to</strong>collo TCP.<br />
Attraverso due Thread sarà possibile rispettivamente leggere e scrivere<br />
<strong>su</strong>llo stream dal proprio TCPNode all’EndPoint specifica<strong>to</strong>, e viceversa.<br />
Quando <strong>su</strong>llo stream viene in<strong>di</strong>vidua<strong>to</strong> <strong>un</strong> messaggio, cioè quando si<br />
presentano i caratteri termina<strong>to</strong>ri “\r\n”, ques<strong>to</strong> viene memorizza<strong>to</strong><br />
in <strong>un</strong>’apposita coda, e <strong>su</strong>ccessivamente, passa<strong>to</strong> al me<strong>to</strong>do ReadLine(string<br />
message). In ReadLine() viene chiama<strong>to</strong> a <strong>su</strong>a volta il me<strong>to</strong>do<br />
ProcessMessage(ILink link, string message) del proprio TCPNode, che<br />
si occuperà <strong>di</strong> processare il messaggio.<br />
3.2.1 Commands<br />
La maggior parte dei messaggi scambiati tra i no<strong>di</strong> appartenenti alla<br />
Membership è realizzata tramite i Commands.<br />
L’idea che sta alla base dei Commands ricalca quella en<strong>un</strong>ciata dal Command<br />
Pattern.<br />
Sostanzialmente ogni comando è implementa<strong>to</strong> in <strong>un</strong>’apposita classe che concretizza<br />
l’interfaccia ICommand, ed ha <strong>un</strong>a duplice f<strong>un</strong>zione:<br />
Da <strong>un</strong>a parte permette <strong>di</strong> generare in modo au<strong>to</strong>matico e <strong>un</strong>iforme la stringa<br />
da inviare come messaggio, mentre dall’altra, attraverso il me<strong>to</strong>do “Exec()”,<br />
esegue le operazioni che caratterizzano il comando stesso.<br />
A livello <strong>di</strong> Layer NET, questi sono implementati dalla classe base Net-<br />
Command, estesa poi per ogni singolo comando. Un NetCommand è in<strong>di</strong>vidua<strong>to</strong><br />
dai Parameters, dal INode destinatario e dal ILink mittente.<br />
Tra questi vi sono i 3 coman<strong>di</strong> de<strong>di</strong>cati all’HandShaking (si veda Figura 2.1):<br />
• HandShakeBegin: Nel <strong>su</strong>o me<strong>to</strong>do Exec() viene chiama<strong>to</strong> Node.Set-<br />
NewIdentifierOfLink(ILink Link, string Parameters), che confermerà o<br />
aggiornerà l’identità del Link conosciu<strong>to</strong> dal Node <strong>su</strong>l quale è sta<strong>to</strong> ese-
3.2. LAYER NET 75<br />
Figura 3.5: Per inviare <strong>un</strong> comando da gestire a livello NET, da <strong>un</strong> Nodo A<br />
ad <strong>un</strong> Nodo B, viene prima creata <strong>un</strong>’istanza dell’apposita classe ere<strong>di</strong>tata<br />
da NetCommand, ed inizializzata secondo i parametri desiderati; quin<strong>di</strong> serializzata<br />
attraverso l’ovveride del me<strong>to</strong>do ToString() e scritta <strong>su</strong>llo stream<br />
del Link A-B.<br />
Quando il messaggio gi<strong>un</strong>ge a B, viene prima invoca<strong>to</strong> il Processor appartenente<br />
al Layer NET. Se il messaggio deve essere esegui<strong>to</strong> <strong>su</strong>l Layer NET,<br />
allora tale Processor istanzierà au<strong>to</strong>maticamente, grazie alla Reflection, <strong>un</strong><br />
ogget<strong>to</strong> della classe che definisce il comando, e, a seconda dei casi, lo eseguirà<br />
<strong>di</strong>rettamente, chiamando il <strong>su</strong>o me<strong>to</strong>do Exec() o lo inserirà in <strong>un</strong>a coda <strong>di</strong> esecuzione.<br />
Se invece non si tratta <strong>di</strong> <strong>un</strong> messaggio da eseguire <strong>su</strong>l Layer NET,<br />
allora l’INode destinatario chiamerà gli eventuali me<strong>to</strong><strong>di</strong> delegati registrati<br />
al proprio even<strong>to</strong> OnRead, cosicché i Layer <strong>su</strong>periori possano processare il<br />
messaggio allo stesso modo.
76 CAPITOLO 3. IMPLEMENTAZIONE<br />
gui<strong>to</strong> il comando, e quin<strong>di</strong> Link.Write(new HandShakeResponse( Node.GetNetID()<br />
).ToString() ) , che <strong>di</strong> fat<strong>to</strong> corrisponderà alla risposta<br />
che il Node invierà al Link per notificare la propria identità.<br />
• HandShakeResponse: analogamente a HandShakeBegin, viene prima<br />
chiama<strong>to</strong> Node.SetNew- IdentifierOfLink( ILink Link, string Parameters<br />
) (questa volta <strong>su</strong>ll’altro Nodo), e quin<strong>di</strong> Link.Write( new Hand-<br />
ShakeEnd( Node.GetNetID() ) ) per notificare a Link l’avvenuta ricezione<br />
del comando HandShakeResponse. Inoltre viene flagga<strong>to</strong> a “true”<br />
l’attribu<strong>to</strong> “Active” relativo alla connessione tra il Node e l’EndPoint<br />
<strong>di</strong> Link.<br />
• HandShakeEnd: analogamente ad HandShakeResponse, <strong>su</strong>ll’Exec() viene<br />
attivata la connessione tra il Node e l’EndPoint <strong>di</strong> Link.<br />
Tra gli sviluppi futuri è stata considerata la possibilità <strong>di</strong> implementare<br />
<strong>un</strong> sot<strong>to</strong>-stra<strong>to</strong> ulteriore de<strong>di</strong>ca<strong>to</strong> alla compressione / decompressione dei dati,<br />
da inserire o a livello del ToString() del NetCommand base, o a livello dei<br />
threads Read / Write della classe NetChannel, oppure <strong>di</strong>rettamente sot<strong>to</strong> il<br />
Layer NET.<br />
In Figura 3.6 è illustrata la struttura della stringa che viene generata <strong>di</strong><br />
default dall’override del ToString().<br />
Figura 3.6: Struttura della stringa dei messaggi implementati dai Commands
3.3. LAYER P2P 77<br />
3.3 Layer P2P<br />
Figura 3.7: Diagramma delle Classi - Layer P2P<br />
Il Layer P2P organizza gli INode esposti dal Layer NET sot<strong>to</strong>stante in<br />
<strong>un</strong>a Membership <strong>di</strong> <strong>Peer</strong> completamente connessi tra loro.<br />
Qui risiedono alc<strong>un</strong>e classi che per nome e f<strong>un</strong>zionalità sono del tut<strong>to</strong> simili<br />
alle controparti presenti nel Layer NET, ma ri<strong>su</strong>ltano finalizzate al contes<strong>to</strong><br />
del Layer P2P: oltre alle classi Setup, Constants e Delegates, vi sono i coman<strong>di</strong><br />
Add<strong>Peer</strong> e TimeSync, entrambi ere<strong>di</strong>tati da P2PCommand.<br />
É presente inoltre <strong>un</strong> sot<strong>to</strong> modulo, che al momen<strong>to</strong> contiene <strong>un</strong>a singola<br />
classe, de<strong>di</strong>ca<strong>to</strong> alla gestione del tempo (si veda la sezione 2.3.1).
78 CAPITOLO 3. IMPLEMENTAZIONE<br />
Infine sono qui implementate le due classi principali che permet<strong>to</strong>no <strong>di</strong> gestire<br />
la Membership: <strong>Peer</strong> e <strong>Peer</strong>Group<br />
La classe <strong>Peer</strong> è composta da <strong>un</strong>’istanza <strong>di</strong> INode che viene invocata per<br />
inviare e ricevere messaggi <strong>di</strong> rete. Contiene inoltre <strong>un</strong>’istanza della classe<br />
<strong>Peer</strong>Group, che tiene traccia <strong>di</strong> tutti i <strong>Peer</strong> conosciuti appartenenti alla<br />
Membership, ed <strong>un</strong>’istanza della classe Time, che viene utilizzata per la gestione<br />
del tempo. A livello <strong>di</strong> f<strong>un</strong>zionalità astrae il Layer NET esponendo<br />
i me<strong>to</strong><strong>di</strong> ConnectTo (), che fa da Wrapper all’omonimo me<strong>to</strong>do <strong>di</strong> INode,<br />
SendTo (), che permette <strong>di</strong> inviare messaggi ad altri <strong>Peer</strong> specificandone il<br />
NetID, e BroadCast () che invia au<strong>to</strong>maticamente <strong>un</strong> messaggio a tutti i <strong>Peer</strong><br />
conosciuti.<br />
Alla creazione <strong>di</strong> <strong>un</strong> ogget<strong>to</strong> <strong>di</strong> tipo <strong>Peer</strong>, viene istanzia<strong>to</strong>, attraverso il<br />
Fac<strong>to</strong>ry del Layer NET, <strong>un</strong> ogget<strong>to</strong> <strong>di</strong> <strong>un</strong>a classe che concretizza l’interfaccia<br />
INode (attualmente quest’ultima è in<strong>di</strong>viduata dalla classe TCPNode).<br />
Viene poi creata <strong>un</strong>’istanza <strong>di</strong> <strong>Peer</strong>Group, alla quale viene aggi<strong>un</strong><strong>to</strong> au<strong>to</strong>maticamente<br />
il riferimen<strong>to</strong> all’INode appena istanzia<strong>to</strong>, ed <strong>un</strong> ogget<strong>to</strong> <strong>di</strong> classe<br />
Time.<br />
Infine vengono registrati i delegati in ascol<strong>to</strong> <strong>su</strong>l Layer NET relativi ai me<strong>to</strong><strong>di</strong><br />
OnConnect(), OnRead() e OnLinksChanged().<br />
Quando viene invoca<strong>to</strong> OnConnect, attraverso il me<strong>to</strong>do AddToKnown-<br />
<strong>Peer</strong>s() viene aggi<strong>un</strong><strong>to</strong> nel proprio <strong>Peer</strong>Group il <strong>Peer</strong> che vi si è appena<br />
connesso.<br />
Inoltre viene notificata l’esistenza <strong>di</strong> quest’ultimo a tutti i gli altri <strong>Peer</strong> conosciuti<br />
(quelli già inclusi nella Membership), tramite il comando Add<strong>Peer</strong>()<br />
parametrizza<strong>to</strong> con il <strong>su</strong>o NetID.<br />
Sull’Exec() <strong>di</strong> Add<strong>Peer</strong>() viene chiama<strong>to</strong> a <strong>su</strong>a volta <strong>un</strong> ConnectTo() verso<br />
il NetID passa<strong>to</strong> come parametro: in ques<strong>to</strong> modo, quando <strong>su</strong>bentra <strong>un</strong><br />
nuovo <strong>Peer</strong> all’interno della Membership, tutti i <strong>Peer</strong> presenti vi si connetteranno<br />
au<strong>to</strong>maticamente (si veda la sezione 2.2).
3.3. LAYER P2P 79<br />
La classe <strong>Peer</strong>Group è quella che, associata alla classe <strong>Peer</strong>, concretizza il<br />
concet<strong>to</strong> <strong>di</strong> Membership.<br />
Si presenta come <strong>un</strong> piccolo Manager che gestisce <strong>un</strong>a lista <strong>di</strong> identifica<strong>to</strong>ri<br />
(NetID) sot<strong>to</strong> forma <strong>di</strong> stringhe: non è quin<strong>di</strong> vincola<strong>to</strong> dall’implementazione<br />
della classe <strong>Peer</strong>. Fornisce inoltre due me<strong>to</strong><strong>di</strong> <strong>di</strong> serializzazione e deserializzazione<br />
che consen<strong>to</strong>no <strong>di</strong> trasformare in stringa (e viceversa) CSV 5 la lista<br />
<strong>di</strong> identifica<strong>to</strong>ri, per poter essere facilmente scambiata, attraverso il Layer<br />
NET, tra due <strong>Peer</strong>.<br />
Figura 3.8: Classi principali- Layer P2P<br />
5 Comma-Separated Values
80 CAPITOLO 3. IMPLEMENTAZIONE<br />
3.3.1 Modulo Time<br />
Il modulo Time è attualmente compos<strong>to</strong> da <strong>un</strong>’<strong>un</strong>ica classe: Time. Questa<br />
contiene <strong>un</strong>a lista <strong>di</strong> TimeSpan (.NET Framework) in<strong>di</strong>cizzati per NetID,<br />
ed espone alc<strong>un</strong>i me<strong>to</strong><strong>di</strong> accessori per la <strong>su</strong>a gestione: AddDelta (), GetDelta<br />
() e GetAllDeltas ().<br />
Implementa inoltre <strong>un</strong> me<strong>to</strong>do polimorfo Convert () che permette <strong>di</strong> convertire,<br />
laddove possibile, TimeStamp calcolati <strong>su</strong>lla base temporale <strong>di</strong> altri<br />
<strong>Peer</strong> rispet<strong>to</strong> al proprio (si veda 2.3.1).<br />
Infine, grazie al me<strong>to</strong>do Now() è possibile ricavare il proprio TimeStamp.<br />
Tale me<strong>to</strong>do utilizza la proprietà statica del .NET framework DateTime.Now.<br />
In fase <strong>di</strong> debug e <strong>di</strong> analisi delle prestazioni, è ri<strong>su</strong>lta<strong>to</strong> mol<strong>to</strong> utile aggi<strong>un</strong>gere<br />
2 fat<strong>to</strong>ri alea<strong>to</strong>ri: il primo emula <strong>un</strong>a <strong>di</strong>fferente timezone (od <strong>un</strong> <strong>di</strong>fferente<br />
settaggio dell’orario <strong>di</strong> sistema), mentre il secondo introduce <strong>un</strong> fat<strong>to</strong>re <strong>di</strong><br />
Lag tra 0 e 1000 millisecon<strong>di</strong>.<br />
La lista contenuta in Time viene popolata perio<strong>di</strong>camente grazie al comando<br />
TimeSync: ogni <strong>Peer</strong> invia agli altri <strong>Peer</strong> conosciuti <strong>un</strong> comando<br />
TimeSync contenente il proprio TimeStamp. Quando ques<strong>to</strong> viene ricevu<strong>to</strong>,<br />
verrà esegui<strong>to</strong> quan<strong>to</strong> implementa<strong>to</strong> nel <strong>su</strong>o me<strong>to</strong>do Exec(), ovvero verrà<br />
calcola<strong>to</strong> il delta tra il TimeStamp ricevu<strong>to</strong> e quello ri<strong>to</strong>rna<strong>to</strong> dal me<strong>to</strong>do<br />
Now() relativo all’istanza Time appartenente al <strong>Peer</strong> destinatario. Quin<strong>di</strong><br />
inseri<strong>to</strong> nella lista, in<strong>di</strong>cizza<strong>to</strong> utilizzando il NetID del mittente.<br />
3.4 Modulo SharedComponents<br />
Il modulo si basa <strong>su</strong>l concet<strong>to</strong> <strong>di</strong> SharedComponent, implementa<strong>to</strong> nell’omonima<br />
classe. Le istanze <strong>di</strong> tale classe sono gestite e memorizzate in<br />
<strong>un</strong>’apposi<strong>to</strong> Manager (ISharedComponentsManager), e create da <strong>un</strong>’apposi<strong>to</strong><br />
Fac<strong>to</strong>ry (ISharedComponentsFac<strong>to</strong>ry).
3.4. MODULO SHAREDCOMPONENTS 81<br />
Figura 3.9: Diagramma delle Classi - Modulo SharedComponents
82 CAPITOLO 3. IMPLEMENTAZIONE<br />
Come illustra<strong>to</strong> nel capi<strong>to</strong>lo 2.4, ogni SharedComponent è identifica<strong>to</strong> da<br />
<strong>un</strong> GlobalID, qui implementa<strong>to</strong> attraverso l’attribu<strong>to</strong> ID ed <strong>un</strong> Value, qui<br />
rappresenta<strong>to</strong> sot<strong>to</strong> forma <strong>di</strong> stringa nell’attribu<strong>to</strong> SerializedValue: tipicamente,<br />
com<strong>un</strong>que, ogni classe che ere<strong>di</strong>ta da SharedComponents contiene al<br />
<strong>su</strong>o interno <strong>un</strong>a variabile privata appositamente tipizzata, a<strong>di</strong>bita alla memorizzazione<br />
del valore vero e proprio.<br />
Facoltativamente possono essere valorizzati anche gli attributi ParentID e<br />
LocalID, se l’istanza <strong>di</strong> SharedComponent si tratta <strong>di</strong> <strong>un</strong> sot<strong>to</strong>-componente.<br />
Inoltre ogni istanza <strong>di</strong> SharedComponent può essere “taggata” per essere raggruppata,<br />
in<strong>di</strong>viduata o filtrata in maniera efficace.<br />
Dal p<strong>un</strong><strong>to</strong> <strong>di</strong> vista f<strong>un</strong>zionale, sono presenti quattro me<strong>to</strong><strong>di</strong> virtuali <strong>di</strong><br />
inizializzazione: il primo, Initialize(), chiama in sequenza gli altri tre: InitializeClass(),<br />
InitializeSubComponents() e InitializeUpdate(). Possono <strong>su</strong>bire<br />
quin<strong>di</strong> <strong>un</strong>’override nel caso le operazioni <strong>di</strong> default non implementino le f<strong>un</strong>zionalità<br />
richieste, o lo facciano solo in parte.<br />
Ad esempio il componente Object3D esegue sia <strong>un</strong> override <strong>di</strong> Initialize-<br />
Class(), nel quale viene aggi<strong>un</strong><strong>to</strong> <strong>un</strong> Tag “View” dal momen<strong>to</strong> che si tratta<br />
<strong>di</strong> <strong>un</strong> componente au<strong>to</strong>maticamente lega<strong>to</strong> ad <strong>un</strong> elemen<strong>to</strong> grafico, sia <strong>un</strong><br />
override <strong>di</strong> InitializeSubComponents() per istanziare i due sot<strong>to</strong>componenti<br />
Vec<strong>to</strong>r3 Position e Vec<strong>to</strong>r3 Rotation. Ogni componente, <strong>di</strong> default, è tagga<strong>to</strong><br />
con il tag Constants.ComponentTag NotifyChange, che ne attiva la notifica<br />
au<strong>to</strong>matica <strong>su</strong>lle mo<strong>di</strong>fiche apportate al valore del componente stesso.<br />
La f<strong>un</strong>zione <strong>di</strong> InitializeUpdate() è strettamente legata al me<strong>to</strong>do virtuale<br />
Update(): <strong>di</strong> default infatti, se il componente che ere<strong>di</strong>ta da SharedComponent<br />
esegue <strong>un</strong> override <strong>di</strong> Update, in InitializeUpdate ques<strong>to</strong> verrà registra<strong>to</strong><br />
nel proprio Manager <strong>di</strong> appartenenza come componente da aggiornare ad<br />
ogni iterazione.<br />
SharedComponent espone inoltre <strong>un</strong>a serie <strong>di</strong> me<strong>to</strong><strong>di</strong> accessori per la gestione<br />
au<strong>to</strong>matizzata dei sot<strong>to</strong>-componenti (Add(), Remove(), FindByLocalID(),
3.4. MODULO SHAREDCOMPONENTS 83<br />
FindByGlobalID() e FindByType()) e per la gestione dei Tags (Tag Add(),<br />
Tag Remove() e Tag Has()).<br />
Infine è presente <strong>un</strong> me<strong>to</strong>do virtuale OnChange(), au<strong>to</strong>maticamente invoca<strong>to</strong><br />
ogniqualvolta viene mo<strong>di</strong>fica<strong>to</strong> il Value del componente. In ques<strong>to</strong> me<strong>to</strong>do,<br />
se si tratta <strong>di</strong> <strong>un</strong> proprio componente (non appartenente ad <strong>un</strong> contes<strong>to</strong><br />
esterno, quin<strong>di</strong>) e se ques<strong>to</strong> è tagga<strong>to</strong> con Constants.ComponentTag NotifyChange,<br />
allora viene chiamata la f<strong>un</strong>zione NotifyChange() del SharedComponentsManager.<br />
La classe SharedComponentsManager ha la f<strong>un</strong>zione principale <strong>di</strong> mantenere<br />
e gestire la lista <strong>di</strong> tutte le istanze <strong>di</strong> SharedComponent, sia quelle create<br />
<strong>di</strong>rettamente dal proprio Fac<strong>to</strong>ry (<strong>un</strong> ogget<strong>to</strong> <strong>di</strong> <strong>un</strong>a classe che concretizza<br />
ISharedComponentsFac<strong>to</strong>ry), che quelle provenienti da <strong>un</strong> contes<strong>to</strong> esterno.<br />
É identificata da <strong>un</strong> Name. Quest’ultimo sarà estremamente importante per<br />
la gestione del contes<strong>to</strong> logico introdotta dal Layer Logic.<br />
Sono inoltre implementati i seguenti me<strong>to</strong><strong>di</strong> ausiliari:<br />
• FindByGlobalID(): per cercare <strong>un</strong> componente all’interno della lista<br />
conoscendo il solo GlobalID.<br />
• GetOnlyMine(): per ricavare solo i propri componenti, cioè quelli <strong>di</strong>rettamente<br />
generati dal proprio Fac<strong>to</strong>ry.<br />
• IsMine(): per sapere se il componente passa<strong>to</strong> come parametro, appartiene<br />
o meno a ques<strong>to</strong> Manager.<br />
• AddToUpdater(): aggi<strong>un</strong>ge il componente passa<strong>to</strong> come parametro alla<br />
lista dei componenti da aggiornare ad ogni iterazione.<br />
• RemoveFromUpdater(): rimuove il componente passa<strong>to</strong> come parametro<br />
dalla lista dei componenti da aggiornare ad ogni iterazione.
84 CAPITOLO 3. IMPLEMENTAZIONE<br />
• Update(): il me<strong>to</strong>do da chiamare ad ogni iterazione per aggiornare tutti<br />
i componenti registrati.<br />
Infine vi sono i quattro me<strong>to</strong><strong>di</strong> utilizzati per invocare gli eventi OnCreate,<br />
OnChange, OnActive e OnDestroy.<br />
OnCreate viene invoca<strong>to</strong>, attraverso il Fac<strong>to</strong>ry, <strong>su</strong>lla creazione <strong>di</strong> <strong>un</strong> proprio<br />
componente, mentre OnDestroy viene invoca<strong>to</strong>, sempre attraverso il Fac<strong>to</strong>ry,<br />
<strong>su</strong>lla <strong>su</strong>a <strong>di</strong>struzione. OnChange viene invoca<strong>to</strong> quando cambia il valore <strong>di</strong><br />
<strong>un</strong> proprio componente, e OnActive quando quest’ultimo cambia sta<strong>to</strong> e <strong>di</strong>venta<br />
attivo (cioè quando ogni <strong>su</strong>o eventuale sot<strong>to</strong>-componente è sta<strong>to</strong> crea<strong>to</strong><br />
ed inizializza<strong>to</strong>). Tali eventi verranno poi ascoltati dal Layer Logic, che si<br />
occuperà <strong>di</strong> propagarne la loro notifica attraverso la rete.<br />
La classe SharedComponentFac<strong>to</strong>ry viene utilizzata per creare e <strong>di</strong>struggere<br />
istanze <strong>di</strong> SharedComponents.<br />
Quando il componente da creare appartiene al Manager lega<strong>to</strong> all’istanza del<br />
Fac<strong>to</strong>ry in questione, allora verrà crea<strong>to</strong> attraverso il mo<strong>to</strong>do Create().<br />
Quando invece il componente da creare appartiene ad <strong>un</strong> altro contes<strong>to</strong> (tipicamente<br />
sono copie <strong>di</strong> componenti appartenenti ad altri <strong>Peer</strong>), allora viene<br />
invoca<strong>to</strong> il me<strong>to</strong>do CreateFromOtherContext().<br />
3.5 Layer Logic<br />
Il Layer Logic è sostanzialmente <strong>di</strong>viso in due regioni, <strong>di</strong>fferenziate dal<br />
livello <strong>di</strong> generalizzazione implici<strong>to</strong> nelle classi che ne fanno parte.<br />
La regione più Generic Oriented introduce il contes<strong>to</strong> logico, in<strong>di</strong>vidua<strong>to</strong> dalla<br />
classe <strong>Peer</strong>Context: questa <strong>un</strong>isce le f<strong>un</strong>zionalità esposte dal Layer P2P e<br />
quelle caratteristiche del Data Layer rappresenta<strong>to</strong> dal modulo SharedComponents.<br />
La classe <strong>Peer</strong>Context, infatti, é composta da <strong>un</strong>’istanza <strong>di</strong> <strong>Peer</strong> e <strong>un</strong>a <strong>di</strong><br />
SharedcomponentsManager; queste ri<strong>su</strong>ltano legate tra loro tramite il mede-
3.5. LAYER LOGIC 85<br />
Figura 3.10: Classi Principali - Modulo SharedComponents
86 CAPITOLO 3. IMPLEMENTAZIONE<br />
Figura 3.11: Diagramma delle Classi - Layer Logic
3.6. LAYER VIEW 87<br />
simo identificativo: l’attribu<strong>to</strong> NetID dell’istanza <strong>di</strong> <strong>Peer</strong> e l’attribu<strong>to</strong> Name<br />
dell’istanza <strong>di</strong> SharedComponentsManager hanno lo stesso valore.<br />
Tale vincolo ha l’effet<strong>to</strong> implici<strong>to</strong> <strong>di</strong> estendere la proprietà <strong>di</strong> <strong>un</strong>o SharedComponent,<br />
non più al solo Manager ma anche all’intero <strong>Peer</strong>.<br />
Sono inoltre implementati i Commands che permet<strong>to</strong>no la sincronizzazione<br />
au<strong>to</strong>matica del DataLayer tra i <strong>di</strong>versi <strong>Peer</strong> ( CreateComponent, Update-<br />
Component, ActivateComponent e SendToComponent) ed i componenti che<br />
consen<strong>to</strong>no <strong>di</strong> rappresentare le informazioni più com<strong>un</strong>i per l’identificazione<br />
si <strong>un</strong> elemen<strong>to</strong> grafico all’interno <strong>di</strong> <strong>un</strong> generico videogioco tri<strong>di</strong>mensionale<br />
(Object3D e MovingObject3D).<br />
La seconda regione è più <strong>Game</strong> Oriented, nel senso che da qui in poi iniziano<br />
a presentarsi classi che implementano logiche strettamente legate alle<br />
specifiche <strong>di</strong> gioco e alle relative <strong>di</strong>namiche <strong>di</strong> <strong>Game</strong>Play.<br />
Qui si trova la classe PlayerContext, ere<strong>di</strong>tata da <strong>Peer</strong>Context, che da <strong>un</strong>a<br />
parte astrae il contes<strong>to</strong> lega<strong>to</strong> al concet<strong>to</strong> <strong>di</strong> “<strong>Peer</strong>”, limitandolo a quello<br />
più specifico <strong>di</strong> Player, e dall’altra implementa <strong>un</strong>a serie <strong>di</strong> logiche che caratterizzano<br />
quest’ultimo: ad esempio viene esegui<strong>to</strong> <strong>un</strong> override <strong>su</strong>l me<strong>to</strong>do<br />
Join, nel quale viene istanzia<strong>to</strong> <strong>un</strong> componente <strong>di</strong> tipo Character; in ques<strong>to</strong><br />
modo, quando inizia la partita, ogni Player creerà au<strong>to</strong>maticamente nel proprio<br />
contes<strong>to</strong> logico <strong>un</strong>’istanza Character, la quale sarà quin<strong>di</strong> con<strong>di</strong>visa tra<br />
tutti i <strong>Peer</strong>.<br />
3.6 Layer View<br />
Come evidenzia<strong>to</strong> nel capi<strong>to</strong>lo 2.6, il Layer View è mol<strong>to</strong> vas<strong>to</strong>, e fa fronte<br />
ad <strong>un</strong> notevole numero <strong>di</strong> problematiche e f<strong>un</strong>zionalità, molte delle quali non<br />
sono strettamente connesse all’argomen<strong>to</strong> <strong>di</strong> tesi.<br />
Aspetti come il Rendering, la gestione degli Input, la gestione della riprodu-
88 CAPITOLO 3. IMPLEMENTAZIONE<br />
Figura 3.12: Classi Principali - Layer Logic
3.6. LAYER VIEW 89<br />
Figura 3.13: Diagramma delle Classi - Layer View
90 CAPITOLO 3. IMPLEMENTAZIONE<br />
zione Au<strong>di</strong>o e la simulazione della fisica, sono infatti delegati agli strumenti<br />
messi a <strong>di</strong>sposizione da Unity3D.<br />
Quest’ultimo permette <strong>di</strong> definire i comportamenti che caratterizzano gli elementi<br />
presenti nella scena, me<strong>di</strong>ante <strong>un</strong> sistema <strong>di</strong> “Scripting” basa<strong>to</strong> <strong>su</strong>lla<br />
classe “Behaviour”.<br />
La classe principale, ContexView, concretizza il contes<strong>to</strong> “View” e fa da<br />
“Bridge” tra ques<strong>to</strong> ed il contes<strong>to</strong> “Logic” via composition. Ri<strong>su</strong>lta essere<br />
quin<strong>di</strong> il p<strong>un</strong><strong>to</strong> d’accesso a tutti i Layer sot<strong>to</strong>stanti (Figura 3.14).<br />
Figura 3.14: Catena dei Layer, legati via composition<br />
Parallelamente la classe ViewContextSync, estesa dalla classe Behaviour,<br />
si occupa della sincronizzazione tra il contes<strong>to</strong> logico e quello vi<strong>su</strong>ale.<br />
Ad ogni iterazione, infatti, esegue <strong>un</strong> polling <strong>su</strong>l Data Layer, controllando<br />
che non vi siano componenti logici taggati con il tag “View” senza <strong>un</strong>a<br />
rispettiva controparte vi<strong>su</strong>ale all’interno della scena 3D. Quando ciò accade,<br />
viene istanzia<strong>to</strong> au<strong>to</strong>maticamente <strong>un</strong> elemen<strong>to</strong> grafico ed applicata ad esso<br />
<strong>un</strong>a classe (che segue la naming convention “[nome componente]Script”),<br />
estesa da ComponentScript (Behaviour), che ne definisce il comportamen<strong>to</strong><br />
(si veda 2.6).<br />
La classe ComponentScript è definita secondo il seguente schema:
3.6. LAYER VIEW 91<br />
• String LogicComponentID: attribu<strong>to</strong> al quale viene assegna<strong>to</strong> il valore<br />
del GlobalID appartenente allo SharedComponent che rappresenta lo<br />
sta<strong>to</strong> logico dell’elemen<strong>to</strong> grafico.<br />
• Update(): il me<strong>to</strong>do che viene invoca<strong>to</strong> ad ogni iterazione. Il <strong>su</strong>o comportamen<strong>to</strong><br />
<strong>di</strong> default, eventualmente mo<strong>di</strong>ficabile via override, prevede<br />
la chiamata <strong>di</strong> Update Writer() se lo SharedComponent assegna<strong>to</strong><br />
appartiene al contes<strong>to</strong> logico del Player. In caso contrario viene chiama<strong>to</strong><br />
Update Reader(). Infine, attraverso CheckDestroy(), viene verificata<br />
l’esistenza del componente logico all’interno del Data Layer:<br />
se ques<strong>to</strong> non è più presente, allora verrà <strong>di</strong>strut<strong>to</strong> l’elemen<strong>to</strong> grafico<br />
corrispondente (e <strong>di</strong> conseguenza anche il relativo ComponentScript)<br />
Ad esempio, il ComponentScript relativo al componente <strong>di</strong> tipo Character<br />
(cioè la classe CharacterScript), all’interno del me<strong>to</strong>do Update Writer()<br />
eseguirà l’aggiornamen<strong>to</strong> perio<strong>di</strong>co delle coor<strong>di</strong>nate e della rotazione del personaggio<br />
controlla<strong>to</strong> dal Player, mentre nel me<strong>to</strong>do Update Reader() vi sarà<br />
implementata <strong>un</strong>a logica <strong>di</strong> Dead Reckoning (Figura 3.15).<br />
Figura 3.15: CharacterScript
92 CAPITOLO 3. IMPLEMENTAZIONE
Capi<strong>to</strong>lo 4<br />
Analisi delle prestazioni<br />
Il contes<strong>to</strong> nel quale è sta<strong>to</strong> sviluppa<strong>to</strong> il proget<strong>to</strong> rende <strong>di</strong>fficol<strong>to</strong>sa l’in<strong>di</strong>viduazione<br />
<strong>di</strong> parametri e delle relative mi<strong>su</strong>razioni che si possono effettuare,<br />
invece, in scenari più ampi e strutturati. Mi<strong>su</strong>re derivanti da fat<strong>to</strong>ri come<br />
la latenza, la <strong>su</strong>a variazione ed il numero <strong>di</strong> gioca<strong>to</strong>ri non sono facilmente<br />
simulabili in modo realistico in <strong>un</strong> contes<strong>to</strong> locale.<br />
In ques<strong>to</strong> senso è sta<strong>to</strong> implementa<strong>to</strong> <strong>un</strong> sistema che consente <strong>di</strong> simulare la<br />
presenza <strong>di</strong> Lag tra i <strong>di</strong>versi <strong>Peer</strong> che compongono la Membership, ritardando<br />
l’esecuzione dei coman<strong>di</strong> inviati e ricevuti.<br />
Introducendo infatti <strong>un</strong> valore <strong>di</strong> latenza relativamente al<strong>to</strong> (200 / 500<br />
millisecon<strong>di</strong>) in <strong>un</strong>o dei <strong>Peer</strong> connessi alla Membership <strong>di</strong> prova è sta<strong>to</strong> possibile<br />
ricavare alc<strong>un</strong>e considerazioni qualitative:<br />
I processi <strong>di</strong> interazione che coinvolgono elementi (SharedComponent) gestiti<br />
dal <strong>Peer</strong> sogget<strong>to</strong> a Lag, ri<strong>su</strong>ltano rallentati <strong>su</strong> tutti i <strong>Peer</strong>.<br />
Mentre, dal p<strong>un</strong><strong>to</strong> <strong>di</strong> vista del <strong>Peer</strong> sogget<strong>to</strong> a Lag, tale ritardo si ripercuote<br />
<strong>su</strong> qualsiasi tipo <strong>di</strong> aggiornamen<strong>to</strong> proveniente dagli altri <strong>Peer</strong>.<br />
Come era preve<strong>di</strong>bile, l’esperienza <strong>di</strong> gioco ri<strong>su</strong>lta quin<strong>di</strong> essere abbastanza<br />
compromessa, specialmente per i <strong>Peer</strong> con la latenza più elevata.<br />
Un primo scenario analizzabile quantitativamente in <strong>un</strong> contes<strong>to</strong> locale<br />
può essere in<strong>di</strong>vidua<strong>to</strong> nella mi<strong>su</strong>razione del tempo trascorso tra l’invio <strong>di</strong> <strong>un</strong><br />
93
94 CAPITOLO 4. ANALISI DELLE PRESTAZIONI<br />
messaggio da parte <strong>di</strong> <strong>un</strong> <strong>Peer</strong> e la <strong>su</strong>a esecuzione da parte degli altri <strong>Peer</strong><br />
appartenenti alla Membership. Ques<strong>to</strong> prova è stata eseguita istanziando<br />
10 oggetti <strong>di</strong> classe <strong>Peer</strong>Context (si veda la sezione 3.5): Il “<strong>Peer</strong> 1 ” invia 7<br />
aggiornamenti consecutivi <strong>di</strong> <strong>un</strong> componente presente nel proprio Data Layer,<br />
incrementandone ogni volta il valore all’interno <strong>di</strong> <strong>un</strong> ciclo For.<br />
In Figura 4.1 sono riportati i ri<strong>su</strong>ltati sot<strong>to</strong>forma <strong>di</strong> grafico a <strong>di</strong>spersione: i<br />
<strong>di</strong>versi stati <strong>di</strong> gioco (in ques<strong>to</strong> caso limitati al valore del singolo componente<br />
mo<strong>di</strong>fica<strong>to</strong>) sono rappresentati da linee curve che interpolano i p<strong>un</strong>ti nei quali<br />
i <strong>di</strong>versi <strong>Peer</strong> (linee verticali) eseguono l’aggiornamen<strong>to</strong> del componente in<br />
questione.<br />
Figura 4.1: Tempo <strong>di</strong> ricezione ed esecuzione <strong>di</strong> <strong>un</strong> aggiornamen<strong>to</strong> <strong>di</strong> <strong>un</strong><br />
componente logico<br />
L’esecuzione degli aggiornamenti, nonostante si presenti nel medesimo<br />
or<strong>di</strong>ne <strong>su</strong>i <strong>di</strong>versi <strong>Peer</strong> (grazie all’utilizzo del TCP), non avviene in modo<br />
sincronizza<strong>to</strong>: lo “Sta<strong>to</strong> 5 ”, ad esempio, viene esegui<strong>to</strong> dal “<strong>Peer</strong> 2 ” in T2,
95<br />
e dal “<strong>Peer</strong> 10 ” in T6.<br />
Il TimeSpan preso in esame è com<strong>un</strong>que estremamente ridot<strong>to</strong> (minore <strong>di</strong><br />
<strong>un</strong> millisecondo), e le variazioni riscontrate sono da ricondurre alla politica<br />
con la quale vengono schedulati i Thread <strong>di</strong> lettura e scrittura utilizzati da<br />
ogni <strong>Peer</strong> per com<strong>un</strong>icare con gli altri <strong>Peer</strong> appartenenti alla Membership .<br />
Utilizzando <strong>un</strong> sistema <strong>di</strong> sincronizzazione “S<strong>to</strong>p-And-Wait” (si veda la<br />
sezione ), tali variazioni non si sarebbero riscontrate; o meglio, l’istante <strong>di</strong><br />
tempo <strong>di</strong> esecuzione sarebbe sta<strong>to</strong> com<strong>un</strong>que <strong>di</strong>fferente <strong>su</strong>i <strong>di</strong>versi <strong>Peer</strong>, ma<br />
all’interno <strong>di</strong> <strong>un</strong>o stesso periodo <strong>di</strong> tempo lo sta<strong>to</strong> <strong>di</strong> gioco sarebbe ri<strong>su</strong>lta<strong>to</strong><br />
il medesimo (Figura 4.2).<br />
Figura 4.2: Tempo simula<strong>to</strong> <strong>di</strong> ricezione ed esecuzione <strong>di</strong> <strong>un</strong> aggiornamen<strong>to</strong><br />
<strong>di</strong> <strong>un</strong> componente logico con sistema <strong>di</strong> sincronizzazione S<strong>to</strong>p-And-Wait<br />
Il passo <strong>su</strong>ccessivo è sta<strong>to</strong> quello <strong>di</strong> introdurre nello scenario precedente<br />
la simulazione <strong>di</strong> latenza <strong>di</strong> rete: ogni <strong>Peer</strong> è sta<strong>to</strong> imposta<strong>to</strong> per simulare<br />
<strong>un</strong>a latenza variabile da 5 a 30 millisecon<strong>di</strong>, ad esclusione del “<strong>Peer</strong> 3 ”,
96 CAPITOLO 4. ANALISI DELLE PRESTAZIONI<br />
la cui latenza è stata settata <strong>su</strong>i 100 millisecon<strong>di</strong>. La frequenza <strong>di</strong> invio<br />
degli aggiornamenti è stata abbassata appositamente a 10 millisecon<strong>di</strong> per<br />
consentire <strong>un</strong>a migliore leggibilità del grafico (Figura 4.3).<br />
Figura 4.3: Tempo <strong>di</strong> ricezione ed esecuzione introducendo latenza <strong>di</strong> rete<br />
Come era facile prevedere, il “<strong>Peer</strong> 3 ” riceverà ed eseguirà gli aggiornamenti<br />
in ritardo rispet<strong>to</strong> agli altri <strong>Peer</strong>. L’or<strong>di</strong>ne <strong>di</strong> esecuzione rimane<br />
com<strong>un</strong>que coerente: graficamente ques<strong>to</strong> è visibile dal fat<strong>to</strong> che non sono<br />
presenti linee che si intersecano.<br />
Queste mi<strong>su</strong>razioni sono state effettuate <strong>di</strong>sabilitando il Layer View poichè<br />
la richiesta <strong>di</strong> risorse da parte del Renderer non consentiva l’esecuzione contemporanea<br />
<strong>di</strong> più <strong>di</strong> 4 <strong>Peer</strong>.<br />
Utilizzando Unity3D si è vincolati all’utilizzo <strong>di</strong> <strong>un</strong> <strong>un</strong>ico Thread, <strong>su</strong>l quale<br />
processare alternativamente la logica prima ed il rendering poi; quest’ultimo
97<br />
è in assolu<strong>to</strong> il processo che richiede più risorse, sia a livello <strong>di</strong> utilizzo CPU<br />
che <strong>di</strong> memoria (Figura 4.4).<br />
Figura 4.4: Threads <strong>di</strong> esecuzione: il Thread principale è gesti<strong>to</strong> da Unity3D<br />
e processa alternativamente le <strong>di</strong>namiche logiche e la pipeline <strong>di</strong> rendering.<br />
Per ogni <strong>Peer</strong> appartenente alla Membership vengono inoltre istanziati due<br />
Thread, <strong>un</strong>o <strong>di</strong> lettura e <strong>un</strong>o <strong>di</strong> scrittura.<br />
Successivamente è sta<strong>to</strong> analizza<strong>to</strong> <strong>un</strong>o scenario comprensivo del Layer<br />
View: sono stati mi<strong>su</strong>rati il numero <strong>di</strong> messaggi scambiati tra 4 <strong>Peer</strong> durante<br />
<strong>un</strong>a sessione <strong>di</strong> gioco. Il Update Write() <strong>di</strong> ogni CharacterScript è sta<strong>to</strong><br />
mo<strong>di</strong>fica<strong>to</strong> in modo da produrre aggiornamenti <strong>su</strong>fficientemente realistici per<br />
lo scenario <strong>di</strong> analisi, in maniera au<strong>to</strong>matica, senza cioè che sia richiesta la<br />
presenza <strong>di</strong> <strong>un</strong> gioca<strong>to</strong>re reale, simulando il movimen<strong>to</strong> del Character e la<br />
generazione <strong>di</strong> Bullets.<br />
Da i ri<strong>su</strong>ltati ottenuti è emersa l’esistenza <strong>di</strong> alc<strong>un</strong>e fasi critiche: facendo<br />
riferimen<strong>to</strong> alla Figura 4.5, in T2, T4 e T6 sono in<strong>di</strong>viduabili perio<strong>di</strong> <strong>di</strong> picco,<br />
esponenzialmente crescenti, sia per quan<strong>to</strong> rigurada il numero <strong>di</strong> messaggi
98 CAPITOLO 4. ANALISI DELLE PRESTAZIONI<br />
inviati, che per la durata dei perio<strong>di</strong> stessi, in f<strong>un</strong>zione dell’incremen<strong>to</strong> del<br />
numero dei <strong>Peer</strong> connessi alla Membership. Tali perio<strong>di</strong> sono contestualizzati<br />
all’interno della fase <strong>di</strong> sincronizzazione del Data Layer che avviene conseguentemente<br />
al join <strong>di</strong> <strong>un</strong> nuovo <strong>Peer</strong> all’interno della Membership, nella<br />
quale ogni <strong>Peer</strong> è tenu<strong>to</strong> ad inviare la lista dei propri componenti presenti<br />
nel modulo SharedComponents (capi<strong>to</strong>lo 2). In T1, T3, T5 e T7, invece il<br />
numero <strong>to</strong>tale <strong>di</strong> messaggi scambiati ri<strong>to</strong>rna nel range <strong>di</strong> 0-5 messaggi ogni<br />
0.25 secon<strong>di</strong>. Chiaramente anche quest’ultimo sarà destina<strong>to</strong> a crescere al<br />
crescere del numero <strong>di</strong> <strong>Peer</strong> connessi.<br />
Figura 4.5: Messaggi scambiati in <strong>un</strong>a sessione <strong>di</strong> gioco:
Capi<strong>to</strong>lo 5<br />
Sviluppi futuri<br />
5.1 Anti-Cheating<br />
Per “Cheating” si intende quella attività messa in at<strong>to</strong> da alc<strong>un</strong>i gioca<strong>to</strong>ri<br />
(“Cheaters”) in grado <strong>di</strong> mo<strong>di</strong>ficare l’esperienza <strong>di</strong> gioco e trarne vantaggio.<br />
Per alterare la <strong>di</strong>namica <strong>di</strong> gioco è possibile operare in <strong>di</strong>versi contesti e non<br />
necessariamente a livello software: si pensi ad esempio ad <strong>un</strong> gioco le cui<br />
regole prevedono <strong>un</strong> equo scontro tra N gioca<strong>to</strong>ri. Se alc<strong>un</strong>i <strong>di</strong> questi si coalizzano<br />
tra loro, guadagnano <strong>un</strong> vantaggio <strong>su</strong>i gioca<strong>to</strong>ri che invece non si sono<br />
coalizzati. La <strong>di</strong>namica <strong>di</strong> gioco viene così alterata, e le soluzioni software per<br />
far fronte a ques<strong>to</strong> problema sono, in ques<strong>to</strong> caso (“Cheating by collusion”),<br />
inefficaci.<br />
Tendenzialmente per far fronte a queste tipologie <strong>di</strong> Cheating è necessario<br />
lavorare <strong>di</strong>rettamente <strong>su</strong>l <strong>Game</strong>play, cercando <strong>di</strong> evitare, cioè, <strong>di</strong> far<br />
emergere meccaniche “sociali” <strong>di</strong> ques<strong>to</strong> tipo, ed eventualmente <strong>di</strong>sincentivarle,<br />
rendendole notevolmente svantaggiose per il gioca<strong>to</strong>re che le sfrutta.<br />
Non sempre è possibile: il solo at<strong>to</strong> <strong>di</strong> <strong>di</strong>sconnessione (o logout) durante <strong>un</strong>a<br />
partita, non solo turba pesantemente il flusso e l’asset<strong>to</strong> <strong>di</strong> gioco, ma è anche<br />
impossibile evitare.<br />
99
100 CAPITOLO 5. SVILUPPI FUTURI<br />
Un altro scenario particolarmente interessante che non coinvolge problematiche<br />
e soluzioni software è quello del cosiddet<strong>to</strong> “Gold farming”, ovvero<br />
la compraven<strong>di</strong>ta, esterna al contes<strong>to</strong> <strong>di</strong> gioco, <strong>di</strong> items e abilità virtuali in<br />
cambio <strong>di</strong> denaro reale.<br />
I sistemi <strong>di</strong> Cheating basati <strong>su</strong> exploit software operano <strong>su</strong> <strong>di</strong>versi livelli.<br />
E’ possibile infatti mo<strong>di</strong>ficare il Client in modo da au<strong>to</strong>matizzare alc<strong>un</strong>i processi,<br />
rimpiazzando <strong>di</strong> fat<strong>to</strong> il gioca<strong>to</strong>re, che in ques<strong>to</strong> modo può de<strong>di</strong>carsi<br />
ad altri aspetti <strong>di</strong> gioco: in <strong>un</strong> RTS, <strong>un</strong> Cheat Software può occuparsi della<br />
gestione economica del regno virtuale, lasciando le sezioni <strong>di</strong> combattimen<strong>to</strong><br />
in mano al gioca<strong>to</strong>re, o viceversa. O ancora, si possono vi<strong>su</strong>alizzare dati e<br />
informazioni presenti nel Data Layer ma volutamente nascoste nel Presentation<br />
Layer, ad esempio eliminando la cosiddetta “Fog Of War” e quin<strong>di</strong>, <strong>di</strong><br />
conseguenza, conoscere l’intera area <strong>di</strong> gioco, anche quella inesplorata.<br />
In ambi<strong>to</strong> FPS, invece, i sistemi <strong>di</strong> Cheating più utilizzati sono da <strong>un</strong>a<br />
parte quelli che permet<strong>to</strong>no <strong>di</strong> migliorare le prestazioni del gioca<strong>to</strong>re, attraverso<br />
lo Speed Hacking, che aumenta la velocità del Character, e l’Au<strong>to</strong><br />
Aiming, che ruota la vi<strong>su</strong>ale au<strong>to</strong>maticamente <strong>su</strong>l target più vicino, e dall’altra<br />
quei sistemi che si basano <strong>su</strong>lla riduzione e <strong>su</strong>ll’alterazione della qualità<br />
grafica, in modo tale da evidenziare o vi<strong>su</strong>alizzare elementi grafici altrimenti<br />
poco visibili o ad<strong>di</strong>rittura nascosti.<br />
Tipicamente questa tipologia <strong>di</strong> Cheat opera la<strong>to</strong> Client e pertan<strong>to</strong>, attraverso<br />
sistemi quali P<strong>un</strong>k Buster 1 e AntiTCC, è possibile in qualche modo<br />
limitare la loro azione. Tali sistemi infatti eseguono <strong>un</strong>a scansione locale, sia<br />
a livello <strong>di</strong> FileSystem, verificando l’integrità dei file utilizzati dal videogioco,<br />
che a livello dei processi e relativa memoria. Se la scansione <strong>di</strong> Integrity<br />
Check, solitamente avviata ad inizio e fine partita, o in concomitanza <strong>di</strong> particolari<br />
situazioni <strong>di</strong> gioco, ad esempio <strong>su</strong>bi<strong>to</strong> dopo <strong>un</strong> Frag, fallisce, allora il<br />
1 http://www.evenbalance.com
5.1. ANTI-CHEATING 101<br />
gioca<strong>to</strong>re viene esplulso dalla partita.<br />
Sistemi <strong>di</strong> Cheating come lo Speed Hacking e Au<strong>to</strong> Aiming, però, possono<br />
essere implementati anche ad <strong>un</strong> livello inferiore rispet<strong>to</strong> a quello applicativo<br />
in<strong>di</strong>vidua<strong>to</strong> dal Client. Utilizzando appositi programmi esterni è infatti<br />
possibile moni<strong>to</strong>rare e mo<strong>di</strong>ficare ogni singolo pacchet<strong>to</strong> invia<strong>to</strong> al Server al<br />
fine <strong>di</strong> trarne <strong>un</strong> vantaggio nel contes<strong>to</strong> delle <strong>di</strong>namiche <strong>di</strong> gioco.<br />
In <strong>un</strong>’architettura Client-Server si tende a delegare la logica <strong>di</strong> gioco ed<br />
i relativi controlli <strong>su</strong>l Server poichè si pre<strong>su</strong>me sia <strong>un</strong>’entità “trusted”, limitando<br />
il più possibile i Clients a quelle che sono le operazioni meno sensibili<br />
dal p<strong>un</strong><strong>to</strong> <strong>di</strong> vista dell’avanzamen<strong>to</strong> dello sta<strong>to</strong> <strong>di</strong> gioco.<br />
In <strong>un</strong>a logica <strong>Peer</strong>-To-<strong>Peer</strong>, la mancanza <strong>di</strong> <strong>un</strong> asset<strong>to</strong> centralizza<strong>to</strong> porta ad<br />
avere come <strong>un</strong>ici elementi potenzialmente “trusted” gli stessi <strong>Peer</strong>.<br />
In <strong>un</strong>a rete au<strong>to</strong>gestita, ques<strong>to</strong> implica da <strong>un</strong>a parte <strong>un</strong> sistema <strong>di</strong> Cheatdetection<br />
<strong>su</strong> ogni singolo <strong>Peer</strong>, e dall’altra <strong>un</strong>’organizzazione interna alla Memebership<br />
in grado <strong>di</strong> in<strong>di</strong>viduare <strong>un</strong>’au<strong>to</strong>rità a<strong>di</strong>bita al Cheat-management.<br />
Inoltre sistemi <strong>di</strong> sincronizizzazione temporale, come la Bucket Synchronization,<br />
possono essere aggirati sfruttando il ritardo tra la ricezione <strong>di</strong> eventi<br />
provenienti dagli altri <strong>Peer</strong> e la loro effettiva esecuzione: <strong>un</strong> <strong>Peer</strong> può ad esempio<br />
inviare <strong>un</strong> even<strong>to</strong> opport<strong>un</strong>amente crea<strong>to</strong> bastandosi <strong>su</strong>lle “intenzioni”<br />
ricevute ma non ancora eseguite (Look Ahead Cheat). O più semplicemente<br />
mo<strong>di</strong>ficare il TimeStamp <strong>di</strong> <strong>un</strong> even<strong>to</strong> così da ri<strong>su</strong>ltare essere sta<strong>to</strong> invia<strong>to</strong><br />
in <strong>un</strong> istante <strong>di</strong> tempo precedente (TimeStamp Cheat).<br />
Di segui<strong>to</strong> viene proposta l’implementazione <strong>di</strong> <strong>un</strong> Modulo de<strong>di</strong>ca<strong>to</strong> al<br />
Cheat-detection: come anticipa<strong>to</strong> nel capi<strong>to</strong>lo 1, tipicamente i MOGs che si<br />
basano <strong>su</strong> <strong>un</strong> modello <strong>Peer</strong>-To-<strong>Peer</strong> vengono <strong>su</strong>pportati com<strong>un</strong>que da <strong>un</strong>’architettura<br />
centralizzata, utilizzata come p<strong>un</strong><strong>to</strong> d’accesso alle partite, ed eventualmente<br />
come au<strong>to</strong>rità per la gestione dell’Anti-Cheating. Il contes<strong>to</strong> in<strong>di</strong>vidua<strong>to</strong><br />
del proget<strong>to</strong> <strong>di</strong> tesi, invece, non contempla ques<strong>to</strong> tipo <strong>di</strong> <strong>su</strong>ppor<strong>to</strong>.
102 CAPITOLO 5. SVILUPPI FUTURI<br />
Tale mancanza sposta il problema del Cheat-detection da <strong>un</strong> livello <strong>su</strong>periore<br />
al livello della <strong>Game</strong> Logic.<br />
Infatti è possibile estendere la classe ComponentScript, aggi<strong>un</strong>gendo la<br />
chiamata <strong>di</strong> <strong>un</strong>a f<strong>un</strong>zione astratta CheatDetection() all’interno del me<strong>to</strong>do<br />
Update Reader(). Eseguendo <strong>un</strong> Override <strong>di</strong> ques<strong>to</strong> me<strong>to</strong>do, a seconda delle<br />
caratteristiche del componente associa<strong>to</strong> al ComponentScript, si possono<br />
eseguire determinati controlli specifici atti a controllare la coerenza delle<br />
informazioni gi<strong>un</strong>te da altri <strong>Peer</strong>.<br />
Per quan<strong>to</strong> riguarda il Cheat-management è necessario implementare <strong>un</strong><br />
sistema “democratico” in grado <strong>di</strong> prendere decisioni quali, ad esempio,<br />
l’espulsione <strong>di</strong> <strong>un</strong> determina<strong>to</strong> <strong>Peer</strong> dalla Membership.<br />
Un sistema potrebbe essere quello <strong>di</strong> attribuire ad ogni Player <strong>un</strong> p<strong>un</strong>teggio<br />
<strong>di</strong> “Fairness”. Quando, in <strong>un</strong>a specifica implementazione <strong>di</strong> Cheat-<br />
Detection(), viene rilevata <strong>un</strong>’incoerenza sospetta tale p<strong>un</strong>teggio viene decrementa<strong>to</strong>.<br />
Ogni Player attribuisce agli altri Player <strong>un</strong>a propria visione <strong>di</strong><br />
Fairness: non è det<strong>to</strong>, cioè, che il p<strong>un</strong>teggio <strong>di</strong> “Fairness” appartenente al<br />
Player B, secondo il Player A, sia lo stesso attribui<strong>to</strong>gli dal Player C.<br />
Il p<strong>un</strong>teggio <strong>di</strong> Fairness attribu<strong>to</strong> da ogni Player ad ogni Player, dal<br />
momen<strong>to</strong> che deve rappresentare <strong>un</strong>’informazione costantemente con<strong>di</strong>visa,<br />
può prendere forma nel Data Layer, sot<strong>to</strong> forma <strong>di</strong> SharedComponent, e<br />
gesti<strong>to</strong> da <strong>un</strong>’apposi<strong>to</strong> modulo de<strong>di</strong>ca<strong>to</strong> all’Anti-Cheating.<br />
In ques<strong>to</strong> modo ogni Player può conoscere il p<strong>un</strong>teggio <strong>di</strong> Fairness globale<br />
(cioè la somma <strong>di</strong> tutti i p<strong>un</strong>teggi <strong>di</strong> Fairness che ogni singolo <strong>Peer</strong> attribuisce<br />
ad <strong>un</strong> determina<strong>to</strong> Player sospetta<strong>to</strong> <strong>di</strong> Cheating), e se ques<strong>to</strong> è al <strong>di</strong> sot<strong>to</strong> <strong>di</strong><br />
<strong>un</strong>a certa soglia <strong>di</strong> <strong>to</strong>lleranza, il Player incrimina<strong>to</strong> sarà rimosso dalla visione<br />
della Membership <strong>di</strong> ogni <strong>Peer</strong> (Figura 5.1).<br />
Ques<strong>to</strong> tipo <strong>di</strong> meccaniche <strong>di</strong> Cheat-management decentralizzate e au<strong>to</strong>gestite,<br />
non può però f<strong>un</strong>zionare in <strong>un</strong> contes<strong>to</strong> <strong>Peer</strong>-To-<strong>Peer</strong> nel quale la<br />
maggioranza dei Player fa uso <strong>di</strong> Cheats.<br />
Se si considera, inoltre, che le valutazioni <strong>di</strong> Cheat-Detection vengono eseguite<br />
<strong>su</strong> specifiche informazioni provenienti da generici messaggi in entata,
5.1. ANTI-CHEATING 103<br />
Figura 5.1: Il valore <strong>di</strong> Fairness attribu<strong>to</strong> al Player B dai Player A, C, D ed<br />
E è rispettivamente <strong>di</strong> -12, -9, -10 e 1 p<strong>un</strong>ti. La somma <strong>di</strong> tali valori è minore<br />
<strong>di</strong> zero, e per tan<strong>to</strong> il Player B viene escluso dalla Membership
104 CAPITOLO 5. SVILUPPI FUTURI<br />
senza <strong>un</strong> <strong>su</strong>ppor<strong>to</strong> la<strong>to</strong> Client (come l’Integrity Check esegui<strong>to</strong> da AntiTCC )<br />
ed <strong>un</strong> <strong>su</strong>ppor<strong>to</strong> la<strong>to</strong> server (come gestione e tracciamen<strong>to</strong> degli utenti malevoli),<br />
e dal momen<strong>to</strong> che alc<strong>un</strong>i comportamenti sospetti potrebbero essere<br />
causati dalla latenza, dalla <strong>su</strong>a variazione, e dalla congestione <strong>di</strong> rete, tali<br />
sistemi non possono mirare all’eliminazione del problema <strong>di</strong> Cheating, ma<br />
rappresentano solo <strong>un</strong> tentativo at<strong>to</strong> ad arginarne gli effetti.<br />
5.1.1 Time Based Cheating<br />
Come illustra<strong>to</strong> nel capi<strong>to</strong>lo 2.3.1, perio<strong>di</strong>camente ogni <strong>Peer</strong>, tramite il<br />
comando TimeSync, richiede agli altri <strong>Peer</strong> appartenenti alla Membership<br />
<strong>di</strong> notificare il valore del proprio TimeStamp, cosicché vi si possa possa<br />
calcolare, e memorizzare, il delta relativo.<br />
Quando viene memorizza<strong>to</strong> il nuovo valore <strong>di</strong> tale delta, ques<strong>to</strong> teoricamente<br />
non dovrebbe <strong>di</strong>scostarsi troppo dal valore memorizza<strong>to</strong> precedentemente.<br />
Se questa <strong>di</strong>fferenza è maggiore <strong>di</strong> <strong>un</strong>a certa soglia (che tiene con<strong>to</strong><br />
<strong>di</strong> eventuali oscillazioni dovute al Lag e Jitter), allora viene <strong>di</strong>minu<strong>to</strong> il<br />
p<strong>un</strong>teggio <strong>di</strong> Fairness relativo al <strong>Peer</strong> “sospetta<strong>to</strong>” <strong>di</strong> cheating.<br />
La soglia <strong>di</strong> <strong>to</strong>lleranza, sot<strong>to</strong> ques<strong>to</strong> aspet<strong>to</strong>, può anche essere relativamente<br />
alta, poiché a ques<strong>to</strong> livello, il sistema <strong>di</strong> Timing deve semplicemente<br />
garantire <strong>un</strong>a velocità <strong>di</strong> esecuzione “simile” <strong>su</strong> ogni <strong>Peer</strong>. Non deve essere<br />
possibile, quin<strong>di</strong>, avere <strong>un</strong> <strong>Peer</strong> A il cui tempo avanza a velocità N ed <strong>un</strong>’altro<br />
<strong>Peer</strong> B il cui tempo invece avanza a velocità 2N. Dal momen<strong>to</strong> che ogni<br />
singolo comando in grado <strong>di</strong> apportare mo<strong>di</strong>fiche allo sta<strong>to</strong> <strong>di</strong> gioco in<strong>di</strong>vidua<strong>to</strong><br />
nel modulo SharedComponents è accompagna<strong>to</strong> dal Timestamp, sarà<br />
possibile valutare, dal p<strong>un</strong><strong>to</strong> <strong>di</strong> vista temporale, la <strong>su</strong>a coerenza.<br />
Se si prende come riferimen<strong>to</strong> il Player A in Figura 5.2 e si analizza il<br />
<strong>su</strong>o delta time rispet<strong>to</strong> agli altri Player ogni 5 secon<strong>di</strong>, emergono i seguenti<br />
comportamenti:<br />
Il delta rispet<strong>to</strong> a B è costante per i primi due istanti <strong>di</strong> tempo, mentre al<br />
terzo ques<strong>to</strong> <strong>su</strong>bisce <strong>un</strong> decremen<strong>to</strong> <strong>di</strong> 5 secon<strong>di</strong>, per poi ristabilizzarsi al<br />
delta originale all’istante T4.
5.1. ANTI-CHEATING 105<br />
Il Player C ha <strong>un</strong> timing due volte più veloce rispet<strong>to</strong> ad A: il delta infatti<br />
decrementa costantemente fino a invertire il segno.<br />
Il Player D Invece ha <strong>un</strong> delta più o meno costante, ma nell’istante T3 ques<strong>to</strong><br />
invia <strong>un</strong> comando riportante <strong>un</strong> TimeStamp valorizza<strong>to</strong> come se fosse sta<strong>to</strong><br />
invia<strong>to</strong> in T4.<br />
E’ <strong>di</strong>fficile valutare con sicurezza se l’alterazione del delta del Player B sia<br />
dovuta a problemi <strong>di</strong> latenza o sia stata causata dall’utilizzo <strong>di</strong> <strong>un</strong> Cheat.<br />
Anche nel caso del Player D la valutazione ri<strong>su</strong>lta delicata, poichè può<br />
capitare che in <strong>un</strong> momen<strong>to</strong> <strong>di</strong> congestione il TimeSync invia<strong>to</strong> dal Player<br />
D al Player Player A, venga ricevu<strong>to</strong> da quest’ultimo con <strong>un</strong> ritardo tale da<br />
giustificare il TimeStamp riporta<strong>to</strong> <strong>su</strong>l comando invia<strong>to</strong> <strong>su</strong>ccessivamente.<br />
Nel caso del Player C, invece, il timing è palesemente accelera<strong>to</strong> (2X), e<br />
per tan<strong>to</strong> deve essere escluso dalla Membership in ogni caso.<br />
5.1.2 Space Based Cheating<br />
Un primo sistema in grado <strong>di</strong> scremare quelle situazioni palesemente sospette,<br />
come la velocità del Character raddoppiata, è relativamente semplice<br />
da implementare: in CheatDetection() <strong>di</strong> <strong>un</strong> MovingObjectScript è infatti<br />
possibile controllare, da <strong>un</strong>a parte che i valori dei componenti NextPosition e<br />
NextTimeStamp siano coerenti rispet<strong>to</strong> alle velocità <strong>di</strong> movimen<strong>to</strong> specificata<br />
all’interno della classe stessa (ovvero il valore <strong>su</strong>l quale, in Update Writer()<br />
verrà calcola<strong>to</strong> il vet<strong>to</strong>re <strong>di</strong> spostamen<strong>to</strong>), e dall’altra verificare che, salvo<br />
casi particolari (ed opport<strong>un</strong>amente gestiti) come il Respawn 2 , la <strong>di</strong>stanza<br />
tra il valore del componente Position appena aggiorna<strong>to</strong> ed il valore ass<strong>un</strong><strong>to</strong><br />
precedentemente stia entro i limiti imposti dalla velocità <strong>di</strong> spostamen<strong>to</strong><br />
(Figura 5.3).<br />
Da ques<strong>to</strong> p<strong>un</strong><strong>to</strong> <strong>di</strong> vista Cheats come lo Speed-Hack sono facilmente in<strong>di</strong>viduabili.<br />
2 Azione <strong>di</strong> riposizionamen<strong>to</strong>, all’interno della mappa <strong>di</strong> gioco, del Character quando<br />
quest’ultimo muore o viene <strong>di</strong>strut<strong>to</strong>
106 CAPITOLO 5. SVILUPPI FUTURI<br />
Figura 5.2: Time Based Cheating
5.1. ANTI-CHEATING 107<br />
Figura 5.3: In A viene esegui<strong>to</strong> <strong>un</strong> movimen<strong>to</strong> spazialmente coerente, ma<br />
temporalmente incoerente. In B, invece, il movimen<strong>to</strong> esegui<strong>to</strong> ri<strong>su</strong>lta incoerente<br />
poichè la posizione attuale (o prevista) non ricade entro l’area <strong>di</strong><br />
spostamen<strong>to</strong> consenti<strong>to</strong> nel periodo <strong>di</strong> tempo specifica<strong>to</strong> (cerchio verde).<br />
Maggiori <strong>di</strong>fficoltà sorgono quando vi è la necessità <strong>di</strong> controllare il comportamen<strong>to</strong><br />
<strong>di</strong> ogni singolo movimen<strong>to</strong>, non solo dal p<strong>un</strong><strong>to</strong> <strong>di</strong> vista della<br />
rapi<strong>di</strong>tà <strong>di</strong> spostamen<strong>to</strong>, quin<strong>di</strong>, ma anche dal p<strong>un</strong><strong>to</strong> <strong>di</strong> vista della rotazione<br />
e dei relativi cambi <strong>di</strong> <strong>di</strong>rezione.<br />
Ri<strong>su</strong>lta impossibile valutare, infatti, se l’agilità <strong>di</strong> movimen<strong>to</strong> <strong>di</strong> <strong>un</strong> Character<br />
sia dovuta all’abilità del gioca<strong>to</strong>re che lo controlla, o all’utilizzo <strong>di</strong> <strong>un</strong><br />
apposi<strong>to</strong> Cheat in grado <strong>di</strong> spingere tali capacità appena al <strong>di</strong> sot<strong>to</strong> del limite<br />
impos<strong>to</strong> dalle regole <strong>di</strong> gioco.<br />
Quello che però è sicuramente possibile (e necessario) controllare, è la<br />
coerenza delle rotazioni in relazione al TimeSpan tra <strong>un</strong> aggiornamen<strong>to</strong> e<br />
l’altro: se ad esempio il gioco prevede <strong>un</strong> Character in grado <strong>di</strong> compiere<br />
<strong>un</strong>a rotazione <strong>di</strong> 20 ◦ ogni secondo, nel me<strong>to</strong>do Update Reader() del relativo<br />
ComponentScript sarà possibile valutare se gli eventuali cambi <strong>di</strong> <strong>di</strong>rezione<br />
segnalati rientrino effettivamente nei limiti imposti dalle specifiche <strong>di</strong> gioco
108 CAPITOLO 5. SVILUPPI FUTURI<br />
(Figura 5.4).<br />
Figura 5.4: Le rotazioni effettuate dal Character (p<strong>un</strong>ti blu) in A rientrano<br />
nei limiti imposti dalle regole <strong>di</strong> gioco, mentre quelle in B ri<strong>su</strong>ltano, in relazione<br />
al TimeSpan intrercorso tra <strong>un</strong>’aggiornamen<strong>to</strong> e l’altro, essere troppo<br />
ampie.<br />
Vi sono inoltre alc<strong>un</strong>e situazioni particolari nelle quali è richies<strong>to</strong> <strong>un</strong> controllo<br />
<strong>su</strong>lle coor<strong>di</strong>nate spaziali che <strong>un</strong> ogget<strong>to</strong> 3D as<strong>su</strong>me in fase <strong>di</strong> inizializzazione:<br />
la creazione <strong>di</strong> <strong>un</strong> Bullet, ad esempio deve avvenire in prossimità<br />
del Character che l’ha genera<strong>to</strong>. Non è <strong>to</strong>llerabile, viceversa, che <strong>un</strong> Bullet<br />
venga istanzia<strong>to</strong> lontano dal proprio Character, o ad<strong>di</strong>rittura posiziona<strong>to</strong><br />
appositamente in prossimità <strong>di</strong> <strong>un</strong> Character nemico (Figura 5.5).<br />
Un’altro problema fondamentale lega<strong>to</strong> al Cheating è rappresenta<strong>to</strong> da<br />
quelle collisioni che implicano mo<strong>di</strong>fiche allo sta<strong>to</strong> <strong>di</strong> gioco: grazie ai controlli<br />
effettuati <strong>su</strong>llo spazio e <strong>su</strong>l tempo, è possibile garantire <strong>un</strong>a cer<strong>to</strong> grado<br />
<strong>di</strong> coerenza in quelle che sono le <strong>di</strong>namiche <strong>di</strong> gioco che coinvolgono movimenti<br />
e interazioni tra gli elementi <strong>di</strong> gioco. Come anticipa<strong>to</strong> nella sezione<br />
2.7.2, quando <strong>un</strong>a collisione coinvolge <strong>un</strong> Bullet ed <strong>un</strong> Character, il Player<br />
proprietario del Bullet segnala l’avvenuta collisione al Player proprietario del<br />
Character che decrementerà i propri p<strong>un</strong>ti HP <strong>di</strong> conseguenza.
5.1. ANTI-CHEATING 109<br />
Figura 5.5: Player A crea <strong>un</strong> proprio Bullet all’interno dell’area consentita<br />
(Cerchio verde, calcola<strong>to</strong> tenendo con<strong>to</strong> degli effetti causati dal Lag); Player<br />
B invece crea il proprio Bullet esternamente, e ques<strong>to</strong> viene interpreta<strong>to</strong><br />
come possibile segno <strong>di</strong> Cheating.<br />
Evidentemente <strong>un</strong> asset<strong>to</strong> <strong>di</strong> ques<strong>to</strong> tipo, se non controlla<strong>to</strong>, si presta ad<br />
essere sogget<strong>to</strong> a problematiche <strong>di</strong> Cheating: infatti da <strong>un</strong>a parte il Player<br />
che ha genera<strong>to</strong> il Bullet può notificare collisioni in realtà non avvenute,<br />
mentre dall’altra il Player possessore <strong>di</strong> <strong>un</strong> Character realmente colpi<strong>to</strong> può<br />
non operare le dovute mo<strong>di</strong>fiche al proprio HP (Figura 5.5).<br />
Una soluzione al primo problema potrebbe essere quella <strong>di</strong> controllare,<br />
<strong>su</strong>lla ricezione del messaggio Collision, che il Bullet coinvol<strong>to</strong> nella pres<strong>un</strong>ta<br />
collisione, esista nel proprio Data Layer e che abbia <strong>un</strong>a posizione ed <strong>un</strong>a<br />
<strong>di</strong>rezione tale da giustificare <strong>un</strong>a collisione con il Character (Figura 5.5).<br />
Per quan<strong>to</strong> riguarda il secondo problema si può procedere nel seguente<br />
modo: quando <strong>un</strong> Bullet appartenente al Player A colpisce il Character appartenente<br />
al B, ci si aspetta che B decrementi il proprio HP e lo notifichi,<br />
au<strong>to</strong>maticamente, a tutti gli altri Player. Parallelamente però, il Player A<br />
può prevedere tale decremen<strong>to</strong> e mo<strong>di</strong>ficando <strong>di</strong> conseguenza il valore del<br />
componente HP relativo al Character colpi<strong>to</strong>, all’interno del proprio Data<br />
Layer. Se il valore <strong>di</strong> HP invia<strong>to</strong> da B ri<strong>su</strong>lterà maggiore, allora si può<br />
sospettare l’utilizzo <strong>di</strong> <strong>un</strong> Cheat. E lo si può eventualmente accertare, dal<br />
momen<strong>to</strong> che ad ogni incremen<strong>to</strong> del valore <strong>di</strong> HP deve corrispondere la<br />
<strong>di</strong>struzione <strong>di</strong> <strong>un</strong> HealthPack.
110 CAPITOLO 5. SVILUPPI FUTURI<br />
Figura 5.6: Nella figura B viene invia<strong>to</strong> <strong>un</strong> messaggio Collision quando il<br />
Bullet in realtà non è avvenuta ness<strong>un</strong>a collisione<br />
5.2 Ottimizzazione NET Layer<br />
Attualmente le <strong>un</strong>iche classi che concretizzano le interfacce esposte dal<br />
Layer NET sono basate <strong>su</strong>l pro<strong>to</strong>collo TCP. In quest’ottica si può vagliare<br />
la possibilità <strong>di</strong> <strong>un</strong>a seconda implementazione, basata invece <strong>su</strong>l pro<strong>to</strong>collo<br />
UDP. Un’alternativa da valutare è l’utilizzo <strong>di</strong> librerie esterne <strong>di</strong> <strong>Game</strong> Networking<br />
(si veda il capi<strong>to</strong>lo 1.4).<br />
Nel primo caso gli interventi da effettuare a livello strutturale sono minimi,<br />
ma è com<strong>un</strong>que richiesta l’implementazione <strong>di</strong> <strong>un</strong>a serie <strong>di</strong> sistemi <strong>di</strong> controllo,<br />
che nel TCP sono gestiti <strong>di</strong>rettamente dal sistema operativo, come il<br />
controllo <strong>di</strong> flusso ed il controllo <strong>di</strong> congestione, mirati a rendere tale pro<strong>to</strong>collo<br />
Reliable.<br />
Il secondo caso, invece, implica la sostituzione <strong>di</strong> <strong>un</strong>o o più Layer a seconda<br />
della libreria utilizzata, e richiede <strong>un</strong> interven<strong>to</strong> <strong>di</strong> Refac<strong>to</strong>ring relativamente<br />
esteso.<br />
Sot<strong>to</strong> quest’aspet<strong>to</strong> può ri<strong>su</strong>ltare imprescin<strong>di</strong>bile l’introduzione <strong>di</strong> <strong>un</strong> si-
5.2. OTTIMIZZAZIONE NET LAYER 111<br />
Figura 5.7: In T1 avviene la collsione tra il Bullet del Player A ed il Character<br />
del Player B; in T2, il Player A decrementa il valore <strong>di</strong> HP appartenente<br />
al Player B <strong>di</strong> 10 p<strong>un</strong>ti come da specfiche, mentre il Player B, cheatando,<br />
decrementa il valore del proprio HP <strong>di</strong> solo <strong>un</strong> p<strong>un</strong><strong>to</strong>. In T3 il Player A riceve<br />
la notifica <strong>di</strong> aggiornamen<strong>to</strong> e nota la <strong>di</strong>fferenza tra il valore previs<strong>to</strong> (90) e<br />
quello notifica<strong>to</strong> (99).
112 CAPITOLO 5. SVILUPPI FUTURI<br />
stema <strong>di</strong> sincronizzazione temporale, perché se è vero che il modulo Shared-<br />
Components limita l’impat<strong>to</strong> <strong>di</strong> problemi legati alla latenza <strong>su</strong>lla consistenza<br />
dello sta<strong>to</strong> <strong>di</strong> gioco, utilizzando il pro<strong>to</strong>collo UDP la sicurezza <strong>di</strong> ricevere i<br />
messaggi nello stesso or<strong>di</strong>ne con il quale sono stati inviati viene meno.<br />
Un’ulteriore possibilità <strong>di</strong> ottimizzazione da vagliare è rappresentata dall’utilizzo<br />
<strong>di</strong> <strong>un</strong> sistema <strong>di</strong> compressione dati: attualmente i Commands vengono<br />
scritti <strong>su</strong>llo Stream sot<strong>to</strong>forma <strong>di</strong> stringhe UTF-8 (ogni carattere occupa<br />
da 1 a 4 byte), e l’utilizzo <strong>di</strong> <strong>un</strong>a libreria <strong>di</strong> compressione come Zlib 3 o<br />
GZip 4 , entrambe <strong>su</strong>pportate nativamente da .NET, può ridurre la richiesta<br />
<strong>di</strong> banda. L’efficacia <strong>di</strong> ques<strong>to</strong> tipo <strong>di</strong> compressione può però ri<strong>su</strong>ltare relativamente<br />
bassa, dal momen<strong>to</strong> che le stringhe scambiate tra i <strong>di</strong>versi <strong>Peer</strong><br />
sono piut<strong>to</strong>s<strong>to</strong> corte.<br />
5.3 Gestione utenti e MatchMaking<br />
Nell’attuale implementazione non sono presenti macrostrutture a<strong>di</strong>bite<br />
alla gestione del concet<strong>to</strong> <strong>di</strong> “partita” ed ai sot<strong>to</strong>-concetti ad esso connessi,<br />
come l’inizio e la fine <strong>di</strong> <strong>un</strong> match, la vit<strong>to</strong>ria e la sconfitta.<br />
Attualmente infatti non c’è ness<strong>un</strong> tipo <strong>di</strong> limitazione alla formazione au<strong>to</strong>noma<br />
<strong>di</strong> <strong>un</strong>a Membership, né tan<strong>to</strong> meno <strong>un</strong> sistema <strong>di</strong> controllo <strong>su</strong>l numero<br />
<strong>di</strong> partecipanti: ogni <strong>Peer</strong> può decidere <strong>di</strong> entrare in <strong>un</strong>a Membership<br />
in qualsiasi momen<strong>to</strong>, semplicemente connettendosi ad <strong>un</strong>o dei <strong>su</strong>oi no<strong>di</strong><br />
(Figura 5.8).<br />
Il primo problema da affrontare è il <strong>Peer</strong> Discovery e, nella fattispecie l’in<strong>di</strong>viduazione<br />
<strong>di</strong> <strong>un</strong> sistema in grado <strong>di</strong> notificare ai <strong>Peer</strong> non ancora connessi<br />
l’esistenza <strong>di</strong> Membership attive, e le informazioni necessarie che consentano<br />
<strong>di</strong> effettuarne il join.<br />
Tipicamente ques<strong>to</strong> viene realizza<strong>to</strong> attraverso <strong>un</strong> approccio centralizza<strong>to</strong>,<br />
3 http://www.zlib.net/<br />
4 http://www.gzip.org/
5.3. GESTIONE UTENTI E MATCHMAKING 113<br />
Figura 5.8: Campi testuali per la configurazione dll’in<strong>di</strong>rizzo IP e della porta<br />
d’ascol<strong>to</strong>, e per il join in <strong>un</strong>a Membership
114 CAPITOLO 5. SVILUPPI FUTURI<br />
caratterizza<strong>to</strong> da <strong>un</strong> “Master server” (o “Lobby Server”) che si occupa della<br />
gestione delle partite attive.<br />
Supponendo che <strong>un</strong> Player A voglia creare <strong>un</strong>a partita, <strong>un</strong>a volta specificati<br />
in<strong>di</strong>rizzo IP e porta (operazione in futuro au<strong>to</strong>matizzabile), da <strong>un</strong>a parte<br />
rimane in ascol<strong>to</strong> <strong>di</strong> eventuali <strong>Peer</strong> che vogliono “joinare” nella Membership,<br />
e dall’altra riferisce al Lobby Server dell’avvenuta creazione.<br />
Un Player B intenziona<strong>to</strong> a partecipare ad <strong>un</strong>a partita già esistente, interrogherà<br />
il Lobby Server, che invierà <strong>di</strong> conseguenza lista delle partite attive<br />
e le informazioni relative ai singoli partecipanti (Figura 5.9).<br />
Un’ulteriore au<strong>to</strong>mazione contestualizzabile nel Lobby Server è rappresentata<br />
dal Matchmaking, ovvero <strong>un</strong>a selezione delle partite attive più adatte<br />
al gioca<strong>to</strong>re, basata <strong>su</strong>lla valutazione <strong>di</strong> dati statistici espressi da <strong>un</strong> sistema<br />
<strong>di</strong> Ranking. Quest’ultimo, partita dopo partita, memorizza dati utili ad<br />
identificare l’abilità (Skill) <strong>di</strong> ogni singolo gioca<strong>to</strong>re.<br />
Alla base <strong>di</strong> tale au<strong>to</strong>mazione è necessario però che sia presente <strong>un</strong> sistema<br />
<strong>di</strong> autenticazione in grado <strong>di</strong> identificare i singoli gioca<strong>to</strong>ri.
5.3. GESTIONE UTENTI E MATCHMAKING 115<br />
Figura 5.9: <strong>Peer</strong> Discovery tramite Lobby server
116 CAPITOLO 5. SVILUPPI FUTURI
Capi<strong>to</strong>lo 6<br />
Conclusioni<br />
Negli ultimi venti anni, ed in particolare in quest’ultimo decennio, nonostante<br />
la crisi economica, l’industria dei videogiochi ha <strong>su</strong>bi<strong>to</strong> <strong>un</strong>a forte<br />
crescita, tan<strong>to</strong> da <strong>su</strong>perare le entrate <strong>di</strong> altri set<strong>to</strong>ri del merca<strong>to</strong> dell’intrattenimen<strong>to</strong>,<br />
come il cinema e l’home video[EntMerch 2008]. Complici <strong>di</strong>versi<br />
fat<strong>to</strong>ri: dall’ampliamen<strong>to</strong> del target demografico, alla <strong>di</strong>ffusione <strong>di</strong> nuove<br />
tecnologie e nuovi <strong>su</strong>pporti (si pensi agli SmartPhone) in grado <strong>di</strong> offrire<br />
esperienze videolu<strong>di</strong>che, anche <strong>Multiplayer</strong>, in luoghi, tempi e mo<strong>di</strong> impensabili<br />
anche solo qualche anno fa.<br />
Parallelamente sono cresciuti i costi e gli investimenti stanziati per lo<br />
sviluppo, per il marketing e per le infrastrutture necessarie al <strong>su</strong>ppor<strong>to</strong> <strong>Multiplayer</strong>.<br />
La realizzazione <strong>di</strong> <strong>un</strong> videogioco, intesa come processo produttivo, è oggigiorno<br />
<strong>un</strong>’attività trasversale, caratterizzata da temi, problematiche, ed in<br />
ultima analisi, da figure professionali specializzate in ambiti anche notevolmente<br />
<strong>di</strong>fferenti tra loro.<br />
In questa tesi <strong>di</strong> proget<strong>to</strong> si é cerca<strong>to</strong> <strong>di</strong> affrontare i problemi che stanno<br />
<strong>di</strong>etro all’implementazione <strong>di</strong> <strong>un</strong> videogioco <strong>Multiplayer</strong> <strong>Peer</strong>-To-<strong>Peer</strong>, esaminando<br />
l’intero processo da <strong>un</strong> p<strong>un</strong><strong>to</strong> <strong>di</strong> vista generale, e mantenendo il<br />
117
118 CAPITOLO 6. CONCLUSIONI<br />
focus <strong>su</strong> quelli che sono gli aspetti relativi alla progettazione e allo sviluppo<br />
della parte prettamente Software.<br />
Il contes<strong>to</strong> analizza<strong>to</strong> è vas<strong>to</strong> e complesso e non è sta<strong>to</strong> possibile quin<strong>di</strong><br />
entrare nel dettaglio <strong>di</strong> ogni singolo aspet<strong>to</strong>: ad esempio le problematiche<br />
legate allo sviluppo <strong>di</strong> <strong>un</strong> Engine grafico o <strong>di</strong> <strong>un</strong> Engine fisico, grazie all’utilizzo<br />
<strong>di</strong> <strong>un</strong> Middleware come Unity3D, sono state affrontate solo in maniera<br />
marginale.<br />
Anche per quan<strong>to</strong> riguarda ciò che concerne maggiormente l’argomen<strong>to</strong><br />
<strong>di</strong> tesi alc<strong>un</strong>e caratteristiche che si possono in<strong>di</strong>viduare nella maggior parte<br />
dei giochi <strong>Multiplayer</strong> commerciali, come i sistemi <strong>di</strong> Anti-Cheating ed i Lobby<br />
Server, per questioni <strong>di</strong> tempo non sono state sviluppate concretamente<br />
all’interno del proget<strong>to</strong> (si veda il capi<strong>to</strong>lo 5 relativo agli sviluppi futuri).<br />
Ciò nonostante, la realizzazione <strong>di</strong> <strong>un</strong> videogioco <strong>Multiplayer</strong> basa<strong>to</strong> <strong>su</strong><br />
reti <strong>Peer</strong>-To-<strong>Peer</strong>, ha permesso <strong>di</strong> sperimentare con mano quelli che sono i<br />
problemi e le <strong>di</strong>fficoltà caratteristiche che emergono durante lo sviluppo <strong>di</strong><br />
<strong>un</strong> software videolu<strong>di</strong>co, ed in particolare nel caso in cui quest’ultimo ri<strong>su</strong>lti<br />
contestualizza<strong>to</strong> in <strong>un</strong>o scenario <strong>di</strong> rete decentralizza<strong>to</strong>:<br />
In <strong>un</strong>a prima fase sono state analizzate le tecnologie, gli strumenti e le<br />
architetture prevalentemente utilizzate nel panorama attuale, al fine <strong>di</strong> selezionare<br />
quelle più adatte all’obiettivo <strong>di</strong> tesi.<br />
Sono stati valutati quelli che sono i vantaggi e gli svantaggi del modello<br />
<strong>Peer</strong>-To-<strong>Peer</strong> in contrapposizione al modello Client-Server, e <strong>di</strong> conseguenza<br />
esaminati i sistemi <strong>di</strong> sincronizzazione utilizzati per mantenere <strong>un</strong>o sta<strong>to</strong> <strong>di</strong><br />
gioco con<strong>di</strong>viso da tutti i gioca<strong>to</strong>ri.<br />
Quest’ultimo aspet<strong>to</strong> rappresenta probabilmente il cuore del problema:
119<br />
Sostanzialmente, astraendo dalle caratteristiche specifiche <strong>di</strong> gioco (come le<br />
<strong>di</strong>namiche <strong>di</strong> gameplay, la grafica, l’au<strong>di</strong>o e l’interazione utente), il requisi<strong>to</strong><br />
più importante per <strong>un</strong> MOG è garantire -al medesimo istante <strong>di</strong> tempo- <strong>un</strong>a<br />
rappresentazione dell’ambiente <strong>di</strong> gioco il più possibile simile per ogni singolo<br />
gioca<strong>to</strong>re, nonostante la presenza <strong>di</strong> fat<strong>to</strong>ri quali il Lag ed il Jitter.<br />
Infine, dal p<strong>un</strong><strong>to</strong> <strong>di</strong> vista del design del software è ri<strong>su</strong>ltata estremamente<br />
utile, sia in fase <strong>di</strong> progettazione che <strong>di</strong> implementazione, la separazione<br />
concettuale tra il contes<strong>to</strong> logico e gli aspetti prettamente vi<strong>su</strong>ali, poiché ha<br />
permesso <strong>di</strong> organizzare, identificare e soprattut<strong>to</strong> vincolare, gli elementi in<br />
grado <strong>di</strong> apportare informazioni allo sta<strong>to</strong> <strong>di</strong> gioco, al fine <strong>di</strong> generalizzare e<br />
au<strong>to</strong>matizzare le modalità <strong>di</strong> aggiornamen<strong>to</strong> <strong>di</strong> quest’ultimo.<br />
In conclusione l’approccio <strong>Peer</strong>-To-<strong>Peer</strong>, rispet<strong>to</strong> al modello Client-Server,<br />
pone <strong>un</strong>a serie <strong>di</strong> problemi dovuti alla <strong>su</strong>a natura decentralizzata e “<strong>un</strong>trusted”.<br />
Ri<strong>su</strong>lta inoltre meno <strong>di</strong>ffuso e relativamente ancora poco sfrutta<strong>to</strong><br />
in ambi<strong>to</strong> videolu<strong>di</strong>co, specialmente nella <strong>su</strong>a versione “pura”. Ma può<br />
rappresenta <strong>un</strong>a potenziale alternativa per quelle tipologie <strong>di</strong> gioco che non<br />
richiedono necessariamente la presenza <strong>di</strong> <strong>su</strong>pporti centralizzati.
120 CAPITOLO 6. CONCLUSIONI
Bibliografia<br />
[Abrash 1996] ABRASH M. 1996. Ramblings in Realtime<br />
[Bettner 2001] BETTNER P., TERRANO M. 2001. 1500 Archers on a<br />
28.8: Network Programming in Age of Empires and Beyond,<br />
URL: http://zoo.cs.yale.edu/classes/cs538/rea<strong>di</strong>ngs/papers/terrano<br />
1500arch.pdf<br />
[Rhalibi 2005] EL RHALIBI A., MERABTI M., 2005. Agent-Based Modeling<br />
for a <strong>Peer</strong>-<strong>to</strong>-<strong>Peer</strong> MMOG Architecture<br />
[Due Billing 2006] DUE BILLING O., PETERSEN J., 2006. Aspects of<br />
<strong>Peer</strong> <strong>to</strong> <strong>Peer</strong> game networks,<br />
URL: http://www.p2pgamenetwork.com/downloads/p2pgamenetwork.pdf<br />
[Ferretti 2008] FERRETTI S. 2008. A Synchronization Pro<strong>to</strong>col For Supporting<br />
<strong>Peer</strong>-<strong>to</strong>-<strong>Peer</strong> <strong>Multiplayer</strong> <strong>Online</strong> <strong>Game</strong>s in Overlay<br />
Networks,<br />
URL: http://sferrett.web.cs.<strong>un</strong>ibo.it/papers/debs08 p083-<br />
ferretti.pdf<br />
[Griwodz 2006] GRIWODZ C., HALVORSEN P., 2006. The F<strong>un</strong> of using<br />
TCP for an MMORPG<br />
[Smith 2000] SMITH R.D. 2000, Synchronizing Distribuited Virtual Worlds<br />
[Luo 2010]<br />
LUO J., CHANG H., 2010, A scalable architecture for massive<br />
Multi-Player <strong>Online</strong> <strong>Game</strong>s using peer-<strong>to</strong>-peer overlay<br />
121
122 BIBLIOGRAFIA<br />
[Yong-Tae 2008] YONG-TAE H., HONG-SHIK P., 2008, UDP based P2P<br />
game traffic classification with transport layer behaviors<br />
[Hampel 2006] HAMPEL T., BOPP T., HINN R., 2006, A <strong>Peer</strong>-<strong>to</strong>-<strong>Peer</strong><br />
Architecture for Massive <strong>Multiplayer</strong> <strong>Online</strong> <strong>Game</strong>s<br />
[Knutsson 2004] KNUTSSON B., LU T., XU W., HOPKINS B., 2004, <strong>Peer</strong><strong>to</strong>-<strong>Peer</strong><br />
Support for Massively <strong>Multiplayer</strong> <strong>Game</strong>s<br />
[Gang of Four 2004] GAMME E., RALPH R.H., JOHNSON R., VLISSIDES<br />
J., 1995. Design Patterns Elements of reusable Object Oriented<br />
Software<br />
[Cronin 2002] CRONIN E., FILSTRUP B., KURC A.R., JAMIN S., 2002.<br />
An efficient synchronization mechanism for mirrored game<br />
architectures<br />
[Gautier 1999] GAUTIER L., DIOT C., KUROSE J., 1999. End-<strong>to</strong>-end<br />
transmission control mechanisms for multiparty interactive<br />
applications on the Internet<br />
[Gregory 2009] GREGORY J., 2009 <strong>Game</strong> Engine Architecture<br />
[Chen 2007]<br />
[Ko 2005]<br />
CHEN B. His<strong>to</strong>ry Of <strong>Multiplayer</strong> <strong>Game</strong>s<br />
URL: http://www.ssagsg.org/LearningSpace/<br />
EntertainmentGaming/His<strong>to</strong>ryMPG.htm<br />
KO B.J., RUBENSTEIN D., CALO S., 2005 Dynamic server<br />
selection for large scale interactive online games<br />
[Hong 2003] HONG E., LEE E.D, KANG K, 2003 An efficient synchronization<br />
mechanism adapting <strong>to</strong> dynamic network state for<br />
networked virtual environment<br />
[Baughman 2001] BAUGHMAN N., LEVINE B., 2001 Cheat-proof playout<br />
for centralized and <strong>di</strong>stributed online games
BIBLIOGRAFIA 123<br />
[Paik 2008]<br />
PAIK D., YUN C., HWANG J., 2008 Effective message<br />
synchronization methods for multiplayer online games with<br />
maps<br />
[Neumann 2007] NEUMANN C., PRIGENT N., VARVELLO M., 2007<br />
Challenges in <strong>Peer</strong>-<strong>to</strong>-<strong>Peer</strong> Gaming<br />
[Mogaki 2007] MOGAKI S., KAMADA M., YONEKURA T., 2007, Minimization<br />
of Latency in Cheat-Proof Real-Time Gaming by<br />
Trusting Time-Stamp Servers<br />
[EntMerch 2008] http://www.entmerch.org/
124 BIBLIOGRAFIA
Ringraziamenti<br />
Desidero innanzitut<strong>to</strong> ringraziare il Professore Stefano Ferretti per i <strong>su</strong>oi<br />
preziosi <strong>su</strong>ggerimenti e la grande <strong>di</strong>sponibilità <strong>di</strong>mostratemi.<br />
Inoltre ringrazio sentitamente tutti i professori del corso, in particolare Vania<br />
Sordoni e Carla Guerrini, docenti delle materie degli ultimi due esami,<br />
forse i più ostici ma allo stesso tempo i più appaganti. Ringrazio tutti i miei<br />
compagni <strong>di</strong> corso con cui ho con<strong>di</strong>viso lezioni, ore <strong>di</strong> stu<strong>di</strong>o e <strong>di</strong>vertimenti,<br />
in particolare Daniele (Viva), Gianmarco (Giammolo), Marco (Bot), Giacomo<br />
(Jack), Marco, Nicolò, Matteo, Alessandro (Zacagno), Matteo (Fixxxer),<br />
Valentina, Marco (Ket<strong>to</strong>), Alessio (Torre) e soprattut<strong>to</strong> mio fratello Riccardo<br />
che mi ha sempre aiuta<strong>to</strong> in questi anni <strong>di</strong> Università e con cui ho con<strong>di</strong>viso<br />
ore e ore <strong>di</strong> stu<strong>di</strong>o.<br />
Infine, ho il desiderio <strong>di</strong> ringraziare con affet<strong>to</strong> i miei geni<strong>to</strong>ri Carlo e Laura<br />
per il sostegno ed il grande aiu<strong>to</strong> che mi hanno da<strong>to</strong> sia dal la<strong>to</strong> economico<br />
che dal la<strong>to</strong> affettivo e per avermi sprona<strong>to</strong> più volte a stu<strong>di</strong>are con più<br />
continuità. Ringrazio anche i miei nonni Livio e Renata e tutti i miei parenti.<br />
125