23 Jun 2008

This commit is contained in:
g-cont 2008-06-23 00:00:00 +04:00 committed by Alibek Omarov
parent e2b8110780
commit d8eb784740
16 changed files with 609 additions and 259 deletions

View File

@ -372,7 +372,7 @@ void CL_ClearState (void)
CL_ClearEffects ();
CL_ClearTEnts ();
// wipe the entire cl structure
// wipe the entire cl structure
memset (&cl, 0, sizeof(cl));
memset (&cl_entities, 0, sizeof(cl_entities));
@ -556,60 +556,169 @@ void CL_ParseStatusMessage (void)
M_AddToServerList (net_from, s);
}
/*
=================
CL_PingServers_f
=================
===================
CL_StatusLocal_f
===================
*/
void CL_PingServers_f (void)
void CL_GetServerList_f( void )
{
int i;
netadr_t adr;
char name[32];
char *adrstring;
cvar_t *noudp;
cvar_t *noipx;
NET_Config (true); // allow remote
NET_Config( true ); // allow remote
// send a broadcast packet
Msg ("pinging broadcast...\n");
MsgDev( D_INFO, "status pinging broadcast...\n" );
cls.pingtime = cls.realtime;
noudp = Cvar_Get ("noudp", "0", CVAR_INIT);
if (!noudp->value)
adr.type = NA_BROADCAST;
adr.port = BigShort( PORT_SERVER );
Netchan_OutOfBandPrint( NS_CLIENT, adr, "status" );
}
/*
=============
CL_FreeServerInfo
=============
*/
static void CL_FreeServerInfo( serverinfo_t *server )
{
if( server->mapname ) Mem_Free( server->mapname );
if( server->hostname ) Mem_Free( server->hostname );
if( server->shortname ) Mem_Free( server->shortname );
if( server->gamename ) Mem_Free( server->gamename );
if( server->netaddress ) Mem_Free( server->netaddress );
if( server->playerstr ) Mem_Free( server->playerstr );
if( server->pingstring ) Mem_Free( server->pingstring);
memset( server, 0, sizeof(serverinfo_t));
}
/*
=============
CL_FreeServerList
=============
*/
static void CL_FreeServerList_f( void )
{
int i;
for( i = 0; i < cls.numservers; i++ )
CL_FreeServerInfo( &cls.serverlist[i] );
cls.numservers = 0;
}
/*
=============
CL_DupeCheckServerList
Checks for duplicates and returns true if there is one...
Since status has higher priority than info, if there is already an instance and
it's not status, and the current one is status, the old one is removed.
=============
*/
static bool CL_DupeCheckServerList( char *adr, bool status )
{
int i;
for( i = 0; i < cls.numservers; i++ )
{
adr.type = NA_BROADCAST;
adr.port = BigShort(PORT_SERVER);
Netchan_OutOfBandPrint (NS_CLIENT, adr, va("info %i", PROTOCOL_VERSION));
}
noipx = Cvar_Get ("noipx", "0", CVAR_INIT);
if (!noipx->value)
{
adr.type = NA_BROADCAST_IPX;
adr.port = BigShort(PORT_SERVER);
Netchan_OutOfBandPrint (NS_CLIENT, adr, va("info %i", PROTOCOL_VERSION));
}
// send a packet to each address book entry
for (i = 0; i < 16; i++)
{
com.sprintf (name, "adr%i", i);
adrstring = Cvar_VariableString (name);
if (!adrstring || !adrstring[0])
continue;
Msg ("pinging %s...\n", adrstring);
if (!NET_StringToAdr (adrstring, &adr))
if(!cls.serverlist[i].netaddress && !cls.serverlist[i].hostname )
{
Msg ("Bad address: %s\n", adrstring);
CL_FreeServerInfo( &cls.serverlist[i] );
continue;
}
if (!adr.port)
adr.port = BigShort(PORT_SERVER);
Netchan_OutOfBandPrint (NS_CLIENT, adr, va("info %i", PROTOCOL_VERSION));
if( cls.serverlist[i].netaddress && !com.strcmp( cls.serverlist[i].netaddress, adr ))
{
if( cls.serverlist[i].statusPacket && status )
{
return true;
}
else if( status )
{
CL_FreeServerInfo( &cls.serverlist[i] );
return false;
}
}
}
return false;
}
/*
=============
CL_ParseServerStatus
Parses a status packet from a server
FIXME: check against a list of sent status requests so it's not attempting to parse things it shouldn't
=============
*/
bool CL_ParseServerStatus( char *adr, char *info )
{
serverinfo_t *server;
char *token;
char shortName[32];
if( !info || !info[0] )return false;
if( !adr || !adr[0] ) return false;
if( !com.strchr( info, '\\')) return false;
if( cls.numservers >= MAX_SERVERS )
return true;
if( CL_DupeCheckServerList( adr, true ))
return true;
server = &cls.serverlist[cls.numservers];
CL_FreeServerInfo( server );
cls.numservers++;
// add net address
server->netaddress = copystring( adr );
server->mapname = copystring(Info_ValueForKey( info, "mapname"));
server->maxplayers = com.atoi(Info_ValueForKey( info, "maxclients"));
server->gamename = copystring(Info_ValueForKey( info, "gamename"));
server->hostname = copystring(Info_ValueForKey( info, "hostname"));
if( server->hostname )
{
com.strncpy( shortName, server->hostname, sizeof(shortName));
server->shortname = copystring( shortName );
}
// Check the player count
server->numplayers = com.atoi(Info_ValueForKey( info, "curplayers"));
if( server->numplayers <= 0 )
{
server->numplayers = 0;
token = strtok( info, "\n" );
if( token )
{
token = strtok( NULL, "\n" );
while( token )
{
server->numplayers++;
token = strtok( NULL, "\n" );
}
}
}
// check if it's valid
if( !server->mapname[0] && !server->maxplayers && !server->gamename[0] && !server->hostname[0] )
{
CL_FreeServerInfo( server );
return false;
}
server->playerstr = copystring( va("%i/%i", server->numplayers, server->maxplayers ));
// add the ping
server->ping = (int)(cls.realtime - cls.pingtime) * 1000.0f;
server->pingstring = copystring( va("%ims", server->ping ));
server->statusPacket = true;
// print information
MsgDev( D_NOTE, "%s %s ", server->hostname, server->mapname );
MsgDev( D_NOTE, "%i/%i %ims\n", server->numplayers, server->maxplayers, server->ping );
return true;
}
/*
@ -619,10 +728,9 @@ CL_ConnectionlessPacket
Responses to broadcasts, etc
=================
*/
void CL_ConnectionlessPacket (void)
void CL_ConnectionlessPacket( void )
{
char *s;
char *c;
char *s, *c;
MSG_BeginReading (&net_message);
MSG_ReadLong (&net_message); // skip the -1
@ -630,7 +738,6 @@ void CL_ConnectionlessPacket (void)
s = MSG_ReadStringLine (&net_message);
Cmd_TokenizeString(s);
c = Cmd_Argv(0);
MsgDev(D_INFO, "%s: %s\n", NET_AdrToString (net_from), c);
@ -675,8 +782,10 @@ void CL_ConnectionlessPacket (void)
// print command from somewhere
if (!strcmp(c, "print"))
{
// print command from somewhere
s = MSG_ReadString (&net_message);
Msg ("%s", s);
if(!CL_ParseServerStatus( NET_AdrToString(net_from), s ))
Msg( s );
return;
}
@ -701,7 +810,6 @@ void CL_ConnectionlessPacket (void)
Netchan_OutOfBandPrint (NS_CLIENT, net_from, "%s", Cmd_Argv(1) );
return;
}
Msg ("Unknown command.\n");
}
@ -1175,7 +1283,8 @@ void CL_InitLocal (void)
// register our commands
Cmd_AddCommand ("cmd", CL_ForwardToServer_f, "send a console commandline to the server" );
Cmd_AddCommand ("pause", CL_Pause_f, "pause the game (if the server allows pausing)" );
Cmd_AddCommand ("pingservers", CL_PingServers_f, "send a broadcast packet" );
Cmd_AddCommand ("getserverlist", CL_GetServerList_f, "get info about local servers" );
Cmd_AddCommand ("freeserverlist", CL_FreeServerList_f, "clear info about local servers" );
Cmd_AddCommand ("userinfo", CL_Userinfo_f, "print current client userinfo" );
Cmd_AddCommand ("changing", CL_Changing_f, "sent by server to tell client to wait for level change" );

