Welcome, Guest! Login | Register

New HL HUD Message System [Print this Article]
Posted by: Pongles
Date posted: May 28 2003
User Rating: 5 out of 5.0
Number of views: 2981
Number of comments: 0
Description:
I noticed that a lot of bandwidth is consumed when trying to display a HUD Message. To fix this I coded a new type of message system that uses a lot less bandwidth. My first attempt to recode it was ruined when I took a look at message.cpp, I thought the client and server was coded in C++, not bit-bashing C. So I decided to recode the entire thing.

First things first, go to your client workspace and create a new file called custom_message.cpp or something similar, it doesnt really matter, just remember to call it something that you can remember.

Somewhere in hud.h add the following:
 CODE  

// Pongles [
class CCustomMessage
{
public:
   byte   r, g, b;
   float   y;
   float   fadein;
   float   fadeout;
   float   holdtime;
   char   *pText;
   float   time;
   char   szText[64];

   CCustomMessage() {}
   
   CCustomMessage(byte rr, byte gg, byte bb, float yy, float fo, float ht,
      float st, char *szt);
};

const int maxCustomMessages = 16;

class CHudCustomMsg : public CHudBase
{
   CCustomMessage   *m_pCustomMsgs[maxCustomMessages];

public:
   int   Init(void);
   int   VidInit( void );
   int   Draw(float flTime);
   int   MsgFunc_CustomMsg(const char *pszName, int iSize, void *pbuf);
   int   CenterPos(char *szMessage);
   void MessageAdd( int type, float time, char *text );
   void Reset( void );

   ~CHudCustomMsg();
};
// Pongles ]


While in hud.h you need to let the base class know about it otherwise it cannot be initialised.

So under public in CHud add the following:
 CODE  

// Pongles [
CHudCustomMsg   m_CustomMsg;
// Pongles ]


Close hud.h and open up hud.cpp, under the function void CHud :: Init( void ) add the following:
 CODE  

// Pongles [
m_CustomMsg.Init();
// Pongles ]


Slightly further on in the code you find the function void CHud :: VidInit( void ) add this following:
 CODE  

// Pongles [
m_CustomMsg.VidInit();
// Pongles ]


In your newly created source file create , add this:
 CODE  

//
// custom_message.cpp
//
// implementation of CHudCustomMsg class
//
// Coded By: Pongles

#include "hud.h"
#include "cl_util.h"
#include "parsemsg.h"
#include <string.h>
#include <stdio.h>

#define MSG_RESPAWN      1
#define MSG_GAME         2
#define MSG_FIRSTBLOOD   3
#define MSG_NAME         4
#define MSG_VICTIM       5
#define MSG_KILLER       6
#define MSG_WEAPON       7

CCustomMessage::CCustomMessage(byte rr, byte gg, byte bb, float yy, float fo, float ht,
      float st, char *szt)
{
   r = rr;
   g = gg;
   b = bb;
   y = yy;
   fadeout = fo;
   holdtime = ht;
   time = st;
   strcpy(szText, szt);
}


DECLARE_MESSAGE(m_CustomMsg, CustomMsg);

int CHudCustomMsg::Init(void)
{
   HOOK_MESSAGE(CustomMsg);

   gHUD.AddHudElem(this);

   Reset();

   return 1;
}

int CHudCustomMsg::VidInit(void)
{
   return 1;
}

void CHudCustomMsg::Reset( void )
{
   for(int i = 0; i < maxCustomMessages; i++)
   {
      if (m_pCustomMsgs[i])
         delete m_pCustomMsgs[i];
      m_pCustomMsgs[i] = NULL;
   }
}

CHudCustomMsg::~CHudCustomMsg( )
{
   for(int i = 0; i < maxCustomMessages; i++)
   {
      if(m_pCustomMsgs[i])
      {
         delete m_pCustomMsgs[i];
      }
   }
}

