sdk


Questa guida e' molto semplice e sicuramente incompleta, e' soltanto per iniziare. Sara' naturalmente integrata, modificata, aggiornata ed anche riscritta da capo se sara' necessario in base ai vostri commenti, alle vostre domande, ed agli sviluppi futuri del client. A fondo pagina trovate le versioni scaricabili dei sorgenti dei due plug-ins che ho scritto io, spero vi siano utili per farvi un'idea del funzionamento.

(le specifiche qui descritte sono valide per GosClient 1.6.0 versione finale)

Introduzione

I plug-ins di GosClient sono praticamente dll standard di windows e comunicano con il client attraverso due metodi:
- il primo consiste nell'esportazione di alcune funzioni da parte della dll, questo metodo permette l'inizializzazione e il passaggio delle prime informazioni al client
- eseguita l'inizializzazione entra in gioco il secondo metodo, basato sulla comunicazione tramite socket utilizzando il protocollo tcp-ip, come in una applicazione client-server
Esiste un preciso protocollo che viene utilizzato durante le comunicazioni tramite tcp-ip, che illustrero' piu' avanti. Tramite questo protocollo il plug-in potra' ricevere (e se lo desidera bloccare) l'output che il client riceve dal MUD, cosi' come ricevera' l'input proveniente dall'utente, potra' quindi a sua volta inviare un output sostitutivo a quello bloccato, inviare messaggi di stato e di errore ed inviare comandi da eseguire nel MUD. Oltre a questi canali di comunicazione basilari esistono alcune notifiche (quando viene cambiata la configurazione, o si cambia profilo, per esempio) ed altre informazioni (nome del mud, nome del profilo, cartella del mud e del profilo, cartella del client ecc...).

Funzionamento interno del client

