Forum

[Tutorial PSP/PC] - In Game Server List -PSP Use Other Tut

Post tutorials on how to do certain tasks within game or engine code here.

Moderator: InsideQC Admins

[Tutorial PSP/PC] - In Game Server List -PSP Use Other Tut

Postby Team Xlink » Fri Nov 20, 2009 12:05 am

NOTICE
this is NOT recommended for the PSP

For the psp use the tutorial located here:

viewtopic.php?t=2175

Hello.


Today you will learn (hopefully) how to add an in game server list to the Quake Engine.

This tutorial is very simple and easy to do.

Step one

Create a new file called slist.c

Step Two

In that file add this code:
Code: Select all
/*
Copyright (C) 1999-2000, contributors of the QuakeForge project

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 

See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

*/
// slist.c -- serverlist addressbook

#include "quakedef.h"

server_entry_t   slist[MAX_SERVER_LIST];

void SList_Init (void)
{
   memset (&slist, 0, sizeof(slist));   
}

void SList_Shutdown (void)

   FILE   *f;

   if (!(f = fopen (va("%s/servers.lst", com_gamedir), "wt")))
   {
      Con_DPrintf ("Couldn't open servers.lst\n");
      return;
   }
   SList_Save (f);
   fclose (f);
}
         
void SList_Set (int i, char *addr, char *desc)
{
   if (i >= MAX_SERVER_LIST || i < 0)
      Sys_Error ("SList_Set: Bad index %d", i);

   if (slist[i].server)
      Z_Free (slist[i].server);
   if (slist[i].description)
      Z_Free (slist[i].description);

   slist[i].server = CopyString (addr);
   slist[i].description = CopyString (desc);
}

void SList_Reset_NoFree (int i)
{
   if (i >= MAX_SERVER_LIST || i < 0)
      Sys_Error ("SList_Reset_NoFree: Bad index %d", i);

   slist[i].description = slist[i].server = NULL;
}

void SList_Reset (int i)
{
   if (i >= MAX_SERVER_LIST || i < 0)
      Sys_Error ("SList_Reset: Bad index %d", i);

   if (slist[i].server)
   {
      Z_Free (slist[i].server);
      slist[i].server = NULL;
   }

   if (slist[i].description)
   {
      Z_Free (slist[i].description);
      slist[i].description = NULL;
   }
}

void SList_Switch (int a, int b)
{
   server_entry_t   temp;

   if (a >= MAX_SERVER_LIST || a < 0)
      Sys_Error ("SList_Switch: Bad index %d", a);
   if (b >= MAX_SERVER_LIST || b < 0)
      Sys_Error ("SList_Switch: Bad index %d", b);

   memcpy (&temp, &slist[a], sizeof(temp));
   memcpy (&slist[a], &slist[b], sizeof(temp));
   memcpy (&slist[b], &temp, sizeof(temp));
}

int SList_Length (void)
{
   int   count;

   for (count = 0 ; count < MAX_SERVER_LIST && slist[count].server ; count++)
      ;

   return count;
}

void SList_Load (void)
{
   int   c, len, argc, count;
   char   line[128], *desc, *addr;
   FILE   *f;

   if (!(f = fopen (va("%s/servers.lst", com_gamedir), "rt")))
      return;

   count = len = 0;
   while ((c = getc(f)))
   {
      if (c == '\n' || c == '\r' || c == EOF)
      {
         if (c == '\r' && (c = getc(f)) != '\n' && c != EOF)
            ungetc (c, f);

         line[len] = 0;
         len = 0;
         Cmd_TokenizeString (line);

         if ((argc = Cmd_Argc()) >= 1)
         {
            addr = Cmd_Argv(0);
            desc = (argc >= 2) ? Cmd_Args() : "Unknown";
            SList_Set (count, addr, desc);
            if (++count == MAX_SERVER_LIST)
               break;
         }
         if (c == EOF)
            break;   //just in case an EOF follows a '\r'
      }
      else
      {
         if (len + 1 < sizeof(line))
            line[len++] = c;
      }
   }

   fclose (f);
}

void SList_Save (FILE *f)
{
   int   i;

   for (i=0 ; i<MAX_SERVER_LIST ; i++)
   {
      if (!slist[i].server)
         break;

      fprintf (f, "%s\t%s\n", slist[i].server, slist[i].description);
   }
}


Step Three

Create another new file called slist.h

Step Four

In that file add this code:
Code: Select all
/*
Copyright (C) 1999-2000, contributors of the QuakeForge project

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 

See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

*/
// slist.h

#define   MAX_SERVER_LIST   256
#define MAX_PLAYERS      16

typedef struct
{
    int      id;
    int      frags;
    int      time;
    char   *name;
    int      top;
    int      bottom;
} playerinfo_t;

