Massive Multiplayer Role Play Game


Questo documento prova ad affrontare i problemi teorici che ruotano attorno al concetto di Gioco di Ruolo Online partendo dal punto di vista grafico fino ad arrivare ai protocolli di rete. Queste sono tutte mia considerazioni personali, fondate solo dall'esperienza, che comunque è molto poca - per ora -. La visione è puramente teorica e sta ad ognuno implementare il problema come crede.
 

Un gioco di Ruolo

Questo discorso investe prevalentemente il Gameplay. Un gioco non online, permette di inserire una trama, visto che il giocatore quando lascia il gioco e salva può continuare in tempi successivi l'avventura. Un gioco online invece non permette questa formula, a scapito di una parte di divertimento legata al gioco di ruolo. Questo però non implica che non ci possa essere in ogni caso una trama. Esistono diverse forme surrogate di trama: Le missioni sono avventure brevi (neanche un'ora) e si limitano nell'uccidere un PNG o ritrovare un oggetto. Le Quest sono brevi avventure che il personaggio/i possono compiere nell'arco massimo di un paio d'ore, cioè il tempo massimo che un utente (italiano) concede a questo genere di cose. Le Quest, a differenza delle missioni che possono essere create da un PNG grazie a un semplice algoritmo, devono essere creata a misura da un DM. Il Background del personaggio permette invece a un PG di avere uno scopo nella vita, un obiettivo principale a cui giungere.
Il gioco di Ruolo consiste nel poter impersonare un personaggio virtuale (chiamiamolo pure Avatar, burattino) che compie azioni secondo un proprio schema logico. Se il gioco non fissa un obiettivo finale a cui arrivare, il giocatore potrebbe non sentire la volontà di giocare, a meno che non si dia al giocatore una libertà nel far quello che più gli piace e che nella vita reale (IRL) non ha tempo, coraggio, voglia di fare.
 

Gioco Online o Gioco locale

Per quello che riguarda le differenze sono elencate nella tabella seguente, solo per bellezza credo.
 
Gioco Online Gioco Locale
Salvataggi 1 sono salvataggio e non possibilità di recuperare o fermare il tempo. Salvataggi a volontà e possibilità di recuperare da punti precedenti
Morte La morte non pregiudica il gioco. Mal che vada si perdono delle caratteristiche o esperienza La Morte termina il gioco. I Salvataggi comunque rendono questa evenienza un semplice evento.
Interazione con persone Con PNG e con altri giocatori Solo con PNG
Trama Semplice. E' il giocatore stesso che con il suo operato crea un'avventura per se stesso e per gli altri. In questo modo il gioco è virtualmente infinito. C'è una trama, anche molto complessa ed eccitante, ma che termina con un obiettivo finale, o nella possibilità di ricominciare, ripetitiva a un certo punto.

Testo o Grafica

Le denominazioni sono tante, MUD (Multi User Dungeon), MUG (Multi User Game), MOO (MUD orientato ad oggetti), la prima definizione di gioco online. L'epoca non permetteva grande potenza di calcolo delle macchine client, ne tanto meno la rete permetteva scambi elevati di dati tra gli utenti. In queste condizioni i giochi erano testuali supportati da un programma Client standard come è il Telnet. In questo caso il protocollo di comunicazione, visto il tipo di Client, è il TCP. Al giorno d'oggi invece la banda dati di Internet è tale da permette un trasferimento sostenuto di dati che permettono un gioco più vario e graficamente parlando più vicino a un giocatore moderno. Ovviamente i giochi testuali locali sono un ricordo del passato, mentre i giochi online testuali continuano nonostante tutto a sopravvivere, visto che lo sviluppo e il mantenimento da parte del Server è minimo, e la mancanza di grafica può essere sopperita dalla fantasia degli utenti (e in più sono sempre delle ottime chat!).

Grafica a Tile

La bellezza di un gioco Online, ma anche Locale, sta nella possibilità di avere un mondo molto vasto. Online questa richiesta si fa ancora più esigente per due motivi: spazio (troppi giocatori in un piccolo ambiente non ci stanno) e varietà, la varietà che dovrebbe sopperire alle mancanze di trama agli avventurieri. Un mondo molto grande permette al giocatore di poter passare diverso tempo ad esplorare e scoprire nuovi posti.

