08.09.2019 Views

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

SHOW MORE
SHOW LESS

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

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!