View File

@ -162,11 +162,11 @@ VM_CvarRegister, // #24 void Cvar_Register( string name, string value, float f
VM_CvarSetValue, // #25 void Cvar_SetValue( string name, float value )
VM_CvarGetValue, // #26 float Cvar_GetValue( string name )
VM_CvarSetString, // #27 void Cvar_SetString( string name, string value )
VM_ComVA, // #28 string va( ... )
VM_ComStrlen, // #29 float strlen( string text )
VM_TimeStamp, // #30 string Com_TimeStamp( float format )
VM_LocalCmd, // #31 void LocalCmd( ... )
NULL, // #32 -- reserved --
VM_CvarGetString, // #28 void VM_CvarGetString( void )
VM_ComVA, // #29 string va( ... )
VM_ComStrlen, // #30 float strlen( string text )
VM_TimeStamp, // #31 string Com_TimeStamp( float format )
VM_LocalCmd, // #32 void LocalCmd( ... )
NULL, // #33 -- reserved --
NULL, // #34 -- reserved --
NULL, // #35 -- reserved --

View File

@ -28,6 +28,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define MAX_EDIT_LINE 256
#define COMMAND_HISTORY 32
#define MAX_SERVERS 64
//=============================================================================
typedef struct
@ -229,6 +230,24 @@ typedef enum {
dl_single
} dltype_t; // download type
typedef struct serverinfo_s
{
char *mapname;
char *hostname;
char *shortname;
char *gamename;
char *netaddress;
char *playerstr;
int numplayers;
int maxplayers;
char *pingstring;
bool statusPacket;
int ping;
} serverinfo_t;
typedef enum {key_game, key_console, key_message, key_menu} keydest_t;
typedef struct
@ -236,9 +255,9 @@ typedef struct
connstate_t state;
keydest_t key_dest;
int framecount;
float realtime; // always increasing, no clamping, etc
float frametime; // seconds since last frame
int framecount;
float realtime; // always increasing, no clamping, etc
float frametime; // seconds since last frame
// connection information
string servername; // name of server from original connect
@ -266,6 +285,9 @@ typedef struct
string demoname; // for demo looping
file_t *demofile;
serverinfo_t serverlist[MAX_SERVERS]; // servers to join
int numservers;
float pingtime; // servers timebase
// hudprogram stack
byte *hud_program;