Il difetto di tutto ciò sta nella dimensione che questo mondo possa occupare. Bisogna dunque trovare dunque un compromesso. Un mondo completamente vario obbliga a riservare una quantità di memoria fisica al di fuori totalmente della nostra (attuale) concezione. Se il mondo fosse completamente in 3D potremmo occupare anche 1CD di dati per Kmq, e ricordiamo che Baldur's Gate occupa 5 CD nonostante le ambientazioni siano solo una trentina, perché le mappe del gioco sono delle pure e semplici Bitmap. Da molto tempo si è cercato un modo di rappresentare il mondo con unità semplici da poterle poi duplicare. Questi singoli oggetti sono chiamati Tile, e come le tessere del mosaico, permettono di creare ambienti molto vasti con poco occupazione di HD. Per esempio, sia che le Tile siano 3D o 2D isometrico, queste occuperanno una dimensione ridottissima, e il mondo potrà essere rappresentato semplicemente da una matrice dove a ogni elemento (entry) è assegnato il codice di una particolare tile. Ovviamente fare il mondo a mesh o in bitmap lo rende molto migliore graficamente, e permette una varietà di ambienti praticamente infinita. Si pensi solo che in una foresta ogni albero sarà diverso dagli altri, come in realtà. Con le tile invece ci sarà sempre una scelta (comunque anche ampia) dei possibili elementi.
Questo metodo permette di disegnare solo le Tile che si vedono e nessuna di più tramite un semplice algoritmo di visibilità, e visto che la distanza tra Osservatore e Mondo è costante, lo è anche il livello di dettaglio (LOD), e questo valore può essere impostato dall'utente.

Singola Tile


Matrice. Ogni elemento è un codice che indica quale tile disegnare in quel punto

Scelta della Grafica

Grafica 2D o 3D? Ovviamente visto i tempi che corrono si può pensare che la grafica 2D sia morta. Invece c'è da notare che ancora oggi è preferibile usare la 2D, sempre per motivi di performance. Baldur's Gate ne è stato un esempio, ma anche Baldur's Gate II seguirà l'esempio del predecessore, introducendo però la modalità mista che va molto per la maggiore al giorno d'oggi. La scelta comunque dipende da ogni implementazione, e dal mio punto di vista sia la modalità 3D che in modalità mista danno molte soddisfazioni. La modalità mista risolve con Bitmap i problemi di performance della 3D introducendo invece la possibilità di animazione che invece solo la grafica in 3D può permettere (rotazioni del personaggio, IK e Bone). Questa tecnica consiste nel memorizzare gli sfondi (oggetti, case, alberi...) in Bitmap insieme a uno ZBuffer (in questo caso specifico relativo alla tile) e invece i personaggi, animali, magie, etc etc in 3D, e integrare il tutto. E' una tecnica vecchia (Alone in the Dark) ma che continua a rendere ancora moltissimo. L'unico metodo di scelta sta nelle capacità che si hanno e quanto grosso si vuole fare il database grafico sul client.
I terreni possono essere creati usando bitmap, ma visti i tempi è buona cosa implementarli come texture su poligoni, e affidare il rendering alla scheda 3d o, se ne si possiede uno, al proprio engine di rendering software. In questa maniera sarà possibile disegnare avvallamenti e alture, con effetti di luce e ombra in modo molto semplice.

Grafica. Idee Varie

Questo capitoletto andrebbe letto alla fine di tutto, perché fa riferimento a concetti spiegati di seguito.

Visto che il concetto di Pavimento, sia in 2D e in 3D, è fondamentale per alcuni motivi, primo fra tutti l'altezza del personaggio rispetto al livello zero, è cosa utile codificare a parte l'altezza del terreno rispetto alla grafica che ne verrà fuori sopra questo. In questo modo si può codificare che texture assegnare al pavimento e aggiungere un valore per ogni vertice per indicare l'altezza del vertice del terreno. Ecco come sarebbe una entry (public) della mappa:

