Newsgroup: it.comp.lang.c++
Titolo: Mud in C++ - Consigli per una discussione

Con questo ha inizio una serie di messaggi relativi al progetto che ho
deciso di intraprendere, e che seguiranno successivamente, mano a mano che
il programma prenderà corpo.
Il progetto è quello di realizzare un MUD (Multi User Dungeon) in C++ sotto
Windows NT/2000.
Probabilmente questa frase farà storcere la bocca a molti, ma passo a
esporre le ragioni che sono dietro a queste scelte.
Inizio con una breve descrizioni per i non esperti: un MUD è un gioco di
ruolo multiutente giocato via Internet, composto esclusivamente da testo. A
livello tecnico si tratta di un programma che accetta connessioni di tipo
telnet e utilizzando una lista di socket legge a intervalli regolari gli
eventuali comandi dei giocatori, per poi processarli mediante un parser e
intraprendere le azioni adeguate. Contemporaneamente, mantiene in memoria
una complessa rete di strutture dati collegate tra di loro, rappresentanti
personaggi, oggetti e stanze del gioco, oltre a tutti gli altri dati
necessari. Apposite procedure si preoccupano di gestire combattimenti,
magie, effetti e tutto quanto necessario per un buon gioco di ruolo fantasy
(oppure no).
Quelli che già mi conoscono (in particolare su ICGM) sanno che da tempo ho
in programma di scrivere un nuovo MUD, non basato su alcun server
precedente, e quindi libero da dettagli implementativi vecchi ormai di vari
anni (e chi ha mai tentato di far funzionare decentemente un DikuMUD o un
suo derivato sa di che lavoro improbo si tratti). Si tratta di un lavoro a
cui mi dedico per hobby puro, quindi a tempo perso e senza alcun impegno. Ho
realizzato più volte lo scheletro di un programma, sempre in C e in
particolare sotto Linux, arrivando anche a quello che consideravo un buon
punto di realizzazione, per poi accorgermi che avevo semplicemente copiato
quasi tutti gli algoritmi del DikuMUD. E se questo può essere normale per
gestire la comunicazione via socket (dopotutto le librerie BSD sono sempre
le stesse), lo è un po' meno quando ci si accorge di avere in mano una
gestione dei database interni già vista da qualche parte.
Così ho deciso di intraprendere qualcosa di completamente originale, e vista
la struttura del programma, che si presta particolarmente bene ad essere
rappresentato mediante oggetti comunicanti tra di loro, ho pensato di
rivolgermi al C++. La piattaforma scelta è Win32, in parte perché ho
sottomano prevalentemente quello a casa e al lavoro, e in parte perché il
Visual C++ 6 rimane un IDE particolarmente comodo, almeno secondo il mio
punto di vista (No Religious War Intended). Avendo poi a disposizione una
rete Windows 2000 (che, al contrario del 98, presenta un'ottima stabilità) e
un server gestito da me medesimo, la scelta diventa quasi obbligata.
Però dietro le comodità si nascondono una serie di enormi potenziali
problemi, e per questo ho deciso di interessare con questo primo messaggio
ben tre newsgroup, prima ancora di iniziare a postare dettagli su problemi
specifici, in modo tale che ogni gruppo possa stabilire se l'argomento è di
interesse comune o è preferibile che la discussione continui da un'altra
parte.
La parte puramente teorica riguardante il gioco, la sua impostazione e il
suo funzionamento, è prevalentemente un argomento da it.comp.giochi.mud, e
pur riflettendosi in modo notevole sugli algoritmi da utilizzare, non ha
alla fine poi molta importanza a livello di codice se un personaggio ha 6 o
7 attributi fondamentali o se una magia deve fare 3d7+5 danni. Allo stesso
tempo però una serie di soluzioni implementative che mi piacerebbe
realizzare (o altre che potrebbero essere suggerite da eventuali
collaboratori che si uniranno al progetto) richiede una pesante discussione
sul codice da utilizzare. In particolare, si manifestano in un programma del
genere una serie di problematiche relative al C++, quali il modo migliore di
impostare una gerarchia di classi, se utilizzare o no determinate "features"
del linguaggio, ecc., oltre poi a dettagli più tecnici come l'utilizzo di
determinate librerie e funzioni, in particolare la STL (credete di poter
fare un MUD senza liste ?) e alcuni operatori da ridefinire nei modi
appropriati. Inoltre, un'ottima diea potrebbe essere di rendere il codice
quanto più platform-free possibile, evitando il ricorso a librerie
specifiche e utilizzando ove possibile librerie standard, magari
incapsulando le chiamate di sistema in classi appropriate, in modo tale che
il porting richieda solo di modificare ad esempio la gestione dei files di
dati e della comunicazione di rete, lasciando inalterata la struttura di
fondo del programma. Il problema si fa qui più specifico della piattaforma,
ed è qui che it.comp.programmare.win32 entra in gioco. In particolare,
dell'eseguibile saranno prodotte due versioni, una di debug in grado di
girare da linea di comando, e una di funzionamento operante come servizio di
Windows NT/2000 (l'unico modo, e comunque il più sicuro, per realizzare un
programma che lavori in background sotto Windows). In questo modo, si
eviterà tra l'altro di dover ricorrere alle temibili MFC (anche se la
CAsyncSocket potrebbe tornare comoda), in particolare per la gestione delle
finestre, che saranno del tutto assenti.
Realizzare un servizio di Windows 2000 non è però così semplice (ho letto
esempi di codice da far rabbrividire), e crea inoltre problemi di debug, che
tra l'altro rendono necessaria la presenza di un eseguibile a linea di
comando. Inoltre, sarà sicuramente necessario usare chiamate di sistema e
librerie per l'accesso ai files, per gestire i socket, per il timing, ecc.
Invito chi ha un parere sul modo giusto di intraprendere questa discussione
a rispondere, lasciando possibilmente il followup su tutti e tre i
newsgroup, visto che si tratta di una piccola discussione preliminare. Mi
scuso con i non interessati per l'eventuale intrusione, e invito gli
interessati a contattarmi personalmente, se desiderano maggiori dettagli o
partecipare alla realizzazione del programma.
Massimo (Octavius su Lumen & Umbra, tanto tempo fa)

 Massimo (Octavius su Lumen & Umbra, tanto tempo fa)