View File

@ -686,6 +686,26 @@ void VM_CvarGetValue( void )
}
/*
=========
VM_CvarGetString
string Cvar_GetString( string name )
=========
*/
void VM_CvarGetString( void )
{
const char *name;
if(!VM_ValidateArgs( "Cvar_GetString", 1 ))
return;
VM_ValidateString(PRVM_G_STRING(OFS_PARM0));
name = PRVM_G_STRING(OFS_PARM0);
PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(Cvar_VariableString( name ));
}
/*
=================
VM_LocalCmd
@ -1306,11 +1326,11 @@ VM_CvarRegister, // #24 void Cvar_Register( string name, string value, float f
VM_CvarSetValue, // #25 void Cvar_SetValue( string name, float value )
VM_CvarGetValue, // #26 float Cvar_GetValue( string name )
VM_CvarSetString, // #27 void Cvar_SetString( string name, string value )
VM_ComVA, // #28 string va( ... )
VM_ComStrlen, // #29 float strlen( string text )
VM_TimeStamp, // #30 string Com_TimeStamp( float format )
VM_LocalCmd, // #31 void LocalCmd( ... )
NULL, // #32 -- reserved --
VM_CvarGetString, // #28 void VM_CvarGetString( void )
VM_ComVA, // #29 string va( ... )
VM_ComStrlen, // #30 float strlen( string text )
VM_TimeStamp, // #31 string Com_TimeStamp( float format )
VM_LocalCmd, // #32 void LocalCmd( ... )
NULL, // #33 -- reserved --
NULL, // #34 -- reserved --
NULL, // #35 -- reserved --
@ -1384,14 +1404,14 @@ Info_Print
printing current key-value pair
===============
*/
void Info_Print (char *s)
void Info_Print( char *s )
{
char key[512];
char value[512];
char *o;
int l;
if (*s == '\\') s++;
if( *s == '\\' )s++;
while (*s)
{
@ -1431,7 +1451,7 @@ Searches the string for the given
key and returns the associated value, or an empty string.
===============
*/
char *Info_ValueForKey (char *s, char *key)
char *Info_ValueForKey( char *s, char *key )
{
char pkey[512];
static char value[2][512]; // use two buffers so compares work without stomping on each other
@ -1439,13 +1459,13 @@ char *Info_ValueForKey (char *s, char *key)
char *o;
valueindex ^= 1;
if (*s == '\\') s++;
while (1)
if( *s == '\\' ) s++;
while( 1 )
{
o = pkey;
while (*s != '\\')
while( *s != '\\' && *s != '\n' )
{
if (!*s) return "";
if(!*s) return "";
*o++ = *s++;
}
*o = 0;
@ -1453,15 +1473,15 @@ char *Info_ValueForKey (char *s, char *key)
o = value[valueindex];
while (*s != '\\' && *s)
while( *s != '\\' && *s != '\n' && *s)
{
if (!*s) return "";
*o++ = *s++;
}
*o = 0;
if (!strcmp (key, pkey) ) return value[valueindex];
if (!*s) return "";
if(!com.strcmp( key, pkey )) return value[valueindex];
if(!*s) return "";
s++;
}
}
@ -1959,6 +1979,133 @@ bool Cmd_GetSoundList( const char *s, char *completedname, int length )
return true;
}
bool Cmd_CheckMapsList( void )
{
byte buf[MAX_SYSPATH]; // 1 kb
char *buffer, string[MAX_STRING];
search_t *t;
file_t *f;
int i;
if(FS_FileExists("scripts/maps.lst"))
return true; // exist
t = FS_Search( "maps/*.bsp", false );
if(!t) return false;
buffer = Z_Malloc( t->numfilenames * 2 * sizeof(string));
for( i = 0; i < t->numfilenames; i++ )
{
const char *data = NULL;
char *entities = NULL;
char entfilename[MAX_QPATH];
int ver = -1, lumpofs = 0, lumplen = 0;
char mapname[MAX_QPATH], message[MAX_QPATH];
f = FS_Open(t->filenames[i], "rb");
FS_FileBase( t->filenames[i], mapname );
if( f )
{
int num_spawnpoints = 0;
memset(buf, 0, 1024);
FS_Read(f, buf, 1024);
if(!memcmp(buf, "IBSP", 4))
{
dheader_t *header = (dheader_t *)buf;
ver = LittleLong(((int *)buf)[1]);
switch(ver)
{
case 38: // quake2
case 39: // xash
case 46: // quake3
case 47: // return to castle wolfenstein
lumpofs = LittleLong(header->lumps[LUMP_ENTITIES].fileofs);
lumplen = LittleLong(header->lumps[LUMP_ENTITIES].filelen);
break;
}
}
else
{
lump_t ents; // quake1 entity lump
memcpy(&ents, buf + 4, sizeof(lump_t)); // skip first four bytes (version)
ver = LittleLong(((int *)buf)[0]);
switch( ver )
{
case 28: // quake 1 beta
case 29: // quake 1 regular
case 30: // Half-Life regular
lumpofs = LittleLong(ents.fileofs);
lumplen = LittleLong(ents.filelen);
break;
default:
ver = 0;
break;
}
}
com.strncpy(entfilename, t->filenames[i], sizeof(entfilename));
FS_StripExtension( entfilename );
FS_DefaultExtension( entfilename, ".ent" );
entities = (char *)FS_LoadFile(entfilename, NULL);
if( !entities && lumplen >= 10 )
{
FS_Seek(f, lumpofs, SEEK_SET);
entities = (char *)Z_Malloc(lumplen + 1);
FS_Read(f, entities, lumplen);
}
if(entities)
{
// if there are entities to parse, a missing message key just
// means there is no title, so clear the message string now
message[0] = 0;
data = entities;
com.strncpy(message, "No Title", MAX_QPATH);
while(Com_ParseToken(&data))
{
if(!strcmp(com_token, "{" )) continue;
else if(!strcmp(com_token, "}" )) break;
else if(!strcmp(com_token, "message" ))
{
// get the message contents
Com_ParseToken(&data);
if(!strcmp(com_token, "" )) continue;
com.strncpy(message, com_token, sizeof(message));
}
else if(!strcmp(com_token, "classname" ))
{
Com_ParseToken(&data);
if(!com.strcmp(com_token, "info_player_deatchmatch"))
num_spawnpoints++;
else if(!com.strcmp(com_token, "info_player_start"))
num_spawnpoints++;
}
if(num_spawnpoints > 0) break; // valid map
}
}
if( entities) Mem_Free(entities);
if( f ) FS_Close(f);
// format: mapname "maptitle"\n
com.sprintf(string, "%s \"%s\"\n", mapname, message );
com.strcat(buffer, string); // add new string
}
}
if( t ) Mem_Free(t); // free search result
// write generated maps.lst
if(FS_WriteFile("scripts/maps.lst", buffer, strlen(buffer)))
{
if( buffer ) Mem_Free(buffer);
return true;
}
return false;
}
/*
============
Cmd_WriteVariables

View File

@ -262,6 +262,7 @@ void VM_Cmd_Reset( void );
#define PRVM_GetString vm->GetString
#define PRVM_SetEngineString vm->SetEngineString
#define PRVM_SetTempString vm->SetTempString
#define PRVM_AllocString vm->AllocString
#define PRVM_FreeString vm->FreeString
@ -317,6 +318,7 @@ void VM_CvarRegister( void );
void VM_CvarSetValue( void );
void VM_CvarGetValue( void );
void VM_CvarSetString( void );
void VM_CvarGetString( void );
void VM_ComVA( void );
void VM_ComStrlen( void );
void VM_TimeStamp( void );
@ -389,6 +391,7 @@ bool Cmd_GetDemoList(const char *s, char *completedname, int length );
bool Cmd_GetMovieList(const char *s, char *completedname, int length );
bool Cmd_GetMusicList(const char *s, char *completedname, int length );
bool Cmd_GetSoundList(const char *s, char *completedname, int length );
bool Cmd_CheckMapsList( void );
void Sys_Error( const char *msg, ... );
void Sys_SendKeyEvents( void );

View File

@ -250,16 +250,6 @@ typedef enum
Handles byte ordering and avoids alignment errors
==============================================================================
*/
typedef struct sizebuf_s
{
bool overflowed; // set to true if the buffer size failed
byte *data;
int maxsize;
int cursize;
int readcount;
int errorcount; // cause by errors
} sizebuf_t;
#define SZ_GetSpace(buf, len) _SZ_GetSpace(buf, len, __FILE__, __LINE__ )
#define SZ_Write(buf, data, len) _SZ_Write(buf, data, len, __FILE__, __LINE__ )
void SZ_Init (sizebuf_t *buf, byte *data, int length);

View File

@ -125,20 +125,20 @@ char *SV_StatusString (void)
int statusLength;
int playerLength;
strcpy (status, Cvar_Serverinfo());
strcat (status, "\n");
com.strcpy( status, Cvar_Serverinfo());
com.strcat( status, "\n" );
statusLength = strlen(status);
for (i=0 ; i<maxclients->value ; i++)
for( i = 0; i < maxclients->value; i++ )
{
cl = &svs.clients[i];
if (cl->state == cs_connected || cl->state == cs_spawned )
{
com.sprintf (player, "%i %i \"%s\"\n", cl->edict->priv.sv->client->ps.stats[STAT_FRAGS], cl->ping, cl->name);
playerLength = strlen(player);
if (statusLength + playerLength >= sizeof(status) )
break; // can't hold any more
strcpy (status + statusLength, player);
if( statusLength + playerLength >= sizeof(status))
break; // can't hold any more
com.strcpy( status + statusLength, player );
statusLength += playerLength;
}
}
@ -479,13 +479,13 @@ void SV_ConnectionlessPacket (void)
c = Cmd_Argv(0);
MsgWarn("SV_ConnectionlessPacket: %s : %s\n", NET_AdrToString(net_from), c);
if (!strcmp(c, "ping")) SVC_Ping ();
else if (!strcmp(c, "ack")) SVC_Ack ();
else if (!strcmp(c,"status")) SVC_Status ();
else if (!strcmp(c,"info")) SVC_Info ();
else if (!strcmp(c,"getchallenge")) SVC_GetChallenge ();
else if (!strcmp(c,"connect")) SVC_DirectConnect ();
else if (!strcmp(c, "rcon")) SVC_RemoteCommand ();
if (!strcmp(c, "ping")) SVC_Ping();
else if (!strcmp(c, "ack")) SVC_Ack();
else if (!strcmp(c,"status")) SVC_Status();
else if (!strcmp(c,"info")) SVC_Info();
else if (!strcmp(c,"getchallenge")) SVC_GetChallenge();
else if (!strcmp(c,"connect")) SVC_DirectConnect();
else if (!strcmp(c, "rcon")) SVC_RemoteCommand();
else Msg ("bad connectionless packet from %s:\n%s\n", NET_AdrToString (net_from), s);
}