In questo modo si riesce ad esprimere una quantità enorme di ambienti nonostante si abbiano solo 4 byte per entry. Avendo codificato solo un vertice per entry permette di disegnare solo terreni continui, comunque non è un gran problema. Se il dato del bordo non si conosce si può mettere temporaneamente a zero, tanto il bordo non sarà visibile finché non verra caricata la mappa adiacente. 2 byte per le Tile significano 65534 possibili Tile più che sufficienti per qualsiasi esigenza pratica. 1 byte per il terreno invece indicano solo 254 possibili terreni (+ no terreno), comunque un gran numero rispetto alle esigenze odierne. Si ottengono, se completamente riempiti, con 4 byte per entry, 4 Miliardi di combinazioni di altezze (considerando i 4 vertici limitrofi) che vanno moltiplicate per le 256 combinazioni del terreno e alle 65mila combinazioni dovute alle tile (unico indice dove c'è del reale lavoro da lasciar fare ai grafici). A conti fatti sono 2^56 combinazioni possibili, con un lavoro reale di grafica solo per 65536 mesh di tile massimo, un tool per generare altimetrie e 256 texture per il terreno. Tra le texture bisognerà includere una texture 0 indicante la totale mancanza di terreno e tutte le transizioni tra due texture (tipo erba->strada) a senconda dei possibili angoli. Ovviamente questa transizioni potrebbe essere anche codificata come parte della mesh della tile sovrastante per risparmiare.
E' poi anche vero che se si usa un rendering 3D è abbastanza stupido disegnare 4 tile per rappresentare la medesima tile ruotata di 90° alla volta. Nella visualizzazione bisognerà dunque considerare di allocare 2 bit (o più bit) per indicare la rotazione della tile rispetto a un riferimento.

Formato delle Tile

Affrontiamo adesso il formato delle tile. Questo formato però è da suddividere in due punti di vista, quello del client e quello del server. Infatti i dati che a uno servono all'altro sarebbero inutili. Ecco una tabella sintetica:
Client Server
Grafica Al Server non interessa l'aspetto del mondo dal punto di vista estetico
Entry Tile (Dati Privati) Sono dati sotto la diretta gestione del server
Bounding Box Dipende dall'implementazione.
Action (Dati Comuni)
La Grafica ovviamente è gestita solo dal Client per visualizzare il mondo. Che questa sia una collezione di mesh tridimensionali, che una bitmap, non interessa al Server. Infatti in molti casi moderni, come Ultima Online 3.0 o o nati dalla Open Source generation, a un server unico corrispondono sia un client a bitmap 2d che un client 3D: è un ottimo esempio di come un software si può basare benissimo su molteplici livelli di astrazione.
I Dati Privati invece sono quello che il Client non vede, ma che il Server manda al Giocatore sotto altri formati. Questi dati comunque possono essere anche non esistere. Questi dati differenziano due Tile che hanno lo stesso codice e perciò stesso aspetto. Invece i Dati Comuni sono dati che come dice la parola sono sia sul Server e sincronizzati sul Client. Sono questi dati che permettono ai giocatori (e anche ai PNG) di agire sul mondo. Questi dati possono essere una estensione del concetto di oggetto, relativo però a entità fisse del paesaggio.
Le Bounding Box indicano un artificio per le prestazioni. Dipende comunque dall'implementazione e per esempio la bounding box più semplice (di default) è la Tile stessa. La bounding box è un concetto che si può applicare sia in 2D che per estensione alla 3D. Rappresenta per estensione una scatola dove dentro è contenuto un oggetto virtuale che determina alcuni effetti. Questa è una mera approssimazione dello spazio che il server e il client usano per determinare questi effetti, visto che controllare poligono per poligono la tile è un'impresa abbastanza complessa, perciò si raccolgono i poligoni in una forma semplice che contiene tutti i poligoni legati da una relazione comune. Le Bounding Box possono perciò non esistere, cioè occupare l'intera tile, o essere rappresentate da rettangoli bidimensionali nel caso di Tile su Bitmap, fino all'estensione a rettangoli e sfere tridimensionali.
Le Bounding box poi possono essere diverse tra Client e il Server. Questo infatti è una conseguenza del fatto che l'interazione tra PG e ambiente è diversa tra PNG e ambiente, o in ogni caso è di una forma diversa.
Per esempio le BB posso essere usate per indicare quali zone dello spazio non possono essere attraversate dai giocatori, dove c'è perciò un ostacolo, per esempio una tile con una panchina e un lampione . Al Server che interessa poter muovere molti personaggi contemporaneamente e che preferisce fare pochi controlli a scapito della precisione, preferisce una bounding box che racchiuda tutti i due oggetti, mentre il client preferisce poter spostarsi in modo più libero, ha due box per i due oggetti.
Altre BB (che possono essere comunque le stesse delle intersezioni, visto che indicano sempre oggetti) possono permettere di interagire tra Client e il Server. Per esempio per sapere che la panchina si chiama "panchina" e che permette di "sedersi". Per esempio la stringa "panchina" dovrà essere memorizzata insieme alla Tile sul Client, ma al Server ciò non interessa, mentre "sedersi" è un azione che il Server deve per prima cosa verificare che il Client può fare, ma potrebbe usare anche per eventuali PNG come azione.  Ovviamente questo può anche essere relativo ai dati privati la stringa "panchina" può essere inviata dal Server.

Facciamo alcuni esempi su questi dati che mi vengono in mente adesso:
L'albero è uno degli oggetti più interessanti di Ultima Online. Permette di fare molti esempi:
L'albero per esempio occupa più di una casella elementare, e perciò può essere spezzato in più di una casella, o fare in modo che le bitmap siano di dimensione fissa. L'albero permette anche alcune azioni su di se, per esempio una è quella di essere "tagliato". Questa azione è possibile cliccando sulla BB dell'albero che lo contiene o su una BB privata relativa ai rami, la quale BB contiene una flag che permette il taglio. Il numero di rami che rimangono dall'essere tagliati è memorizzato insieme al codice dell'albero nella mappa del mondo, mentre l'azione tagliare è condivisa tra Client e Server.
Lo stesso si può fare con l'arredamento: cliccando sopra a un comodino potremo vedere cosa contengono i cassetti per esempio.

Dunque ci sono tre concetti di Tile:

  1. Versione Client
  2. Versione Server
  3. Dati privati relativi alla Tile memorizzati in ogni entry della mappa.

Dati Privati: Overhead di memoria

Come memorizzare i dati privati sul Server? Ci sono diverse teorie e implementazioni. Una che usa Entrate della mappa di dimensioni fisse, dimensioni che permettono di inserire i dati privati più grandi, o usare dei puntatori alla memoria che contiene tutta la Tile della dimensione che si desidera. Questa soluzione ha senso ovviamente se l'entry massima della mappa ha dimensione  > 12 byte, visto che 2-4byte sono richiesti dall'ID del tipo di Tile e approssimativamente 8 sono usati dal SO come descrittori della memoria allocata e un dato privato sarà almeno di 4 byte. Ovviamente se buona parte del mondo è occupata da tile che non accettano dati questo puntatore può essere lasciato a NULL risparmiando l'overhead di allocazione.
Questo metodo è vantaggioso se F < (E-4)/g, con F la percentuale del mondo che necessita di dati allocati, E i dati extra massimi, 4 è la dimensione di un puntatore, g la quantità media di memoria allocata (comprensiva di Overhead di allocazione). Con un mondo coperto al 50% (acqua e campi) e un overhead di 8 byte si ottiene che se i dati extra massimi sono minori o uguali a 16 byte conviene utilizzare una allocazione fissa, veloce e facile da gestire.

Mondo paginato

Ogni Entry a questo punto è formata da questi dati
 
Chiave Dimensione Significato
ID 2-4 byte Che tipo di immagine è rappresentata sul questa casella della matrice.
data 4(puntatore)-16 byte I Dati privati che determinano la condizione della tile
oggetti 4(puntatore)-16 byte Oggetti contenuti nella casella.

A conti fatti ogni casella occupa da 12 a 36 byte (non considerando eventuale memoria allocata). Un Server con 64MB di Ram assegnati alla Mappa permette mappe di dimensione massima 2048*2048 a un livello. Questo limite può essere superato usando il SO che permette di gestire il file della mappa in modo virtuale caricando solo i dati che effettivamente servono: una mappa di 64MB memorizzata su un HD è piccola rispetto alla dimensione del supporto. Questo lavoro però lo può fare anche l'utente il quale può tenere conto che più dell 50% del mondo (Mari, Zone desertiche o disabitate) non sono normalmente attraversate da gente e addirittura i PNG in essi contenute possono anche essere disabilitati. Ultima Online ha per esempio una mappa 6144x4096 divisa in sottomappe quadrate di dimensione fissa 256x256 che vengono caricate in memoria solo se servono. In questo modo il mondo è visto dal''utente lineare, ma dal punto di vista logico è diviso in sezioni non coincidenti. Una conseguenza di questo sistema di dividere il mondo in Pagine è che anche verticalmente può non essere lineare. Possiamo collegare per esempio alla pagina 54, la pagina 96, come suo livello superiore.
Con questa tecnica basta aggiungere a ogni pagina del mondo un piccolo header per indicare il codice della pagina superiore e quello della pagina inferiore (ma anche alle direzioni nord, sud, ovest, est). Con un indice a 16 bit (1word) e mappe da 256x256 si possono usare mondi fino a 65536x65536 (4GB di entry).

Dati Privati: Liste di oggetti

Come per i dati privati anche gli oggetti sul terreno necessitano di un modo di memorizzione sul Server. Il valore di memoria riservata agli oggetti è lo stesso dei dati privati, intorno ai 12 byte. Diablo per esempio permetteva di posare un sono oggetto per entry e questa è stata una filosofia molto seguita soprattutto sui giochi in locale. Se invece si vogliono posare infiniti oggetti in un posto è preferibile usare liste di oggetti, dove ogni oggetto ha un puntatore al successivo in una lista a cascata. I MUD testuali usano questo sistema per esempio, visto che il giocatore vede l'intera stanza.
C'è anche da considerare che alcune Tile possono essere formate da contenitori, come cassetti, armadi e roba simile, e contenere addirittura molteplici di questi contenitori. Ogni contenitore deve avere l'ID o il puntatore sul Server alla lista degli oggetti (sia che essa sia Dinamica che Statica).
Se invece si considera il mondo diviso in sottomappe sarà possibile associare gli oggetti non tanto alla singola Tile, ma alla mappa, indicando la posizione dell'oggetto all'interno della mappa. Questo è facilitato dal fatto che in un mondo a pagine, ogni pagina ha un header e la lista potrà essere inserita (con una qualsiasi tecnica) in questa struttura.

Ricordiamo che anche il giocatore ha una lista degli oggetti trasportati. Questo complica il salvataggio del giocatore sul Server, visto che la dimensione dei dati del giocatore varia di molto e probabilmente non sarà possibile salvare il giocatore su disco nell'offset precedente. Assegnare una dimensione fissa occupabile massimo dal giocatore (una dimensione abbondantemente sovrastimata) è una soluzione rapida. Deframmentare e spostare allocazioni, è una soluzione più lenta e complicata, ma risparmia spazio su disco. La soluzione scelta per la maggionre, che occupa una quantità enorme di spazio su disco, è quella di salvare i dati in file di testo, in un formato totalemente ASCII (non binario). In questo modo è il gestore del file system che si prende cura di riservare lo spazio per il file, e l'editing delle strutture è possibile in maniera immediata con qualsiasi editor di testo. Spesso comunque ho visto che tutti i dati dei giocatori (anche quelli che in quel momento non stanno giocando) sono caricati in memoria. Dopotutto i dati occupati dal giocatore saranno di circa 2K massimo, ben poca cosa rispetto al resto della memoria usata (mappa, oggetti, descrizioni...).
Normalmente in memoria si cerca di non fare distinzione tra NPG/MOB e PG, in modo da dare da principio la sensazione che chi il giocatore abbia di fronte possa sia essere un'altro giocatore che una IA. Abbiamo anche detto (e se non l'ho detto, lo dirò in seguito) che aree non attraversate da nessun giocatore (giocante) possono essere disabilitate e swappate su disco. Se l'elenco dei giocatori è riferito a un area, allora è possibile scaricare su disco mappa, mob e giocatori offline allo stesso modo.
In ogni modo si usa una lista dinamica di persone, dove nell'header dell'area c'è il puntatore (l'identificatore) a un giocatore, e ogni giocatore ha un puntatore (l'identificatore) nei suoi dati privati a uno successivo nell'area. Quando un giocatore esce da un'area prima viene tolto dalla lista e viene aggiunto (solitamente in cima per velocità) alla lista della nuova area.

Il difetto di avere il Server su una macchina e il Client su un'altra pregiudica il poter usare puntatore per indirizzare la memoria. Viene perciò più comodo riferirsi a ogni PG/PNG, oggetto, etc etc con un identificatore (un numero intero), e sul Server questo identificatore sarà gestito in un modo, e sul Client (per la gestione della cache di rete) sarà gestito in un'altro modo.

Server Multiprocessore o Distribuito

Nuovi problemi nascono se si sceglie di usare un sistema multiprocessore o distribuito. Normalmente il Server deve fare carico di leggere i dati UDP dai clienti e da questi compiere delle variazioni sul mondo. E' possibile che questo lavoro non si riesca a fare per le ridotte potenze di calcolo del sistema. Il mio consiglio a questo punto e associare dei meccanismi di lettori e scrittori ad Aree del mondo (le dimensioni vanno scelte usando quelle già stabilite dalle sottomappe o altre, come si vuole). Il modo più semplice è associare a ogni area un Mutex ed accedere all'area in mutua esclusione. Ovviamente sarebbe stato impossibile usare un mutex per ogni tile, mentre, visto che, come da me sopra consigliato, la lista degli oggetti è associata a ogni area, diventa ovvia la scelta di associare a ogni area anche un mutex (questa è per esempio la soluzione adottata dai server Origin di Ultima Online). Soluzioni più corrette dal punto di vista teorico le considero inutili, perchè usano più mutex e il tempo necessario per entrare in una sezione critica in questo modo è più lungo del tempo in cui si sta dentro la stessa sezione. Riporto comunque, per completezza, uno dei tanti algoritmi di lettori e scrittori. Per chi fosse interessato ne può trovare quanti ne vuole su Internet o su un libro di Sistemi Operativi.

Lettori e Scrittori (Weak Writer) con 3 mutex: mutex.c

E' importante osservervare che se si ha che fare con un multiprocessore, nel 99.9% dei casi saranno due i processori in questione. Il server perciò dovrà essere diviso normalmente di un fattore 2. Perciò si potranno fare girare 2 aree per server, o un'area sola, ma per esempio la IA, o un server Http con le statistiche del gioco, dal sottosistema di input/output da rete, abiterà in un thread diverso da quello del gioco.

La necessità di implementare il software lato server in maniera distribuita è dettata dal fatto che normalmente una macchina potrà gestire al massimo un migliaio di connessioni alla volta (molte meno se in TCP/IP). Il server perfetto, è un server scalabile linearmente, dove il numero di utenti massimo è in relazione perfettamente lineare con il numero di macchine in dotazione.

Gestione Dati: Overhead di comunicazione

Per migliorare le prestazioni del gioco l'utente al momento dell'esecuzione del software (client) a casa, deve avere già installati i dati che il server dovrebbe (solo in teoria) mandargli più spesso.
Questi dati possono essere i seguenti. A questi poi si aggiungono i dati relativi alla grafica dei menu e i suoni. Bisogna comunque fare delle opportune precisazioni, dettate dalla possibilità che alcune cose siano
a) Troppo Ingombranti sul Computer Client.
b) Facilmente modificabili.
Se sono troppo ingombranti, l'utente potrebbe anche non riuscire (o non volere) installare il gioco.
La Mappa e la grafica rientrano in questa sezione. La mappa però, a differenza delle Tile, oltre alla possibilità di occupare molto di più (teoricamente) della grafica delle tile, potrebbe essere spesso modificabile.
Se l'oggetto non è modificabile spesso, e occupa molto spazio, la sincronizzazione dei dati tra il computer Client e il Server dovrebbe avvenire al momento del lancio del programma, prima cioè di entrare effettivamente nel gioco. Se invece i dati sono pochi (per esempio la mappa è divisa in piccole sottomappe) queste possono essere inviate sul momento.
Il concetto di sincronizzazione introduce la necessità di inserire in ogni oggetto (Tile, Grafica, Programma, etc...) logico del gioco un codice sequenziale per sincronizzare Client e Server.
Per esempio un numero sequenziale o l'orario e il giorno in cui è stato modificato l'oggetto. In questo modo ci possono essere due logiche:
  1. Il server manda al Client il timecode, il Client confronta con il timecode locale in cache, e se necessita di un aggiornamento fa una richiesta al server. Questa richiesta è simile a quella a cui il Client non ha proprio l'oggetto in questione. A questo punto il Server invia una copia aggiornata dell'oggetto al Client. Il Server comunque dovrebbe sapere che dato serve in precedenza al client (e non conosce gli eventi che offline possono essere accaduti al client... reinstallazioni e simili), e questo spesso non è possibile, e inviare tutti i possibili dati è notevolmente ridondante.
  2. Il Client manda al Server il timecode. Se questo codice è 0, il Client richiede un dato che non ha. Il Server fa il confronto e se c'è bisogno invia il dato.

