Recevoir un message depuis un VGUI

Écrit le 03/07/2003 par Bicou
Dernière mise à jour : 30/01/2006

Introduction

Voilà un petit tutorial pour permettre de recevoir un message depuis un menu VGUI. C'est un complément du tutorial sur les messages, et je partirai du fait que vous savez comment faire un menu VGUI, et que vous avez déjà la classe correspondante (si c'est pas le cas, MiK a fait trois tutoriaux à ce sujet).
Le principe est simple, il faut ajouter la fonction MsgFunc_MonMessage dans la classe TeamFortressViewport, et la spécifier comme celle qui va recevoir le message. C'est très simple, vous verrez avec l'exemple.

La fonction MsgFunc_MonMessage

Tout d'abord nous allons ajouter la fonction à la classe TeamFortressViewport, pour cela allez dans vgui_TeamFortressViewport.h vers la ligne 400. Vous voyez une série de fonctions MsgFunc_*** :

// Message Handlers
int MsgFunc_ValClass(const char *pszName, int iSize, void *pbuf );
int MsgFunc_TeamNames(const char *pszName, int iSize, void *pbuf );
int MsgFunc_Feign(const char *pszName, int iSize, void *pbuf );
int MsgFunc_Detpack(const char *pszName, int iSize, void *pbuf );
int MsgFunc_MOTD( const char *pszName, int iSize, void *pbuf );
int MsgFunc_BuildSt( const char *pszName, int iSize, void *pbuf );
int MsgFunc_RandomPC( const char *pszName, int iSize, void *pbuf );

int MsgFunc_MonMessage( const char *pszName, int iSize, void *pbuf );

La traditionnelle fonction MsgFunc_MonMessage est donc déclarée. Il faut l'implémenter (lui donner son contenu), pour cela allez dans vgui_TeamFortressViewport.cpp vers la fin du fichier :

int TeamFortressViewport::MsgFunc_AllowSpec( const char *pszName, int iSize, void *pbuf )
{
    BEGIN_READ( pbuf, iSize );

    m_iAllowSpectators = READ_BYTE();

    // Force the menu to update
    UpdateCommandMenu();

    // if the team menu is up, update it too
    if (m_pTeamMenu)
        m_pTeamMenu->Update();

    return 1;
}

int TeamFortressViewport::MsgFunc_MonMessage( const char *pszName, int iSize, void *pbuf )
{
    [...]

    return 1;
}

Le contenu de cette fonction est le même que dans le tutorial sur les messages. Je ne vais pas m'attarder dessus.

L'enregistrement du message

Je n'ai pas trouvé de titre très explicite pour cette partie. Il va simplement s'agir de dire au moteur que c'est telle fonction qui va réceptionner tel message.
Commençons par hud.cpp ligne 250 et quelques :

int __MsgFunc_Spectator(const char *pszName, int iSize, void *pbuf)
{
    if (gViewPort)
        return gViewPort->MsgFunc_Spectator( pszName, iSize, pbuf );
    return 0;
}

int __MsgFunc_AllowSpec(const char *pszName, int iSize, void *pbuf)
{
    if (gViewPort)
        return gViewPort->MsgFunc_AllowSpec( pszName, iSize, pbuf );
    return 0;
}
//Mon code:
int __MsgFunc_MonMessage( const char *pszName, int iSize, void *pbuf)
{
    if (gViewPort)
        return gViewPort->MsgFunc_AllowSpec( pszName, iSize, pbuf );
    return 0;
}

Ici, on déclare une autre fonction globale qui a un nom similaire à l'autre. En fait c'est celle-ci qui va réceptionner le message, et elle va appeler la première.
Maintenant, il faut dire au moteur que la fonction __MsgFunc_MonMessage() doit recevoir le message : un peu plus bas, vers la ligne 320 :

HOOK_MESSAGE( ScoreInfo );
HOOK_MESSAGE( TeamScore );
HOOK_MESSAGE( TeamInfo );

HOOK_MESSAGE( Spectator );
HOOK_MESSAGE( AllowSpec );

HOOK_MESSAGE( MonMessage );//Mon code

Ici donc on indique grâce à une macro au moteur quelle fonction doit recevoir le message. Si vous regardez la déclaration de la macro, ça donne :

#define HOOK_MESSAGE(x) gEngfuncs.pfnHookUserMsg(#x, __MsgFunc_##x );

Donc en faisant HOOK_MESSAGE( MonMessage ), on fait gEngfuncs.pfnHookUserMsg( "MonMessage", __MsgFunc_MonMessage );
En fait on relie « MonMessage » à la fonction __MsgFunc_MonMessage(). Beaucoup de baratin pour quelque chose de pas très important.

Voilà, notre fonction est reliée au message. La fonction est donc « capable » de recevoir le message ; la boucle est bouclée.

Conclusion

C'est vraiment un petit tutorial pour montrer qu'on est pas obligé d'utiliser une classe dérivée de CHudBase pour réceptionner un message, mais en fait ce qu'on veut. Dans le code on n'utilise qu'un CHudBase ou un menu VGUI.

J'espère que j'aurai été clair, si vous avez des questions, n'hésitez pas.