View File

@ -323,7 +323,7 @@ SV_WriteSaveFile
void SV_WriteSaveFile( char *name )
{
char path[MAX_SYSPATH];
char comment[32];
string comment;
dsavehdr_t *header;
file_t *savfile;
bool autosave = false;
@ -390,7 +390,7 @@ void Sav_LoadComment( lump_t *l )
if (l->filelen % sizeof(*in)) Host_Error("Sav_LoadComment: funny lump size\n" );
size = l->filelen / sizeof(*in);
com.strncpy(svs.comment, in, size );
com.strncpy( svs.comment, in, size );
}
void Sav_LoadCvars( lump_t *l )
@ -601,7 +601,7 @@ bool SV_ReadComment( char *comment, int savenum )
if(!savfile)
{
com.strncpy( comment, "<empty>", MAX_QPATH );
com.strncpy( comment, "<empty>", MAX_STRING );
return false;
}
@ -611,13 +611,13 @@ bool SV_ReadComment( char *comment, int savenum )
if(id != IDSAVEHEADER || i != SAVE_VERSION)
{
com.strncpy( comment, "<corrupted>", MAX_QPATH );
com.strncpy( comment, "<corrupted>", MAX_STRING );
return false;
}
sav_base = (byte *)header;
Sav_LoadComment(&header->lumps[LUMP_COMMENTS]);
com.strncpy( comment, svs.comment, MAX_QPATH );
com.strncpy( comment, svs.comment, MAX_STRING );
Mem_Free( savfile );
return true;
@ -2217,11 +2217,11 @@ VM_CvarRegister, // #24 void Cvar_Register( string name, string value, float f
VM_CvarSetValue, // #25 void Cvar_SetValue( string name, float value )
VM_CvarGetValue, // #26 float Cvar_GetValue( string name )
VM_CvarSetString, // #27 void Cvar_SetString( string name, string value )
VM_ComVA, // #28 string va( ... )
VM_ComStrlen, // #29 float strlen( string text )
VM_TimeStamp, // #30 string Com_TimeStamp( float format )
VM_LocalCmd, // #31 void LocalCmd( ... )
NULL, // #32 -- reserved --
VM_CvarGetString, // #28 void VM_CvarGetString( void )
VM_ComVA, // #29 string va( ... )
VM_ComStrlen, // #30 float strlen( string text )
VM_TimeStamp, // #31 string Com_TimeStamp( float format )
VM_LocalCmd, // #32 void LocalCmd( ... )
NULL, // #33 -- reserved --
NULL, // #34 -- reserved --
NULL, // #35 -- reserved --