L'altra faccia della medaglia è che comunque il pacchetto UDP/IP o TCP/IP ha un suo header che deve essere inviato. Questo header è di 26 byte nel caso dell'UDP, mentre nel caso TCP la situazione è molto più complessa dove poi un po' di banda viene sempre consumata dal protocollo stesso per restare connesso.

Ulteriori Considerazioni: Aggiornamento del Mondo

Se il mondo non è normalmente aggiornabile, mappe di 256x256 sono una ottima soluzione. Capiterà solo ogni tanto che l'utente dovrò perdere quel mezzo minuto per aggiornare la pagina modificata e se questo lavoro viene fatto in fase di Login non è essenziale ai fini del gioco. Resta però il fatto che l'utente non va di dover memorizzare sul proprio HD 40GB di una mappa di un gioco... e il primo aggiornamento sarà un po' lento... E' opportuno dunque dividere le mappe in unità più piccole e tenere sul Client solo le mappe più usate recentemente (come da sezione precedente spiegato), chiedendo all'utente quanto spazio riservare alla cache della mappa. Ovviamente però inviare 1 tile per volta è sconsigliato: troppi dati da trasferire tra client e server e comunque alla fine occuperebbero troppo sul computer (Client e Server) in relazione allo spazio effettivamente coperto.
Per semplificare la gestione del Server si potrebbe adattare la dimensione della pagina a quella delle mappe che si mandano al Client, riducendo drasticamente la dimensione delle pagine sul Server. Questa soluzione, quando possibile, é comunque meglio evitarla per evitare la frammentazione della memoria sul Server. In queste condizioni comunque saranno necessari indici per le mappe a 32 bit.
Nel caso di un TimeCode per Entry comunque l'organizzazione del Server e del Client resterà' a pagine ragionevolmente grandi (256x256) e nel caso di trasferimenti a pagine queste dovranno avere dimensione sottomultipla della dimensione della pagina in cache.
Se T è la dimensione del time code, W la dimensione totale della pagina, D la dimensione del dato:
 