typedef struct
{
   char   *server;
   char   *description;
} server_entry_t;

extern   server_entry_t   slist[MAX_SERVER_LIST];

void SList_Init (void);
void SList_Shutdown (void);
void SList_Set (int i,char *addr,char *desc);
void SList_Reset_NoFree (int i);
void SList_Reset (int i);
void SList_Switch (int a,int b);
int SList_Length (void);
void SList_Load (void);
void SList_Save (FILE *f);


Step Five:


Open up Quakedef.h and at the bottom of the include list add this line of code:

#include "slist.h"

Step Six


Open up menu.c and replace the sever list menu with this:

Code: Select all
///=============================================================================
/* SERVER LIST MENU */

#define   MENU_X   50
#define   MENU_Y   21
#define TITLE_Y 4
#define   STAT_Y   166
extern qboolean   keydown[256];
int   slist_cursor = 0, slist_mins = 0, slist_maxs = 15, slist_state;

#define   SLIST_BUFSIZE   128

playerinfo_t plist[16]; int numPlayers;

void M_Menu_ServerList_f (void)
{
SList_Load ();
   key_dest = key_menu;
   m_state = m_slist;
   m_entersound = true;

   slist_state = 0;
}

void M_ServerList_Draw (void)
{
   int   serv, line;

   M_DrawTextBox (MENU_X, TITLE_Y, 23, 1);
   M_PrintWhite (MENU_X + 60, TITLE_Y + 8, "Server List");

   if (!slist[0].server)
   {
      M_PrintWhite   (84, MENU_Y + 32, "Empty server list");
      M_Print         (60, MENU_Y + 48, "By Team Xlink");
      return;
   }

   M_DrawTextBox (MENU_X, STAT_Y, 23, 1);
   M_DrawTextBox (MENU_X, MENU_Y, 23, slist_maxs - slist_mins + 1);
   for (serv = slist_mins, line = 1 ; serv <= slist_maxs && serv < MAX_SERVER_LIST && slist[serv].server ; serv++, line++)
      M_Print (MENU_X + 18, line * 8 + MENU_Y, va("%1.21s", slist[serv].description));
   M_Print (MENU_X - 36, STAT_Y - 4, "By Team Xlink");
   M_PrintWhite (MENU_X + 18, STAT_Y + 8, va("%1.22s", slist[slist_cursor].server));
   M_DrawCharacter (MENU_X + 8, (slist_cursor - slist_mins + 1) * 8 + MENU_Y, 12+((int)(realtime*4)&1));
}

void M_ServerList_Key (key)
{

   if (!slist[0].server && key != K_ESCAPE && key != K_INS)
      return;

   switch (key)
   {
   case K_ESCAPE:
      M_Menu_MultiPlayer_f ();
      break;

   case K_UPARROW:
      S_LocalSound ("misc/menu1.wav");
      if (slist_cursor > 0)
      {
         if (keydown[K_CTRL])
            SList_Switch (slist_cursor, slist_cursor - 1);
         slist_cursor--;
      }
      break;

   case K_DOWNARROW:
      S_LocalSound ("misc/menu1.wav");
      if (keydown[K_CTRL])
      {
         if (slist_cursor != SList_Length() - 1)
         {
            SList_Switch (slist_cursor, slist_cursor + 1);
            slist_cursor++;
         }
      }
      else if (slist_cursor < MAX_SERVER_LIST - 1 && slist[slist_cursor+1].server)
         slist_cursor++;
      break;

   case K_HOME:
      S_LocalSound ("misc/menu1.wav");
      slist_cursor = 0;
      break;

   case K_END:
      S_LocalSound ("misc/menu1.wav");
      slist_cursor = SList_Length() - 1;
      break;
      
   case K_AUX1:
      S_LocalSound ("misc/menu1.wav");
      slist_cursor -= (slist_maxs - slist_mins);
      if (slist_cursor < 0)
         slist_cursor = 0;
      break;

   case K_AUX2:
      S_LocalSound ("misc/menu1.wav");
      slist_cursor += (slist_maxs - slist_mins);
      if (slist_cursor >= MAX_SERVER_LIST)
         slist_cursor = MAX_SERVER_LIST - 1;
      while (!slist[slist_cursor].server)
         slist_cursor--;
      break;

   case K_ENTER:
      m_state = m_main;
      M_ToggleMenu_f ();
      Cbuf_AddText ( va ("connect \"%s\"\n", slist[slist_cursor].server) );
break;


   }

   if (slist_cursor < slist_mins)
   {
      slist_maxs -= (slist_mins - slist_cursor);
      slist_mins = slist_cursor;
   }
   if (slist_cursor > slist_maxs)
   {
      slist_mins += (slist_cursor - slist_maxs);
      slist_maxs = slist_cursor;
   }

}