View File

@ -1831,7 +1831,7 @@ void SearchLocalGames( void )
M_Print( 16 + 16, 120 - 48 + 24, "please be patient." );
re->EndFrame(); // the text box won't show up unless we do a buffer swap
CL_PingServers_f(); // send out info packets
//CL_PingServers_f(); // send out info packets
}
void SearchLocalGamesFunc( void *self )
@ -1978,132 +1978,6 @@ void StartServerActionFunc( void *self )
M_ForceMenuOff();
}
bool Menu_CheckMapsList( void )
{
byte buf[MAX_SYSPATH]; // 1 kb
char *buffer, string[MAX_STRING];
search_t *t;
file_t *f;
int i;
if(FS_FileExists("scripts/maps.lst"))
return true; // exist
t = FS_Search( "maps/*.bsp", false );
if(!t) return false;
buffer = Z_Malloc( t->numfilenames * 2 * sizeof(string));
for(i = 0; i < t->numfilenames; i++)
{
const char *data = NULL;
char *entities = NULL;
char entfilename[MAX_QPATH];
int ver = -1, lumpofs = 0, lumplen = 0;
char mapname[MAX_QPATH], message[MAX_QPATH];
f = FS_Open(t->filenames[i], "rb");
FS_FileBase( t->filenames[i], mapname );
if( f )
{
int num_spawnpoints = 0;
memset(buf, 0, 1024);
FS_Read(f, buf, 1024);
if(!memcmp(buf, "IBSP", 4))
{
dheader_t *header = (dheader_t *)buf;
ver = LittleLong(((int *)buf)[1]);
switch(ver)
{
case 38: // quake2 (xash)
case 46: // quake3
case 47: // return to castle wolfenstein
lumpofs = LittleLong(header->lumps[LUMP_ENTITIES].fileofs);
lumplen = LittleLong(header->lumps[LUMP_ENTITIES].filelen);
break;
}
}
else
{
lump_t ents; // quake1 entity lump
memcpy(&ents, buf + 4, sizeof(lump_t)); // skip first four bytes (version)
ver = LittleLong(((int *)buf)[0]);
switch( ver )
{
case 28: // quake 1 beta
case 29: // quake 1 regular
case 30: // Half-Life regular
lumpofs = LittleLong(ents.fileofs);
lumplen = LittleLong(ents.filelen);
break;
default:
ver = 0;
break;
}
}
com.strncpy(entfilename, t->filenames[i], sizeof(entfilename));
FS_StripExtension( entfilename );
FS_DefaultExtension( entfilename, ".ent" );
entities = (char *)FS_LoadFile(entfilename, NULL);
if( !entities && lumplen >= 10 )
{
FS_Seek(f, lumpofs, SEEK_SET);
entities = (char *)Z_Malloc(lumplen + 1);
FS_Read(f, entities, lumplen);
}
if(entities)
{
// if there are entities to parse, a missing message key just
// means there is no title, so clear the message string now
message[0] = 0;
data = entities;
com.strncpy(message, "No Title", MAX_QPATH);
while(Com_ParseToken(&data))
{
if(!strcmp(com_token, "{" )) continue;
else if(!strcmp(com_token, "}" )) break;
else if(!strcmp(com_token, "message" ))
{
// get the message contents
Com_ParseToken(&data);
if(!strcmp(com_token, "" )) continue;
com.strncpy(message, com_token, sizeof(message));
}
else if(!strcmp(com_token, "classname" ))
{
Com_ParseToken(&data);
if(!com.strcmp(com_token, "info_player_deatchmatch"))
num_spawnpoints++;
else if(!com.strcmp(com_token, "info_player_start"))
num_spawnpoints++;
}
if(num_spawnpoints > 0) break; // valid map
}
}
if( entities) Mem_Free(entities);
if( f ) FS_Close(f);
// format: mapname "maptitle"/r
com.sprintf(string, "%s \"%s\"\r", mapname, message );
com.strcat(buffer, string); // add new string
}
}
if( t ) Mem_Free(t); // free search result
// write generated maps.lst
if(FS_WriteFile("scripts/maps.lst", buffer, strlen(buffer)))
{
if( buffer ) Mem_Free(buffer);
return true;
}
return false;
}
void StartServer_MenuInit( void )
{
static const char *dm_coop_names[] =
@ -2119,7 +1993,7 @@ void StartServer_MenuInit( void )
file_t *fp;
// create new maplist if not exist
if(!Menu_CheckMapsList())
if(!Cmd_CheckMapsList())
{
MsgWarn("StartServer_MenuInit: maps.lst not found\n");
return;

View File

@ -44,11 +44,139 @@ void PF_readcomment( void )
return;
savenum = (int)PRVM_G_FLOAT(OFS_PARM0);
PRVM_G_FLOAT(OFS_PARM1) = (float)SV_ReadComment( comment[savenum], savenum );
SV_ReadComment( comment[savenum], savenum );
PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString( comment[savenum] );
}
/*
=========
PF_joinserver
float JoinServer( float serevernum )
=========
*/
void PF_joinserver( void )
{
string buffer;
int i;
if(!VM_ValidateArgs( "JoinServer", 1 ))
return;
i = (int)PRVM_G_FLOAT(OFS_PARM0);
PRVM_G_FLOAT(OFS_RETURN) = 0;
if( i < cls.numservers && cls.serverlist[i].maxplayers > 1 && cls.serverlist[i].netaddress )
{
com.sprintf( buffer, "connect %s\n", cls.serverlist[i].netaddress );
Cbuf_AddText( buffer );
PRVM_G_FLOAT(OFS_RETURN) = 1;
}
}
/*
=========
PF_getserverinfo
string ServerInfo( float num )
=========
*/
void PF_getserverinfo( void )
{
static string serverinfo[MAX_SERVERS];
serverinfo_t *s;
int i;
if(!VM_ValidateArgs( "ServerInfo", 1 ))
return;
i = (int)PRVM_G_FLOAT(OFS_PARM0);
PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString( "<empty>" );
if( i < cls.numservers )
{
s = &cls.serverlist[i];
if( s && s->hostname && s->maxplayers > 1 ) // ignore singleplayer servers
{
com.snprintf( serverinfo[i], MAX_STRING, "%s %15s %7i/%i %7i\n", s->hostname, s->mapname, s->numplayers, s->maxplayers, s->ping );
PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString( serverinfo[i] );
}
}
}
/*
=========
PF_getmapslist
string GetMapsList( void )
=========
*/
int mapcount = 0;
void PF_getmapslist( void )
{
static char mapstring[MAX_INPUTLINE];
if(!VM_ValidateArgs( "GetMapsList", 0 ))
return;
PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString( "'none'" );
mapstring[0] = '\0';
mapcount = 0;
// create new maplist if not exist
if(!Cmd_CheckMapsList())
{
MsgWarn("GetMapsList: maps.lst not found\n");
return;
}
// paranoid mode :-)
if(!Com_LoadScript( "scripts/maps.lst", NULL, 0 ))
return;
while(Com_GetToken( true ))
{
com.strcat( mapstring, va("'%s'", com_token ));
while(Com_TryToken()); // skip other stuff
mapcount++;
}
PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString( mapstring );
}
/*
=========
PF_getmapscount
string GetMapsCount( void )
=========
*/
void PF_getmapscount( void )
{
if(!VM_ValidateArgs( "GetMapsCount", 0 ))
return;
PRVM_G_FLOAT(OFS_RETURN) = mapcount;
}
/*
=========
PF_newserver
void NewServer( string mapname )
=========
*/
void PF_newserver( void )
{
const char *s;
if(!VM_ValidateArgs( "NewServer", 1 ))
return;
s = PRVM_G_STRING(OFS_PARM0);
VM_ValidateString( s );
Cbuf_AddText( va("map %s\n", s ));
}
/*
=========
PF_substring
@ -478,11 +606,11 @@ VM_CvarRegister, // #24 void Cvar_Register( string name, string value, float f
VM_CvarSetValue, // #25 void Cvar_SetValue( string name, float value )
VM_CvarGetValue, // #26 float Cvar_GetValue( string name )
VM_CvarSetString, // #27 void Cvar_SetString( string name, string value )
VM_ComVA, // #28 string va( ... )
VM_ComStrlen, // #29 float strlen( string text )
VM_TimeStamp, // #30 string Com_TimeStamp( float format )
VM_LocalCmd, // #31 void LocalCmd( ... )
NULL, // #32 -- reserved --
VM_CvarGetString, // #28 void VM_CvarGetString( void )
VM_ComVA, // #29 string va( ... )
VM_ComStrlen, // #30 float strlen( string text )
VM_TimeStamp, // #31 string Com_TimeStamp( float format )
VM_LocalCmd, // #32 void LocalCmd( ... )
NULL, // #33 -- reserved --
NULL, // #34 -- reserved --
NULL, // #35 -- reserved --
@ -560,6 +688,11 @@ PF_callfunction, // #117 void callfunction( ..., string function_name )
PF_testfunction, // #118 float testfunction( string function_name )
PF_newgame, // #119 void NewGame( void )
PF_readcomment, // #120 string ReadComment( float savenum )
PF_joinserver, // #121 float JoinServer( float num )
PF_getserverinfo, // #122 string ServerInfo( float num )
PF_getmapslist, // #123 string GetMapsList( void )
PF_getmapscount, // #124 float GetMapsCount( void )
PF_newserver, // #125 void NewServer( string mapname )
};
const int vm_ui_numbuiltins = sizeof(vm_ui_builtins) / sizeof(prvm_builtin_t);

View File

@ -22,13 +22,6 @@ void UI_KeyEvent( int key )
PRVM_ExecuteProgram (prog->globals.ui->m_keydown, "QC function m_keydown is missing");
PRVM_End;
switch( key )
{
case K_ESCAPE:
UI_HideMenu();
break;
}
}
void UI_Draw( void )

View File

@ -375,8 +375,9 @@ bool SC_EndOfScript (bool newline)
return false;
}
// release script
Mem_Free (script->buffer);
// FIXME: stupid xash bug
if(Mem_IsAllocated( script->buffer ))
Mem_Free( script->buffer );
if(script == scriptstack + 1)
{
endofscript = true;

View File

@ -316,6 +316,16 @@ typedef struct pmove_s
int (*pointcontents)( vec3_t point );
} pmove_t;
typedef struct sizebuf_s
{
bool overflowed; // set to true if the buffer size failed
byte *data;
int maxsize;
int cursize;
int readcount;
int errorcount; // cause by errors
} sizebuf_t;
/*
==============================================================================
@ -519,6 +529,7 @@ typedef struct vprogs_exp_s
// string manipulations
const char *(*GetString)( int num );
int (*SetEngineString)( const char *s );
int (*SetTempString)( const char *s );
int (*AllocString)( size_t bufferlength, char **pointer );
void (*FreeString)( int num );

View File

@ -6,6 +6,7 @@
#include "vprogs.h"
static prvm_prog_t prog_list[PRVM_MAXPROGS];
sizebuf_t vm_tempstringsbuf;
int prvm_type_size[8] = {1, sizeof(string_t)/4,1,3,1,1, sizeof(func_t)/4, sizeof(void *)/4};
@ -1972,29 +1973,55 @@ edict_t *PRVM_EDICT_NUM_ERROR(int n, char *filename, int fileline)
const char *PRVM_GetString(int num)
{
if (num >= 0 && num < vm.prog->stringssize)
return vm.prog->strings + num;
else if (num < 0 && num >= -vm.prog->numknownstrings)
if( num >= 0 )
{
num = -1 - num;
if (!vm.prog->knownstrings[num])
PRVM_ERROR("PRVM_GetString: attempt to get string that is already freed");
return vm.prog->knownstrings[num];
if( num < vm.prog->stringssize ) return vm.prog->strings + num;
else if( num <= vm.prog->stringssize + vm_tempstringsbuf.maxsize)
{
num -= vm.prog->stringssize;
if( num < vm_tempstringsbuf.cursize )
return (char *)vm_tempstringsbuf.data + num;
else
{
VM_Warning("PRVM_GetString: Invalid temp-string offset (%i >= %i vm_tempstringsbuf.cursize)\n", num, vm_tempstringsbuf.cursize);
return "";
}
}
else
{
VM_Warning("PRVM_GetString: Invalid constant-string offset (%i >= %i prog->stringssize)\n", num, vm.prog->stringssize);
return "";
}
}
else
{
PRVM_ERROR("PRVM_GetString: invalid string offset %i", num);
return "";
num = -1 - num;
if (num < vm.prog->numknownstrings)
{
if (!vm.prog->knownstrings[num])
VM_Warning("PRVM_GetString: Invalid zone-string offset (%i has been freed)\n", num);
return vm.prog->knownstrings[num];
}
else
{
VM_Warning("PRVM_GetString: Invalid zone-string offset (%i >= %i)\n", num, vm.prog->numknownstrings);
return "";
}
}
}
int PRVM_SetEngineString(const char *s)
int PRVM_SetEngineString( const char *s )
{
int i;
if (!s)
return 0;
if (s >= vm.prog->strings && s <= vm.prog->strings + vm.prog->stringssize)
PRVM_ERROR("PRVM_SetEngineString: s in vm.prog->strings area");
// if it's in the tempstrings area, use a reserved range
// (otherwise we'd get millions of useless string offsets cluttering the database)
if (s >= (char *)vm_tempstringsbuf.data && s < (char *)vm_tempstringsbuf.data + vm_tempstringsbuf.maxsize)
return vm.prog->stringssize + (s - (char *)vm_tempstringsbuf.data);
// see if it's a known string address
for (i = 0;i < vm.prog->numknownstrings;i++)
if (vm.prog->knownstrings[i] == s)
return -1 - i;
@ -2025,6 +2052,44 @@ int PRVM_SetEngineString(const char *s)
return -1 - i;
}
// temp string handling
// all tempstrings go into this buffer consecutively, and it is reset
// whenever PRVM_ExecuteProgram returns to the engine
// (technically each PRVM_ExecuteProgram call saves the cursize value and
// restores it on return, so multiple recursive calls can share the same
// buffer)
// the buffer size is automatically grown as needed
int PRVM_SetTempString( const char *s )
{
int size;
char *t;
if (!s) return 0;
size = (int)com.strlen(s) + 1;
MsgDev( D_MEMORY, "PRVM_SetTempString: cursize %i, size %i\n", vm_tempstringsbuf.cursize, size);
if (vm_tempstringsbuf.maxsize < vm_tempstringsbuf.cursize + size)
{
size_t old_maxsize = vm_tempstringsbuf.maxsize;
if( vm_tempstringsbuf.cursize + size >= 1<<28 )
PRVM_ERROR("PRVM_SetTempString: ran out of tempstring memory! (refusing to grow tempstring buffer over 256MB, cursize %i, size %i)\n", vm_tempstringsbuf.cursize, size);
vm_tempstringsbuf.maxsize = max( vm_tempstringsbuf.maxsize, 65536 );
while( vm_tempstringsbuf.maxsize < vm_tempstringsbuf.cursize + size )
vm_tempstringsbuf.maxsize *= 2;
if (vm_tempstringsbuf.maxsize != old_maxsize || vm_tempstringsbuf.data == NULL)
{
MsgDev( D_NOTE, "PRVM_SetTempString: enlarging tempstrings buffer (%iKB -> %iKB)\n", old_maxsize/1024, vm_tempstringsbuf.maxsize/1024);
vm_tempstringsbuf.data = Mem_Realloc( vm.prog->progs_mempool, vm_tempstringsbuf.data, vm_tempstringsbuf.maxsize );
}
}
t = (char *)vm_tempstringsbuf.data + vm_tempstringsbuf.cursize;
Mem_Copy( t, s, size );
vm_tempstringsbuf.cursize += size;
return PRVM_SetEngineString( t );
}
int PRVM_AllocString(size_t bufferlength, char **pointer)
{
int i;

View File

@ -323,6 +323,7 @@ vprogs_exp_t DLLEXPORT *CreateAPI( stdlib_api_t *input, void *unused )
vm.LoadFromFile = PRVM_ED_LoadFromFile;
vm.GetString = PRVM_GetString;
vm.SetEngineString = PRVM_SetEngineString;
vm.SetTempString = PRVM_SetTempString;
vm.AllocString = PRVM_AllocString;
vm.FreeString = PRVM_FreeString;

View File

@ -418,6 +418,7 @@ void PRVM_ED_PrintNum (int ent);
const char *PRVM_GetString(int num);
int PRVM_SetEngineString(const char *s);
int PRVM_SetTempString( const char *s );
int PRVM_AllocString(size_t bufferlength, char **pointer);
void PRVM_FreeString(int num);