mirror of
https://github.com/nzp-team/fteqw.git
synced 2024-11-22 20:11:44 +00:00
46c63cbedb
device ids with rawinput and xinput are now assigned only on the first event. this means the ordering is easily controllable, thus helping splitscreen usability. fix compile errors with the nolegacy builds. client updates "chat" userinfo to match ezquake. does not display them still. server now forwards them correctly for ezquake. android can now switch gles version. a bit crashy with it though. android: gyroscope is now available to csqc. android: added vid_dpi_x/y cvars. will be 0 on other platforms, for now. added screenshot_vr command, for 360-degree stereoscopic screenshots. fix a potential crash from frag parsing. added m_accel_style and friends, for nicer mouse acceleration. fixed const-correctness in a few places. added friendly spectate button to the server browser display a warning if an mdl has dodgy seam values. this won't affect fte, but can crash winquake. qcc: fix struct fields to at least appear to work. qcc: -I is finally implemented. qccgui: options now has tooltips, so people might have a chance of actually figuring out what each option does. menusys: game configs menu now scans for files rather than listing specific ones. should probably be tested more. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4998 fc73d0e0-1445-4013-8a0c-d673dee63da5
411 lines
No EOL
14 KiB
C++
411 lines
No EOL
14 KiB
C++
//very very basic server browser.
|
|
//this was written as an example for the api, rather than a truely usable server browser.
|
|
|
|
//WARNING: make sure you only create one server browser widgit otherwise they'll fight each other
|
|
|
|
#ifndef MOD_GAMEDIR
|
|
//look up what its meant to be.
|
|
//#define MOD_GAMEDIR cvar_string("game")
|
|
#endif
|
|
|
|
#include "../menusys/mitem_menu.qc" //subwindow
|
|
|
|
var float autocvar_sb_shownumplayers = 1;
|
|
var float autocvar_sb_showmaxplayers = 0;
|
|
var float autocvar_sb_showfraglimit = 0;
|
|
var float autocvar_sb_showtimelimit = 0;
|
|
var float autocvar_sb_showping = 1;
|
|
var float autocvar_sb_showgamedir = 0;
|
|
var float autocvar_sb_showaddress = 0;
|
|
var float autocvar_sb_showmap = 1;
|
|
var float autocvar_sb_showname = 1;
|
|
|
|
//#define COLUMN(width, sortname, title, draw)
|
|
#define COLUMN_NUMPLAYERS COLUMN(2*8, numplayers, "Pl", ui.drawstring(pos, sprintf("%-2g", gethostcachenumber(field_numplayers, sv)), '8 8', col, 1, 0);)
|
|
#define COLUMN_MAXPLAYERS COLUMN(2*8, maxplayers, "MP", ui.drawstring(pos, sprintf("%-2g", gethostcachenumber(field_maxplayers, sv)), '8 8', col, 1, 0);)
|
|
#define COLUMN_PING COLUMN(4*8, ping, "Ping", ui.drawstring(pos, sprintf("%-4g", gethostcachenumber(field_ping, sv)), '8 8', col, 1, 0);)
|
|
#define COLUMN_FRAGLIMIT COLUMN(4*8, fraglimit, "FL", ui.drawstring(pos, sprintf("%-3g", gethostcachenumber(field_fraglimit, sv)), '8 8', col, 1, 0);)
|
|
#define COLUMN_TIMELIMIT COLUMN(4*8, timelimit, "TL", ui.drawstring(pos, sprintf("%-3g", gethostcachenumber(field_timelimit, sv)), '8 8', col, 1, 0);)
|
|
#define COLUMN_GAMEDIR COLUMN(8*8, gamedir, "Gamedir", ui.drawstring(pos, sprintf("%-.8s", gethostcachestring(field_gamedir, sv)), '8 8', col, 1, 0);)
|
|
#define COLUMN_ADDRESS COLUMN(16*8, address, "Address", ui.drawstring(pos, sprintf("%-.16s", gethostcachestring(field_address, sv)), '8 8', col, 1, 0);)
|
|
#define COLUMN_MAP COLUMN(8*8, map, "Map", ui.drawstring(pos, sprintf("%-.8s", gethostcachestring(field_map, sv)), '8 8', col, 1, 0);)
|
|
#define COLUMN_HOSTNAME COLUMN(64*8, name, "Name", ui.drawstring(pos, sprintf("%s", gethostcachestring(field_name, sv)), '8 8', col, 1, 0);)
|
|
//FIXME: add a little * icon before the hostname for favourites or something
|
|
|
|
#define COLUMNS COLUMN_NUMPLAYERS COLUMN_MAXPLAYERS COLUMN_PING COLUMN_FRAGLIMIT COLUMN_TIMELIMIT COLUMN_GAMEDIR COLUMN_ADDRESS COLUMN_MAP COLUMN_HOSTNAME
|
|
|
|
class mitem_servers : mitem
|
|
{
|
|
float server_selected;
|
|
mitem_vslider slider;
|
|
float dbltime;
|
|
float dobound;
|
|
|
|
void() mitem_servers =
|
|
{
|
|
dbltime = cltime - 10;
|
|
this.item_flags |= IF_SELECTABLE;
|
|
server_selected = -1;
|
|
|
|
//clear the filter
|
|
resethostcachemasks();
|
|
#ifdef MOD_GAMEDIR
|
|
if (MOD_GAMEDIR != "")
|
|
{
|
|
//constrain the list to only servers with the right gamedir.
|
|
sethostcachemaskstring(0, gethostcacheindexforkey("gamedir"), MOD_GAMEDIR, SLIST_TEST_EQUAL);
|
|
}
|
|
#endif
|
|
//sort by ping by default
|
|
sethostcachesort(gethostcacheindexforkey("ping"), FALSE);
|
|
//(re)query the servers.
|
|
refreshhostcache();
|
|
|
|
resorthostcache();
|
|
};
|
|
|
|
virtual void(vector pos) item_draw =
|
|
{
|
|
local float sv, maxsv = gethostcachevalue(SLIST_HOSTCACHEVIEWCOUNT);
|
|
local float maxy = self.item_size_y;
|
|
float left = pos_x;
|
|
|
|
local vector omin = ui.drawrectmin, omax = ui.drawrectmax;
|
|
local vector cmin = pos + '0 8', cmax = pos + item_size;
|
|
|
|
cmin_x = max(omin_x, cmin_x);
|
|
cmin_y = max(omin_y, cmin_y);
|
|
cmax_x = min(omax_x, cmax_x);
|
|
cmax_y = min(omax_y, cmax_y);
|
|
|
|
slider.maxv = maxsv - (floor(maxy/8) - 1);
|
|
|
|
//constrain the view the lazy way.
|
|
if (dobound)
|
|
{
|
|
dobound = FALSE;
|
|
if (slider.val < 0)
|
|
slider.val = 0;
|
|
while (slider.val + floor(maxy/8) - 1 <= server_selected)
|
|
slider.val+=1;
|
|
while (server_selected < slider.val && slider.val > 0)
|
|
slider.val-=1;
|
|
}
|
|
|
|
float field_name = gethostcacheindexforkey("name");
|
|
float field_ping = gethostcacheindexforkey("ping");
|
|
float field_numplayers = gethostcacheindexforkey("numhumans");
|
|
if (field_numplayers < 0)
|
|
field_numplayers = gethostcacheindexforkey("numplayers");
|
|
float field_maxplayers = gethostcacheindexforkey("maxplayers");
|
|
float field_gamedir = gethostcacheindexforkey("gamedir");
|
|
if (field_gamedir < 0)
|
|
field_gamedir = gethostcacheindexforkey("mod");
|
|
float field_address = gethostcacheindexforkey("cname");
|
|
float field_map = gethostcacheindexforkey("map");
|
|
float field_timelimit = gethostcacheindexforkey("timelimit");
|
|
float field_fraglimit = gethostcacheindexforkey("fraglimit");
|
|
|
|
maxy = ceil(maxy/8) - 1;
|
|
if (maxsv > slider.val + maxy)
|
|
maxsv = slider.val + maxy;
|
|
|
|
float sort = gethostcachevalue(SLIST_SORTFIELD);
|
|
string colkey;
|
|
#define COLUMN(width, sortname, title, draw) if (autocvar_sb_show##sortname) {if (ui.mousepos[0] > pos_x && ui.mousepos[1] < pos_y+8) colkey = #sortname; pos_x += width+8;}
|
|
COLUMNS
|
|
#undef COLUMN
|
|
|
|
vector col;
|
|
pos_x = left;
|
|
#define COLUMN(width, sortname, title, draw) if (autocvar_sb_show##sortname) {col = '1 1 1'; if (sort == field_##sortname) col_z = 0; if (colkey == #sortname) col_x = 0; ui.drawstring(pos, title, '8 8', col, 1, 0); pos_x += width+8;}
|
|
COLUMNS
|
|
#undef COLUMN
|
|
|
|
//make sure things get cut off if we have too many rows (or fractional start)
|
|
ui.setcliparea(cmin[0], cmin[1], cmax[0] - cmin[0], cmax[1] - cmin[1]);
|
|
|
|
pos_y += 8 * (1-(slider.val-floor(slider.val)));
|
|
for (float y=pos_y, sv = max(0, floor(slider.val)); sv < maxsv; sv+=1)
|
|
{
|
|
col = (sv&1)?'0.1 0.1 0.1':'0.15 0.1 0.05';
|
|
drawfill([left, y], [item_size_x,8], col, 0.8, 0);
|
|
y += 8;
|
|
}
|
|
for ( sv = max(0, floor(slider.val)); sv < maxsv; sv+=1)
|
|
{
|
|
col = ((server_selected==sv)?'1 1 0':'1 1 1');
|
|
|
|
//if isproxy
|
|
//if islocal
|
|
//if isfavorite
|
|
|
|
pos_x = left;
|
|
#define COLUMN(width, sortname, title, draw) if (autocvar_sb_show##sortname) {draw pos_x += width+8; }
|
|
COLUMNS
|
|
#undef COLUMN
|
|
pos_y += 8;
|
|
}
|
|
|
|
ui.setcliparea(omin_x, omin_y, omax_x - omin_x, omax_y - omin_y);
|
|
};
|
|
virtual float(vector pos, float scan, float char, float down) item_keypress =
|
|
{
|
|
float displaysize;
|
|
string addr;
|
|
/*just sink all inputs*/
|
|
if (!down)
|
|
return FALSE;
|
|
if (scan != K_MOUSE1)
|
|
dbltime = cltime - 10;
|
|
if (scan == K_MOUSE1)
|
|
{
|
|
float news = ui.mousepos[1] - (pos_y+8);
|
|
news = floor(news / 8);
|
|
if (news == -1)
|
|
{
|
|
string colkey = "";
|
|
#define COLUMN(width, sortname, title, draw) if (autocvar_sb_show##sortname) {if (ui.mousepos[0] > pos_x) colkey = #sortname; pos_x += width+8;}
|
|
COLUMNS
|
|
#undef COLUMN
|
|
if (colkey != "")
|
|
{
|
|
float fld = gethostcacheindexforkey(colkey);
|
|
if (colkey == "numplayers")
|
|
{
|
|
//favour descending order
|
|
sethostcachesort(fld, (gethostcachevalue(SLIST_SORTFIELD) != fld) || !gethostcachevalue(SLIST_SORTDESCENDING));
|
|
}
|
|
else
|
|
{
|
|
//favour ascending order
|
|
sethostcachesort(fld, (gethostcachevalue(SLIST_SORTFIELD) == fld) && !gethostcachevalue(SLIST_SORTDESCENDING));
|
|
}
|
|
resorthostcache(); //tell the engine that its okay to resort everything.
|
|
dobound = TRUE;
|
|
}
|
|
}
|
|
if (news < 0 || news >= gethostcachevalue(SLIST_HOSTCACHEVIEWCOUNT))
|
|
return FALSE;
|
|
|
|
news += floor(slider.val);
|
|
|
|
if (server_selected == news && dbltime > cltime)
|
|
{
|
|
//connect on double clicks. because we can.
|
|
addr = gethostcachestring(gethostcacheindexforkey("cname"), server_selected);
|
|
if (addr)
|
|
localcmd(sprintf("m_pop;connect \"%s\"\n", addr));
|
|
}
|
|
else
|
|
server_selected = news;
|
|
dobound = TRUE;
|
|
|
|
dbltime = cltime + 0.5;
|
|
}
|
|
else if (scan == K_ENTER)
|
|
{ //connect normally
|
|
addr = gethostcachestring(gethostcacheindexforkey("cname"), server_selected);
|
|
if (addr)
|
|
localcmd(sprintf("m_pop;connect \"%s\"\n", addr));
|
|
}
|
|
else if (scan == 's')
|
|
{ //s = join as a spectator
|
|
addr = gethostcachestring(gethostcacheindexforkey("cname"), server_selected);
|
|
if (addr)
|
|
localcmd(sprintf("m_pop;observe \"%s\"\n", addr));
|
|
}
|
|
else if (scan == 'j')
|
|
{ //s = join as a spectator
|
|
addr = gethostcachestring(gethostcacheindexforkey("cname"), server_selected);
|
|
if (addr)
|
|
localcmd(sprintf("m_pop;join \"%s\"\n", addr));
|
|
}
|
|
else if (scan == K_UPARROW || scan == K_MWHEELUP)
|
|
{
|
|
this.server_selected -= 1;
|
|
if (this.server_selected < 0)
|
|
{
|
|
this.server_selected = gethostcachevalue(SLIST_HOSTCACHEVIEWCOUNT);
|
|
if (this.server_selected)
|
|
this.server_selected -= 1;
|
|
}
|
|
dobound = TRUE;
|
|
}
|
|
else if (scan == K_DOWNARROW || scan == K_MWHEELDOWN)
|
|
{
|
|
this.server_selected += 1;
|
|
if (this.server_selected >= gethostcachevalue(SLIST_HOSTCACHEVIEWCOUNT))
|
|
this.server_selected = 0;
|
|
dobound = TRUE;
|
|
}
|
|
else if (scan == K_PGUP)
|
|
{
|
|
displaysize = (item_size[1]-8)/(8); //this many rows
|
|
displaysize = floor(displaysize*0.5);
|
|
if (displaysize < 1)
|
|
displaysize = 1;
|
|
this.server_selected -= displaysize ;
|
|
if (this.server_selected < 0)
|
|
this.server_selected = 0;
|
|
dobound = TRUE;
|
|
}
|
|
else if (scan == K_PGDN)
|
|
{
|
|
displaysize = (item_size[1]-8)/(8); //this many rows
|
|
displaysize = floor(displaysize*0.5);
|
|
if (displaysize < 1)
|
|
displaysize = 1;
|
|
this.server_selected += displaysize;
|
|
if (this.server_selected >= gethostcachevalue(SLIST_HOSTCACHEVIEWCOUNT))
|
|
this.server_selected = gethostcachevalue(SLIST_HOSTCACHEVIEWCOUNT)-1;
|
|
dobound = TRUE;
|
|
}
|
|
else if (scan == K_HOME)
|
|
{
|
|
this.server_selected = 0;
|
|
dobound = TRUE;
|
|
}
|
|
else if (scan == K_END)
|
|
{
|
|
this.server_selected = gethostcachevalue(SLIST_HOSTCACHEVIEWCOUNT)-1;
|
|
if (this.server_selected < 0)
|
|
this.server_selected = 0;
|
|
dobound = TRUE;
|
|
}
|
|
else if (char == 'r' || char == 'R' || scan == K_F5)
|
|
{
|
|
refreshhostcache();
|
|
resorthostcache();
|
|
}
|
|
else
|
|
return FALSE;
|
|
return TRUE;
|
|
};
|
|
};
|
|
|
|
class mitem_servers_players : mitem
|
|
{
|
|
mitem_servers listing;
|
|
|
|
void() mitem_servers_players =
|
|
{
|
|
// this.item_flags |= IF_SELECTABLE;
|
|
};
|
|
|
|
virtual void(vector pos) item_draw =
|
|
{
|
|
float player;
|
|
float y;
|
|
float m;
|
|
vector opos = pos;
|
|
if (listing.server_selected < 0)
|
|
return;
|
|
for (player = 0, y = 0; player < 256; player++)
|
|
{
|
|
string playerinfo = gethostcachestring(gethostcacheindexforkey(sprintf("player%g", player)), listing.server_selected);
|
|
if (!playerinfo)
|
|
break;
|
|
tokenize(playerinfo);
|
|
float userid = stof(argv(0));
|
|
float frags = stof(argv(1));
|
|
float ontime = stof(argv(2));
|
|
float ping = stof(argv(3));
|
|
string name = argv(4);
|
|
string skin = argv(5);
|
|
vector top = stov(argv(6));
|
|
vector bot = stov(argv(7));
|
|
|
|
drawfill(pos, '16 4', top, 1, 0);
|
|
drawfill(pos+'0 4 0', '16 4', bot, 1, 0);
|
|
drawstring(pos, sprintf("%g", frags), '8 8', '1 1 1', 1, 0);
|
|
drawstring(pos+'20 0', name, '8 8', '1 1 1', 1, 0);
|
|
pos_y += 8;
|
|
if (++y == 8)
|
|
{
|
|
y-= 8;
|
|
pos_y = opos_y;
|
|
pos_x += 16*8;
|
|
}
|
|
}
|
|
|
|
if (y)
|
|
{
|
|
pos_y = opos_y;
|
|
pos_x += 16*6;
|
|
y = 0;
|
|
}
|
|
// drawtextfield(opos, item_size, 3, gethostcachestring(gethostcacheindexforkey("serverinfo"), listing.server_selected));
|
|
m = tokenizebyseparator(gethostcachestring(gethostcacheindexforkey("serverinfo"), listing.server_selected), "\\");
|
|
for(player = 1; player <= m; player += 2)
|
|
{
|
|
drawtextfield(pos, '64 8', 6, argv(player));
|
|
drawtextfield(pos+'68 0', [32*8-40, 8], 3, argv(player+1));
|
|
|
|
pos_y += 8;
|
|
if (++y == 8)
|
|
{
|
|
y-= 8;
|
|
pos_y -= 8*8;
|
|
pos_x += 32*8;
|
|
}
|
|
}
|
|
};
|
|
};
|
|
|
|
|
|
nonstatic void(mitem_desktop desktop) M_Servers =
|
|
{
|
|
mitem_menu o;
|
|
|
|
if (assumefalsecheckcommand("menu_servers") && argv(1) != "force")
|
|
{
|
|
localcmd("menu_servers\n");
|
|
return;
|
|
}
|
|
|
|
#ifdef CSQC
|
|
if not (checkextension("FTE_CSQC_SERVERBROWSER"))
|
|
{
|
|
print(_("Sorry, your client does not support FTE_CSQC_SERVERBROWSER\n"));
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
o = (mitem_menu)desktop.findchildtext(_("Servers List"));
|
|
if (o)
|
|
o.totop();
|
|
else
|
|
{
|
|
#if 1
|
|
mitem_exmenu m;
|
|
m = spawn(mitem_exmenu, item_text:_("Options"), item_flags:IF_SELECTABLE, item_command:"m_main");
|
|
desktop.add(m, RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_PARENT_MAX, '0 0', '0 0');
|
|
desktop.item_focuschange(m, IF_KFOCUSED);
|
|
m.totop();
|
|
#else
|
|
mitem_menu m;
|
|
m = menu_spawn(desktop, _("Servers List"), '320 200');
|
|
m.item_command = "m_main";
|
|
m.item_flags |= IF_RESIZABLE;
|
|
desktop.item_focuschange(m, IF_KFOCUSED);
|
|
m.totop();
|
|
#endif
|
|
|
|
mitem_vslider sl = spawn(mitem_vslider, stride:4, item_flags:IF_SELECTABLE);
|
|
mitem_servers ls = spawn(mitem_servers, slider:sl);
|
|
|
|
m.add(ls, RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_PARENT_MAX, '0 0', '-16 -68');
|
|
m.add(spawn(mitem_servers_players, listing:ls), RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MAX | RS_X_MAX_PARENT_MAX|RS_Y_MAX_PARENT_MAX, [8*20, -8*8], [0, -8*0]);
|
|
m.add(sl, RS_X_MIN_PARENT_MAX|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_PARENT_MAX, [-16, 8], [0, -68]);
|
|
|
|
m.add(menuitemcheck_spawn(_("Ping"), "sb_showping", [8*8, 8]), RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MAX | RS_X_MAX_PARENT_MIN|RS_Y_MAX_PARENT_MAX, [0, -8*8], [8*20, -8*7]);
|
|
m.add(menuitemcheck_spawn(_("Address"), "sb_showaddress", [8*8, 8]), RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MAX | RS_X_MAX_PARENT_MIN|RS_Y_MAX_PARENT_MAX, [0, -8*7], [8*20, -8*6]);
|
|
m.add(menuitemcheck_spawn(_("Map"), "sb_showmap", [8*8, 8]), RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MAX | RS_X_MAX_PARENT_MIN|RS_Y_MAX_PARENT_MAX, [0, -8*6], [8*20, -8*5]);
|
|
m.add(menuitemcheck_spawn(_("Gamedir"), "sb_showgamedir", [8*8, 8]), RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MAX | RS_X_MAX_PARENT_MIN|RS_Y_MAX_PARENT_MAX, [0, -8*5], [8*20, -8*4]);
|
|
m.add(menuitemcheck_spawn(_("NumPlayers"), "sb_shownumplayers", [8*8, 8]), RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MAX | RS_X_MAX_PARENT_MIN|RS_Y_MAX_PARENT_MAX, [0, -8*4], [8*20, -8*3]);
|
|
m.add(menuitemcheck_spawn(_("MaxPlayers"), "sb_showmaxplayers", [8*8, 8]), RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MAX | RS_X_MAX_PARENT_MIN|RS_Y_MAX_PARENT_MAX, [0, -8*3], [8*20, -8*2]);
|
|
m.add(menuitemcheck_spawn(_("Fraglimit"), "sb_showfraglimit", [8*8, 8]), RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MAX | RS_X_MAX_PARENT_MIN|RS_Y_MAX_PARENT_MAX, [0, -8*2], [8*20, -8*1]);
|
|
m.add(menuitemcheck_spawn(_("Timelimit"), "sb_showtimelimit", [8*8, 8]), RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MAX | RS_X_MAX_PARENT_MIN|RS_Y_MAX_PARENT_MAX, [0, -8*1], [8*20, -8*0]);
|
|
}
|
|
}; |