With the current discussion of adding a map filter, I figured it would
be a good time to post this.
Back in November of last year I was working on improving the filters to
allow you to define filters based on the RULES section. My first
attempt was mentioned in this list. See:
http://sourceforge.net/mailarchive/message.php?msg_id=6639951
I got as far as having the filter working (not the best code - should be
using more Glib data structures etc) and just started on the GUI front
end. I think I basically completed the GUI in Glade, but I did not
finish the code for the edit boxes etc.
Here are a couple examples of what the filter would look like (first
line just describes it) in your ~/.qf/config file:
version contains the string 'linux'
1,true,version,=~,linux
map contains the string 'q2dm'
1,true,map,~=,q2dm
time limit is >5 and less than 30
1,true,timelimit,>,5,1,true,timelimit,<,30
I have not had the time to finish the filters, so I am posting the code
I have so far here, hoping someone else wants to take the time to clean
up the code and finish the GUI. Maybe I'll get to it some day, but
there's no point having is sitting on my computer when other people may
be able to finish it.
I'm not sure if the patch will even apply to the current CVS tree as I
have not tried since last November.
I have a .tgz file with both patch-xqf-rule-filter2 and my latest
patch-xqf-rule-filter3 patch. It looks like patch-xqf-rule-filter3
contains the start of the new GUI code. I have also included the Glade
file.
I was discussing the filters with Ludwig back in November. Here is part
of an email from myself to Ludwig describing the patch. The email was
based on patch-xqf-rule-filter2.
************
This version uses a single function 'logical_expression_check' to do the
logical comparisons. It is now used for the regular rules such as ping,
full, empty etc plus the 'rules' section.
The filter entry is still called 'rule' although it's not limited to
just the rules sections. I just have to rename it.
The new format of a filter contains 5 parts:
1) type of filter - 0=regular, 1=rule, 2=rule exists
2) true or false (NOT)
3) variable name
4) operator
5) value
If 1) is 0, then it's a 'regular' filter as in it's not based on the
rules section. This includes ping, server full, number of retries etc.
If 1) is 1, then it looks it up in the rules section. This is basically
what I did before without the 'required' part.
If 1) is 2, then it just checks to see if that rule exists. Example:
give me all servers that are running BW-Admin regardless of value.
2) If you want to 'NOT' the result, use 'false'. Otherwise, use 'true'
3) predefined variable name (ping, retries, players, full, empty,
cheats, password, game, game_type, map, server_name), or the variable
name in the rules section
4) operators:
numeric equals: ==
text equals: eq
text contains: ~=
greater than: >
greater or equal: >=
less than: <
less or equal: <=
Obviously if you compare 3.20 with 3.2 using 'eq', it will be false.
If you use ==, it will be true.
Here are some examples of filter entries.
An example of my filter 4:
4/filter_name=Rule Test
4/rule=0,true,ping,<,9999
Other examples:
ping is less than 9999:
0,true,ping,<,9999
ping is not greater than 100:
0,false,ping,>,100
ping is not greater than 100:
0,true,ping,<=,100
number of retries is less than 2:
0,true,retries,<,2
server is not full:
0,false,full,0,0
server is full:
0,true,full,0,0
server is not empty:
0,false,empty,0,0
server is empty:
0,true,empty,0,0
cheats are not allowed:
0,false,cheats,0,0
cheats ARE allowed:
0,true,cheats,0,0
password is not required:
0,false,password,0,0
password IS required:
0,true,password,0,0
game contains the string 'battle'
0,true,game,=~,action
game IS 'battle'
0,true,game,eq,battle
game type contains the string 'osp'
0,true,gametype,=~,osp
version contains the string 'linux'
1,true,version,=~,linux
version is 3.21:
1,true,version,==,3.21
version is 3.20 or higher:
1,true,version,>=,3.20
(note: atoi is used on the version string, which could be for example:
3.21 x86 Oct 16.... atoi pulls out 3.21 and stops which is why this
works)
map contains the string 'q2dm'
1,true,map,~=,q2dm
server name does NOT contains the string 'clan':
0,false,server_name,=~,clan
time limit is >5 and less than 30
1,true,timelimit,>,5,1,true,timelimit,<,30
Notes:
-when I say 'filter' below, I am referring to the above defined filters
(0,false,server_name,=~,clan), NOT the filter definition (such as Rule
Test)
-this patch disables all the other filters that can be defined in the
the filter edit menu except for the country filter
-if you edit a filter in the GUI, it will erase your hand-made filters -
so don't use the GUI
-all the existing filters seem to fit nicely (in the GUI), except the
country filter which is why I didn't touch it
-you can combine multiple (up to 10) of these filters on one line
-the code still uses a not very good method of storing the filters in
memory. I haven't tried using over 10, so don't bother trying yourself
-all filters are basically 'ANDed' together, which means you can't look
for 'all servers with a port of 27910' and 'all servers without a port
defined' as you could with my previous patch. They would cancel each
other out.
-A new 'language' of some sort would still be nice to allow grouping
using (), AND, OR etc. What I have done 'should' be able to fit into
that by adding the logic parser to 'server_pass_filter' and moving the
current 'server_pass_filter' to a new function. It's not something I
indend to work on right now.
-Some filters such as game and gametype could be done using a 'rule'
type filter instead of a regular filter. The reason I kept a 'regular'
filter is so that it compares against s->game which matches the Game
column. Each game is different, so matching the Game column is best.
(For Quake2, s->game is the same as the 'gamename'. For UT, the Game
column is the 'gametype' rule)
The same applies for the cheats filter. You could just look for cheats'
in the rules, but some games may use different variable names to
represent cheats.
This keeps the 'regular' filters easy for users to use.
-The logical_expression_check function expects everything in strings, so
it's not the most efficient way when passing existing integers. For
example, ping converts the integer to a string, and then passes it to
logical_expression_check. I'm not sure if this really matters, but
trying to have two 'logical_expression_check' type functions depending
on the type of value being passed would be a pain.
************
Here are some other discussions between Ludwig and I that should be
considered:
=============
Alex:
-this patch disables all the other filters that can be defined in the
the filter edit menu except for the country filter
Ludwig:
I wouldn't disable all. It's faster to just click "not full". If the
user clicked something in the "easy" dialog, those settings should take
precendence over the more complex filters.
=============
Alex:
-Some filters such as game and gametype could be done using a 'rule'
type filter instead of a regular filter. The reason I kept a 'regular'
filter is so that it compares against s->game which matches the Game
column. Each game is different, so matching the Game column is best.
(For Quake2, s->game is the same as the 'gamename'. For UT, the Game
column is the 'gametype' rule)
The same applies for the cheats filter. You could just look for
'cheats' in the rules, but some games may use different variable names
to represent cheats.
This keeps the 'regular' filters easy for users to use.
Ludwig:
Good.
=============
Alex:
+ /* Filter for custom rule */
+ if( filter->rule && *filter->rule)
+ {
+ //printf("RULE!!\n");
Ludwig:
-you may use debug(0,"foo") instead. debug() displays file, function
and line.
=============
Alex:
+ char* rule_copy = g_strdup(filter->rule);
+ static const char delim[] = ",\n\r";
+ int match = 0;
+
+ char* rules[50];
+ int num = 0;
+ int i;
+ char buf[10];
+
+ char *type = NULL;
+ char *truefalse = NULL;
+ char *varname = NULL;
+ char *operator = NULL;
+ char *value = NULL;
+
+ rules[num++] = strtok(rule_copy, delim);
Ludwig:
use g_strsplit
=============
Alex:
+int logical_expression_check (const char *truefalse, const char *left,
const char *operator, const char *right)
+{
+ int match = 0;
+
+ if (!truefalse || !left || !operator || !right)
+ return FALSE;
+
+ //printf("logical_expression_check: %s %s %s\n", left, operator, right);
+
+ if(strcasecmp( operator ,"eq") == 0){
+ //printf("Rule: eq\n");
+ if(strcasecmp( left, right ) == 0){
+ match = 1; // Found!
+ }
Ludwig:
operator should be an enum, then you can use switch(operator) {...}.
String compares are expensive.
=============
Alex:
+}
+
/*
- This applies a filter's attributes to a server entry and returns true
if it
- passes the filter or false if not.
+ This applies a filter's attributes to a server entry and returns TRUE
if it
+ passes the filter or FALSE if not.
*/
static int server_pass_filter (struct server *s){
[...]
+
+ adv_filter = g_strsplit(adv_filter_copy, delim, 0);
Ludwig:
Parse the string when reading the config file. Doing that here is
extremely expensive, the function is called (multiple times) for
each server. Remember Half-Life has >30000 servers! See below.
+ /* A regular 'easy' filter based on pre-defined variable names */
+ if (strcmp (type, "0") == 0)
^ enum
+ {
+ if (strcasecmp (varname, "ping") ==0) {
^^^^ enum
=============
Alex:
@@ -460,6 +717,24 @@
filter->game_type = config_get_string("game_type");
filter->map_contains =
config_get_string("map_contains");
filter->server_name_contains =
config_get_string("server_name_contains");
+
+ /* Advanced filters */
+ char buf[30];
+ int j=1;
+
+ while(1) {
+ snprintf( buf, 30, "%d/advanced", j);
Ludwig:
maybe "rule%d" instead? start j at zero. Parse the string you get
here directly into a struct to speed up processing in
server_pass_filter. e.g:
enum { RF_EQ, RF_STREQ, RF_LT, ... , RF_EXISTS } server_rule_filter_op;
enum { RF_RULE, RF_PING, RF_PLAYERS, RF_MAP, ... } server_rule_filter_type;
struct server_rule_filter
{
server_rule_filter_type type;
gboolean negate;
const char* key; // only used with RF_RULE
server_rule_filter_op op;
const char* value; // not honored by RF_EXISTS
};
=============
Alex

On Wed, 2004-07-21 at 00:05, Ludwig Nussel wrote:
> You don't need to put it into an archive. It's easier without.
35K vs 6K .. its smaller ;)
> Map names in xqf are always lowercase.
But not always the inputs are lowercase, so somewhere needs to be some
conversion. And I just took the code-samples from other "compares".
> The filter dialog is incredibly huge with the additional list boxes.
Thats one reason I went for having a separate map-filter in the
beginning.
> I don't see the benefit of that, looks like overkill to me. What
> about allowing to specify multiple maps in the simple textentry that
> is already there? One could enter maps separated by e.g. space.
Mhmm.. Some maps have spaces in the name (e.g. Americas Army). That
would force the user to use a different char, and that is non-intuitive
(but still valid solution). But maybe one could resize the listboxes to
just one or two entries per box?
The "map contains NOT"-filter I would like to leave in place, since that
way one can filter out special map-types ("Pipeline" - "Pipeline SF",
"Bridge SE", etc.. (from AAO again)).
Good night - HPJ
--=20
no gods, no masters
Jabber: Weasel75@... (ICQ: 15733915)
HomePa: http://www.cs.tu-berlin.de/~hanspete
GPGkey: http://www.cs.tu-berlin.de/~hanspete/pubkey_gmx.asc

Hans-Peter Jacobs wrote:
> Patch attached.
You don't need to put it into an archive. It's easier without.
> Its the filter.c and filter.h. The stats.c-file was modified too and I
> marked the 2 lines with a "TODO" (since I dont know what to do there).
> Will removal of this 2 lines decrease "qstat"s performance?
That's the server side filter of the Half-Life master. I doubt it
supports more than just a single map name.
> Its now all back in one filter (server_filter), just two list-boxes,
> nothing fancy. Matches are done via "lowcasestrstr".
Map names in xqf are always lowercase.
> The maps are stored with "|" separated. Old config-files can be read
> ("map_contains" is still used, but now it can store multiple maps).
>
> Small optical adjustments were necessary in the filter-config
> notebook/menu.
The filter dialog is incredibly huge with the additional list boxes.
I don't see the benefit of that, looks like overkill to me. What
about allowing to specify multiple maps in the simple textentry that
is already there? One could enter maps separated by e.g. space.
cu
Ludwig
--
(o_ Ludwig.Nussel@...
//\ PGP Key ID: FF8135CE
V_/_ ICQ: 52166811

On Mon, 2004-07-19 at 20:48, Ludwig Nussel wrote:=20
> > The MAP-Filter got a separate menu/button, so it works in combination
> > with any other filters.
>=20
> Sounds all overly complicated. Why should there be an extra map
> filter in addition to the normal server filter? What about just
> extending the existing map filter entry with regexp support?
Would do fine with regexp. Two things:
1.) regexp is *not* userfriendly (please consider, that not all
Linux-users hack kernels in spare-time ;) ).
2.) A seperate filter for maps/map-sets reduces the total number of
filters. One filter selects the servers, the second filter can be used
to check maps/map-sets independently of the server-filter.
> 'code cleanup' increases the size of the diff. Don't do that if you
> want to get a new feature in.
Na.. its not clean ;) Rather a try to separate filters from each other.
But since that causes problems with the translation-files (work that
would have to be redone), I'll put it back into one file :)
Cheers - HPJ
--=20
no gods, no masters
Jabber: Weasel75@... (ICQ: 15733915)
HomePa: http://www.cs.tu-berlin.de/~hanspete
GPGkey: http://www.cs.tu-berlin.de/~hanspete/pubkey_gmx.asc

Hans-Peter Jacobs wrote:
> It took some time and now its done (but still problems): the
> maplist-filter.
>
> At the moment it contains:
> 2 single entries for partial matches (substr) of mapname (one for IN,
> one entry for OUT)
> 2 lists for exact matches of mapnames (one list for IN, one for OUT)
>
> The filter-process is simple:
> 1. If a server's map is matched in "substr" out-entry or in exact
> out-list, then the server is filtered out.
> 2. If there is no "substr" in-entry and no exact matching IN-list set,
> then the map is IN (not filtered out).
> If there is at least one of the 2 IN-entries set, the server's map has
> to match .. or it will be filtered out.
>
>
> The MAP-Filter got a separate menu/button, so it works in combination
> with any other filters.
Sounds all overly complicated. Why should there be an extra map
filter in addition to the normal server filter? What about just
extending the existing map filter entry with regexp support?
> Problem: the "dot" for the selected map-filter is not set correct. I do
> not understand the xqf-source in detail, so I hope that someone can help
> me there ......
>
> Greetings HPJ - aka weasel75@...
>
> PS: code.whereTo(??)
cvs diff -u | mail -s 'PATCH: mapfilter' xqf-developer@...
> PPS: I tried to move all the server-filter code from filter.c to
> filter_server.c since the filter_map is just one step, filter_servervar
> might follow some day ;)
'code cleanup' increases the size of the diff. Don't do that if you
want to get a new feature in.
cu
Ludwig
--
(o_ Ludwig.Nussel@...
//\ PGP Key ID: FF8135CE
V_/_ ICQ: 52166811

Hello!
It took some time and now its done (but still problems): the
maplist-filter.
At the moment it contains:
2 single entries for partial matches (substr) of mapname (one for IN,
one entry for OUT)
2 lists for exact matches of mapnames (one list for IN, one for OUT)
The filter-process is simple:
1. If a server's map is matched in "substr" out-entry or in exact
out-list, then the server is filtered out.
2. If there is no "substr" in-entry and no exact matching IN-list set,
then the map is IN (not filtered out).
If there is at least one of the 2 IN-entries set, the server's map has
to match .. or it will be filtered out.
The MAP-Filter got a separate menu/button, so it works in combination
with any other filters.
Problem: the "dot" for the selected map-filter is not set correct. I do
not understand the xqf-source in detail, so I hope that someone can help
me there ......
Greetings HPJ - aka weasel75@...
PS: code.whereTo(??)
PPS: I tried to move all the server-filter code from filter.c to
filter_server.c since the filter_map is just one step, filter_servervar
might follow some day ;)
--=20
no gods, no masters
Jabber: Weasel75@... (ICQ: 15733915)
HomePa: http://www.cs.tu-berlin.de/~hanspete
GPGkey: http://www.cs.tu-berlin.de/~hanspete/pubkey_gmx.asc

Ruediger Meier wrote:
> Ive noticed that xqf-0.9.14/GeoIP-1.3.1 doesnt show the right geographical
> location for some servers.
> Because the automatical database-update via "geoipupdate" doesnt wok for
> non-subscribers Ive updated GeoIP to version 1.3.5. Now all is fine.
>
> So maybe its a good idea to provide the new GeoIP-version on xqf-Homepage?!
Thanks for the tip. I'll upload the new version with the next xqf
release. In the meantime people can just update GeoIP.dat which is
available separately at
http://www.maxmind.com/download/geoip/database/
> You can download the sources here
> http://www.maxmind.com/download/geoip/api/c/
>
> If you are intersted - Ive built rpm-packages for SuSE-9.1
I build the rpms available via the xqf homepage on 8.1. Building on
newer releases would make xqf depend on glibc 2.3.
cu
Ludwig
--
(o_ Ludwig.Nussel@...
//\ PGP Key ID: FF8135CE
V_/_ ICQ: 52166811

Ludwig, how far are we from releasing .15?
The Russian translator asked me on IRC last night, as he's waiting for
the Russian translation to appear in the package officially.
Jordi
--=20
Jordi Mallach P=E9rez -- Debian developer http://www.debian.org/
jordi@... jordi@... http://www.sindominio.net/
GnuPG public key information available at http://oskuro.net/~jordi/

Hi,
Ive noticed that xqf-0.9.14/GeoIP-1.3.1 doesnt show the right geographical
location for some servers.
Because the automatical database-update via "geoipupdate" doesnt wok for
non-subscribers Ive updated GeoIP to version 1.3.5. Now all is fine.
So maybe its a good idea to provide the new GeoIP-version on xqf-Homepage?!
You can download the sources here
http://www.maxmind.com/download/geoip/api/c/
If you are intersted - Ive built rpm-packages for SuSE-9.1
Last but not least I want to say thanks for xqf!! I wont miss it anymore!
cu
Rudi