Step 7
Scroll down to:

Code: Select all
void M_Init (void)


Before this:

Code: Select all
Cmd_AddCommand ("menu_quit", M_Menu_Quit_f);


Add this:

Code: Select all
Cmd_AddCommand ("menu_serverlist", M_Menu_ServerList_f);


Now when you want to load your server list go to the console and type:
Code: Select all
menu_serverlist


Or you can add a menu option in your engine by calling it like this:

Code: Select all
Cbuf_AddText ("menu_serverlist");


Make sure to include slist.c in your engine.

PSP

Step 8


Well, since more people are interested in PSP Quake then I thought, I will throw in the steps for the psp.

Go to your subdirectory called psp and open up the file called makefile

*It will most likely make a confirmation pop up that talks about which program to use to open it. You can use any text editor (As long as it doesn't have automatic formatting) *cough* Microsoft Word, if you have no idea what to use, just use notepad

Find this:
Code: Select all
   $(OBJ_DIR)/world.o \
   $(OBJ_DIR)/zone.o


Change that to this:

Code: Select all
   $(OBJ_DIR)/world.o \
   $(OBJ_DIR)/zone.o \
   $(OBJ_DIR)/slist.o


**PSP TIP START**

Whenever you need to add a file to your engine at the end of the file, your last line of the $(OBJ_DIR) has to NOT have a frontslash \.
Every other &(OBG_DIR) line MUST have a front slash \.

**PSP TIP END**


There you go.

If you have any comments or questions, improvements or anything just replay away!

Additional Credit:

Quake Forge Project

Team Xlink
Last edited by Team Xlink on Sun Jul 11, 2010 6:59 pm, edited 9 times in total.
Team Xlink
 
Posts: 368
Joined: Thu Jun 25, 2009 4:45 am
Location: Michigan

Postby ceriux » Fri Nov 20, 2009 2:21 am

so this would add a server list to the engine (so you dont have to know an ip and connect manually?)
User avatar
ceriux
 
Posts: 2223
Joined: Sat Sep 06, 2008 3:30 pm
Location: Indiana, USA

Postby Team Xlink » Wed Dec 02, 2009 1:19 am

Yes.

They are stored in the Servers.lst file.
Team Xlink
 
Posts: 368
Joined: Thu Jun 25, 2009 4:45 am
Location: Michigan

Postby ceriux » Wed Dec 02, 2009 3:25 am

awesome thanks for the tutorial im going to try it out.

[code
mycoolbuild
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 15.00.30729.01 for 80x86
Copyright (C) Microsoft Corporation. All rights reserved.
worlda.s
Assembling: .\release_gl\worlda.asm
Microsoft (R) Macro Assembler Version 9.00.30729.01
Copyright (C) Microsoft Corporation. All rights reserved.
mycoolbuild
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 15.00.30729.01 for 80x86
Copyright (C) Microsoft Corporation. All rights reserved.
sys_wina.s
Assembling: .\release_gl\sys_wina.asm
Microsoft (R) Macro Assembler Version 9.00.30729.01
Copyright (C) Microsoft Corporation. All rights reserved.
mycoolbuild
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 15.00.30729.01 for 80x86
Copyright (C) Microsoft Corporation. All rights reserved.
snd_mixa.s
Assembling: .\release_gl\snd_mixa.asm
Microsoft (R) Macro Assembler Version 9.00.30729.01
Copyright (C) Microsoft Corporation. All rights reserved.
mycoolbuild
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 15.00.30729.01 for 80x86
Copyright (C) Microsoft Corporation. All rights reserved.
math.s
Assembling: .\release_gl\math.asm
Microsoft (R) Macro Assembler Version 9.00.30729.01
Copyright (C) Microsoft Corporation. All rights reserved.
Compiling...
zone.c
c:\fantasy\slist.h(53) : error C2061: syntax error : identifier 'slist'
c:\fantasy\slist.h(53) : error C2059: syntax error : ';'
c:\fantasy\slist.h(54) : error C2449: found '{' at file scope (missing function header?)
c:\fantasy\slist.h(58) : error C2059: syntax error : '}'
C:\Program Files\Microsoft Visual Studio 9.0\VC\include\excpt.h(59)
[/code]


and it goes on...
Last edited by ceriux on Wed Dec 02, 2009 7:10 am, edited 2 times in total.
User avatar
ceriux
 
Posts: 2223
Joined: Sat Sep 06, 2008 3:30 pm
Location: Indiana, USA

Postby ceriux » Wed Dec 02, 2009 5:52 am

sorry cut it down to this

Code: Select all
1>slist.c
1>.\slist.c(35) : error C2065: 'com_basedir' : undeclared identifier
1>.\slist.c(54) : warning C4047: '=' : 'char *' differs in levels of indirection from 'int'
1>.\slist.c(55) : warning C4047: '=' : 'char *' differs in levels of indirection from 'int'
1>.\slist.c(114) : error C2065: 'com_basedir' : undeclared identifier
User avatar
ceriux
 
Posts: 2223
Joined: Sat Sep 06, 2008 3:30 pm
Location: Indiana, USA

Postby Team Xlink » Thu Dec 10, 2009 8:51 pm

Alright, I will look into that because it works in my engine.

Of course my engine is for the PSP but I didn't see anything that is platform specific so this post will be edited later tonight with the fix for your problem.

EDIT: I fixed it, it turns out I had something spelled differently in both of my engines.
Team Xlink
 
Posts: 368
Joined: Thu Jun 25, 2009 4:45 am
Location: Michigan

Postby ceriux » Fri Dec 11, 2009 7:37 am

cool tutorial =p but my first suggestion would be to rename it to in-game player list =p instead of in-game server list.
User avatar
ceriux
 
Posts: 2223
Joined: Sat Sep 06, 2008 3:30 pm
Location: Indiana, USA

Postby Team Xlink » Thu Dec 24, 2009 7:34 am

I just noticed I didn't write the last step for the tutorial.

So I updated the tutorial.

Also a proper server list would get a list of all servers being hosted from a master server like QuakeWorld does it.
Team Xlink
 
Posts: 368
Joined: Thu Jun 25, 2009 4:45 am
Location: Michigan

Postby ceriux » Thu Dec 24, 2009 7:37 am

yeah lol thats what i thought this was.
User avatar
ceriux
 
Posts: 2223
Joined: Sat Sep 06, 2008 3:30 pm
Location: Indiana, USA

Postby Baker » Thu Dec 24, 2009 9:03 am

Team Xlink wrote:from a master server like QuakeWorld does it.


For the stock Quake engine, that'd be a large amount of work. Servers don't send out a heartbeat to a master server, you'd have to setup a master server and you'd be messing with network code (fun!) and even worse, probably platform specific network code for a PSP targeted mod.

You can get 80% of the benefit using libcurl just to download a text file of the servers. Downsider told me that libcurl has been ported to the PSP (libcurl 7.19 release), so libcurl is available on at least 4 platforms (Windows, Linux, OS X, PSP).

Image

This is an example of the server browser in ProQuake 4.01, which obviously is a bit more sophisticated than just a server list, but the information is retrieved via libcurl in a similar way as this little tutorial: viewtopic.php?t=1669
User avatar
Baker
 
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Postby Team Xlink » Fri Dec 25, 2009 3:52 am

Well there is a box in my server list that I am trying to fix.

In the SERVERS.lst file if you have one in there that uses a different port like this:
The syntax is this:

q1.terra.com.br:26011 Terra

That in the server list will show up as

q1.terra.com.br :26011 Terra

Soto get the port to display right you have to do this:

q1.terra.com.br;26011 Terra

Which won't let you connect.


I am going to upload a fix for that right away.
Team Xlink
 
Posts: 368
Joined: Thu Jun 25, 2009 4:45 am
Location: Michigan

Postby Baker » Fri Dec 25, 2009 6:05 am

Team Xlink wrote:Well there is a box in my server list that I am trying to fix.

In the SERVERS.lst file if you have one in there that uses a different port like this:
The syntax is this:

q1.terra.com.br:26011 Terra

That in the server list will show up as

q1.terra.com.br :26011 Terra

Soto get the port to display right you have to do this:

q1.terra.com.br;26011 Terra

Which won't let you connect.

I am going to upload a fix for that right away.


Well, you are likely to have another problem.

GLQuake didn't support ip:port, so that feature will likely need to be added into the engine until someone has ported that into the engine being modified.

GLQuake can't do, for instance: "connect myserver.com:26001" but would have to do "port 26001; connect myserver.com"

The easiest Quake engine to borrow ip:port connecting from would be from either ProQuake or JoeQuake.

I'm personally waiting on a USB to 5 pin cable for my PSP, once I receive that in the mail I can be a little more proactive in helping ;)
User avatar
Baker
 
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Postby Team Xlink » Mon Jan 04, 2010 11:31 pm

I updated the tutorial by adding a PSP part to it.

Baker, I was totally unaware that stock Quake didn't have the :ip port code, now I know why it never seemed to work for me.

So, I could either add the :ipport support or do some hackish code based on the console commands you just gave me.

I will go with the first but I may add some hackish code as an optional thing to this tutorial to make it work fully, I may even make another tutorial for the :ipport support after I port it.
Team Xlink
 
Posts: 368
Joined: Thu Jun 25, 2009 4:45 am
Location: Michigan


Return to Programming Tutorials

Who is online

Users browsing this forum: No registered users and 1 guest