Metodo di Archiviazione Occupazione di W entry Size (W=8*8=64, T=4, D=16) World Size (4096*4096: 262144 mappe)
1 Time Code per Pagina T+WD 1028 byte 257MB
1 Time Code per Entry (T+D)W 1280 byte 320MB

Visto che in questo caso D>>T, la dimensione del mondo e' solamente piu grande del 20%. Il problema pero' non e' relativo all'occupazione sul Server, ma quanti dati trasferire tra il Client e il Server.
Prendiamo dunque il caso di comunicazione della sezione precedente (2), e valutiamo quanti dati saranno trasferiti tra i due computer:
Caso 1: 1 Time Code Per Entry

  1. Il Client si sposta di una casella e invia al Server m TimeCode di T byte
  2. Il Server confronta e con probabilità' di variazione h dei dati invia al client (T+D)m dati (D sono i dati condivisi < dati privati). In questo caso D é confrontabile con T.
Caso 2: 1 Time Code Per Pagina
  1. Il Client si sposta di una casella e se esce fuori dalla mappa (m/W) invia al Server 1 TimeCode di T byte. (m << W)
  2. Il Server confronta e con probabilita' di variazione h*W dei dati invia al client T+WD dati.
Metodo di Archiviazione Client -> Server Server -> Client
1 Time Code per Pagina (m/W)T h*W*(T+WD)*(m/W)
1 Time Code per Entry mT h*(T+D)m