Ciao Massimo, forse ti ricorderai di me, sono Lorenzo (Ydwen su Lumen &
Umbra, tanto tempo fa :).
La tua idea mi sembra interessantissima e possibilmente molto feconda. Non
mi posso pronunciare sulle scelte tecniche di realizzazione vista la mia
scarsa conoscenza della programmazione in C e C++, trovo pero' ottima l'idea
di partire da una piattaforma in forte diffusione come Windows 2000 e
dirigersi verso un concetto di estrema portabilita'.
Per quanto riguarda invece la parte 'muddistica' dell'impresa mi piacerebbe
apportare qualche idea alla discussione:
-Tutti i mud esistenti (i + moderni Smaug meno degli altri) soffrono spesso
di una estrema rigidita' derivante dal fatto che implementano soluzioni
legate solo a concetti effettivamente utilizzati..e non anche per idee
potenziali non sfuttate e questo, a mio avviso, e' uno dei loro + grossi
difetti.
Un esempio
Quasi tutti i mud prevedono che un determinato oggetto appaia in mano ad un
Mob (personaggio gestito dal gioco) o all'interno di una locazione. Ma
questo e' quasi sempre legato ad un concetto binario: L'oggetto appare/ o
non appare, in mano ad un determinato mob.
Molto piu' interessante e feconda potrebbe essere l'ipotesi in cui un
oggetto abbia un tot di possibilita' di apparire o meno su un determinato
mob, su una classe di mob o addirittura su qualunque mob del mud. In questo
caso chi volesse utilizzare la procedura standard di repop dovrebbe solo
scegliere che l'oggetto appaia con il 100% di probabilita' su un mob
determinato. Altri invece potrebbero sfruttare le notevoli possibilita' date
dalla procedura di repop a random.
Lo stesso concetto e' applicabile anche per la qualita' degli oggetti e dei
mob.
Molti mud stabiliscono che un certo mob 'nasca' con un numero di punti vita
pari, ad esempio, a 80d10 questo porta una certa possibile variazione nella
potenza del mob, ancora minima pero'.
Molto meglio sarebbe prevedere che un certo mob ha il (es) 70% di essere
Resistente al fuoco...o meglio ancora, che questi abbia una certa
probabilita' di Resistere al fuoco del 50% (ovvero subendo la meta' dei
danni da fuoco) e una certa altra probabilita' di Resistere al fuoco al 70%,
80%, 100% e cosi' via.
A mio avviso si tende a notare una certa tendenza dei mud a divenire sempre
+ ripetitivi, favorendo quei giochi invece che utilizzino molte componenti
random (Everquest, Asheron's Call, probabilmente Ultima Online 2 : questi
sono veri e propri MUD grafici).
Se il mud (testuale e non) vuole avere una lunga vita e' a mio avviso
assolutamente necessario strutturarlo in maniera elastica, in modo che possa
essere cambiato in maniera semplice e con poco sforzo.
Alla prox :)
Lorenzo
(Una volta Ydwen su L&U, ora Kyrasys su Tempora Sanguinis 2)

 (Una volta Ydwen su L&U, ora Kyrasys su Tempora Sanguinis 2)
