Oct 8th 2000: xqf-0.9.4f - Alex Burger <alex@fragit.net>
-UnrealTournament master support using Gamespy style master via QStat 2.4a -Add Epic UT Master server to default master list -Remove Gamespy master server entry from default master list -Fixed master list bug Oct 4th 2000: xqf-0.9.4e - Alex Burger <alex@fragit.net> -Soldier of Fortune support -Gamespy master server support when used with QStat 2.4a -Format of 'lists' file changed to record game type in master entry -Ability to add the same master to multiple games such as Gamespy's master xqf-0.9.4d - Bill Adams <webmaster@evil.inetarena.com> -When browsing Q3A games the mods (e.g. arena, osp, beryllium, etc.) show up in the "Game" column along with the game type (FFA, etc.). -The mod appears in its own column for Q3A games -You can filter by mod -You can filter by the version string git-svn-id: http://svn.code.sf.net/p/xqf/code/trunk@8 d2ac09be-c843-0410-8b1f-f8a84130e0ec
This commit is contained in:
parent
9ca134e3c3
commit
85e3cf4db0
@ -0,0 +1,20 @@
|
||||
Oct 8th 2000: xqf-0.9.4f - Alex Burger <alex@fragit.net>
|
||||
-UnrealTournament master support using Gamespy style master via QStat 2.4a
|
||||
-Add Epic UT Master server to default master list
|
||||
-Remove Gamespy master server entry from default master list
|
||||
-Fixed master list bug
|
||||
|
||||
Oct 4th 2000: xqf-0.9.4e - Alex Burger <alex@fragit.net>
|
||||
-Soldier of Fortune support
|
||||
-Gamespy master server support when used with QStat 2.4a
|
||||
-Format of 'lists' file changed to record game type in master entry
|
||||
-Ability to add the same master to multiple games such as Gamespy's master
|
||||
|
||||
xqf-0.9.4d - Bill Adams <webmaster@evil.inetarena.com>
|
||||
-When browsing Q3A games the mods (e.g. arena, osp, beryllium, etc.) show
|
||||
up in the "Game" column along with the game type (FFA, etc.).
|
||||
-The mod appears in its own column for Q3A games
|
||||
-You can filter by mod
|
||||
-You can filter by the version string
|
||||
|
||||
|
34
xqf/README
34
xqf/README
@ -1,6 +1,6 @@
|
||||
|
||||
XQF 0.9.4
|
||||
(March 18 2000)
|
||||
XQF 0.9.4f
|
||||
(October 4th 2000)
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
@ -13,8 +13,10 @@ Development platform: Debian/Linux (glibc2.1), XFree86 3.3.6, GTK+ 1.2.7.
|
||||
|
||||
Features:
|
||||
- Supports Quake, QuakeWorld, Quake2, Quake3: Arena, Hexen2, HexenWorld,
|
||||
Sin, Half-Life, Kingpin, Heretic2, Unreal Tournament
|
||||
Sin, Half-Life, Kingpin, Heretic2, Unreal Tournament,
|
||||
Soldier of Fortune
|
||||
- Uses QStat to communicate with masters/servers
|
||||
- Support (unauthenticated) Gamespy style master servers using QStat 2.4a
|
||||
- Displays server rules and player info
|
||||
- Players and servers sorting
|
||||
- Favorite servers list
|
||||
@ -35,7 +37,7 @@ REQUIREMENTS
|
||||
- A UNIX computer and C compiler (gcc)
|
||||
- X11 (X Window System)
|
||||
- GTK+ 1.2.5+ http://www.gtk.org
|
||||
- QStat 2.3g http://www.activesw.com/people/steve/qstat.html
|
||||
- QStat 2.4 http://www.activesw.com/people/steve/qstat.html
|
||||
- [Optionally] wget ftp://ftp.gnu.org/gnu/wget/ to retrieve server
|
||||
listings from the Web
|
||||
- [Optionally] gzip http://www.gnu.org/software/gzip/gzip.html
|
||||
@ -56,9 +58,23 @@ To install the binary become root if necessary and run "make install".
|
||||
USAGE
|
||||
-----
|
||||
|
||||
QStat 2.2b or 2.3[cdefg] is required. QStat 2.3g is *HIGHLY* recommended.
|
||||
QStat 2.2b or 2.3[cdefg] is required. QStat 2.4 is *HIGHLY* recommended.
|
||||
It must be in your $PATH.
|
||||
|
||||
Gamespy style master and Soldier of Fortune support is only available with
|
||||
QStat 2.4a.
|
||||
|
||||
Note: Gamespy's master servers use an authentication sequence that is not
|
||||
supported by QStat 2.4a. This means that you can not query a Gamespy master
|
||||
using QStat and XQF. The Unreal Tournament master server at Epic also
|
||||
uses a Gamespy style master server but does not require authentication.
|
||||
This means that you can query Epic's UT master server using:
|
||||
|
||||
gmaster://unreal.epicgames.com:28900
|
||||
|
||||
Please see the QStat documentation for more information on the types of
|
||||
master servers.
|
||||
|
||||
QStat home page is http://www.activesw.com/people/steve/qstat.html
|
||||
|
||||
Server list navigation:
|
||||
@ -69,6 +85,14 @@ Server list navigation:
|
||||
XQF can be customized via GTK's rc files. XQF parses files
|
||||
/etc/gtkrc, $HOME/.gtkrc, $HOME/.qf/gtkrc.
|
||||
|
||||
When adding a master server, the following prefixes are support:
|
||||
|
||||
master:// (regular master server)
|
||||
gmaster:// (Gamespy style master server)
|
||||
http:// (html page containing list)
|
||||
|
||||
Not specifying a prefix will default to master://
|
||||
|
||||
Please send bug reports or suggestions to roma@botik.ru
|
||||
|
||||
|
||||
|
137
xqf/src/filter.c
137
xqf/src/filter.c
@ -65,6 +65,8 @@ int filter_not_full;
|
||||
int filter_not_empty;
|
||||
int filter_no_cheats;
|
||||
int filter_no_password;
|
||||
char *mod_contains;
|
||||
char *version_contains;
|
||||
|
||||
unsigned filter_current_time = 1;
|
||||
|
||||
@ -75,6 +77,8 @@ static GtkWidget *filter_not_full_check_button;
|
||||
static GtkWidget *filter_not_empty_check_button;
|
||||
static GtkWidget *filter_no_cheats_check_button;
|
||||
static GtkWidget *filter_no_password_check_button;
|
||||
static GtkWidget *mod_contains_entry;
|
||||
static GtkWidget *version_contains_entry;
|
||||
|
||||
|
||||
void apply_filters (unsigned mask, struct server *s) {
|
||||
@ -124,11 +128,31 @@ GSList *build_filtered_list (unsigned mask, GSList *servers) {
|
||||
|
||||
|
||||
static int server_filter (struct server *s) {
|
||||
char **info_ptr;
|
||||
if (s->ping == -1) /* no information */
|
||||
return TRUE;
|
||||
|
||||
if( mod_contains && strlen( mod_contains ) && ! s->mod )
|
||||
return FALSE;
|
||||
|
||||
if( version_contains && strlen (version_contains)) {
|
||||
/* Filter for the version */
|
||||
for (info_ptr = s->info; info_ptr && *info_ptr; info_ptr += 2) {
|
||||
if (strcmp (*info_ptr, "version") == 0) {
|
||||
if( !strstr( info_ptr[1], version_contains )){
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}/*end version check */
|
||||
|
||||
if (s->retries < filter_retries &&
|
||||
s->ping < filter_ping &&
|
||||
s->ping < filter_ping &&
|
||||
|
||||
( !mod_contains || !strlen( mod_contains ) ||
|
||||
( s->mod && strstr( s->mod, mod_contains ))) &&
|
||||
|
||||
|
||||
(!filter_not_full || s->curplayers != s->maxplayers) &&
|
||||
(!filter_not_empty || s->curplayers != 0) &&
|
||||
(!filter_no_cheats || (s->flags & SERVER_CHEATS) == 0) &&
|
||||
@ -148,13 +172,17 @@ static void server_filter_init (void) {
|
||||
filter_not_empty = config_get_bool ("not empty=false");
|
||||
filter_no_cheats = config_get_bool ("no cheats=false");
|
||||
filter_no_password = config_get_bool ("no password=false");
|
||||
|
||||
mod_contains = config_get_string_with_default ("mod_contains",NULL);
|
||||
version_contains = config_get_string_with_default ("version_contains",NULL);
|
||||
config_pop_prefix ();
|
||||
}
|
||||
|
||||
|
||||
static void server_filter_new_defaults (void) {
|
||||
int i;
|
||||
char *cptr;
|
||||
gchar *gcptr;
|
||||
int text_changed;
|
||||
|
||||
config_push_prefix ("/" CONFIG_FILE "/Server Filter");
|
||||
|
||||
@ -171,6 +199,72 @@ static void server_filter_new_defaults (void) {
|
||||
filters[FILTER_SERVER].changed = FILTER_CHANGED;
|
||||
}
|
||||
|
||||
|
||||
/* MOD string values -- baa */
|
||||
gcptr = gtk_editable_get_chars (GTK_EDITABLE (mod_contains_entry), 0, -1 );
|
||||
text_changed = 0;
|
||||
if( strlen( gcptr )){
|
||||
/*
|
||||
First case, the user entered something. See if the value
|
||||
is different
|
||||
*/
|
||||
if (mod_contains){
|
||||
if( strcmp( gcptr, mod_contains )) text_changed = 1;
|
||||
g_free( mod_contains );
|
||||
} else {
|
||||
text_changed = 1;
|
||||
}
|
||||
mod_contains = g_malloc( sizeof( char ) * ( strlen( gcptr ) + 1 ));
|
||||
sprintf( mod_contains, "%s\0", gcptr );
|
||||
if (text_changed) {
|
||||
config_set_string ("mod_contains", mod_contains );
|
||||
filters[FILTER_SERVER].changed = FILTER_CHANGED;
|
||||
}
|
||||
} else {
|
||||
if (mod_contains){
|
||||
text_changed = 1; /* From something to nothing */
|
||||
g_free( mod_contains );
|
||||
config_set_string ("mod_contains", "" );
|
||||
filters[FILTER_SERVER].changed = FILTER_CHANGED;
|
||||
}
|
||||
mod_contains = NULL;
|
||||
}
|
||||
g_free( gcptr );
|
||||
|
||||
|
||||
/* Version string values -- baa */
|
||||
gcptr = gtk_editable_get_chars (GTK_EDITABLE (version_contains_entry), 0, -1 );
|
||||
text_changed = 0;
|
||||
if( strlen( gcptr )){
|
||||
/*
|
||||
First case, the user entered something. See if the value
|
||||
is different
|
||||
*/
|
||||
if (version_contains){
|
||||
if( strcmp( gcptr, version_contains )) text_changed = 1;
|
||||
g_free( version_contains );
|
||||
} else {
|
||||
text_changed = 1;
|
||||
}
|
||||
version_contains = g_malloc( sizeof( char ) * ( strlen( gcptr ) + 1 ));
|
||||
sprintf( version_contains, "%s\0", gcptr );
|
||||
if (text_changed) {
|
||||
config_set_string ("version_contains", version_contains );
|
||||
filters[FILTER_SERVER].changed = FILTER_CHANGED;
|
||||
}
|
||||
} else {
|
||||
if (version_contains){
|
||||
text_changed = 1; /* From something to nothing */
|
||||
g_free( version_contains );
|
||||
config_set_string ("version_contains", "" );
|
||||
filters[FILTER_SERVER].changed = FILTER_CHANGED;
|
||||
}
|
||||
version_contains = NULL;
|
||||
}
|
||||
g_free( gcptr );
|
||||
|
||||
|
||||
|
||||
i = GTK_TOGGLE_BUTTON (filter_not_full_check_button)->active;
|
||||
if (filter_not_full != i) {
|
||||
config_set_bool ("not full", filter_not_full = i);
|
||||
@ -225,7 +319,7 @@ static void server_filter_page (GtkWidget *notebook) {
|
||||
alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
|
||||
gtk_container_add (GTK_CONTAINER (frame), alignment);
|
||||
|
||||
table = gtk_table_new (6, 2, FALSE);
|
||||
table = gtk_table_new (6, 5, FALSE);
|
||||
gtk_table_set_row_spacings (GTK_TABLE (table), 2);
|
||||
gtk_table_set_col_spacings (GTK_TABLE (table), 4);
|
||||
gtk_container_set_border_width (GTK_CONTAINER (table), 6);
|
||||
@ -264,6 +358,43 @@ static void server_filter_page (GtkWidget *notebook) {
|
||||
1, 2, 1, 2);
|
||||
gtk_widget_show (filter_retries_spinner);
|
||||
|
||||
|
||||
/* MOD Filter -- baa */
|
||||
/* http://developer.gnome.org/doc/API/gtk/gtktable.html */
|
||||
|
||||
label = gtk_label_new ("the mod contains the string");
|
||||
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
|
||||
gtk_table_attach (GTK_TABLE (table), label, 3, 4, 0, 1, GTK_FILL, GTK_FILL,
|
||||
0, 0);
|
||||
gtk_widget_show (label);
|
||||
mod_contains_entry = gtk_entry_new_with_max_length (32);
|
||||
gtk_widget_set_usize (mod_contains_entry, 64, -1);
|
||||
gtk_entry_set_editable (GTK_ENTRY (mod_contains_entry), TRUE);
|
||||
gtk_entry_set_text (GTK_ENTRY (mod_contains_entry),
|
||||
(mod_contains)? mod_contains : "");
|
||||
|
||||
gtk_table_attach_defaults (GTK_TABLE (table), mod_contains_entry, 4, 5, 0, 1);
|
||||
gtk_widget_show (mod_contains_entry);
|
||||
|
||||
|
||||
/* Version Filter -- baa */
|
||||
|
||||
label = gtk_label_new ("the version contains the string");
|
||||
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
|
||||
gtk_table_attach (GTK_TABLE (table), label, 3, 4, 1, 2, GTK_FILL, GTK_FILL,
|
||||
0, 0);
|
||||
gtk_widget_show (label);
|
||||
version_contains_entry = gtk_entry_new_with_max_length (32);
|
||||
gtk_widget_set_usize (version_contains_entry, 64, -1);
|
||||
gtk_entry_set_editable (GTK_ENTRY (version_contains_entry), TRUE);
|
||||
gtk_entry_set_text (GTK_ENTRY (version_contains_entry),
|
||||
(version_contains)? version_contains : "");
|
||||
|
||||
gtk_table_attach_defaults (GTK_TABLE (table), version_contains_entry, 4, 5, 1, 2);
|
||||
gtk_widget_show (version_contains_entry);
|
||||
|
||||
|
||||
|
||||
/* not full */
|
||||
|
||||
filter_not_full_check_button =
|
||||
|
@ -307,6 +307,27 @@ struct game games[] = {
|
||||
NULL,
|
||||
quake_save_info
|
||||
},
|
||||
{
|
||||
SFS_SERVER,
|
||||
GAME_CONNECT | GAME_RCON,
|
||||
"Soldier of Fortune",
|
||||
SFS_DEFAULT_PORT,
|
||||
0,
|
||||
"SFS",
|
||||
"SFS",
|
||||
"-sfs",
|
||||
"-q2s", // assume a standard Quake2 style master. May be wrong.
|
||||
&sfs_pix,
|
||||
|
||||
q2_parse_player,
|
||||
quake_parse_server,
|
||||
q2_analyze_serverinfo,
|
||||
config_is_valid_generic,
|
||||
NULL,
|
||||
q2_exec_generic,
|
||||
NULL,
|
||||
quake_save_info
|
||||
},
|
||||
{
|
||||
HR_SERVER,
|
||||
GAME_CONNECT | GAME_RCON,
|
||||
@ -339,7 +360,7 @@ struct game games[] = {
|
||||
"UNS",
|
||||
"UNS",
|
||||
"-uns",
|
||||
NULL,
|
||||
"uns",
|
||||
&un_pix,
|
||||
|
||||
un_parse_player,
|
||||
@ -735,12 +756,13 @@ static void q2_analyze_serverinfo (struct server *s) {
|
||||
|
||||
#ifdef QSTAT23
|
||||
|
||||
static char *q3a_gametypes[5] = {
|
||||
static char *q3a_gametypes[6] = {
|
||||
"<FFA>", /* Free for All */
|
||||
"<1v1>", /* Tournament */
|
||||
NULL, /* Single Player */
|
||||
"<TDM>", /* Team Deathmatch */
|
||||
"<CTF>"
|
||||
"<CTF>",
|
||||
" mod ", /* 5 is usually a client-side mod */
|
||||
};
|
||||
|
||||
|
||||
@ -753,17 +775,36 @@ static void q3_analyze_serverinfo (struct server *s) {
|
||||
s->flags |= SERVER_SPECTATE;
|
||||
|
||||
for (info_ptr = s->info; info_ptr && *info_ptr; info_ptr += 2) {
|
||||
|
||||
/*
|
||||
fs_game sets the active directory and is how one chooses
|
||||
a mod on the command line. This should not show up in
|
||||
the server string but some times it does. We will
|
||||
take either fs_game or gamename as the "mod" string.
|
||||
--baa
|
||||
*/
|
||||
|
||||
if (strcmp (*info_ptr, "fs_game") == 0) {
|
||||
s->game = info_ptr[1];
|
||||
if (strcmp (info_ptr[1], "baseq3")) {
|
||||
s->mod = info_ptr[1];
|
||||
}
|
||||
}
|
||||
else if (strcmp (*info_ptr, "gamename") == 0) {
|
||||
if (strcmp (info_ptr[1], "baseq3")) {
|
||||
/* We only set the mod if the name is NOT baseq3. */
|
||||
s->mod = info_ptr[1];
|
||||
}
|
||||
}
|
||||
|
||||
else if (!s->game && strcmp (*info_ptr, "g_gametype") == 0) {
|
||||
/* A value of 5 is usually a mod */
|
||||
n = strtol (info_ptr[1], &endptr, 10);
|
||||
|
||||
if (endptr == info_ptr[1]) {
|
||||
s->game = info_ptr[1];
|
||||
}
|
||||
else {
|
||||
if (n < 5)
|
||||
if (n < 6)
|
||||
s->game = q3a_gametypes[n];
|
||||
}
|
||||
}
|
||||
|
@ -45,6 +45,7 @@
|
||||
#include "xpm/sn.xpm"
|
||||
#include "xpm/hl.xpm"
|
||||
#include "xpm/kp.xpm"
|
||||
#include "xpm/sfs.xpm"
|
||||
#include "xpm/hr2.xpm"
|
||||
#include "xpm/un.xpm"
|
||||
|
||||
@ -92,6 +93,7 @@ struct pixmap hw_pix;
|
||||
struct pixmap sn_pix;
|
||||
struct pixmap hl_pix;
|
||||
struct pixmap kp_pix;
|
||||
struct pixmap sfs_pix;
|
||||
struct pixmap hr_pix;
|
||||
struct pixmap un_pix;
|
||||
|
||||
@ -186,6 +188,7 @@ void free_pixmaps (void) {
|
||||
free_pixmap (&sn_pix);
|
||||
free_pixmap (&hl_pix);
|
||||
free_pixmap (&kp_pix);
|
||||
free_pixmap (&sfs_pix);
|
||||
free_pixmap (&hr_pix);
|
||||
free_pixmap (&un_pix);
|
||||
|
||||
@ -248,6 +251,7 @@ void init_pixmaps (GtkWidget *window) {
|
||||
create_pixmap (window, &sn_pix, sn_xpm);
|
||||
create_pixmap (window, &hl_pix, hl_xpm);
|
||||
create_pixmap (window, &kp_pix, kp_xpm);
|
||||
create_pixmap (window, &sfs_pix, sfs_xpm);
|
||||
create_pixmap (window, &hr_pix, hr2_xpm);
|
||||
create_pixmap (window, &un_pix, un_xpm);
|
||||
|
||||
|
@ -55,6 +55,7 @@ extern struct pixmap hw_pix;
|
||||
extern struct pixmap sn_pix;
|
||||
extern struct pixmap hl_pix;
|
||||
extern struct pixmap kp_pix;
|
||||
extern struct pixmap sfs_pix;
|
||||
extern struct pixmap hr_pix;
|
||||
extern struct pixmap un_pix;
|
||||
|
||||
|
@ -186,6 +186,11 @@ void server_free_info (struct server *s) {
|
||||
s->info = NULL;
|
||||
s->game = NULL;
|
||||
}
|
||||
|
||||
if (s->mod) { /* Added by baa */
|
||||
s->mod = NULL;
|
||||
}
|
||||
|
||||
if (s->players) {
|
||||
g_slist_foreach (s->players, (GFunc) g_free, NULL);
|
||||
g_slist_free (s->players);
|
||||
|
@ -99,6 +99,10 @@ int compare_servers (const struct server *s1, const struct server *s2,
|
||||
res = compare_strings (s1->game, s2->game);
|
||||
break;
|
||||
|
||||
case SORT_SERVER_MOD:
|
||||
res = compare_strings (s1->mod, s2->mod);
|
||||
break;
|
||||
|
||||
case SORT_SERVER_PLAYERS:
|
||||
res = s1->curplayers - s2->curplayers;
|
||||
if (!res) {
|
||||
|
@ -29,7 +29,8 @@ enum ssort_mode {
|
||||
SORT_SERVER_TO,
|
||||
SORT_SERVER_PLAYERS,
|
||||
SORT_SERVER_MAP,
|
||||
SORT_SERVER_GAME
|
||||
SORT_SERVER_GAME,
|
||||
SORT_SERVER_MOD
|
||||
};
|
||||
|
||||
enum psort_mode {
|
||||
|
165
xqf/src/source.c
165
xqf/src/source.c
@ -1,5 +1,5 @@
|
||||
/* XQF - Quake server browser and launcher
|
||||
* Copyright (C) 1998-2000 Roman Pozlevich <roma@botik.ru>
|
||||
/* XQF - Quake server browser and launcher Copyright (C) 1998-2000 Roman
|
||||
* Pozlevich <roma@botik.ru>
|
||||
*
|
||||
* 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
|
||||
@ -68,18 +68,25 @@ static void save_list (FILE *f, struct master *m) {
|
||||
}
|
||||
else {
|
||||
if (m->url) {
|
||||
fprintf (f, "[%s]\n", m->url);
|
||||
fprintf (f, "[%s %s]\n", games[m->type].id, m->url);
|
||||
}
|
||||
else {
|
||||
fprintf (f, "[%s%s:%d]\n", PREFIX_MASTER,
|
||||
(m->hostname)? m->hostname : inet_ntoa (m->host->ip), m->port);
|
||||
if (m->master_type == 1)
|
||||
{
|
||||
fprintf (f, "[%s %s%s:%d]\n", games[m->type].id, PREFIX_GMASTER,
|
||||
(m->hostname)? m->hostname : inet_ntoa (m->host->ip), m->port);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf (f, "[%s %s%s:%d]\n", games[m->type].id, PREFIX_MASTER,
|
||||
(m->hostname)? m->hostname : inet_ntoa (m->host->ip), m->port);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (srv = m->servers; srv; srv = srv->next) {
|
||||
s = (struct server *) srv->data;
|
||||
fprintf (f, "%s %s:%d\n", games[s->type].id,
|
||||
inet_ntoa (s->host->ip), s->port);
|
||||
fprintf (f, "%s %s:%d\n", games[s->type].id, inet_ntoa (s->host->ip), s->port);
|
||||
}
|
||||
|
||||
fprintf (f, "\n");
|
||||
@ -171,7 +178,7 @@ static void save_server_info (const char *filename, GSList *servers) {
|
||||
}
|
||||
|
||||
|
||||
static struct master *find_master_server (char *addr, unsigned short port) {
|
||||
static struct master *find_master_server (char *addr, unsigned short port, char *str) {
|
||||
GSList *list;
|
||||
struct master *m;
|
||||
struct in_addr ip;
|
||||
@ -181,15 +188,25 @@ static struct master *find_master_server (char *addr, unsigned short port) {
|
||||
|
||||
for (list = all_masters; list; list = list->next) {
|
||||
m = (struct master *) list->data;
|
||||
if (m->port && m->port == port) {
|
||||
if (m->hostname) {
|
||||
if (m->port && m->port == port)
|
||||
{
|
||||
if (m->hostname)
|
||||
{
|
||||
if (!g_strcasecmp (m->hostname, addr))
|
||||
return m;
|
||||
{
|
||||
if (!str) // pre 0.9.4e list file
|
||||
return m;
|
||||
if (!g_strcasecmp (games[m->type].id, str)) // list file in new format
|
||||
return m;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (m->host && inet_aton (addr, &ip) &&
|
||||
ip.s_addr == m->host->ip.s_addr) {
|
||||
return m;
|
||||
else
|
||||
{
|
||||
if (m->host && inet_aton (addr, &ip) && ip.s_addr == m->host->ip.s_addr) {
|
||||
if (!str) // pre 0.9.4e list file
|
||||
return m;
|
||||
if (!g_strcasecmp (games[m->type].id, str))
|
||||
return m;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -298,7 +315,7 @@ static struct master *find_master_url (char *url) {
|
||||
}
|
||||
|
||||
|
||||
static struct master *read_list_parse_master (char *str) {
|
||||
static struct master *read_list_parse_master (char *str, char *str2) {
|
||||
char *addr;
|
||||
unsigned short port;
|
||||
struct master *m;
|
||||
@ -308,7 +325,15 @@ static struct master *read_list_parse_master (char *str) {
|
||||
|
||||
if (g_strncasecmp (str, PREFIX_MASTER, sizeof (PREFIX_MASTER) - 1) == 0) {
|
||||
if (parse_address (str + sizeof (PREFIX_MASTER) - 1, &addr, &port)) {
|
||||
m = find_master_server (addr, port);
|
||||
m = find_master_server (addr, port, str2);
|
||||
g_free (addr);
|
||||
return m;
|
||||
}
|
||||
}
|
||||
|
||||
if (g_strncasecmp (str, PREFIX_GMASTER, sizeof (PREFIX_GMASTER) - 1) == 0) {
|
||||
if (parse_address (str + sizeof (PREFIX_GMASTER) - 1, &addr, &port)) {
|
||||
m = find_master_server (addr, port, str2);
|
||||
g_free (addr);
|
||||
return m;
|
||||
}
|
||||
@ -373,16 +398,28 @@ static void read_lists (const char *filename) {
|
||||
if (n < 1)
|
||||
continue;
|
||||
|
||||
if (token[0][0] == '[') {
|
||||
ch = strchr (token[0] + 1, ']');
|
||||
if (token[0][0] == '[') { // line is a master
|
||||
ch = strchr (token[0] + 1, ']'); // does token 0 have a ]?
|
||||
if (ch) { // it's a favorites or pre 0.9.4e lists file
|
||||
*ch = '\0';
|
||||
|
||||
if (m && m->servers)
|
||||
m->servers = g_slist_reverse (m->servers);
|
||||
|
||||
m = read_list_parse_master (token[0] + 1, NULL);
|
||||
}
|
||||
else {
|
||||
ch = strchr (token[1], ']'); // does token 1 have a ]?
|
||||
if (ch) {
|
||||
*ch = '\0';
|
||||
|
||||
if (m && m->servers)
|
||||
m->servers = g_slist_reverse (m->servers);
|
||||
*ch = '\0';
|
||||
|
||||
m = read_list_parse_master (token[0] + 1);
|
||||
if (m && m->servers)
|
||||
m->servers = g_slist_reverse (m->servers);
|
||||
|
||||
m = read_list_parse_master (token[1], token[0] + 1); // master, type
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!m || n < 2)
|
||||
@ -555,7 +592,7 @@ struct master *add_master (char *path, char *name, enum server_type type,
|
||||
}
|
||||
}
|
||||
|
||||
m = find_master_server (addr, port);
|
||||
m = find_master_server (addr, port, games[type].id);
|
||||
|
||||
if (lookup_only) {
|
||||
g_free (addr);
|
||||
@ -579,8 +616,12 @@ struct master *add_master (char *path, char *name, enum server_type type,
|
||||
g_free (addr);
|
||||
return m;
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
m = create_master (name, type, FALSE);
|
||||
|
||||
m->master_type = 0; // Regular master
|
||||
|
||||
h = host_add (addr);
|
||||
if (h) {
|
||||
m->host = h;
|
||||
@ -595,6 +636,65 @@ struct master *add_master (char *path, char *name, enum server_type type,
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
else if (g_strncasecmp (path, PREFIX_GMASTER, sizeof (PREFIX_GMASTER) - 1) == 0) {
|
||||
if (parse_address (path + sizeof (PREFIX_GMASTER) - 1, &addr, &port)) {
|
||||
|
||||
if (!port) {
|
||||
if (games[type].default_master_port) {
|
||||
port = games[type].default_master_port;
|
||||
}
|
||||
else {
|
||||
g_free (addr);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
m = find_master_server (addr, port, games[type].id);
|
||||
|
||||
if (lookup_only) {
|
||||
g_free (addr);
|
||||
return m;
|
||||
}
|
||||
|
||||
if (m) {
|
||||
if (user) {
|
||||
/* Master renaming is forced by user */
|
||||
g_free (m->name);
|
||||
m->name = g_strdup (name);
|
||||
m->user = TRUE;
|
||||
}
|
||||
else {
|
||||
/* Automatically rename masters that are not edited by user */
|
||||
if (!m->user) {
|
||||
g_free (m->name);
|
||||
m->name = g_strdup (name);
|
||||
}
|
||||
}
|
||||
g_free (addr);
|
||||
return m;
|
||||
}
|
||||
else
|
||||
{
|
||||
m = create_master (name, type, FALSE);
|
||||
|
||||
m->master_type = 1; // Gamespy master
|
||||
|
||||
h = host_add (addr);
|
||||
if (h) {
|
||||
m->host = h;
|
||||
host_ref (h);
|
||||
g_free (addr);
|
||||
}
|
||||
else {
|
||||
m->hostname = addr;
|
||||
}
|
||||
m->port = port;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
if (g_strncasecmp (path, PREFIX_URL_HTTP, sizeof (PREFIX_URL_HTTP) - 1)
|
||||
== 0) {
|
||||
@ -716,6 +816,11 @@ static char *builtin_masters_update_info[] = {
|
||||
|
||||
"ADD Q2S:HR http://www.gameaholic.com/servers/qspy-heretic2 Gameaholic.Com",
|
||||
|
||||
#ifdef QSTAT_HAS_UNREAL_SUPPORT
|
||||
"ADD UNS gmaster://unreal.epicgames.com:28900 Epic",
|
||||
#endif
|
||||
|
||||
|
||||
NULL
|
||||
};
|
||||
|
||||
@ -857,8 +962,14 @@ static void save_master_list (void) {
|
||||
confstr = g_strjoin (" ", typeid, m->url, m->name, NULL);
|
||||
}
|
||||
else {
|
||||
addr = g_strdup_printf (PREFIX_MASTER "%s:%d",
|
||||
(m->hostname)? m->hostname : inet_ntoa (m->host->ip), m->port);
|
||||
|
||||
if (m->master_type == 1)
|
||||
addr = g_strdup_printf (PREFIX_GMASTER "%s:%d",
|
||||
(m->hostname)? m->hostname : inet_ntoa (m->host->ip), m->port);
|
||||
else
|
||||
addr = g_strdup_printf (PREFIX_MASTER "%s:%d",
|
||||
(m->hostname)? m->hostname : inet_ntoa (m->host->ip), m->port);
|
||||
|
||||
confstr = g_strjoin (" ", typeid, addr, m->name, NULL);
|
||||
g_free (addr);
|
||||
}
|
||||
|
@ -27,6 +27,7 @@
|
||||
#define FILENAME_SRVINFO "srvinfo"
|
||||
|
||||
#define PREFIX_MASTER "master://"
|
||||
#define PREFIX_GMASTER "gmaster://"
|
||||
#define PREFIX_URL_HTTP "http://"
|
||||
|
||||
#define ACTION_ADD "ADD"
|
||||
|
@ -90,7 +90,7 @@ void assemble_server_address (char *buf, int size, struct server *s) {
|
||||
static int server_clist_refresh_row (struct server *s, int row) {
|
||||
GdkPixmap *server_pixmap;
|
||||
GdkBitmap *server_pixmask;
|
||||
char *text[7];
|
||||
char *text[8];
|
||||
char buf1[256], buf2[32], buf3[32], buf4[32];
|
||||
char *retries;
|
||||
struct pixmap *retries_pix = NULL;
|
||||
@ -139,8 +139,9 @@ static int server_clist_refresh_row (struct server *s, int row) {
|
||||
g_snprintf (buf4, 32, "%d/%d", s->curplayers, s->maxplayers);
|
||||
text[4] = (!s->curplayers)? buf4 : NULL;
|
||||
|
||||
text[5] = (s->map)? s->map : NULL;
|
||||
text[5] = (s->map) ? s->map : NULL;
|
||||
text[6] = (s->game)? s->game : NULL;
|
||||
text[7] = (s->mod) ? s->mod : NULL;
|
||||
|
||||
if (row < 0) {
|
||||
row = gtk_clist_append (server_clist, text);
|
||||
|
@ -709,7 +709,11 @@ static struct stat_conn *stat_update_master_qstat (struct stat_job *job,
|
||||
g_snprintf (buf1, 64, "%d", maxretries + 2);
|
||||
|
||||
argv[argi++] = buf2;
|
||||
g_snprintf (buf2, 64, "%s,outfile", games[m->type].qstat_master_option);
|
||||
|
||||
if (m->master_type == 1)
|
||||
g_snprintf (buf2, 64, "-gsm,%s,outfile", games[m->type].qstat_str);
|
||||
else
|
||||
g_snprintf (buf2, 64, "%s,outfile", games[m->type].qstat_master_option);
|
||||
|
||||
argv[argi++] = buf3;
|
||||
g_snprintf (buf3, 64, "%s:%d,-", inet_ntoa (m->host->ip), m->port);
|
||||
|
22
xqf/src/xpm/sfs.xpm
Normal file
22
xqf/src/xpm/sfs.xpm
Normal file
@ -0,0 +1,22 @@
|
||||
/* XPM */
|
||||
static char * sfs_xpm[] = {
|
||||
"17 17 2 1",
|
||||
" c None",
|
||||
". c #000000",
|
||||
" .... ",
|
||||
" . ",
|
||||
" . ",
|
||||
" ... ",
|
||||
" . ",
|
||||
" . ",
|
||||
" .... ... ",
|
||||
" . . ",
|
||||
" . . ",
|
||||
" . . ",
|
||||
" ... ..... ",
|
||||
" . ",
|
||||
" . ",
|
||||
" ... ",
|
||||
" . ",
|
||||
" . ",
|
||||
" . "};
|
@ -38,21 +38,22 @@ GtkWidget *pane1_widget;
|
||||
GtkWidget *pane2_widget;
|
||||
GtkWidget *pane3_widget;
|
||||
|
||||
static struct clist_column server_columns[7] = {
|
||||
static struct clist_column server_columns[8] = {
|
||||
{ "Name", 180, GTK_JUSTIFY_LEFT, NULL },
|
||||
{ "Address", 140, GTK_JUSTIFY_LEFT, NULL },
|
||||
{ "Ping", 45, GTK_JUSTIFY_RIGHT, NULL },
|
||||
{ "TO", 35, GTK_JUSTIFY_RIGHT, NULL },
|
||||
{ "Players", 65, GTK_JUSTIFY_RIGHT, NULL },
|
||||
{ "Map", 55, GTK_JUSTIFY_LEFT, NULL },
|
||||
{ "Game", 55, GTK_JUSTIFY_LEFT, NULL }
|
||||
{ "Game", 55, GTK_JUSTIFY_LEFT, NULL },
|
||||
{ "MOD", 55, GTK_JUSTIFY_LEFT, NULL }
|
||||
};
|
||||
|
||||
struct clist_def server_clist_def = {
|
||||
CWIDGET_CLIST,
|
||||
"Server List",
|
||||
server_columns,
|
||||
7,
|
||||
8,
|
||||
GTK_SELECTION_EXTENDED,
|
||||
630, 270,
|
||||
SORT_SERVER_PING, GTK_SORT_ASCENDING
|
||||
|
@ -1367,6 +1367,9 @@ static void about_dialog (GtkWidget *widget, gpointer data) {
|
||||
"X11 Quake/QuakeWorld/Quake2/Quake3 Front-End\n"
|
||||
"Version " XQF_VERSION "\n\n"
|
||||
"Copyright (C) 1998-2000 Roman Pozlevich <roma@botik.ru>\n\n"
|
||||
"Mod & server version filter: Bill Adams <webmaster@evil.inetarena.com>\n"
|
||||
"SoF & GameSpy support: Alex Burger <alex@fragit.net>\n\n"
|
||||
|
||||
"http://www.linuxgames.com/xqf/");
|
||||
}
|
||||
|
||||
|
@ -49,6 +49,7 @@
|
||||
#define SN_DEFAULT_PORT 22450 /* Sin */
|
||||
#define HL_DEFAULT_PORT 27015 /* Half-Life */
|
||||
#define KP_DEFAULT_PORT 31510 /* Kingpin */
|
||||
#define SFS_DEFAULT_PORT 28910 /* Soldier of Fortune */
|
||||
#define HR_DEFAULT_PORT 28910 /* Heretic2 */
|
||||
#define UN_DEFAULT_PORT 7777 /* Unreal */
|
||||
|
||||
@ -85,6 +86,7 @@ enum server_type {
|
||||
SN_SERVER,
|
||||
HL_SERVER,
|
||||
KP_SERVER,
|
||||
SFS_SERVER,
|
||||
HR_SERVER,
|
||||
#ifdef QSTAT_HAS_UNREAL_SUPPORT
|
||||
UN_SERVER,
|
||||
@ -127,6 +129,7 @@ struct server {
|
||||
|
||||
char *name;
|
||||
char *map;
|
||||
char *mod;
|
||||
unsigned short maxplayers;
|
||||
unsigned short curplayers;
|
||||
short ping;
|
||||
@ -172,6 +175,8 @@ struct master {
|
||||
enum master_state state;
|
||||
|
||||
GSList *masters;
|
||||
|
||||
int master_type;
|
||||
};
|
||||
|
||||
extern time_t xqf_start_time;
|
||||
|
Loading…
x
Reference in New Issue
Block a user