Author Topic: Toward a Better MOTD  (Read 1266 times)

Offline QwazyWabbit

  • Carpal Tunnel Member
  • ******
  • Posts: 1232
    • View Profile
  • Rated:
Toward a Better MOTD
« on: September 21, 2013, 07:37:41 PM »
LOX has a feature that sends a motto of the day (MOTD) to players when they connect. This code was originally in-line in the ClientBeginDeathmatch function and it was an UGLY part of an otherwise simple ClientBeginDeathmatch function.

Today I decided to clean it up a bit, make it a callable function and publish it for use by other mod developers who might be interested in using a MOTD in their mod. I don't know where the original code came from, it was a part of LOX from a very long time ago and also exists in WODX and presumably WOD from where LOX and WODX derive their pedigree.

ClientBeginDeathmatch isn't called frequently so there is no advantage to writing the code in-line and avoiding a function call. It also goes against discipline to write something in line where a function will be more advantageous and the resulting code much more clear.

The ClientPrintMOTD function prototype belongs at the top of p_client.c or in g_local.h if you intend to access it globally:
void ClientPrintMOTD (edict_t *ent);
The function body belongs in p_client.c:
Code: [Select]
// Store the message of the day in memory.
char *gMOTD = ((char *)-1); // initialized at startup as bad pointer
cvar_t *motdfile;

void ClientPrintMOTD (edict_t *ent)
{
FILE *in;
char motdPath[MAX_QPATH + 1];
int c;
int motdBytes;
char *here;

// If the MOTD hasn't been loaded, do so.
if (gMOTD == ((char *)-1))
{

// Generate the path to the MOTD file.
if (gamedir == NULL || motdfile == NULL
|| !gamedir->string[0] || !motdfile->string[0])
{
gMOTD = NULL; // null pointer means we'll never try again
return;
}

sprintf (motdPath, "./%s/%s", gamedir->string, motdfile->string);

// Open the file.
in = fopen (motdPath, "rt");
if (in == NULL)
{
gi.dprintf("Opening MOTD file failed, error: %i.\n", errno);
gMOTD = NULL;
return;
}

// Count the number of bytes in the file.
motdBytes = 0;
while ((c = fgetc (in)), c != EOF)
motdBytes++;

// Make space for that many bytes.
gMOTD = gi.TagMalloc (motdBytes + 1, TAG_GAME);
gi.dprintf("Allocating %i bytes for MOTD\n", motdBytes +1);

// Now read the MOTD in for real.  Null-terminate the string.
fclose (in);
in = fopen (motdPath, "rt");
here = gMOTD; //extra pointer for writing into gMOTD
while ((c = fgetc (in)), c != EOF)
{
*here = c;
here++;
motdBytes--;
}
*here = '\0';

// If anything went wrong, warn the console.
if (motdBytes != 0)
gi.dprintf ("MOTD error: off by %d bytes", motdBytes);

}
if (gMOTD != NULL) // If a MOTD was successfully loaded, print it.
gi.centerprintf (ent, "%s", gMOTD);
return;
}

Define the necessary CVAR in GameInit:
Code: [Select]
motdfile = gi.cvar ("motdfile", "motd.txt", 0);

Add the CVAR to g_local.h:
Code: [Select]
extern cvar_t *motdfile;

Restore the ClientBeginDeathmatch to it's original beauty.
Code: [Select]
/*=====================
ClientBeginDeathmatch

A client has just connected to the server in deathmatch
mode, so clear everything out before starting them.
=====================*/
void ClientBeginDeathmatch (edict_t *ent)
{
G_InitEdict (ent);
InitClientResp (ent->client);

// locate ent at a spawn point
PutClientInServer (ent);

if (level.intermissiontime)
MoveClientToIntermission (ent);
else
{
// send effect
gi.WriteByte (svc_muzzleflash);
gi.WriteShort (ent-g_edicts);
gi.WriteByte (MZ_LOGIN);
gi.multicast (ent->s.origin, MULTICAST_PVS);
gi.bprintf (PRINT_HIGH, "%s entered the game\n", ent->client->pers.netname);
}

ClientPrintMOTD(ent);

// make sure all view stuff is valid
ClientEndServerFrame (ent);
return;
}