Uhm, la componetne della casualita' e' presente in buona parte dei circlemud.
Non lavedo come una modifica poi cosi' irrealizzabile, si tratta di leggere un
campo in piu' da un file e applicare la paercentuale al caricamento.
Penso che Max intendesse operare innovazioni strutturali molto piu' massiccie.
  Razor

 Penso che Max intendesse operare innovazioni strutturali molto piu'
massiccie.
In effetti non hai tutti i torti :-)
E' una buona idea comunque che le caratteristiche di un mob/oggetto non
siano esattamente prevedibili (vedi gli oggetti di Medievia, che perň fanno
bestemmiare assai quando te ne capita uno buono e poi si rompe...)
Massimo

 Massimo (Octavius su Lumen & Umbra, tanto tempo fa)
Ciao Massimo!
Avevo avuto un'idea simile tempo fa quando ho scovato su un CD
Slackware Linux i sorgenti del CircleMUD 2.2: allora stavo imparando il C++
e mi venne l'ispirazione di riscrivere il tutto in C++ (i sorgenti erano in
Objective C): era un'idea molto stimolante, e il fatto di avere classi e
metodi mi aveva fatto venire diverse idee interessanti... Che ne pensi di
un MUD nonlineare? :-) dopo un pò però mi sono reso conto che
la cosa mi prendeva molto tempo, e in fondo un clone del vecchio
Circle non era poi il massimo. In più stavo rendendo il programma
più lento e più affamato di RAM...
... e io lo facevo girare su un 386/33 con 8Mb... :-) Così lasciai stare
C++ e Linux e mi dedicai a Delphi (mi serviva per un esame all'università),
però mi piacerebbe rimettermi al lavoro su un progetto di questo tipo.
Anche se è per Windows... :-)

 Anche se è per Windows... :-)
A Windows puoi dire molte cose orrende, ma il 2000 va che è un amore... e il
VC++ 6 è tuttora il miglior IDE in cui mi sia imbattuto.
Massimo

 VC++ 6 è tuttora il miglior IDE in cui mi sia imbattuto.
Concordo: è ottimo... gli manca l'immediatezza dell'IDE di Delphi, ma per
progetti medio/grandi permette di mantenere meglio sotto controllo i
sorgenti.
Tornando in tema, penso che l'idea di usare un DB SQL per memorizzare
oggetti, MOB e stanze (letta in un'altro thread nato dal tuo post) sia
interessante,
ma da valutare bene. Infatti spesso ai MOB sono associate routine speciali
di comportamento (pensa ai locandieri, ai guildmaster etc.).
Io avevo affrontato la cosa creando classi apposite:
class guildmaster : public MOB
{
ecc. ecc.
void teach(PG*, skill*);
void livella(PG*);
ecc. ecc.
}
però restavo sempre con dei NPC speciali che dovevo trattare
con codice a parte.  Questo però non c'entra niente coi DB SQL :#))
No, volevo dire che un DB esterno sarebbe un grosso aiuto per i coder
e una garanzia di affidabilità, ma (ovviamente) un peso supplementare per
il sistema, che già di suo dovrebbe essere bello impegnato a far
girare il MUD...
Però se il MUD è piccolo il suo peso computazionale non dovrebbe
essere granchè, mentre se il MUD è grosso e ci sono un sacco di
PG attivi, il codice del DB sarà decisamente più efficiente nel gestire
decine di richieste al secondo di quanto potrebbe fare del codice scritto
apposta, considerato che probabilmente il DB ha una serie di buffer interni
in cui conserva i record richiesti più spesso (cache! Ecco la parola... :-))
e/o altre ottimizzazioni... che dei poveri coder potrebbero non avere il
tempo e/o la voglia di implementare... :-)))))
...E comunque con l'hardware di oggi non dovrebbe essere un grosso handicap,
e tanto meno con quello di domani... (Microsoft docet *GRIN*)
Per quanto riguarda il legame con un DB specifico il problema non si pone,
SQL è uno standard mondiale e qualsiasi DB può importare/esportare
dati in formati diversi, se non addirittura farlo via SQL stesso credo...
se mi sbaglio corregimi... quindi se il MUD è capace di interfacciarsi
tramite SQL, si puo' interfacciare a qualsiasi DB SQL uno scelga, su
qualunque piattaforma.
Quindi secondo me potrebbe valer la pena fare un tentativo... in caso vada
storta, copiamo le routine DB del CIRCLE e programmiamo un Reboot
ogni due ore come al solito :-))))
PS: Scusa se ho cambiato pseudonimo... ora sono una persona seria,
ho finito gli esami stamattina e sono diventato tesista... :-)
Massimo Soricetti

 credo...
Non riesco nemmeno a immaginarlo... lascio il crosspost solo perché forse in
it.comp.lang.c++ ne sanno qualcosa, e ormai sono curioso ;-)
Al resto del messaggio rispondo solo su ICGM.
Massimo