All'interno del client esistono diversi "canali" che vengono ricevuti da ogni singola sua parte (quindi anche dai plug-ins).
Quando arrivano dei dati dal MUD, questi vengono trasformati in stringa e inviati una prima volta a tutti i componenti per essere elaborati (e' questa la stringa che sara' possibile bloccare e sostituire), dopo il primo invio la stringa viene suddivisa in singole righe e "ripulita" dalle sequenze ANSI, in modo che ogni riga sia cosi' costituita di testo semplice. Questo output "pulito" viene quindi passato ai componenti ed e' molto utile per alcune elaborazioni (come ad esempio l'estrapolazione di titolo e descrizione di una stanza per il mapper). Questi (normale e pulito) sono i due principali tipi di output, oltre a questi ce ne sono altri che permettono di inviare output alla finestra di stato e di inviare errori, mostrati in rosso nella finestra di stato.
Come l'output del mud, anche l'input dell'utente "passa" attraverso tutti i componenti prima di essere inviato, in modo da permettere eventuali elaborazioni (come ad esempio lo spostamento della posizione corrente nel mapper all'invio di un movimento). Esistono due modi per inviare l'input: il primo e' l'invio diretto, adatto per stringhe abbastanza corte; il secondo consiste nell'accodamento alla coda di invio, utile nel caso in cui si debbano inviare molti comandi insieme (saparati da CRLF) per non che i vari metodi anti-flood dei mud entrino in azione per un invio troppo precipitoso.
Oltre ai sistemi di input e output esiste un sistema di notifica (come gia' accennato in precedenza) che permette di sapere lo stato del sistema attraverso ogni suo cambiamento. Vengono notificati gli eventi piu' importanti, come il cambio di profilo, la disconnessione, il cambio di layout, il cambio di colori eccetera...

Funzioni di inizializzazione

Come accennato in precedenza la dll del plug-in deve esportare alcune funzioni per permettere le inizializzazioni e lo scambio di alcune informazioni. Si tratta in tutto di quattro funzioni, due delle quali facoltative:

gosInit
Questa funzione permette l'inizializzazione del plug-in, prima di ritornare da questa funzione bisogna aver attivato la connessione tramite tcp-ip al client sulla porta indicata nei parametri, il client attendera' per cinque secondi la connessione del plug-in dopodiche', sequesta non sara' andata a buon fine, andra' in errore di timeout e terminera' l'esecuzione dello stesso. Quando si riceve una chiamata a questa funzione bisogna eseguire le inizializzazioni, ma non mostrare finestre, per quello bisogna attendere il segnale 001 (vedi Protocollo)

dichiarazione:
long __stdcall gosInit(HWND hWnd, long s, long lPort, long* lpCanStop)

parametri:

hWnd Contiene un handle alla finestra principale del client, tutte le finestre dei plug-in dovrebbero appartenere a questa finestra. Per stabilire questo legame bisogna creare la finestra inserendo questo valore nel parametro hWndParent delle funzioni CreateWindow o CreateWindowEx.
s non utilizzato
lPort Porta a cui connettersi per attivare la comunicazione tcp-ip gra client e plug-in.
lpCanStop indica se il plug-in e' abilitato a bloccare l'output del MUD o meno. Inizialmente il valore puntato da questa variabile e' 0, variarlo in 1 se si vuole che il plug-in possa modificare l'output del MUD verso il resto del client (vedi Sistema di sostituzione dell'output).

valori di ritorno:
la funzione deve ritornare un valore diverso da0 se l'inizializzazione e' stata completata, altrimenti 0.

gosInfo
Questa funzione permette di passare alcune piccole informazioni generali sul plug-in al client.

dichiarazione:
long __stdcall gosInfo(long a, long b, long c, gosPluginInfo* pGPI)

parametri:

a,b,c non utilizzati
pGPI

punta ad una struttura gosPluginInfo, dichiarata come segue:

typedef struct gosPluginInfo {
    const char lpTitle[128];
    int nMajor;
    int nMinor;
    int nRevision;
} gosPluginInfo;

lpTitle dovra' contenere il titolo del plug-in (per un massimo di 128 caratteri)
nMajor, nMinor e nRevision sono invece tre valori di versione, a partire dal piu' importante fino al meno importante.

valori di ritorno:
la funzione deve ritornare un valore diverso da 0 se e' andata a buon fine, altrimenti 0.

gosConf (facoltativa)
Questa funzione indica al plug-in che e' stato richiesto dall'utente di mostrare la finestra di configurazione. Se il plug-in non ha una finestra di configurazione questa funzione puo' anche non figurare, oppure esistere e non eseguire niente, ritornando 0.

dichiarazione:
long __stdcall gosConf(HWND hParent, long b, long c, gosPaths* pGP)

parametri:

hParent Handle alla finestra principale del client, a cui la finestra di configurazione deve appartenere (secondo le stesse modalita' definite per gosInit)
b,c non utilizzati
pGP

punta ad una struttura gosPaths contenente informazioni sulle varie directory del client (in cui il plug-in puo' scrivere le sue configurazioni sotto forma di files), dichiarata come segue:

typedef struct gosPathsStruct {
    LPCTSTR lpClientPath;
    LPCTSTR lpMudPath;
    LPCTSTR lpProfilePath;
} gosPaths;

tutti i parametri contengono le stringhe dei percorsi assoluti riguardo rispettivamente al client, al mud selezionato ed al profilo selezionato.

valori di ritorno:
la funzione deve ritornare un valore diverso da 0 se il plug-in possiede una finestra di configurazione, altrimenti 0.

gosCred (facoltativa)
Questa funzione informa il plug-in che e' stato richiesto dall'utente di vedere la finestra di informazioni del plug-in.

dichiarazione:
long __stdcall gosCred(long a, long b, long c, long d)

parametri:

a,b,c,d non utilizzati

valori di ritorno:
la funzione deve ritornare un valore diverso da 0 se il plug-in possiede una finestra di informazioni, altrimenti 0.

 

Protocollo

Ogni stringa inviata e ricevuta deve essere preceduta da un carattere iniziale (ASCII 140) e da un codice di 3 cifre che identifica il tipo di dati successivo (i messaggi marcati in blu vengono ricevuti e possono essere inviati solo da un plug-in abilitato a modificare l'output del MUD):

001
partenza
indica che le inizializzazioni per il plug-in sono state completate, quando si riceve questo messaggio bisogna rendere operativo a tutti gli effetti il plug-in, mostrando la finestra del plug-inad esempio.
002
output preliminare

e' il codice per la ricezione dell'output preliminare. Dopo il codice c'e' uno spazio e quindi la stringa di output. Questo messaggio viene inviato come prima cosa appena viene ricevuto dal mud, e' in questa sede che il programma e' in grado di bloccare e sostituire l'output (vedi Sistema di sostituzione dell'output) se ne e' stato abilitato in gosInit.

Es.
"002 stringa di output"

003
output normale

e' il codice per la ricezione dell'output in forma normale. Dopo il codice deve esserci uno spazio e quindi la stringa di output.

Es.
"003 stringa di output"

004
output pulito

codice per la ricezione dell'output pulito, la stringa di output vero e proprio si trova accodata al codice, dopo uno spazio.

Es.
"004 stringa di output"

005
input normale

invio e ricezione dell'input, come al solito la stringa di input e' accodata al codice, dopo uno spazio.

Es.
"005 stringa di input"

006
input da accodare

codice per l'invio di stringhe da accodare per l'invio ritardato. Ogni riga estratta dalla stringa inviata in questo modo viene suddivisa ed iviata a brevi intervalli di tempo.

Es.
"006 stringa di input, prima riga \n seconda riga \n terza riga \n ecc..."

007
messaggi di errore

tramite questo codice si possono inviare messaggi di errore, che verranno mostrati in rosso sulla scheda "status" sul client.

008
messaggi di stato
tramite questo codice si possono inviare messaggi di stato, che verranno mostrati sulla scheda "status" sul client.
010
notifica

questo codice permette di ricevere notifiche dal client. Ogni notifica e' identificata da un numero, che verra' accodato al codice dopo uno spazio. Le possibili notifiche sono:

1 Chiusura della connessione
3 Cambio dei colori
4 Cambio del profilo
5 Cambio nella configurazione
10 Cambio nel layout

Es.
"010 5" //notifica del cambio nella configurazione

011
conferma output

questo messaggio deve essere inviato dal plug-in in risposta ad un messaggio 002 nel caso in cui voglia lasciare l'output del mud invariato.

Es.
"011"

012
sostituisci output

questo messaggio deve essere inviato dal plug-in in risposta ad un messaggio 002 nel caso in cui si voglia variare l'output del mud, la nuova stringa di output dovra' essere accodata al codice stesso (sempre preceduta da uno spazio vuoto).

Es.
"012 StRiNgA dI oUtPuT mOdIfIcAtA"

050
nome del MUD

questo messaggio viene inviato una sola volta prima di quello di partenza (partenza, 001), comunica al plug-in il nome del MUD corrente.

Es.
"050 Silmaril"

051
nome del profilo

questo messaggio viene inviato la prima volta prima dello 001 e poi ogni volta che si verifica un cambio di profilo, comunica al plug-in il nome del profilo selezionato.

Es.
"051 Seph"

052
cartella del client

viene inviato una sola volta prima dello 001, comunica la cartella assoluta del client (sicuramente esistente, termina sempre con \).

Es.
"052 C:\Programmi\GoS\"

053
cartella del MUD

viene inviato una sola volta prima dello 001, comunica la cartella assoluta del MUD selezionato (sicuramente esistente, termina sempre con \).

Es.
"052 C:\Programmi\GoS\silmaril\"

054
cartella del profilo

viene inviato inizialmente prima dello 001 ed ogni volta che si cambia profilo, comunica la cartella assoluta del profilo selezionato (sicuramente esistente, termina sempre con \).

Es.
"052 C:\Programmi\GoS\silmaril\p_seph\"

   

Esempio di sessione

Riporto qui sotto un esempio di sessione per dare un'idea della sequenza di comunicazione che intercorre fra client e plug-ins.
Le scritte fra parentesi quadre indica delle azioni, quelle fra virgolette delle frasi inviate tramite il collegamento tcp-ip.

<client> [chiama gosInfo del plug-in]
<plugin> [in gosInfo: riempie la struttura gosPluginInfo e ritorna 1]
<client> [chiama gosInit del plug-in]
<plugin> [in gosInit: attiva il collegamento con il client]
<client> [riceve la richiesta e conferma il collegamento]
<plugin> [in gosInit: ritorna 1]
<client> [conferma inizializzazione avvenuta]
<client> "050 Silmaril"
<client> "051 Seph"
<client> "052 C:\Programmi\GoS\"
<client> "053 C:\Programmi\GoS\silmaril\"
<client> "054 C.\Programmi\GoS\silmaril\p_seph\"
<client> "001 start"
<plugin> [mostra una finestra]
.. (varie comunicazioni di input e output)
..
<client> [interrompe il collegamento]
<plugin> [distrugge le finestra e chiudi il collegamento a sua volta]
<client> [termina il plugin]

Sistema di sostituzione dell'output

Il sistema di sostituzione dell'output e' molto utile quando il plug-in in questione non solo deve eseguire un'azione in base alle informazioni che riceve, ma deve modificarle per nascondere qualcosa di inutile all'utente oppure mostrare altre informazioni (come nel caso del plug-in per il Mud Sound Protocol, che utilizza questa tecnica per nascondere le sequenze del MSP). Il metodo funziona praticamente cosi':
il client invia ad ogni plug-in abilitato un messaggio 002 ogni volta che riceve una stringa dal mud. Il plug-in deve analizzare quella stringa e decidere se vuole modificarla o meno, se non vuole modificarla deve inviare un messaggio di risposta 011; se, al contrario, vuole modificarla dovra' apportare le modifiche e rispondere con un messaggio 012 accodando la nuova stringa di output (vedi Protocollo per le definizioni dei messaggi). Un client abilitato a bloccare l'output deve _sempre_ rispondere ad un messaggio 002 o con uno 011 o con uno 012, poiche' il client resta in attesa della risposta per 5 secondi prima di ignorarla e dare per scontato che il plug-in non voglia modificare l'output.

Plug-ins di esempio

Per ora un vero e proprio plug-in di esempio non e' disponibile, metto a disposizione di tutti pero' i sorgenti di quelli che sono gli unici due plug-ins che ho scritto. In futuro rendero' disponibile un plug-in di esempio completamente commentato ed un programma che emuli il GosClient per eseguire il debug piu' agevolmente. Il codice e' liberamente riutilizzabile (compresa la classe CAlexfMixer che non ho scritto io).

Pacchetto
Dimensione
Contenuto
Linguaggio
22 Kb
Sorgenti del Mud Sound Protocol Plug-In versione 1.1
Progetto per Visual C++ 6.
C++/MFC
19 Kb
Sorgenti del plug-in per il tastierino numerico versione 1.0
Progetto per Visual C++ 6.
C++/MFC

 

Conclusione

Sono a disposizione per qualsiasi chiarimento su questa piccola guida e sui miei sorgenti, scrivete ogni dubbio a questo indirizzo email, vi rispondero' appena possibile.
Vi prego anche di informarmi qualora abbiate in progetto di sviluppare un plug-in per il mio client, grazie :).


designed by Seph - 1024x768 optimized