You will notice the ClientPrintMOTD function has a trapdoor in the gMOTD pointer. It's initialized at definition to -1 and the function sets it to NULL if there's a problem initializing the cache it is supposed point to that contains the MOTD text. I'm not sure I would have done it exactly that way but you may see a modified version later, I decided to publish this as-is and may polish it up another time. The trapdoor closes the first time the function is called and the gMOTD pointer either points to a valid MOTD string or it is NULL. The trapdoor prevents the function from taking the time to open/read/close the motd.txt file every time someone connects. The problem with this technique is that if you change the MOTD file you must restart the server to get it to read it again and update the cache.

Add a motd.txt file to your server's mod folder and enjoy your center-printed MOTD.
« Last Edit: September 21, 2013, 07:41:01 PM by QwazyWabbit »
  • Insightful
    Informative
    Funny
    Nice Job / Good Work
    Rock On
    Flawless Logic
    Well-Reasoned Argument and/or Conclusion
    Demonstrates Exceptional Knowlege of the Game
    Appears Not to Comprehend Game Fundamentals
    Frag of the Week
    Frag Hall of Fame
    Jump of the Week
    Jump Hall of Fame
    Best Solution
    Wins The Internet
    Whoosh! You done missed the joke thar Cletus!
    Obvious Troll Is Obvious
    DO YOU EVEN LIFT?
    DEMO OR STFU
    Offtopic
    Flamebait
    Redundant
    Factually Challenged
    Preposterously Irrational Arguments
    Blindingly Obvious Logical Fallacies
    Absurd Misconstrual of Scientific Principles or Evidence
    Amazing Conspiracy Theory Bro
    Racist Ignoramus

 

El Box de Shoutamente

Last 10 Shouts:

Sgt. Dick

May 21, 2019, 04:07:06 AM
Foc - where are you.
 

quadz

May 18, 2019, 10:21:55 PM
Thanks, yes, system crashed; unknown reason.

Hopefully everything is restarted now.
 

NIN-IceFox

May 18, 2019, 08:56:59 PM
Some servers seem down currently Quadz, don't know if it's just a hiccup that'll fix itself, maintenance or what, but just in case, I mention it.
 

NoBugsOnMe

May 13, 2019, 09:44:19 PM
pm gang rise up
 

quadz

May 10, 2019, 08:27:35 PM
It's always been that if you mymap and disconnect before the map goes live, it's deleted from the queue.

Occasinally, someone will stick around until their map loads, and THEN disconnect, which is not appreciated. (Currently the only recourse is a full mute, as there's no provision for blocking just mymap usage.)

At least these days, the chosen map has to be roughly compatible with the number of players active on the server. (No more mapping sewer64 on a 3-player server; etc.)

Punk_FAS

May 10, 2019, 08:22:02 AM
Any way to prevent people from trolling with mymap? By that I mean they join the server, mymap a map, then immediately discconnect, forcing whoever's playing to play a map that nobody there necessarily wanted to play in the first place. Maybe have it check to see if the player who issued the command
 

R. Hayabusa

May 07, 2019, 10:16:25 PM
it's tradition to play vanila and listen to something like this
https://www.youtube.com/watch?v=yOSsvue9DM0&t=243s

Punk_FAS

May 07, 2019, 07:44:28 PM
Seems like that did the trick, quadz. I'm sure everyone is happy to have their lower pings back :) Thanks!

0rbisson

May 06, 2019, 08:23:50 PM
Yes it appears to be normal. thanks
 

quadz

May 06, 2019, 01:44:21 PM
OK, they made a routing change that appears to have resolved the issue I was seeing here.

Everyone else's pings back to normal?

Show 50 latest
Welcome, Guest. Please login or register.
May 25, 2019, 10:52:27 AM

Login with username, password and session length