Il sistema a pagine ha senso se ci sono seri problemi di banda tra Client->Server o comunque se h < (T / WD) e questo numero é dell'ordine del 5%. Bisogna considerare peró che questa é la probabilitá di variazione media di TUTTA la mappa del mondo e questo valore, rapportato ai tempi di comunicazione (1-2 spostamenti al secondo), rappresenta un evento infrequente. Dunque una variazione dell'5% a ciclo é una cosa enorme: vorrebbe dire che l'intero mondo possa cambiare costantemente ogni mezzo minuto.

In questo modo si potrebbe stimare la dimensione della pagina W ponendo come limite superiore T/hD ma:


Ulteriori osservazioni:


Mappe di trasferimento 32x32 rappresentano secondo me un compromesso accettabile. Questo valore dipende anche da quanti dati condivisi e' composta la singola entry. Dati composti da  un semplice indice dell'immagine da 2 byte sono downloadabili dal Client in 1 secondo (salvo eventuali lag della rete).

Lista della spesa

Il Server dovrá essere tarato per supportare un numero massimo di giocatori ai quali verrá divisa la banda in uscita del Server. Questo valore potrebbe anche aggirarsi sul migliaio di utenti con una semplice rete da 10Mb/s. Normalmente il protocollo utilizzato sarà l'UDP, molto più leggero dalla parte del server, anche se, se il traffico di rete è sostenuto, i pacchetti tendono a essere eliminati. Si può ovviare cercando di non far saturare il server o inviando più di un pacchetto uguale UDP alla volta. La maggior parte dei giochi online adotta questa tecnica. I pacchetti affidabili dovranno essere implementati a cura del programmatore attraverso tecniche di req/ack. Il pacchetto massimo dovrà avere una dimensione fissata (Quake usa pacchetti affidabili di dimensione massima da 1024 byte). Il Collo di bottiglia a questo punto diverrá la capacitá di elaborazione del Server, visto che dovrá animare e gestire migliaia di Intelligenze Artificiali e tenere traccia degli spostamenti di migliaia di utenti.

