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: 8288
Number of comments: 1
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 doesn’t 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.

That’s 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 won’t 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 (2 Votes)

You have to register to rate this article.
User Comments Showing comments 1-1

Posted By: chbrules on Dec 31 2011 at 22:14:24
Pongles is DA MAN!


You must register to post a comment. If you have already registered, you must login.

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 05 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
knock knock
General | News
By: omega | Dec 22 2016
 
knock knock
General | News
By: MIFUNE | Oct 10 2015
 
New HL HUD Message System
Half-Life | Coding | Shared Tutorials
By: chbrules | Dec 31 2011
 
knock knock
General | News
By: Whistler | Nov 05 2011
 
Particle Engine tutorial part 4
Half-Life | Coding | Client Side Tutorials
By: darkPhoenix | Feb 18 2010
 
Particle Engine tutorial part 2
Half-Life | Coding | Client Side Tutorials
By: darkPhoenix | Feb 11 2010
 
Particle Engine tutorial part 3
Half-Life | Coding | Client Side Tutorials
By: darkPhoenix | Feb 11 2010
 
Game Movement Series #2: Analog Jumping and Floating
Half-Life 2 | Coding | Shared Tutorials
By: mars3554 | Oct 26 2009
 
Particle Engine tutorial part 5
Half-Life | Coding | Client Side Tutorials
By: Deadpool | Aug 02 2009
 
Particle Engine tutorial part 5
Half-Life | Coding | Client Side Tutorials
By: Persuter | Aug 02 2009
 

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

Wavelength version: 3.0.0.9
Valid XHTML 1.0! Valid CSS!