int CHudCustomMsg::Draw(float flTime)
{
   int Index;
   
   bool BeingDrawn = false;

   float factor, endTime, holdTime;

   CCustomMessage *pMessage;

   // loop though 0 - 16
   for ( Index = 0; Index < maxCustomMessages; Index++ )
   {
      // is there one here?
      if ( m_pCustomMsgs[Index] )
      {
         pMessage = m_pCustomMsgs[Index];

         endTime = pMessage->time + pMessage->fadeout
            + pMessage->holdtime;
         holdTime = pMessage->time + pMessage->holdtime;

         BeingDrawn = true;
         
         if ( flTime <= holdTime )
         {
            // hold
            factor = 1;
         }
         else
         {
            // fade out
            factor = 1 - ((flTime - holdTime) / pMessage->fadeout);
         }
           
         gHUD.DrawHudString( (ScreenWidth - CenterPos(pMessage->szText)) / 2,
            pMessage->y, ScreenWidth, pMessage->szText, factor * (pMessage->r),
            factor * (pMessage->g), factor * (pMessage->b) );
           
         // finished ?
         if(flTime >= endTime)
         {
            m_pCustomMsgs[Index] = NULL;
            delete pMessage;
         }
      }
   }

   if ( !BeingDrawn )
      m_iFlags &= ~HUD_ACTIVE;

   return 1;
}

int CHudCustomMsg::MsgFunc_CustomMsg(const char*pszName, int iSize, void *pbuf)
{
   BEGIN_READ(pbuf,iSize);

   int x = READ_BYTE();

   // reads string sent from server
   char *szText = READ_STRING();

   MessageAdd( x, gHUD.m_flTime, szText );

   m_iFlags |= HUD_ACTIVE;

   return 1;
}

int CHudCustomMsg::CenterPos( char *szMessage )
{
   int width = 0;

   for (; *szMessage != 0 && *szMessage != '\n'; szMessage++ )
   {
      width += gHUD.m_scrinfo.charWidths[ *szMessage ];
   }

   return width;
}

void CHudCustomMsg::MessageAdd( int type, float time, char *text )
{
   // check if there is an instance already

   char tempBuffer[64];
   
   if(m_pCustomMsgs[type] != NULL)
   {
      delete m_pCustomMsgs[type];
   }

   // add new instance

   switch ( type )
   {
   case MSG_RESPAWN:
      m_pCustomMsgs[type] = new CCustomMessage(0, 255, 0, (ScreenHeight / 2)
            + (ScreenHeight / 4),1.5, 1, time, "Press [Fire] To Respawn");
      break;
   case MSG_GAME:
      m_pCustomMsgs[type] = new CCustomMessage(192, 192, 192, ScreenHeight / 2,
         1.5, 5, time, text);
      break;
   case MSG_FIRSTBLOOD:
      sprintf(tempBuffer, "%s Drew First Blood", text);
      m_pCustomMsgs[type] = new CCustomMessage(255, 0, 0, ScreenHeight / 4.5,
         1.5, 5, time, tempBuffer);
      break;
   case MSG_NAME:
      sprintf(tempBuffer, "Name: %s", text);
      m_pCustomMsgs[type] = new CCustomMessage(0, 255, 0, ScreenHeight / 2
            + (ScreenHeight / 4),1, 1.5, time, tempBuffer);
      break;
   case MSG_VICTIM:
      sprintf(tempBuffer, "You were killed by %s", text);
      m_pCustomMsgs[type] = new CCustomMessage(0, 0, 255, ScreenHeight / 4,
            1.5, 1, time, tempBuffer);
      break;
   case MSG_KILLER:
      sprintf(tempBuffer, "You Killed %s", text);
      m_pCustomMsgs[type] = new CCustomMessage(255, 0, 0, ScreenHeight / 4.5,
            1.5, 1, time, tempBuffer);
      break;
   case MSG_WEAPON:
      sprintf(tempBuffer, "You got a %s", text);
      m_pCustomMsgs[type] = new CCustomMessage(200, 200, 200, ScreenHeight / 2
            + (ScreenHeight / 4.5), 1.5, 5, time, tempBuffer);
      break;
   }
}

I have created a UT style message system to use.

Thats it for client side, skip over to server side and open up util.cpp.
Add the following somewhere in the file:
 CODE  

// Pongles [
extern int gmsgCustomMsg;

void UTIL_CustomMessage( CBaseEntity *pEntity, int type, const char *pMessage )
{
   if ( !pEntity || !pEntity->IsNetClient() )
      return;

   MESSAGE_BEGIN( MSG_ONE, gmsgCustomMsg, NULL, pEntity->edict() );

      WRITE_BYTE( type );

      if( type > MSG_RESPAWN )
         WRITE_STRING( pMessage );

   MESSAGE_END();
}