Il server dovrà implementare:

Il Client daltra parte dovrà cercare di sobbarcarsi la maggior parte del lavoro possibile, scontrandosi con la possibilità che l'utente possa modificare in qualche maniera il software locale a proprio vantaggio. Le collisioni (fini), le azioni di informazione, e altro possono essere lasciate sul client.

Realizzazione di un gioco Locale (in breve)

Le limitazioni imposte dalla comunicazione via rete vanno eliminate. Le uniche limitazioni che si devono comunque considerare sono quelle del Server: limitata memoria e spazio su HD limitato. Solitamente in un gioco locale comunque si carica in memoria una sola area alla volta (può essere molto grande comunque, a seconda dei requisiti di memoria per visualizzarla e gestirla). Ovviamente in quanto gioco locale è possibile inserire uno storyboard ben fissato che permette di aggiungere notevole coinvolgimento al gioco. La IA dei PNG sarà importante per dare maggiore spessore al gioco, visto che non sarà possibile interagire con altre persone reali.

Varie. Interfaccia con il Mondo. Sincronizzazioni.

Ci sono diverse cose da tenere in considerazione per bilanciare il gioco.

[continua...]

Tool Necessari

A questo punto c'è da chiedersi cosa è ncessario programmare per fare un Gioco di Ruolo (sia su Rete che in locale). Sono, a mio avviso, necessari questi programmi:
 

Glossario

DM.    Dungeon Master.
Una persona reale che ha il compito di creare avventure e gestire l'ambiente di gioco
ENTRY. Elemento di una matrice
In questo contesto indica l'elemento (di posizione generica  i,j,k) nella matrice del mondo. Questo deve contenere almeno il codice della tile che contiene.
MESH.
La Mesh è una collezione di poligoni (normalmente dovrebbero essere continui e adiacenti) che fanno parte dello stesso oggetto concettualmente.
MOB. Mobile
Un Mob è un qualsiasi personaggio, animale, cosa comandata dalla IA del Server.
PNG. Personaggio non Giocate
E' un personaggio comandato dal Computer. Ha un set ridotto di azioni e una limitata interazione con l'ambiente.


Paolo Medici, che ultimamente aveva del tempo da perdere in retorica. Dalla Serie delle Guide Veloci per fare Software Miliardari Tutti i Marchi sono dei rispettivi proprietari: Diablo della Blizzard, Baldur's Gate della BioWare/TSR/Interplay, Ultima Online della Origin. Discuti questo articolo nel forum
Questo articolo è ha avuto 9303 contatti. Pagina Aggiornata il 24 ottobre 2002