void UTIL_CustomMessageAll( int type, const char *pMessage )
{
   MESSAGE_BEGIN( MSG_ALL, gmsgCustomMsg, NULL );
   
   WRITE_BYTE( type );
   
   if( type > MSG_RESPAWN )
      WRITE_STRING( pMessage );
   
   MESSAGE_END();
}
// Pongles ]

Define it in util.h with the following:
 CODE  

// Pongles [
void UTIL_CustomMessage( CBaseEntity *pEntity, int type, const char *pMessage = NULL );
void UTIL_CustomMessageAll( int type, const char *pMessage = NULL );
// Pongles ]

While your there add these following defines somewhere:
 CODE  

// Pongles [
#define MSG_RESPAWN      1
#define MSG_GAME         2
#define MSG_FIRSTBLOOD   3
#define MSG_NAME         4
#define MSG_VICTIM       5
#define MSG_KILLER       6
#define MSG_WEAPON       7
// Pongles ]

We have defined an external integer, so we better go define it in player.cpp.

In the massive block of definitions [ edit: around line 149 - Entropy ] add the following:
 CODE  

// Pongles [
int gmsgCustomMsg = 0;
// Pongles ]

Remember to register it otherwise the engine wont know what to do with it:
[ edit: this line needs to be in the LinkUserMessages function - Entropy ]
 CODE  

// Pongles [
gmsgCustomMsg = REG_USER_MSG("CustomMsg", -1);
// Pongles ]

And there you have it a much simpler message system!

Rate This Article
This article is currently rated: 5 out of 5.0 (1 Votes)

You have to register to rate this article.
User Comments

No User Comments

You must register to post a comment. If you have already registered, you must login.
Donate
Any money that is donated will go towards the server costs that I incur for running our server. Don't feel you HAVE to donate, but the link is there if you want to help us out a little. Thanks :)

Latest Articles
3rd person View in Multiplayer
Half-Life 2 | Coding | Client Side Tutorials
How to enable it in HL2DM

By: cct | Nov 13 2006

Making a Camera
Half-Life 2 | Level Design
This camera is good for when you join a map, it gives you a view of the map before you join a team

By: slackiller | Mar 04 2006

Making a camera , Part 2
Half-Life 2 | Level Design
these cameras are working monitors that turn on when a button is pushed.

By: slackiller | Mar 04 2006

Storing weapons on ladder
Half-Life 2 | Coding | Snippets
like Raven Sheild or BF2

By: British_Bomber | Dec 24 2005

Implementation of a string lookup table
Half-Life 2 | Coding | Snippets
A string lookup table is a set of functions that is used to convert strings to pre-defined values

By: deathz0rz | Nov 13 2005


Latest Comments
3 State Zoom For Any Weapon
Half-Life 2 | Coding | Server Side Tutorials
By: Ennuified | Oct 18 2007
 
Storing weapons on ladder
Half-Life 2 | Coding | Snippets
By: cct | Sep 07 2007
 
CTF Gameplay Part 1
Half-Life | Coding | Shared Tutorials
By: DarkNight | Aug 28 2007
 
CTF Gameplay Part 1
Half-Life | Coding | Shared Tutorials
By: deedok | Aug 20 2007
 
Debugging your half-life 2 mod
Half-Life 2 | Coding | Articles
By: blackshark | Aug 17 2007
 
How to add Ammocrates for missing ammo type and/or create new ammo types
Half-Life 2 | Coding | Server Side Tutorials
By: EoD | Aug 15 2007
 
GameUI
Half-Life 2 | Coding | Client Side Tutorials
By: G.I. Jimbo | May 19 2007
 
Reading and Writing Entire Structures
General | General Coding
By: monokrome | Jan 27 2007
 
VGUI Scope
Half-Life | Coding | Client Side Tutorials
By: Pongles | Jan 19 2007
 
Where do we go from here
General | News
By: SilentSounD | Jan 18 2007
 

Site Info
296 Approved Articless
3 Pending Articles
3940 Registered Members
0 People Online (11 guests)
About - Credits - Contact Us

Wavelength version: 3.0.0.9
Valid XHTML 1.0! Valid CSS!