updated mapcluster mode a little, should be more robust now. also supports cross-server events.

added option for softer/wider lines.
attempt to use hardware cursors in windows. provide api for csqc to specify its own.
cl_downloads cvar blocks all automatic downloads.
QUAKETC: new compile-time setting. if defined lots of stuff will be disabled including built in menus.
remove spam from log files.
try to get the webgl port to complain a bit more reliably when webgl is not usable.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4738 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2014-09-02 02:44:43 +00:00
parent ae9324b970
commit 230ce4e0a0
67 changed files with 2254 additions and 1276 deletions

View file

@ -554,6 +554,7 @@ SERVER_OBJS = \
sv_sql.o \
sv_mvd.o \
sv_ccmds.o \
sv_cluster.o \
sv_rankin.o \
sv_chat.o \
sv_demo.o \

View file

@ -1802,7 +1802,9 @@ void CL_QTVPoll (void)
int len;
qboolean streamavailable = false;
qboolean saidheader = false;
#ifndef NOBUITINMENUS
menu_t *sourcesmenu = NULL;
#endif
int sourcenum = 0;
int streamid;
@ -1969,6 +1971,7 @@ void CL_QTVPoll (void)
{
streamid = atoi(colon);
#ifndef NOBUITINMENUS
//now put it on a menu
if (!sourcesmenu)
{
@ -1983,6 +1986,7 @@ void CL_QTVPoll (void)
MC_AddConsoleCommand(sourcesmenu, 42, 170, (sourcenum++)*8 + 32, va("%s (p%i, v%i)", srchost, numplayers, numviewers), va("qtvplay %i@%s\n", streamid, qtvhostname));
//else
// FIXME: add error message here
#endif
}
//end of sourcelist entry

View file

@ -865,15 +865,6 @@ void CL_FinishMove (usercmd_t *cmd, int msecs, int pnum)
cmd->impulse = 0;
}
void CL_DrawPrydonCursor(void)
{
if (cursor_active && cl_prydoncursor.ival > 0)
{
SCR_DrawCursor(cl_prydoncursor.ival);
V_StopPitchDrift (0);
}
}
void CL_UpdatePrydonCursor(usercmd_t *from, float cursor_screen[2], vec3_t cursor_start, vec3_t cursor_impact, int *entnum)
{
vec3_t cursor_end;
@ -1479,8 +1470,6 @@ qboolean CLQW_SendCmd (sizebuf_t *buf)
MSG_WriteFloat(buf, cursor_impact[2]);
MSG_WriteEntity(buf, cursor_entitynumber);
}
else
cursor_active = false;
MSG_WriteByte (buf, clc_move);
@ -1563,6 +1552,7 @@ void CL_SendCmd (double frametime, qboolean mainloop)
if (cls.demoplayback != DPB_NONE || cls.netchan.remote_address.type == NA_INVALID)
{
cursor_active = false;
if (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV)
{
extern cvar_t cl_splitscreen;
@ -1786,6 +1776,7 @@ void CL_SendCmd (double frametime, qboolean mainloop)
msecs -= (double)msecstouse;
return;
}
cursor_active = false;
switch (cls.protocol)
{
#ifdef NQPROT

View file

@ -146,6 +146,7 @@ cvar_t cl_gunangley = CVAR("cl_gunangley", "0");
cvar_t cl_gunanglez = CVAR("cl_gunanglez", "0");
cvar_t cl_sendguid = CVARD("cl_sendguid", "0", "Send a randomly generated 'globally unique' id to servers, which can be used by servers for score rankings and stuff. Different servers will see different guids. Delete the 'qkey' file in order to appear as a different user.");
cvar_t cl_downloads = CVARFD("cl_downloads", "1", CVAR_NOTFROMSERVER, "Allows you to block all automatic downloads.");
cvar_t cl_download_csprogs = CVARFD("cl_download_csprogs", "1", CVAR_NOTFROMSERVER, "Download updated client gamecode if available. Warning: If you clear this to avoid downloading vm code, you should also clear cl_download_packages.");
cvar_t cl_download_redirection = CVARFD("cl_download_redirection", "2", CVAR_NOTFROMSERVER, "Follow download redirection to download packages instead of individual files. 2 allows redirection only to named packages files. Also allows the server to send nearly arbitary download commands.");
cvar_t cl_download_mapsrc = CVARD("cl_download_mapsrc", "", "Specifies an http location prefix for map downloads. EG: \"http://bigfoot.morphos-team.net/misc/quakemaps/\"");
@ -2454,7 +2455,7 @@ void CL_ConnectionlessPacket (void)
netadr_t adr;
char *data = MSG_ReadStringLine();
Con_TPrintf ("redirect to %s\n", data);
NET_StringToAdr(data, 27500, &adr);
NET_StringToAdr(data, PORT_QWSERVER, &adr);
data = "\xff\xff\xff\xffgetchallenge\n";
connectinfo.istransfer = true;
connectinfo.adr = adr;
@ -3186,7 +3187,7 @@ void CL_Download_f (void)
return;
}
CL_EnqueDownload(url, url, DLLF_IGNOREFAILED|DLLF_REQUIRED|DLLF_OVERWRITE|DLLF_VERBOSE);
CL_EnqueDownload(url, url, DLLF_USEREXPLICIT|DLLF_IGNOREFAILED|DLLF_REQUIRED|DLLF_OVERWRITE|DLLF_VERBOSE);
}
void CL_DownloadSize_f(void)
@ -3512,6 +3513,7 @@ void CL_Init (void)
Cvar_Register (&r_drawflame, "Item effects");
Cvar_Register (&cl_downloads, cl_controlgroup);
Cvar_Register (&cl_download_csprogs, cl_controlgroup);
Cvar_Register (&cl_download_redirection, cl_controlgroup);
Cvar_Register (&cl_download_packages, cl_controlgroup);
@ -3617,7 +3619,7 @@ void CL_Init (void)
Cmd_AddCommandD ("connect", CL_Connect_f, "connect scheme://address:port\nConnect to a server. Use a scheme of tcp:// or tls:// to connect via non-udp protocols."
#if defined(NQPROT) || defined(Q2CLIENT) || defined(Q3CLIENT)
"\nDefault port is port 27500."
"\nDefault port is port "STRINGIFY(PORT_QWSERVER)"."
#ifdef NQPROT
" NQ:"STRINGIFY(PORT_NQSERVER)"."
#endif
@ -4731,8 +4733,10 @@ void CL_StartCinematicOrMenu(void)
{
if (qrenderer > QR_NONE && !m_state)
{
#ifndef NOBUITINMENUS
if (!cls.state && !m_state && !*FS_GetGamedir(false))
M_Menu_Mods_f();
#endif
if (!cls.state && !m_state && cl_demoreel.ival)
CL_NextDemo();
if (!cls.state && !m_state)

View file

@ -179,6 +179,7 @@ serverinfo_t *Master_InfoForNum (int num);
unsigned int Master_TotalCount(void);
unsigned int Master_NumPolled(void);
void Master_SetupSockets(void);
void MasterInfo_Refresh(void);
void Master_QueryServer(serverinfo_t *server);
void MasterInfo_WriteServers(void);

View file

@ -425,6 +425,7 @@ int CL_IsDownloading(const char *localname)
//returns true if the download is going to be downloaded after the call.
qboolean CL_EnqueDownload(const char *filename, const char *localname, unsigned int flags)
{
extern cvar_t cl_downloads;
char *ext;
downloadlist_t *dl;
qboolean webdl = false;
@ -450,6 +451,13 @@ qboolean CL_EnqueDownload(const char *filename, const char *localname, unsigned
return false;
}
if (!(flags & DLLF_USEREXPLICIT) && !cl_downloads.ival)
{
if (flags & DLLF_VERBOSE)
Con_Printf("cl_downloads setting prevents download of \"%s\"\n", filename);
return false;
}
/*reject if it already failed*/
if (!(flags & DLLF_IGNOREFAILED))
{
@ -5819,8 +5827,7 @@ void CLQW_ParseServerMessage (void)
}
else if (cls.state == ca_connected)
{
Host_EndGame ("Server disconnected\n"
"Server version may not be compatible");
Host_EndGame ("Server disconnected\n");
}
else
Host_EndGame ("Server disconnected");

View file

@ -241,6 +241,8 @@ cvar_t show_speed_x = SCVAR("show_speed_x", "-1");
cvar_t show_speed_y = SCVAR("show_speed_y", "-9");
cvar_t scr_loadingrefresh = SCVAR("scr_loadingrefresh", "0");
void *scr_curcursor;
extern char cl_screengroup[];
void CLSCR_Init(void)
{
@ -261,6 +263,12 @@ void CLSCR_Init(void)
Cvar_Register(&show_speed_x, cl_screengroup);
Cvar_Register(&show_speed_y, cl_screengroup);
Cvar_Register(&scr_neticontimeout, cl_screengroup);
memset(&key_customcursor, 0, sizeof(key_customcursor));
scr_curcursor = NULL;
if (rf && rf->VID_SetCursor)
rf->VID_SetCursor(scr_curcursor);
}
/*
@ -612,33 +620,87 @@ void R_DrawTextField(int x, int y, int w, int h, const char *text, unsigned int
SCR_DrawCenterString(&r, &p, font_default);
}
void SCR_DrawCursor(int prydoncursornum)
qboolean SCR_HardwareCursorIsActive(void)
{
extern cvar_t cl_cursor, cl_cursorbias, cl_cursorsize;
if (Key_MouseShouldBeFree())
return !!scr_curcursor;
return false;
}
void SCR_DrawCursor(void)
{
extern cvar_t cl_cursor, cl_cursorbiasx, cl_cursorbiasy, cl_cursorscale, cl_prydoncursor;
mpic_t *p;
char *newc;
int prydoncursornum = 0;
extern qboolean cursor_active;
int cmod = kc_console;
void *oldcurs = NULL;
if (key_dest_absolutemouse & kdm_game)
if (cursor_active && cl_prydoncursor.ival > 0)
prydoncursornum = cl_prydoncursor.ival;
else if (!Key_MouseShouldBeFree())
return;
//choose the cursor based upon the module that has primary focus
if (key_dest_mask & key_dest_absolutemouse & (kdm_console|kdm_editor))
cmod = kc_console;
else if ((key_dest_mask & key_dest_absolutemouse & kdm_menu))
{
//if the game is meant to be drawing a cursor, don't draw one over the top.
key_dest_absolutemouse &= ~kdm_game;
if (!Key_MouseShouldBeFree())
{ //unless something else wants a cursor too.
key_dest_absolutemouse |= kdm_game;
return;
if (m_state == m_menu_dat)
cmod = kc_menu;
else
cmod = kc_console;
}
else// if (key_dest_mask & key_dest_absolutemouse)
cmod = prydoncursornum?kc_console:kc_game;
if (cmod == kc_console)
{
if (!*cl_cursor.string || prydoncursornum>1)
newc = va("gfx/prydoncursor%03i.lmp", prydoncursornum);
else
newc = cl_cursor.string;
if (strcmp(key_customcursor[kc_console].name, newc) || key_customcursor[kc_console].hotspot[0] != cl_cursorbiasx.value || key_customcursor[kc_console].hotspot[1] != cl_cursorbiasy.value || key_customcursor[kc_console].scale != cl_cursorscale.value)
{
key_customcursor[kc_console].dirty = true;
Q_strncpyz(key_customcursor[cmod].name, newc, sizeof(key_customcursor[cmod].name));
key_customcursor[kc_console].hotspot[0] = cl_cursorbiasx.value;
key_customcursor[kc_console].hotspot[1] = cl_cursorbiasy.value;
key_customcursor[kc_console].scale = cl_cursorscale.value;
}
key_dest_absolutemouse |= kdm_game;
}
if (!*cl_cursor.string || prydoncursornum>1)
p = R2D_SafeCachePic(va("gfx/prydoncursor%03i.lmp", prydoncursornum));
else
p = R2D_SafeCachePic(cl_cursor.string);
if (key_customcursor[cmod].dirty)
{
key_customcursor[cmod].dirty = false;
oldcurs = key_customcursor[cmod].handle;
if (rf->VID_CreateCursor)
{
key_customcursor[cmod].handle = rf->VID_CreateCursor(key_customcursor[cmod].name, key_customcursor[cmod].hotspot[0], key_customcursor[cmod].hotspot[1]);
if (!key_customcursor[cmod].handle)
key_customcursor[cmod].handle = rf->VID_CreateCursor("gfx/cursor.lmp", key_customcursor[cmod].hotspot[0], key_customcursor[cmod].hotspot[1]); //try the fallback
}
}
if (scr_curcursor != key_customcursor[cmod].handle)
{
scr_curcursor = key_customcursor[cmod].handle;
rf->VID_SetCursor(scr_curcursor);
}
if (oldcurs)
rf->VID_DestroyCursor(oldcurs);
if (scr_curcursor)
return;
//system doesn't support a hardware cursor, so try to draw a software one.
p = R2D_SafeCachePic(key_customcursor[cmod].name);
if (!p)
p = R2D_SafeCachePic("gfx/cursor.lmp");
if (p)
{
R2D_ImageColours(1, 1, 1, 1);
R2D_Image(mousecursor_x-cl_cursorbias.value, mousecursor_y-cl_cursorbias.value, cl_cursorsize.value, cl_cursorsize.value, 0, 0, 1, 1, p);
R2D_Image(mousecursor_x-key_customcursor[cmod].hotspot[0], mousecursor_y-key_customcursor[cmod].hotspot[1], p->width*cl_cursorscale.value, p->height*cl_cursorscale.value, 0, 0, 1, 1, p);
}
else
{
@ -1714,7 +1776,7 @@ void SCR_SetUpToDrawConsole (void)
// Key_Dest_Add(kdm_console);
scr_conlines = scr_con_current = vid.height * fullscreenpercent;
}
else if (!Key_Dest_Has(kdm_menu) && (!Key_Dest_Has(~(kdm_console|kdm_game))) && SCR_GetLoadingStage() == LS_NONE && cls.state < ca_active && !Media_PlayingFullScreen() && !CSQC_UnconnectedOkay(false))
else if (!Key_Dest_Has(kdm_menu) && (!Key_Dest_Has(~((!con_stayhidden.ival?kdm_console:0)|kdm_game))) && SCR_GetLoadingStage() == LS_NONE && cls.state < ca_active && !Media_PlayingFullScreen() && !CSQC_UnconnectedOkay(false))
{
//go fullscreen if we're not doing anything
#ifdef VM_UI
@ -1728,6 +1790,7 @@ void SCR_SetUpToDrawConsole (void)
if (con_stayhidden.ival)
{
extern qboolean startuppending;
scr_conlines = 0;
if (SCR_GetLoadingStage() == LS_NONE)
{
if (CL_TryingToConnect()) //if we're trying to connect, make sure there's a loading/connecting screen showing instead of forcing the menu visible
@ -2275,8 +2338,6 @@ void SCR_DrawTwoDimensional(int uimenu, qboolean nohud)
SCR_DrawTurtle ();
SCR_DrawPause ();
SCR_ShowPics_Draw();
CL_DrawPrydonCursor();
}
else
{
@ -2304,8 +2365,7 @@ void SCR_DrawTwoDimensional(int uimenu, qboolean nohud)
if (consolefocused)
SCR_DrawConsole (false);
if (Key_MouseShouldBeFree())
SCR_DrawCursor(0);
SCR_DrawCursor();
SCR_DrawSimMTouchCursor();
RSpeedEnd(RSPEED_2D);

View file

@ -504,8 +504,9 @@ typedef struct downloadlist_s {
#define DLLF_IGNOREFAILED (1u<<4) //
#define DLLF_NONGAME (1u<<5) //means the requested download filename+localname is gamedir explicit (so id1/foo.txt is distinct from qw/foo.txt)
#define DLLF_TEMPORARY (1u<<6) //download it, but don't actually save it (DLLF_OVERWRITE doesn't actually overwrite, but does ignore any local files)
#define DLLF_USEREXPLICIT (1u<<7) //use explicitly requested it, ignore the cl_downloads cvar.
#define DLLF_BEGUN (1u<<7) //server has confirmed that the file exists, is readable, and we've opened a file. should not be set on new requests.
#define DLLF_BEGUN (1u<<8) //server has confirmed that the file exists, is readable, and we've opened a file. should not be set on new requests.
struct downloadlist_s *next;
} downloadlist_t;

View file

@ -462,7 +462,7 @@ void Con_ToggleConsole_f (void)
}
#endif
if (con_stayhidden.ival >= 2)
if (con_stayhidden.ival >= 3)
return; //its hiding!
Con_ToggleConsole_Force();

View file

@ -2608,7 +2608,7 @@ qbyte *Read32BitImageFile(qbyte *buf, int len, int *width, int *height, qboolean
int w = LittleLong(((int*)buf)[0]);
int h = LittleLong(((int*)buf)[1]);
int i;
if (w >= 3 && h >= 4 && w*h+sizeof(int)*2 == com_filesize)
if (w >= 3 && h >= 4 && w*h+sizeof(int)*2 == len)
{
qboolean foundalpha = false;
qbyte *in = (qbyte*)((int*)buf+2);

View file

@ -538,10 +538,13 @@ void INS_UpdateGrabs(int fullscreen, int activeapp)
grabmouse = false;
//visiblity
if (grabmouse || (activeapp && mousecursor_x > 0 && mousecursor_y > 0 && mousecursor_x < vid.pixelwidth-1 && mousecursor_y < vid.pixelheight-1))
if (!SCR_HardwareCursorIsActive() && (grabmouse || (activeapp && mousecursor_x > 0 && mousecursor_y > 0 && mousecursor_x < vid.pixelwidth-1 && mousecursor_y < vid.pixelheight-1)))
INS_HideMouse();
else
{
INS_ShowMouse();
grabmouse = false;
}
#ifdef HLCLIENT
//halflife gamecode does its own mouse control... yes this is vile.
@ -1341,7 +1344,7 @@ potentially called multiple times per frame.
*/
void INS_Accumulate (void)
{
static POINT current_pos; //static to avoid bugs in vista with largeaddressaware (this is fixed in win7). fixed exe base address prevents this from going above 2gb.
static POINT current_pos; //static to avoid bugs in vista(32) with largeaddressaware (this is fixed in win7). fixed exe base address prevents this from going above 2gb.
if (mouseactive && !dinput)
{

View file

@ -43,6 +43,8 @@ unsigned int key_dest_mask;
qboolean key_dest_console;
unsigned int key_dest_absolutemouse;
struct key_cursor_s key_customcursor[kc_max];
int key_count; // incremented every key event
char *keybindings[K_MAX][KEY_MODIFIERSTATES];
@ -1969,7 +1971,7 @@ void Key_Event (int devid, int key, unsigned int unicode, qboolean down)
if (shift_down)
{
extern cvar_t con_stayhidden;
if (down && con_stayhidden.ival < 3)
if (down && con_stayhidden.ival < 2)
{
if (!Key_Dest_Has(kdm_console)) //don't toggle it when the console is already down. this allows typing blind to not care if its already active.
Con_ToggleConsole_Force();

View file

@ -192,6 +192,22 @@ extern int key_repeats[K_MAX];
extern int key_count; // incremented every key event
extern int key_lastpress;
enum
{
kc_game,
kc_menu,
kc_console,
kc_max
};
extern struct key_cursor_s
{
char name[MAX_QPATH];
float hotspot[2];
float scale;
qboolean dirty;
void *handle;
} key_customcursor[kc_max];
extern unsigned char *chat_buffer;
extern int chat_bufferpos;
extern qboolean chat_team;

View file

@ -1,6 +1,6 @@
#include "quakedef.h"
#ifdef WEBCLIENT
#if defined(WEBCLIENT) && !defined(NOBUITINMENUS)
#define DOWNLOADMENU
#endif

View file

@ -3,18 +3,6 @@
#include "quakedef.h"
#include "shader.h"
int omousex;
int omousey;
qboolean mousemoved;
qboolean bindingactive;
extern cvar_t cl_cursor;
extern cvar_t cl_cursorsize;
extern cvar_t cl_cursorbias;
extern cvar_t m_preset_chosen;
menu_t *currentmenu;
menu_t *firstmenu;
menuoption_t *M_NextSelectableItem(menu_t *m, menuoption_t *old);
void Draw_TextBox (int x, int y, int width, int lines)
{
mpic_t *p;
@ -88,6 +76,20 @@ void Draw_TextBox (int x, int y, int width, int lines)
R2D_ScalePic (cx, cy+8, 8, 8, p);
}
#ifndef NOBUITINMENUS
int omousex;
int omousey;
qboolean mousemoved;
qboolean bindingactive;
extern cvar_t cl_cursor;
extern cvar_t cl_cursorsize;
extern cvar_t cl_cursorbias;
extern cvar_t m_preset_chosen;
menu_t *currentmenu;
menu_t *firstmenu;
menuoption_t *M_NextSelectableItem(menu_t *m, menuoption_t *old);
void Draw_Hexen2BigFontString(int x, int y, const char *text)
{
int sx, sy;
@ -2283,3 +2285,4 @@ int MC_AddBulk(struct menu_s *menu, menuresel_t *resel, menubulk_t *bulk, int xs
menu->cursoritem = (menuoption_t*)MC_AddCursorSmall(menu, resel, xtextend + 8, selectedy);
return y;
}
#endif

View file

@ -1,6 +1,6 @@
#include "quakedef.h"
#ifdef CL_MASTER
#if defined(CL_MASTER) && !defined(NOBUITINMENUS)
#include "cl_master.h"
//filtering
@ -8,10 +8,10 @@ static cvar_t sb_hideempty = SCVARF("sb_hideempty", "0", CVAR_ARCHIVE);
static cvar_t sb_hidenotempty = SCVARF("sb_hidenotempty", "0", CVAR_ARCHIVE);
static cvar_t sb_hidefull = SCVARF("sb_hidefull", "0", CVAR_ARCHIVE);
static cvar_t sb_hidedead = SCVARF("sb_hidedead", "1", CVAR_ARCHIVE);
cvar_t sb_hidequake2 = SCVARF("sb_hidequake2", "1", CVAR_ARCHIVE);
cvar_t sb_hidequake3 = SCVARF("sb_hidequake3", "1", CVAR_ARCHIVE);
cvar_t sb_hidenetquake = SCVARF("sb_hidenetquake", "1", CVAR_ARCHIVE);
cvar_t sb_hidequakeworld = SCVARF("sb_hidequakeworld","0", CVAR_ARCHIVE);
extern cvar_t sb_hidequake2;
extern cvar_t sb_hidequake3;
extern cvar_t sb_hidenetquake;
extern cvar_t sb_hidequakeworld;
static cvar_t sb_showping = SCVARF("sb_showping", "1", CVAR_ARCHIVE);
static cvar_t sb_showaddress = SCVARF("sb_showaddress", "0", CVAR_ARCHIVE);

View file

@ -579,7 +579,7 @@ void Media_Next_f (void)
#ifndef NOMEDIAMENU
void M_Menu_Media_f (void)
{
@ -742,7 +742,14 @@ void M_Media_Key (int key)
{
int dir;
if (key == K_ESCAPE)
{
#ifndef NOBUITINMENUS
M_Menu_Main_f();
#else
m_state = m_none;
Key_Dest_Remove(kdm_menu);
#endif
}
else if (key == K_RIGHTARROW || key == K_LEFTARROW)
{
if (key == K_RIGHTARROW)
@ -1022,6 +1029,7 @@ void Media_LoadTrackNames (char *listname)
}
}
}
#endif
//safeprints only.
char *Media_NextTrack(int musicchannelnum)
@ -1039,8 +1047,10 @@ char *Media_NextTrack(int musicchannelnum)
if (!fakecdactive)
Media_EndedTrack();
#ifndef NOMEDIAMENU
if (!loadedtracknames)
Media_LoadTrackNames("sound/media.m3u");
#endif
if (!tracks && !fakecdactive)
{
*currenttrack.filename='\0';
@ -1072,7 +1082,6 @@ char *Media_NextTrack(int musicchannelnum)
#undef dwFlags
#undef lpFormat
#undef lpData

View file

@ -4,6 +4,8 @@
#include "winquake.h"
#include "shader.h"
#ifndef NOBUITINMENUS
extern cvar_t maxclients;
/* MULTIPLAYER MENU */
@ -928,3 +930,4 @@ void M_Menu_Network_f (void)
menu = M_Options_Title(&y, 0);
MC_AddBulk(menu, &resel, bulk, 16, 200, y);
}
#endif

View file

@ -2,6 +2,99 @@
#include "quakedef.h"
#include "winquake.h"
static const char *res4x3[] =
{
"640x480",
"800x600",
"960x720",
"1024x768",
"1152x864",
"1280x960",
"1440x1080",
"1600x1200",
// "1792x1344",
// "1856x1392",
"1920x1440",
"2048x1536",
NULL
};
static const char *res5x4[] =
{
"1280x1024",
"1800x1440",
"2560x2048",
NULL
};
static const char *res16x9[] =
{
"856x480",
"1024x576",
"1280x720",
"1366x768",
"1600x900",
"1920x1080",
"2048x1152",
"2560x1440",
"3840x2160",
"4096x2304",
NULL
};
static const char *res16x10[] =
{
"1024x640",
"1152x720",
"1280x800",
"1440x900",
"1680x1050",
"1920x1200",
"2304x1440",
"2560x1600",
NULL
};
#define ASPECT_RATIOS 4
static const char **resaspects[ASPECT_RATIOS] =
{
res4x3,
res5x4,
res16x9,
res16x10
};
#define ASPECT_LIST "4:3", "5:4", "16:9", "16:10",
qboolean M_Vid_GetMode(int num, int *w, int *h)
{
int i;
for (i = 0; i < 4; i++)
{
const char **v = resaspects[i];
while (*v && num)
{
v++;
num--;
}
if (*v)
{
const char *c = *v;
const char *s = strchr(c, 'x');
if (s)
{
*w = atoi(c);
*h = atoi(s + 1);
return true;
}
return false;
}
}
return false;
}
#ifndef NOBUITINMENUS
extern qboolean forcesaveprompt;
extern cvar_t pr_debugger;
@ -554,6 +647,7 @@ const char *presetexec[] =
"seta r_particlesystem null;"
"seta r_particledesc \"\";"
"seta r_part_classic_square 0;"
"seta r_part_classic_expgrav 10;"
"seta r_stains 0;"
"seta r_drawflat 1;"
"seta r_nolerp 1;"
@ -617,6 +711,7 @@ const char *presetexec[] =
"gl_texturemode nn;" //yup, we went there.
"gl_texturemode2d n;" //yeah, 2d too.
"r_part_classic_square 1;" //blocky baby!
"r_part_classic_expgrav 1;" //vanillaery
"cl_sbar 1;" //its a style thing
"sv_nqplayerphysics 1;" //gb wanted this
"cl_demoreel 1;" //yup, arcadey
@ -630,6 +725,7 @@ const char *presetexec[] =
"r_particledesc classic;"
#endif
"r_part_classic_square 0;"
"r_part_classic_expgrav 10;" //gives a slightly more dynamic feel to them
"gl_load24bit 1;"
"r_replacemodels \"md3 md2\";"
"r_coronas 1;"
@ -1989,93 +2085,6 @@ void M_Menu_Singleplayer_Cheats_f (void)
#define MULTIRENDERER // allow options for selecting renderer
#endif
static const char *res4x3[] =
{
"640x480",
"800x600",
"960x720",
"1024x768",
"1152x864",
"1280x960",
"1440x1080",
"1600x1200",
// "1792x1344",
// "1856x1392",
"1920x1440",
"2048x1536",
NULL
};
static const char *res5x4[] =
{
"1280x1024",
"1800x1440",
"2560x2048",
NULL
};
static const char *res16x9[] =
{
"856x480",
"1024x576",
"1280x720",
"1366x768",
"1600x900",
"1920x1080",
"2048x1152",
"2560x1440",
"3840x2160",
"4096x2304",
NULL
};
static const char *res16x10[] =
{
"1024x640",
"1152x720",
"1280x800",
"1440x900",
"1680x1050",
"1920x1200",
"2304x1440",
"2560x1600",
NULL
};
#define ASPECT_RATIOS 4
static const char **resaspects[ASPECT_RATIOS] =
{
res4x3,
res5x4,
res16x9,
res16x10
};
#define ASPECT_LIST "4:3", "5:4", "16:9", "16:10",
qboolean M_Vid_GetMode(int num, int *w, int *h)
{
int i;
for (i = 0; i < 4; i++)
{
const char **v = resaspects[i];
while (*v && num)
{
v++;
num--;
}
if (*v)
{
const char *c = *v;
const char *s = strchr(c, 'x');
if (s)
{
*w = atoi(c);
*h = atoi(s + 1);
return true;
}
return false;
}
}
return false;
}
typedef struct {
menucombo_t *resmode;
menuedit_t *width;
@ -2849,4 +2858,5 @@ void M_Menu_Mods_f (void)
c->key = Mods_Key;
menu->remove = Mods_Remove;
}
}
}
#endif

View file

@ -3,6 +3,8 @@
#include "quakedef.h"
#include "shader.h"
#ifndef NOBUITINMENUS
int selectitem;
menu_t *menu_script;
@ -436,3 +438,4 @@ void M_Script_Init(void)
Cmd_AddCommand("menucomboi", M_MenuS_Comboi_f);
Cmd_AddCommand("menucombos", M_MenuS_Combos_f);
}
#endif

View file

@ -3,6 +3,7 @@
#include "quakedef.h"
#include "winquake.h"
#include "shader.h"
#ifndef NOBUITINMENUS
#ifndef CLIENTONLY
//=============================================================================
/* LOAD/SAVE MENU */
@ -811,5 +812,4 @@ void M_Menu_MediaFiles_f (void)
ShowDemoMenu(menu, "");
}
#endif

View file

@ -21,98 +21,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "winquake.h"
#include "shader.h"
void M_Menu_Audio_f (void);
void M_Menu_Demos_f (void);
void M_Menu_Mods_f (void);
void M_Menu_ModelViewer_f(void);
m_state_t m_state;
extern menu_t *menu_script;
qboolean m_recursiveDraw;
void M_ConfigureNetSubsystem(void);
cvar_t m_helpismedia = SCVAR("m_helpismedia", "0");
cvar_t m_preset_chosen = CVARF("m_preset_chosen", "0", CVAR_ARCHIVE);
//=============================================================================
/* Support Routines */
void M_Print (int cx, int cy, qbyte *str)
{
Draw_AltFunString(cx + ((vid.width - 320)>>1), cy, str);
}
void M_PrintWhite (int cx, int cy, qbyte *str)
{
Draw_FunString(cx + ((vid.width - 320)>>1), cy, str);
}
void M_DrawScalePic (int x, int y, int w, int h, mpic_t *pic)
{
R2D_ScalePic (x + ((vid.width - 320)>>1), y, w, h, pic);
}
void M_BuildTranslationTable(int top, int bottom, unsigned int *translationTable)
{
int j;
int pc = Cvar_Get("cl_playerclass", "1", 0, "Hexen2")->value;
if (h2playertranslations && pc)
{
int i;
unsigned int color_offsets[5] = {2*14*256,0,1*14*256,2*14*256,2*14*256};
unsigned char *colorA, *colorB, *sourceA, *sourceB;
colorA = h2playertranslations + 256 + color_offsets[pc-1];
colorB = colorA + 256;
sourceA = colorB + (top * 256);
sourceB = colorB + (bottom * 256);
for(i=0;i<255;i++)
{
if (bottom > 0 && (colorB[i] != 255))
translationTable[i] = d_8to24rgbtable[sourceB[i]] | 0xff000000;
else if (top > 0 && (colorA[i] != 255))
translationTable[i] = d_8to24rgbtable[sourceA[i]] | 0xff000000;
else
translationTable[i] = d_8to24rgbtable[i] | 0xff000000;
}
}
else
{
for(j=0;j<255;j++)
{
if (j >= TOP_RANGE && j < TOP_RANGE + (1<<4))
{
if (top >= 16)
{
*((unsigned char*)&translationTable[j]+0) = (((top&0xff0000)>>16)**((unsigned char*)&d_8to24rgbtable[j&15]+0))>>8;
*((unsigned char*)&translationTable[j]+1) = (((top&0x00ff00)>> 8)**((unsigned char*)&d_8to24rgbtable[j&15]+1))>>8;
*((unsigned char*)&translationTable[j]+2) = (((top&0x0000ff)>> 0)**((unsigned char*)&d_8to24rgbtable[j&15]+2))>>8;
*((unsigned char*)&translationTable[j]+3) = 0xff;
}
else
translationTable[j] = d_8to24rgbtable[top<8?j-TOP_RANGE+(top<<4):(top<<4)+15-(j-TOP_RANGE)] | 0xff000000;
}
else if (j >= BOTTOM_RANGE && j < BOTTOM_RANGE + (1<<4))
{
if (bottom >= 16)
{
*((unsigned char*)&translationTable[j]+0) = (((bottom&0xff0000)>>16)**((unsigned char*)&d_8to24rgbtable[j&15]+0))>>8;
*((unsigned char*)&translationTable[j]+1) = (((bottom&0x00ff00)>> 8)**((unsigned char*)&d_8to24rgbtable[j&15]+1))>>8;
*((unsigned char*)&translationTable[j]+2) = (((bottom&0x0000ff)>> 0)**((unsigned char*)&d_8to24rgbtable[j&15]+2))>>8;
*((unsigned char*)&translationTable[j]+3) = 0xff;
}
else
translationTable[j] = d_8to24rgbtable[bottom<8?j-BOTTOM_RANGE+(bottom<<4):(bottom<<4)+15-(j-BOTTOM_RANGE)] | 0xff000000;
}
else
translationTable[j] = d_8to24rgbtable[j] | 0xff000000;
}
}
translationTable[255] = 0; //alpha
}
void M_DrawTextBox (int x, int y, int width, int lines)
{
mpic_t *p;
@ -182,6 +96,151 @@ void M_DrawTextBox (int x, int y, int width, int lines)
M_DrawScalePic (cx, cy+8, 8, 8, p);
}
int M_FindKeysForBind (char *command, int *keylist, int total)
{
int count;
int j;
int l;
char *b;
for (count = 0; count < total; count++)
keylist[count] = -1;
l = strlen(command);
count = 0;
for (j=0 ; j<256 ; j++)
{
b = keybindings[j][0];
if (!b)
continue;
if (!strncmp (b, command, l) && (!b[l] || b[l] == ' ' || b[l] == ';'))
{
keylist[count] = j;
count++;
if (count == total)
break;
}
}
return count;
}
void M_FindKeysForCommand (int pnum, const char *command, int *twokeys)
{
char prefix[5];
if (*command == '+' || *command == '-')
{
prefix[0] = *command;
prefix[1] = 0;
if (pnum != 0)
{
prefix[1] = 'p';
prefix[2] = '0'+pnum;
prefix[3] = ' ';
prefix[4] = 0;
}
command++;
}
else
{
prefix[0] = 0;
if (pnum != 0)
{
prefix[0] = 'p';
prefix[1] = '0'+pnum;
prefix[2] = ' ';
prefix[3] = 0;
}
}
M_FindKeysForBind(va("%s%s", prefix, command), twokeys, 2);
}
#ifndef NOBUITINMENUS
void M_Menu_Audio_f (void);
void M_Menu_Demos_f (void);
void M_Menu_Mods_f (void);
void M_Menu_ModelViewer_f(void);
extern menu_t *menu_script;
qboolean m_recursiveDraw;
void M_ConfigureNetSubsystem(void);
cvar_t m_helpismedia = SCVAR("m_helpismedia", "0");
cvar_t m_preset_chosen = CVARF("m_preset_chosen", "0", CVAR_ARCHIVE);
//=============================================================================
/* Support Routines */
void M_Print (int cx, int cy, qbyte *str)
{
Draw_AltFunString(cx + ((vid.width - 320)>>1), cy, str);
}
void M_PrintWhite (int cx, int cy, qbyte *str)
{
Draw_FunString(cx + ((vid.width - 320)>>1), cy, str);
}
void M_BuildTranslationTable(int top, int bottom, unsigned int *translationTable)
{
int j;
int pc = Cvar_Get("cl_playerclass", "1", 0, "Hexen2")->value;
if (h2playertranslations && pc)
{
int i;
unsigned int color_offsets[5] = {2*14*256,0,1*14*256,2*14*256,2*14*256};
unsigned char *colorA, *colorB, *sourceA, *sourceB;
colorA = h2playertranslations + 256 + color_offsets[pc-1];
colorB = colorA + 256;
sourceA = colorB + (top * 256);
sourceB = colorB + (bottom * 256);
for(i=0;i<255;i++)
{
if (bottom > 0 && (colorB[i] != 255))
translationTable[i] = d_8to24rgbtable[sourceB[i]] | 0xff000000;
else if (top > 0 && (colorA[i] != 255))
translationTable[i] = d_8to24rgbtable[sourceA[i]] | 0xff000000;
else
translationTable[i] = d_8to24rgbtable[i] | 0xff000000;
}
}
else
{
for(j=0;j<255;j++)
{
if (j >= TOP_RANGE && j < TOP_RANGE + (1<<4))
{
if (top >= 16)
{
*((unsigned char*)&translationTable[j]+0) = (((top&0xff0000)>>16)**((unsigned char*)&d_8to24rgbtable[j&15]+0))>>8;
*((unsigned char*)&translationTable[j]+1) = (((top&0x00ff00)>> 8)**((unsigned char*)&d_8to24rgbtable[j&15]+1))>>8;
*((unsigned char*)&translationTable[j]+2) = (((top&0x0000ff)>> 0)**((unsigned char*)&d_8to24rgbtable[j&15]+2))>>8;
*((unsigned char*)&translationTable[j]+3) = 0xff;
}
else
translationTable[j] = d_8to24rgbtable[top<8?j-TOP_RANGE+(top<<4):(top<<4)+15-(j-TOP_RANGE)] | 0xff000000;
}
else if (j >= BOTTOM_RANGE && j < BOTTOM_RANGE + (1<<4))
{
if (bottom >= 16)
{
*((unsigned char*)&translationTable[j]+0) = (((bottom&0xff0000)>>16)**((unsigned char*)&d_8to24rgbtable[j&15]+0))>>8;
*((unsigned char*)&translationTable[j]+1) = (((bottom&0x00ff00)>> 8)**((unsigned char*)&d_8to24rgbtable[j&15]+1))>>8;
*((unsigned char*)&translationTable[j]+2) = (((bottom&0x0000ff)>> 0)**((unsigned char*)&d_8to24rgbtable[j&15]+2))>>8;
*((unsigned char*)&translationTable[j]+3) = 0xff;
}
else
translationTable[j] = d_8to24rgbtable[bottom<8?j-BOTTOM_RANGE+(bottom<<4):(bottom<<4)+15-(j-BOTTOM_RANGE)] | 0xff000000;
}
else
translationTable[j] = d_8to24rgbtable[j] | 0xff000000;
}
}
translationTable[255] = 0; //alpha
}
//=============================================================================
int m_save_demonum;
@ -464,65 +523,6 @@ void M_Menu_Keys_f (void)
}
}
int M_FindKeysForBind (char *command, int *keylist, int total)
{
int count;
int j;
int l;
char *b;
for (count = 0; count < total; count++)
keylist[count] = -1;
l = strlen(command);
count = 0;
for (j=0 ; j<256 ; j++)
{
b = keybindings[j][0];
if (!b)
continue;
if (!strncmp (b, command, l) && (!b[l] || b[l] == ' ' || b[l] == ';'))
{
keylist[count] = j;
count++;
if (count == total)
break;
}
}
return count;
}
void M_FindKeysForCommand (int pnum, const char *command, int *twokeys)
{
char prefix[5];
if (*command == '+' || *command == '-')
{
prefix[0] = *command;
prefix[1] = 0;
if (pnum != 0)
{
prefix[1] = 'p';
prefix[2] = '0'+pnum;
prefix[3] = ' ';
prefix[4] = 0;
}
command++;
}
else
{
prefix[0] = 0;
if (pnum != 0)
{
prefix[0] = 'p';
prefix[1] = '0'+pnum;
prefix[2] = ' ';
prefix[3] = 0;
}
}
M_FindKeysForBind(va("%s%s", prefix, command), twokeys, 2);
}
void M_UnbindCommand (const char *command)
{
int j;
@ -1076,7 +1076,9 @@ void M_Init_Internal (void)
Cmd_AddCommand ("menu_keys", M_Menu_Keys_f);
Cmd_AddCommand ("help", M_Menu_Help_f);
Cmd_AddCommand ("menu_quit", M_Menu_Quit_f);
#ifndef NOMEDIAMENU
Cmd_AddCommand ("menu_media", M_Menu_Media_f);
#endif
Cmd_AddCommand ("menu_mediafiles", M_Menu_MediaFiles_f);
Cmd_AddCommand ("menu_mods", M_Menu_Mods_f);
Cmd_AddCommand ("modelviewer", M_Menu_ModelViewer_f);
@ -1146,7 +1148,9 @@ void M_DeInit_Internal (void)
Cmd_RemoveCommand ("menu_keys");
Cmd_RemoveCommand ("help");
Cmd_RemoveCommand ("menu_quit");
#ifndef NOMEDIAMENU
Cmd_RemoveCommand ("menu_media");
#endif
Cmd_RemoveCommand ("menu_mediafiles");
#ifdef CL_MASTER
@ -1180,7 +1184,7 @@ void M_DeInit_Internal (void)
Cmd_RemoveCommand ("menu_download");
Cmd_RemoveCommand ("menu_main"); //I've moved main to last because that way tab give us main and not quit.
Cmd_RemoveCommand ("menu_main"); //I've moved main to last because that way tab gives us main and not quit.
Cmd_RemoveCommand ("quickconnect");
}
@ -1228,6 +1232,31 @@ void M_Init (void)
M_Reinit();
}
//end builtin-menu code.
#else
void M_Init_Internal (void){}
void M_DeInit_Internal (void){}
void M_Shutdown(qboolean total)
{
#ifdef MENU_DAT
MP_Shutdown();
#endif
}
void M_Reinit(void)
{
#ifdef MENU_DAT
if (!MP_Init())
#endif
{
CSQC_UnconnectedInit();
}
}
void M_Init (void)
{
Media_Init();
M_Reinit();
}
#endif
void M_Draw (int uimenu)
@ -1241,10 +1270,13 @@ void M_Draw (int uimenu)
#endif
}
#ifndef NOBUITINMENUS
if (m_state != m_complex)
{
M_RemoveAllMenus();
}
#endif
if (!Key_Dest_Has(kdm_menu))
{
m_state = m_none;
@ -1254,6 +1286,7 @@ void M_Draw (int uimenu)
if (m_state == m_none || m_state == m_menu_dat)
return;
#ifndef NOBUITINMENUS
if ((!menu_script || scr_con_current) && !m_recursiveDraw)
{
extern menu_t *firstmenu;
@ -1266,6 +1299,7 @@ void M_Draw (int uimenu)
{
m_recursiveDraw = false;
}
#endif
R2D_ImageColours(1, 1, 1, 1);
@ -1274,17 +1308,22 @@ void M_Draw (int uimenu)
case m_none:
break;
#ifndef NOBUITINMENUS
case m_help:
M_Help_Draw ();
break;
case m_media:
M_Media_Draw ();
break;
case m_complex:
M_Complex_Draw ();
break;
#endif
#ifndef NOMEDIAMENU
case m_media:
M_Media_Draw ();
break;
#endif
#ifdef PLUGINS
case m_plugin:
Plug_Menu_Event (0, (int)(realtime*1000));
@ -1306,18 +1345,22 @@ void M_Keydown (int key, int unicode)
case m_none:
Key_Dest_Remove(kdm_menu);
return;
#ifndef NOBUITINMENUS
case m_help:
M_Help_Key (key);
return;
case m_media:
M_Media_Key (key);
return;
case m_complex:
M_Complex_Key (key, unicode);
return;
#endif
#ifndef NOMEDIAMENU
case m_media:
M_Media_Key (key);
return;
#endif
#ifdef PLUGINS
case m_plugin:
Plug_Menu_Event (1, key);

View file

@ -96,7 +96,13 @@ void M_SomeInitialisationFunctionCalledAtStartup(void)
}
*/
typedef enum {m_none, m_complex, m_help, m_media, m_plugin, m_menu_dat} m_state_t;
extern m_state_t m_state;
void M_DrawTextBox (int x, int y, int width, int lines);
#define NOMEDIAMENU
#ifndef NOBUITINMENUS
//
// menus
@ -110,16 +116,12 @@ void M_Draw (int uimenu);
void M_ToggleMenu_f (void);
void M_Menu_Mods_f (void); //used at startup if the current gamedirs look dodgy.
mpic_t *M_CachePic (char *path);
void M_DrawTextBox (int x, int y, int width, int lines);
void M_Menu_Quit_f (void);
void M_Menu_Prompt (void (*callback)(void *, int), void *ctx, char *m1, char *m2, char *m3, char *optionyes, char *optionno, char *optioncancel);
struct menu_s;
typedef enum {m_none, m_complex, m_help, m_media, m_plugin, m_menu_dat} m_state_t;
extern m_state_t m_state;
typedef enum {
mt_childwindow,
mt_button,
@ -401,6 +403,7 @@ void M_Menu_Search_f (void);
void M_Menu_ServerList_f (void);
void M_Menu_Media_f (void);
/*
void M_Main_Draw (void);
void M_SinglePlayer_Draw (void);
void M_Load_Draw (void);
@ -416,7 +419,6 @@ void M_LanConfig_Draw (void);
void M_GameOptions_Draw (void);
void M_Search_Draw (void);
void M_ServerList_Draw (void);
void M_Media_Draw (void);
void M_Main_Key (int key);
void M_SinglePlayer_Key (int key);
@ -433,7 +435,7 @@ void M_LanConfig_Key (int key);
void M_GameOptions_Key (int key);
void M_Search_Key (int key);
void M_ServerList_Key (int key);
void M_Media_Key (int key);
*/
void MasterInfo_Refresh(void);
void M_DrawServers(void);
@ -447,9 +449,27 @@ void M_PrintWhite (int cx, int cy, qbyte *str);
void M_DrawScalePic (int x, int y, int w, int h, mpic_t *pic);
void M_FindKeysForCommand (int pnum, const char *command, int *twokeys);
void M_UnbindCommand (const char *command);
#else
//no builtin menu code.
//stubs
#define M_Menu_Prompt(cb,ctx,m1,m2,m3,optionyes,optionno,optioncancel) (cb)(ctx,-1)
#define M_ToggleMenu_f() Cbuf_AddText("togglemenu\n",RESTRICT_LOCAL)
//#define M_Shutdown(t) MP_Shutdown()
void M_Init (void);
void M_Reinit(void);
void M_Shutdown(qboolean total);
void M_Keydown (int key, int unicode);
void M_Keyup (int key, int unicode);
void M_Draw (int uimenu);
#endif
void M_FindKeysForCommand (int pnum, const char *command, int *twokeys);
void M_Media_Draw (void);
void M_Media_Key (int key);
void MP_CvarChanged(cvar_t *var);
qboolean MP_Init (void);
void MP_Shutdown (void);

View file

@ -326,6 +326,11 @@ typedef struct rendererinfo_s {
void (*VID_DeInit) (void);
void (*VID_SwapBuffers) (void); //force a buffer swap, regardless of what's displayed.
qboolean (*VID_ApplyGammaRamps) (unsigned short *ramps);
void *(*VID_CreateCursor) (char *filename, int hotx, int hoty); //may be null, stub returns null
qboolean (*VID_SetCursor) (void *cursor); //may be null
void (*VID_DestroyCursor) (void *cursor); //may be null
void (*VID_SetWindowCaption) (char *msg);
char *(*VID_GetRGBInfo) (int prepad, int *truevidwidth, int *truevidheight);

View file

@ -36,6 +36,10 @@ typedef int SOCKET;
cvar_t slist_cacheinfo = SCVAR("slist_cacheinfo", "0"); //this proves dangerous, memory wise.
cvar_t slist_writeserverstxt = SCVAR("slist_writeservers", "0");
cvar_t sb_hidequake2 = SCVARF("sb_hidequake2", "1", CVAR_ARCHIVE);
cvar_t sb_hidequake3 = SCVARF("sb_hidequake3", "1", CVAR_ARCHIVE);
cvar_t sb_hidenetquake = SCVARF("sb_hidenetquake", "1", CVAR_ARCHIVE);
cvar_t sb_hidequakeworld = SCVARF("sb_hidequakeworld","0", CVAR_ARCHIVE);
void CL_MasterListParse(netadrtype_t adrtype, int type, qboolean slashpad);
void CL_QueryServers(void);
@ -1586,7 +1590,7 @@ void MasterInfo_Refresh(void)
// Master_AddMaster("masterserver.exhale.de:27000", MT_MASTERUDP, MP_QW, "team exhale");
Master_AddMaster("qwmaster.fodquake.net:27000", MT_MASTERUDP, MP_QW, "Fodquake master server.");
Master_AddMaster("qwmaster.ocrana.de:27000", MT_MASTERUDP, MP_QW, "Ocrana2 master server.");
Master_AddMaster("255.255.255.255:27500", MT_BCAST, MP_QW, "Nearby QuakeWorld UDP servers.");
Master_AddMaster("255.255.255.255:"STRINGIFY(PORT_QWSERVER),MT_BCAST, MP_QW, "Nearby QuakeWorld UDP servers.");
}
// if (q1servers) //nq master servers
@ -1602,8 +1606,8 @@ void MasterInfo_Refresh(void)
//Master_AddMaster("[2001:41d0:2:1628::4450]:27950", MT_MASTERUDP, MP_DP, "DarkPlaces Master 4"); // dpmaster.div0.qc.to (admin: divVerent)
//Master_AddMaster("[2604:180::4ac:98c1]:27950", MT_MASTERUDP, MP_DP, "DarkPlaces Master 4"); // dpmaster.deathmask.net (Willis)
#endif
Master_AddMaster("255.255.255.255:26000", MT_BCAST, MP_NQ, "Nearby Quake1 servers");
Master_AddMaster("255.255.255.255:26000", MT_BCAST, MP_DP, "Nearby DarkPlaces servers");
Master_AddMaster("255.255.255.255:"STRINGIFY(PORT_NQSERVER), MT_BCAST, MP_NQ, "Nearby Quake1 servers");
Master_AddMaster("255.255.255.255:"STRINGIFY(PORT_NQSERVER), MT_BCAST, MP_DP, "Nearby DarkPlaces servers");
}
// if (q2servers) //q2
@ -1616,7 +1620,7 @@ void MasterInfo_Refresh(void)
// Master_AddMaster("masterserver.exhale.de:27900", MT_MASTERUDP, MP_Q2, "team exhale");
Master_AddMaster("255.255.255.255:27910", MT_BCAST, MP_Q2, "Nearby Quake2 UDP servers.");
#ifdef USEIPX
Master_AddMaster("00000000:ffffffffffff:27910", MT_BCAST, MP_Q2, "Nearby Quake2 IPX servers.");
Master_AddMaster("00000000:ffffffffffff:"STRINGIFY(PORT_Q2SERVER), MT_BCAST, MP_Q2, "Nearby Quake2 IPX servers.");
#endif
}
@ -1626,7 +1630,7 @@ void MasterInfo_Refresh(void)
Master_AddMaster("master.quake3arena.com:27950", MT_MASTERUDP, MP_Q3, "Quake3 master server.");
// Master_AddMaster("masterserver.exhale.de:27950", MT_MASTERUDP, MP_Q3, "team exhale");
//Master_AddMaster("master3.quake3arena.com:27950", MT_MASTERUDP, MP_Q3, "Quake3 master3 server.");
Master_AddMaster("255.255.255.255:27960", MT_BCAST, MP_Q3, "Nearby Quake3 UDP servers.");
Master_AddMaster("255.255.255.255:"STRINGIFY(PORT_Q3SERVER), MT_BCAST, MP_Q3, "Nearby Quake3 UDP servers.");
}
}

View file

@ -74,7 +74,7 @@ typedef struct cparticle_s
#define ABSOLUTE_MAX_PARTICLES 8192
static int r_numparticles;
static cparticle_t *particles, *active_particles, *free_particles;
extern cvar_t r_part_density;
extern cvar_t r_part_density, r_part_classic_expgrav;
extern qbyte default_quakepal[]; /*for ramps more than anything else*/
static int ramp1[8] = {0x6f, 0x6d, 0x6b, 0x69, 0x67, 0x65, 0x63, 0x61};
@ -501,7 +501,7 @@ static void PClassic_DrawParticles(void)
p->rgb = qpal(ramp1[(int) p->ramp]);
for (i = 0; i < 3; i++)
p->vel[i] += p->vel[i] * dvel;
p->vel[2] -= grav*10;
p->vel[2] -= grav*r_part_classic_expgrav.value;
break;
case pt_explode2:
p->ramp += time3;
@ -511,7 +511,7 @@ static void PClassic_DrawParticles(void)
p->rgb = qpal(ramp2[(int) p->ramp]);
for (i = 0; i < 3; i++)
p->vel[i] -= p->vel[i] * frametime;
p->vel[2] -= grav*10;
p->vel[2] -= grav*r_part_classic_expgrav.value;
break;
case pt_blob:
for (i = 0; i < 3; i++)

View file

@ -2429,6 +2429,17 @@ static void QCBUILTIN PF_cl_setcursormode (pubprogfuncs_t *prinst, struct global
key_dest_absolutemouse |= world->keydestmask;
else
key_dest_absolutemouse &= ~world->keydestmask;
if (prinst->callargc>1)
{
struct key_cursor_s *m = &key_customcursor[(world->keydestmask==kdm_game)?kc_game:kc_menu];
Q_strncpyz(m->name, PR_GetStringOfs(prinst, OFS_PARM1), sizeof(m->name));
m->hotspot[0] = (prinst->callargc>2)?G_FLOAT(OFS_PARM2+0):0;
m->hotspot[1] = (prinst->callargc>2)?G_FLOAT(OFS_PARM2+1):0;
m->scale = (prinst->callargc>2)?G_FLOAT(OFS_PARM2+2):0;
if (m->scale <= 0)
m->scale = 1;
}
}
//get the input commands, and stuff them into some globals.
@ -4644,7 +4655,7 @@ static struct {
{"stringtokeynum", PF_cl_stringtokeynum, 341}, // #341 float(string keyname) stringtokeynum (EXT_CSQC)
{"getkeybind", PF_cl_getkeybind, 342}, // #342 string(float keynum) getkeybind (EXT_CSQC)
{"setcursormode", PF_cl_setcursormode, 343}, // #343 This is a DP extension
{"setcursormode", PF_cl_setcursormode, 343}, // #343 This is originally a DP extension
{"getmousepos", PF_cl_getmousepos, 344}, // #344 This is a DP extension
{"getinputstate", PF_cs_getinputstate, 345}, // #345 float(float framenum) getinputstate (EXT_CSQC)

View file

@ -149,6 +149,7 @@ cvar_t r_part_sparks_textured = CVAR("r_part_sparks_textured", "1");
cvar_t r_part_beams = CVAR("r_part_beams", "1");
cvar_t r_part_contentswitch = CVARFD("r_part_contentswitch", "1", CVAR_ARCHIVE, "Enable particle effects to change based on content (ex. water).");
cvar_t r_part_density = CVARF("r_part_density", "1", CVAR_ARCHIVE);
cvar_t r_part_classic_expgrav = CVARFD("r_part_classic_expgrav", "10", CVAR_ARCHIVE, "Scaler for how fast classic explosion particles should accelerate due to gravity. 1 for like vanilla, 10 for like zquake.");
particleengine_t *pe;
@ -174,6 +175,7 @@ void P_InitParticleSystem(void)
Cvar_Register(&r_part_beams, particlecvargroupname);
Cvar_Register(&r_part_contentswitch, particlecvargroupname);
Cvar_Register(&r_part_density, particlecvargroupname);
Cvar_Register(&r_part_classic_expgrav, particlecvargroupname);
Cvar_Register (&gl_part_flame, particlecvargroupname);

View file

@ -52,8 +52,9 @@ cvar_t _windowed_mouse = CVARF ("_windowed_mouse","1",
cvar_t con_ocranaleds = CVAR ("con_ocranaleds", "2");
cvar_t cl_cursor = CVAR ("cl_cursor", "");
cvar_t cl_cursorsize = CVAR ("cl_cursorsize", "32");
cvar_t cl_cursorbias = CVAR ("cl_cursorbias", "4");
cvar_t cl_cursorscale = CVAR ("cl_cursor_scale", "0.2");
cvar_t cl_cursorbiasx = CVAR ("cl_cursor_bias_x", "7.5");
cvar_t cl_cursorbiasy = CVAR ("cl_cursor_bias_y", "0.8");
cvar_t gl_nocolors = CVARF ("gl_nocolors", "0", CVAR_ARCHIVE);
cvar_t gl_part_flame = CVARFD ("gl_part_flame", "1", CVAR_ARCHIVE, "Enable particle emitting from models. Mainly used for torch and flame effects.");
@ -77,6 +78,7 @@ cvar_t r_drawflat = CVARF ("r_drawflat", "0",
CVAR_ARCHIVE | CVAR_SEMICHEAT | CVAR_RENDERERCALLBACK | CVAR_SHADERSYSTEM);
cvar_t r_wireframe = CVARF ("r_wireframe", "0",
CVAR_CHEAT);
cvar_t r_wireframe_smooth = CVAR ("r_wireframe_smooth", "0");
cvar_t r_refract_fbo = CVARD ("r_refract_fbo", "1", "Use an fbo for refraction. If 0, just renders as a portal and uses a copy of the current framebuffer.");
cvar_t gl_miptexLevel = CVAR ("gl_miptexLevel", "0");
cvar_t r_drawviewmodel = CVARF ("r_drawviewmodel", "1", CVAR_ARCHIVE);
@ -168,8 +170,8 @@ cvar_t scr_conalpha = CVARC ("scr_conalpha", "0.7",
cvar_t scr_consize = CVAR ("scr_consize", "0.5");
cvar_t scr_conspeed = CVAR ("scr_conspeed", "2000");
// 10 - 170
cvar_t scr_fov = CVARFDC("fov", "108",
CVAR_ARCHIVE, "field of vision, 1-170 degrees, standard fov is 90, nquake.",
cvar_t scr_fov = CVARFDC("fov", "90",
CVAR_ARCHIVE, "field of vision, 1-170 degrees, standard fov is 90, nquake defaults to 108.",
SCR_Fov_Callback);
cvar_t scr_printspeed = SCVAR ("scr_printspeed", "8");
cvar_t scr_showpause = SCVAR ("showpause", "1");
@ -646,6 +648,7 @@ void Renderer_Init(void)
Cvar_Register (&r_slimestyle, GRAPHICALNICETIES);
Cvar_Register (&r_telestyle, GRAPHICALNICETIES);
Cvar_Register (&r_wireframe, GRAPHICALNICETIES);
Cvar_Register (&r_wireframe_smooth, GRAPHICALNICETIES);
Cvar_Register (&r_refract_fbo, GRAPHICALNICETIES);
Cvar_Register (&r_stereo_separation, GRAPHICALNICETIES);
Cvar_Register (&r_stereo_method, GRAPHICALNICETIES);
@ -659,8 +662,9 @@ void Renderer_Init(void)
Cvar_Register (&scr_sshot_prefix, SCREENOPTIONS);
Cvar_Register(&cl_cursor, SCREENOPTIONS);
Cvar_Register(&cl_cursorsize, SCREENOPTIONS);
Cvar_Register(&cl_cursorbias, SCREENOPTIONS);
Cvar_Register(&cl_cursorscale, SCREENOPTIONS);
Cvar_Register(&cl_cursorbiasx, SCREENOPTIONS);
Cvar_Register(&cl_cursorbiasy, SCREENOPTIONS);
//screen
@ -821,6 +825,9 @@ rendererinfo_t dedicatedrendererinfo = {
NULL, //VID_DeInit,
NULL, //VID_SwapBuffers
NULL, //VID_ApplyGammaRamps,
NULL,
NULL,
NULL,
NULL, //set caption
NULL, //VID_GetRGBInfo,

View file

@ -63,7 +63,7 @@ void SCR_DrawNet (void);
void SCR_DrawTurtle (void);
void SCR_DrawPause (void);
void SCR_VRectForPlayer(vrect_t *vrect, int pnum); //returns a region for the player's view
void SCR_DrawCursor(int prydoncursornum);
qboolean SCR_HardwareCursorIsActive(void);
void CLSCR_Init(void); //basically so I can register a few friendly cvars.

View file

@ -726,7 +726,7 @@ DWORD CrashExceptionHandler (qboolean iswatchdog, DWORD exceptionCode, LPEXCEPTI
#ifdef _MSC_VER
if (MessageBoxA(0, stacklog, "KABOOM!", MB_ICONSTOP|MB_YESNO) != IDYES)
{
if (pIsDebuggerPresent ())
if (pIsDebuggerPresent && pIsDebuggerPresent ())
{
//its possible someone attached a debugger while we were showing that message
return EXCEPTION_CONTINUE_SEARCH;
@ -3312,14 +3312,14 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin
SV_Init (&parms);
delay = SV_Frame()*1000;
delay = SV_Frame();
while (1)
{
if (!isDedicated)
Sys_Error("Dedicated was cleared");
NET_Sleep(delay, false);
delay = SV_Frame()*1000;
delay = SV_Frame();
}
return TRUE;
}

View file

@ -254,6 +254,9 @@ rendererinfo_t headlessrenderer =
Headless_VID_DeInit,
Headless_VID_SwapBuffers,
Headless_VID_ApplyGammaRamps,
NULL,
NULL,
NULL,
Headless_VID_SetWindowCaption,
Headless_VID_GetRGBInfo,
Headless_SCR_UpdateScreen,

View file

@ -84,6 +84,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define NO_JPEG
#define NO_ZLIB
#define NO_OGG
#else
#define AVAIL_OPENAL
#define AVAIL_FREETYPE
#endif
#define AVAIL_OGGVORBIS
@ -96,9 +99,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define AVAIL_OGGVORBIS
#endif
#define AVAIL_OPENAL
#define AVAIL_FREETYPE
#if !defined(NO_DIRECTX) && !defined(NODIRECTX) && defined(_WIN32)
#define AVAIL_DINPUT
#define AVAIL_DDRAW
@ -106,11 +106,13 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define AVAIL_D3D
#endif
#ifndef MINIMAL
#if defined(_WIN32) && !defined(FTE_SDL) && !defined(WINRT)
#define HAVE_WINSSPI //built in component, checks against windows' root ca database and revocations etc.
#elif defined(__linux__) || defined(__CYGWIN__)
#define HAVE_GNUTLS //currently disabled as it does not validate the server's certificate, beware the mitm attack.
#endif
#endif
#if defined(HAVE_WINSSPI) || defined(HAVE_GNUTLS)
#define HAVE_SSL
#endif
@ -168,7 +170,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#undef AVAIL_JPEGLIB //no jpeg support
#undef AVAIL_PNGLIB //no png support
#undef USE_MADLIB //no internal mp3 playing
#define NOMEDIA //NO playing of avis/cins/roqs
#define SPRMODELS //quake1 sprite models
@ -216,7 +217,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define Q2BSPS //quake 2 bsp support
#define Q3BSPS //quake 3 bsp support
#define TERRAIN //heightmap support
#define SV_MASTER //starts up a master server
// #define SV_MASTER //starts up a master server
#define SVCHAT //serverside npc chatting. see sv_chat.c
#define Q2SERVER //server can run a q2 game dll and switches to q2 network and everything else.
#define Q2CLIENT //client can connect to q2 servers
@ -268,6 +269,20 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#endif
#ifdef QUAKETC
#define NOBUITINMENUS //kill engine menus (should be replaced with ewither csqc or menuqc)
#undef Q2CLIENT //not useful
#undef Q2SERVER //not useful
#undef Q3CLIENT //not useful
#undef Q3SERVER //not useful
#undef HLCLIENT //not useful
#undef HLSERVER //not useful
#undef VM_Q1 //not useful
#undef VM_LUA //not useful
#undef HALFLIFEMODELS //yuck
#undef RUNTIMELIGHTING //presumably not useful
#endif
//#define QUAKESPYAPI //define this if you want the engine to be usable via gamespy/quakespy, which has been dead for a long time now.
#ifdef FTE_TARGET_WEB
@ -287,7 +302,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#undef MAP_PROC //meh
#undef HALFLIFEMODELS //blurgh
#undef WEBSERVER //hah, yeah, right
#undef SUPPORT_ICE //kinda requires udp, but whatever
#undef SUPPORT_ICE //kinda requires udp, so not usable
//extra features stripped to try to reduce memory footprints
#undef RUNTIMELIGHTING //too slow anyway
@ -355,10 +370,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#endif
#endif
#if defined(RTLIGHTS) && !defined(GLQUAKE) && !defined(D3D9QUAKE)
#undef RTLIGHTS
#endif
#ifndef _WIN32
#undef QTERM //not supported - FIXME: move to native plugin
#endif

View file

@ -96,6 +96,25 @@ cvar_t com_modname = CVARD("com_modname", "", "dpmaster information");
cvar_t com_parseutf8 = CVARD("com_parseutf8", "0", "Interpret console messages/playernames/etc as UTF-8. Requires special fonts. -1=iso 8859-1. 0=quakeascii(chat uses high chars). 1=utf8, revert to ascii on decode errors. 2=utf8 ignoring errors"); //1 parse. 2 parse, but stop parsing that string if a char was malformed.
cvar_t com_highlightcolor = CVARD("com_highlightcolor", STRINGIFY(COLOR_RED), "ANSI colour to be used for highlighted text, used when com_parseutf8 is active.");
cvar_t com_nogamedirnativecode = CVARFD("com_nogamedirnativecode", "1", CVAR_NOTFROMSERVER, FULLENGINENAME" blocks all downloads of files with a .dll or .so extension, however other engines (eg: ezquake and fodquake) do not - this omission can be used to trigger remote exploits in any engine (including "FULLENGINENAME"which is later run from the same gamedir.\nQuake2, Quake3(when debugging), and KTX typically run native gamecode from within gamedirs, so if you wish to run any of these games you will need to ensure this cvar is changed to 0, as well as ensure that you don't run unsafe clients.\n");
#ifdef FTE_TARGET_WEB
cvar_t sys_platform = CVAR("sys_platform", "web");
#elif defined(NACL)
cvar_t sys_platform = CVAR("sys_platform", "nacl");
#elif defined(ANDROID)
cvar_t sys_platform = CVAR("sys_platform", "android");
#elif defined(FTE_SDL)
cvar_t sys_platform = CVAR("sys_platform", "sdl");
#elif defined(_WIN64)
cvar_t sys_platform = CVAR("sys_platform", "win64");
#elif defined(_WIN32)
cvar_t sys_platform = CVAR("sys_platform", "win32");
#elif defined(__linux__)
cvar_t sys_platform = CVAR("sys_platform", "linux");
#elif defined(__APPLE__)
cvar_t sys_platform = CVAR("sys_platform", "mac");
#else
cvar_t sys_platform = CVAR("sys_platform", "");
#endif
qboolean com_modified; // set true if using non-id files
@ -4540,6 +4559,7 @@ void COM_Init (void)
Cmd_AddCommand ("errorme", COM_ErrorMe_f);
COM_InitFilesystem ();
Cvar_Register (&sys_platform, "Gamecode");
Cvar_Register (&registered, "Copy protection");
Cvar_Register (&gameversion, "Gamecode");
Cvar_Register (&gameversion_min, "Gamecode");

View file

@ -113,6 +113,7 @@ void InsertLinkAfter (link_t *l, link_t *after);
// FIXME: remove this mess!
#define STRUCT_FROM_LINK(l,t,m) ((t *)((qbyte *)l - (qbyte*)&(((t *)0)->m)))
#define FOR_EACH_LINK(l,node) for (l = node.next ; l != &node ; l = l->next)
//============================================================================
#ifndef NULL

View file

@ -2135,10 +2135,11 @@ char *FS_GetGamedir(qboolean publicpathonly)
//returns the commandline arguments required to duplicate the fs details
char *FS_GetManifestArgs(void)
{
char *homearg = com_homepathenabled?"-usehome ":"-nohome ";
if (fs_manifest->updatefile)
return va("-manifest %s -basedir %s", fs_manifest->updatefile, com_gamepath);
return va("%s-manifest %s -basedir %s -outputdebugstring", homearg, fs_manifest->updatefile, com_gamepath);
return va("-game %s -basedir %s", pubgamedirfile, com_gamepath);
return va("%s-game %s -basedir %s -outputdebugstring", homearg, pubgamedirfile, com_gamepath);
}
//given a 'c:/foo/bar/' path, will extract 'bar'.
@ -3361,6 +3362,7 @@ static void FS_PackageDownloaded(struct dl_download *dl)
}
Sys_remove (fspdl_temppath);
fs_restarts++;
FS_ChangeGame(fs_manifest, true);
FS_BeginNextPackageDownload();

View file

@ -13,8 +13,8 @@ cvar_t log_enable[LOG_TYPES] = { CVARF("log_enable", "0", CVAR_NOTFROMSERVER),
CVARF("log_enable_rcon", "1", CVAR_NOTFROMSERVER)
};
cvar_t log_name[LOG_TYPES] = { CVARFC("log_name", "", CVAR_NOTFROMSERVER, Log_Name_Callback),
CVARFC("log_name_players", "", CVAR_NOTFROMSERVER, Log_Name_Callback),
CVARFC("log_name_rcon", "", CVAR_NOTFROMSERVER, Log_Name_Callback)};
CVARFC("log_name_players", "players", CVAR_NOTFROMSERVER, Log_Name_Callback),
CVARFC("log_name_rcon", "rcon", CVAR_NOTFROMSERVER, Log_Name_Callback)};
cvar_t log_dir = CVARFC("log_dir", "", CVAR_NOTFROMSERVER, Log_Dir_Callback);
cvar_t log_readable = CVARFD("log_readable", "7", CVAR_NOTFROMSERVER, "Bitfield describing what to convert/strip. If 0, exact byte representation will be used.\n&1: Dequakify text.\n&2: Strip special markup.\n&4: Strip ansi control codes.");
cvar_t log_developer = CVARF("log_developer", "0", CVAR_NOTFROMSERVER);

View file

@ -5307,18 +5307,21 @@ void IPX_CloseSocket (int socket)
qboolean NET_Sleep(float seconds, qboolean stdinissocket)
{
#ifdef HAVE_PACKET
struct timeval timeout;
struct timeval timeout;
fd_set fdset;
int maxfd;
qintptr_t maxfd = -1;
int con, sock;
unsigned int usec;
FD_ZERO(&fdset);
if (stdinissocket)
FD_SET(0, &fdset); //stdin tends to be socket 0
{
sock = 0; //stdin tends to be socket/filehandle 0 in unix
FD_SET(sock, &fdset);
maxfd = sock;
}
maxfd = 0;
if (svs.sockets)
for (con = 0; con < MAX_CONNECTIONS; con++)
{
@ -5348,7 +5351,7 @@ qboolean NET_Sleep(float seconds, qboolean stdinissocket)
usec += 1000; //slight extra delay, to ensure we don't wake up with nothing to do.
timeout.tv_sec = usec/(1000*1000);
timeout.tv_usec = usec;
if (!maxfd)
if (maxfd == -1)
Sys_Sleep(seconds);
else
select(maxfd+1, &fdset, NULL, NULL, &timeout);
@ -5449,7 +5452,7 @@ void SVNET_AddPort_f(void)
{
svs.sockets = FTENET_CreateCollection(true);
#ifndef SERVERONLY
FTENET_AddToCollection(svs.sockets, "SVLoopback", "27500", NA_LOOPBACK, true);
FTENET_AddToCollection(svs.sockets, "SVLoopback", STRINGIFY(PORT_QWSERVER), NA_LOOPBACK, true);
#endif
}
@ -5606,7 +5609,7 @@ void SV_Port_Callback(struct cvar_s *var, char *oldvalue)
{
FTENET_AddToCollection(svs.sockets, var->name, var->string, NA_IP, true);
}
cvar_t sv_port_ipv4 = CVARC("sv_port", "27500", SV_Port_Callback);
cvar_t sv_port_ipv4 = CVARC("sv_port", STRINGIFY(PORT_QWSERVER), SV_Port_Callback);
#endif
#ifdef IPPROTO_IPV6
void SV_PortIPv6_Callback(struct cvar_s *var, char *oldvalue)

View file

@ -320,6 +320,8 @@ enum clustercmdops_e
//string message
ccmd_acceptserver,
//serverid
ccmd_lostplayer, //player dropped/timed out
//long plid
ccmd_takeplayer, //master->server, saying to allocate a slot for a player.
//long plid
//long fromsvid (0=no reply needed)
@ -347,8 +349,13 @@ enum clustercmdops_e
//byte statcount
//float stats[statcount]
ccmd_serveraddress, //server->master, contains a few net addresses
//string address[]
//string addresses[]
//byte 0
ccmd_stringcmd,
//string dest (black = broadcast to all)
//string source (player name)
//string cmd (type of event, handled by receiving server/forwarded to client)
//string msg (extra info, like the typed text)
};

View file

@ -24,7 +24,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "winquake.h"
#include <conio.h>
#if (defined(_DEBUG) || defined(DEBUG)) && !defined(SERVERONLY)
#if (defined(_DEBUG) || defined(DEBUG))
#define CATCHCRASH
LONG CALLBACK nonmsvc_CrashExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo);
@ -346,7 +346,7 @@ pubsubserver_t *Sys_ForkServer(void)
GetModuleFileName(NULL, exename, sizeof(exename));
GetCurrentDirectory(sizeof(curdir), curdir);
Q_snprintfz(cmdline, sizeof(cmdline), "foo -clusterslave %s", FS_GetManifestArgs()); //fixme: include which manifest is in use, so configs get set up the same.
Q_snprintfz(cmdline, sizeof(cmdline), "foo -noreset -clusterslave %s", FS_GetManifestArgs()); //fixme: include which manifest is in use, so configs get set up the same.
memset(&startinfo, 0, sizeof(startinfo));
startinfo.cb = sizeof(startinfo);

View file

@ -565,6 +565,7 @@ qboolean D3D11Shader_Init(unsigned int flevel)
sh_config.pCreateProgram = D3D11Shader_CreateProgram;
sh_config.pProgAutoFields = NULL;
sh_config.texture_non_power_of_two = true;
sh_config.tex_env_combine = 1;
sh_config.nv_tex_env_combine4 = 1;
sh_config.env_add = 1;

View file

@ -377,6 +377,7 @@ void D3D9Shader_Init(void)
sh_config.pCreateProgram = D3D9Shader_CreateProgram;
sh_config.pProgAutoFields = D3D9Shader_ProgAutoFields;
sh_config.texture_non_power_of_two = 0;
sh_config.tex_env_combine = 1;
sh_config.nv_tex_env_combine4 = 1;
sh_config.env_add = 1;

View file

@ -1257,6 +1257,9 @@ rendererinfo_t d3d9rendererinfo =
D3D9_VID_DeInit,
D3D9_VID_SwapBuffers,
D3D9_VID_ApplyGammaRamps,
NULL,
NULL,
NULL,
D3D9_VID_SetWindowCaption,
D3D9_VID_GetRGBInfo,

View file

@ -1447,6 +1447,9 @@ rendererinfo_t d3d11rendererinfo =
D3D11_VID_DeInit,
D3D11_PresentOrCrash,
D3D11_VID_ApplyGammaRamps,
NULL,
NULL,
NULL,
D3D11_VID_SetWindowCaption,
D3D11_VID_GetRGBInfo,

View file

@ -1280,7 +1280,9 @@
AdditionalIncludeDirectories="../libs/speex,..\client,../libs/freetype2/include,../common,../server,../gl,../sw,../qclib,../libs,../libs/dxsdk7/include"
PreprocessorDefinitions="_DEBUG;WIN32;_WINDOWS;SERVERONLY;MULTITHREAD"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="0"
EnableFunctionLevelLinking="true"
FloatingPointModel="2"
UsePrecompiledHeader="2"
PrecompiledHeaderThrough="quakedef.h"
@ -3022,6 +3024,10 @@
/>
</FileConfiguration>
</File>
<File
RelativePath="..\server\sv_cluster.c"
>
</File>
<File
RelativePath="..\server\sv_demo.c"
>
@ -27232,6 +27238,13 @@
<File
RelativePath="..\common\net_ssl_winsspi.c"
>
<FileConfiguration
Name="MinGLRelease|Win32"
>
<Tool
Name="VCCLCompilerTool"
/>
</FileConfiguration>
</File>
<File
RelativePath="..\common\net_wins.c"
@ -30034,6 +30047,7 @@
</FileConfiguration>
<FileConfiguration
Name="MinGLRelease|Win32"
ExcludedFromBuild="true"
>
<Tool
Name="VCCLCompilerTool"
@ -30198,6 +30212,7 @@
</FileConfiguration>
<FileConfiguration
Name="MinGLRelease|Win32"
ExcludedFromBuild="true"
>
<Tool
Name="VCCLCompilerTool"
@ -30362,6 +30377,7 @@
</FileConfiguration>
<FileConfiguration
Name="MinGLRelease|Win32"
ExcludedFromBuild="true"
>
<Tool
Name="VCCLCompilerTool"
@ -30526,6 +30542,7 @@
</FileConfiguration>
<FileConfiguration
Name="MinGLRelease|Win32"
ExcludedFromBuild="true"
>
<Tool
Name="VCCLCompilerTool"

View file

@ -772,7 +772,7 @@ static shader_t *GL_ChooseSkin(galiasinfo_t *inf, model_t *model, int surfnum, e
tinheight = inheight;
//don't make scaled width any larger than it needs to be
if (gl_config.texture_non_power_of_two)
if (sh_config.texture_non_power_of_two)
{
scaled_width = tinwidth;
scaled_height = tinheight;

View file

@ -1382,7 +1382,6 @@ void GLBE_Init(void)
BE_SendPassBlendDepthMask(0);
currententity = &r_worldentity;
shaderstate.fogtexture = r_nulltex;
shaderstate.depthonlyshader = R_RegisterShader("depthonly", SUF_NONE,
@ -3318,6 +3317,8 @@ void GLBE_SelectMode(backendmode_t mode)
{
default:
break;
case BEM_WIREFRAME:
break;
case BEM_DEPTHONLY:
#ifndef GLSLONLY
if (!gl_config_nofixedfunc)
@ -3888,7 +3889,7 @@ static void DrawMeshes(void)
{
GL_LazyBind(--shaderstate.lastpasstmus, 0, r_nulltex);
}
BE_SendPassBlendDepthMask(shaderstate.curshader->passes[0].shaderbits | SBITS_MISC_NODEPTHTEST);
BE_SendPassBlendDepthMask((shaderstate.curshader->passes[0].shaderbits & ~SBITS_BLEND_BITS) | SBITS_SRCBLEND_SRC_ALPHA | SBITS_DSTBLEND_ONE_MINUS_SRC_ALPHA | SBITS_MISC_NODEPTHTEST);
BE_EnableShaderAttributes((1u<<VATTR_LEG_VERTEX) | (1u<<VATTR_LEG_COLOUR), 0);
BE_SubmitMeshChain();

View file

@ -54,6 +54,7 @@ cvar_t r_norefresh = SCVAR("r_norefresh","0");
extern cvar_t gl_part_flame;
extern cvar_t r_bloom;
extern cvar_t r_wireframe_smooth;
cvar_t gl_affinemodels = SCVAR("gl_affinemodels","0");
cvar_t gl_reporttjunctions = SCVAR("gl_reporttjunctions","0");
@ -141,6 +142,7 @@ void GL_InitSceneProcessingShaders (void)
GL_InitSceneProcessingShaders_WaterWarp();
}
r_wireframe_smooth.modified = true;
gl_dither.modified = true; //fixme: bad place for this, but hey
vid_srgb.modified = true;
}
@ -499,6 +501,22 @@ void R_SetupGL (float stereooffset)
qglLoadMatrixf(r_refdef.m_view);
}
if (!gl_config.gles && r_wireframe_smooth.modified)
{
r_wireframe_smooth.modified = false;
if (r_wireframe_smooth.ival)
{
qglEnable(GL_LINE_SMOOTH);
if (qglHint)
qglHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
}
else
{
qglDisable(GL_LINE_SMOOTH);
if (qglHint)
qglHint(GL_LINE_SMOOTH_HINT, GL_FASTEST);
}
}
if (!gl_config.gles && gl_dither.modified)
{
gl_dither.modified = false;

View file

@ -356,8 +356,7 @@ static qboolean Shader_EvaluateCondition(shader_t *shader, char **ptr)
}
else
{
if (cv)
conditiontrue = conditiontrue == !!lhs;
conditiontrue = conditiontrue == !!lhs;
}
}
if (*token)

View file

@ -2096,6 +2096,7 @@ void GL_Init(void *(*getglfunction) (char *name))
sh_config.shadernamefmt = "%s_glsl";
}
sh_config.texture_non_power_of_two = gl_config.texture_non_power_of_two;
sh_config.progs_supported = gl_config.arb_shader_objects;
sh_config.progs_required = gl_config_nofixedfunc;
@ -2334,6 +2335,9 @@ rendererinfo_t openglrendererinfo = {
GLVID_DeInit,
GLVID_SwapBuffers,
GLVID_ApplyGammaRamps,
NULL,
NULL,
NULL,
GLVID_SetCaption, //setcaption
GLVID_GetRGBInfo,

View file

@ -2030,6 +2030,9 @@ rendererinfo_t eglrendererinfo =
GLVID_SwapBuffers,
GLVID_ApplyGammaRamps,
NULL,
NULL,
NULL,
GLVID_SetCaption, //setcaption
GLVID_GetRGBInfo,

View file

@ -112,6 +112,7 @@ static qboolean vid_canalttab = false;
static qboolean vid_wassuspended = false;
extern qboolean mouseactive; // from in_win.c
static HICON hIcon;
static HCURSOR hArrowCursor, hCustomCursor;
extern qboolean vid_isfullscreen;
unsigned short originalgammaramps[3][256];
@ -552,6 +553,101 @@ RECT centerrect(unsigned int parentleft, unsigned int parenttop, unsigned int pa
return r;
}
void *WIN_CreateCursor(char *filename, int hotx, int hoty)
{
int width, height;
BITMAPV5HEADER bi;
DWORD x,y;
HCURSOR hAlphaCursor = NULL;
ICONINFO ii;
qbyte *rgbadata, *rgbadata_start, *bgradata, *bgradata_start;
qboolean hasalpha;
void *filedata;
int filelen;
if (!filename || !*filename)
return NULL;
filelen = FS_LoadFile(filename, &filedata);
if (!filedata)
return NULL;
rgbadata_start = Read32BitImageFile(filedata, filelen, &width, &height, &hasalpha, "cursor");
FS_FreeFile(filedata);
if (!rgbadata_start)
return NULL;
memset(&bi,0, sizeof(BITMAPV5HEADER));
bi.bV5Size = sizeof(BITMAPV5HEADER);
bi.bV5Width = width;
bi.bV5Height = height;
bi.bV5Planes = 1;
bi.bV5BitCount = 32;
bi.bV5Compression = BI_BITFIELDS;
// The following mask specification specifies a supported 32 BPP
// alpha format for Windows XP.
bi.bV5RedMask = 0x00FF0000;
bi.bV5GreenMask = 0x0000FF00;
bi.bV5BlueMask = 0x000000FF;
bi.bV5AlphaMask = 0xFF000000;
// Create the DIB section with an alpha channel.
ii.hbmColor = CreateDIBSection(maindc, (BITMAPINFO *)&bi, DIB_RGB_COLORS, (void **)&bgradata_start, NULL, 0);
if (!ii.hbmColor)
{
BZ_Free(rgbadata_start);
return NULL;
}
for (rgbadata=rgbadata_start,y=0;y<height;y++)
{
bgradata = bgradata_start + (height-1-y)*width*4;
for (x=0;x<width;x++)
{
bgradata[0] = rgbadata[2];
bgradata[1] = rgbadata[1];
bgradata[2] = rgbadata[0];
bgradata[3] = rgbadata[3];
bgradata+=4;
rgbadata+=4;
}
}
BZ_Free(rgbadata_start);
ii.fIcon = FALSE; // Change fIcon to TRUE to create an alpha icon
ii.xHotspot = hotx;
ii.yHotspot = hoty;
ii.hbmMask = CreateBitmap(width,height,1,1,NULL);
// Create the alpha cursor with the alpha DIB section.
hAlphaCursor = CreateIconIndirect(&ii);
DeleteObject(ii.hbmColor);
DeleteObject(ii.hbmMask);
return hAlphaCursor;
}
qboolean WIN_SetCursor(void *cursor)
{
static POINT current_pos; //static to avoid bugs in vista(32) with largeaddressaware (this is fixed in win7). fixed exe base address prevents this from going above 2gb.
hCustomCursor = cursor;
//move the cursor to ensure the WM_SETCURSOR thing is invoked properly.
//this ensures all the nastyness of random programs randomly setting the current global cursor is handled by microsoft's code instead of mine.
//if you're using rawinput there'll be no lost inpuit problems, yay...
GetCursorPos(&current_pos);
SetCursorPos(current_pos.x, current_pos.y);
return true;
}
void WIN_DestroyCursor(void *cursor)
{
DestroyIcon(cursor);
}
qboolean VID_SetWindowedMode (rendererstate_t *info)
//qboolean VID_SetWindowedMode (int modenum)
{
@ -1893,12 +1989,12 @@ static void Win_Touch_Event(int points, HTOUCHINPUT ti)
/* main window procedure */
LONG WINAPI GLMainWndProc (
HWND hWnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
HWND hWnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
LONG lRet = 1;
LONG lRet = 1;
// int fActive, fMinimized;
int temp;
extern unsigned int uiWheelMessage;
@ -1906,8 +2002,8 @@ LONG WINAPI GLMainWndProc (
if ( uMsg == uiWheelMessage )
uMsg = WM_MOUSEWHEEL;
switch (uMsg)
{
switch (uMsg)
{
case WM_COPYDATA:
{
COPYDATASTRUCT *cds = (COPYDATASTRUCT*)lParam;
@ -2055,16 +2151,16 @@ LONG WINAPI GLMainWndProc (
mmi->ptMinTrackSize.y = 200 + ((windowrect.bottom - windowrect.top) - (clientrect.bottom - clientrect.top));
}
return 0;
case WM_SIZE:
case WM_SIZE:
vid.isminimized = (wParam==SIZE_MINIMIZED);
if (!vid_initializing)
{
VID_UpdateWindowStatus (hWnd);
Cvar_ForceCallback(&vid_conautoscale);
}
break;
break;
case WM_CLOSE:
case WM_CLOSE:
if (!vid_initializing)
if (MessageBox (mainwindow, "Are you sure you want to quit?", "Confirm Exit",
MB_YESNO | MB_SETFOREGROUND | MB_ICONQUESTION) == IDYES)
@ -2072,7 +2168,7 @@ LONG WINAPI GLMainWndProc (
Cbuf_AddText("\nquit\n", RESTRICT_LOCAL);
}
break;
break;
case WM_ACTIVATE:
// fActive = LOWORD(wParam);
@ -2089,25 +2185,41 @@ LONG WINAPI GLMainWndProc (
break;
case WM_DESTROY:
{
case WM_DESTROY:
if (dibwindow)
DestroyWindow (dibwindow);
}
break;
case MM_MCINOTIFY:
lRet = CDAudio_MessageHandler (hWnd, uMsg, wParam, lParam);
break;
case WM_SETCURSOR:
//only use a custom cursor if the cursor is inside the client area
switch(lParam&0xffff)
{
case 0:
break;
case HTCLIENT:
if (hCustomCursor) //custom cursor enabled
SetCursor(hCustomCursor);
else //fallback on an arrow cursor, just so we have something visible at startup or so
SetCursor(hArrowCursor);
lRet = TRUE;
break;
default:
lRet = DefWindowProc (hWnd, uMsg, wParam, lParam);
break;
}
break;
default:
/* pass all unhandled messages to DefWindowProc */
lRet = DefWindowProc (hWnd, uMsg, wParam, lParam);
break;
}
case MM_MCINOTIFY:
lRet = CDAudio_MessageHandler (hWnd, uMsg, wParam, lParam);
break;
/* return 1 if handled message, 0 if not */
return lRet;
default:
/* pass all unhandled messages to DefWindowProc */
lRet = DefWindowProc (hWnd, uMsg, wParam, lParam);
break;
}
/* return 1 if handled message, 0 if not */
return lRet;
}
@ -2176,6 +2288,11 @@ qboolean GLVID_Init (rendererstate_t *info, unsigned char *palette)
memset(&devmode, 0, sizeof(devmode));
hIcon = LoadIcon (global_hInstance, MAKEINTRESOURCE (IDI_ICON1));
hArrowCursor = LoadCursor (NULL,IDC_ARROW);
rf->VID_CreateCursor = WIN_CreateCursor;
rf->VID_DestroyCursor = WIN_DestroyCursor;
rf->VID_SetCursor = WIN_SetCursor;
/* Register the frame class */
wc.style = CS_OWNDC;
@ -2184,7 +2301,7 @@ qboolean GLVID_Init (rendererstate_t *info, unsigned char *palette)
wc.cbWndExtra = 0;
wc.hInstance = global_hInstance;
wc.hIcon = hIcon;
wc.hCursor = LoadCursor (NULL,IDC_ARROW);
wc.hCursor = hArrowCursor;
wc.hbrBackground = NULL;
wc.lpszMenuName = 0;
wc.lpszClassName = WINDOW_CLASS_NAME;

View file

@ -626,6 +626,7 @@ typedef struct
unsigned int minver; //lowest glsl version usable
unsigned int maxver; //highest glsl version usable
qboolean texture_non_power_of_two;
qboolean tex_env_combine;
qboolean nv_tex_env_combine4;
qboolean env_add;

View file

@ -829,7 +829,7 @@ void GenericMenu(WPARAM wParam)
break;
case IDM_ABOUT:
MessageBox(NULL, "FTE QuakeC Compiler\nWritten by Forethough Entertainment.\n\nIt has a few cool features, like a semi-useful IDE.\n\nSupports:\nPrecompiler (with macros)\nArrays\n+= / -= / *= / /= operations.\nSwitch statements\nfor loops\nLots of optimisations.", "About", 0);
MessageBox(NULL, "FTE QuakeC Compiler ("__DATE__" "__TIME__")\nWritten by Forethought Entertainment.\n\nIt has a few cool features, like a semi-useful IDE.\n\nSupports:\nPrecompiler (with macros)\nArrays\n+= / -= / *= / /= operations.\nSwitch statements\nfor loops\nLots of optimisations.", "About", 0);
break;
case IDM_CASCADE:

View file

@ -144,6 +144,7 @@ struct {
func_t UserInfo_Changed;
func_t localinfoChanged;
func_t ParseClusterEvent; //FTE_SV_CLUSTER
func_t ParseClientCommand; //KRIMZON_SV_PARSECLIENTCOMMAND
func_t ParseConnectionlessPacket; //FTE_QC_SENDPACKET
@ -773,6 +774,7 @@ void PR_LoadGlabalStruct(void)
SpectatorDisconnect = PR_FindFunction(svprogfuncs, "SpectatorDisconnect", PR_ANY);
SpectatorThink = PR_FindFunction(svprogfuncs, "SpectatorThink", PR_ANY);
gfuncs.ParseClusterEvent = PR_FindFunction(svprogfuncs, "SV_ParseClusterEvent", PR_ANY);
gfuncs.ParseClientCommand = PR_FindFunction(svprogfuncs, "SV_ParseClientCommand", PR_ANY);
gfuncs.ParseConnectionlessPacket = PR_FindFunction(svprogfuncs, "SV_ParseConnectionlessPacket", PR_ANY);
@ -1766,6 +1768,27 @@ qboolean PR_GameCodePacket(char *s)
return G_FLOAT(OFS_RETURN);
}
qboolean PR_ParseClusterEvent(char *dest, char *source, char *cmd, char *info)
{
globalvars_t *pr_globals;
if (svprogfuncs && gfuncs.ParseClusterEvent)
{
pr_globals = PR_globals(svprogfuncs, PR_CURRENT);
pr_global_struct->time = sv.world.physicstime;
pr_global_struct->self = 0;
G_INT(OFS_PARM0) = (int)PR_TempString(svprogfuncs, dest);
G_INT(OFS_PARM1) = (int)PR_TempString(svprogfuncs, source);
G_INT(OFS_PARM2) = (int)PR_TempString(svprogfuncs, cmd);
G_INT(OFS_PARM3) = (int)PR_TempString(svprogfuncs, info);
PR_ExecuteProgram (svprogfuncs, gfuncs.ParseClusterEvent);
return true;
}
return false;
}
qboolean PR_KrimzonParseCommand(char *s)
{
globalvars_t *pr_globals;
@ -8307,13 +8330,14 @@ int PF_ForceInfoKey_Internal(unsigned int entnum, const char *key, const char *v
if (!strcmp(key, "*spectator"))
svs.clients[entnum-1].spectator = !!atoi(value);
#ifdef SUBSERVERS
if (!strcmp(key, "*transfer"))
{
#ifdef SUBSERVERS
SSV_InitiatePlayerTransfer(&svs.clients[entnum-1], value);
#else
if (*value)
PF_ForceInfoKey_Internal(entnum, key, "");
#endif
}
return 1;
}
@ -8874,6 +8898,16 @@ static void QCBUILTIN PF_SendPacket(pubprogfuncs_t *prinst, struct globalvars_s
NET_SendPacket(NS_SERVER, strlen(contents), contents, &to);
}
static void QCBUILTIN PF_clusterevent(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
#ifdef SUBSERVERS
const char *dest = PR_GetStringOfs(prinst, OFS_PARM0);
const char *src = PR_GetStringOfs(prinst, OFS_PARM1);
const char *cmd = PR_GetStringOfs(prinst, OFS_PARM2);
const char *info = PF_VarString(prinst, 13, pr_globals);
SSV_Send(dest, src, cmd, info);
#endif
}
#define STUB ,NULL,true
@ -9368,6 +9402,7 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
{"hash_getcb", PF_hash_getcb, 0, 0, 0, 293, D("void(float table, void(string keyname, __variant val) callback, optional string name)", "For each item in the table that matches the name, call the callback. if name is omitted, will enumerate ALL keys."), true},
{"checkcommand", PF_checkcommand, 0, 0, 0, 294, D("float(string name)", "Checks to see if the supplied name is a valid command, cvar, or alias. Returns 0 if it does not exist.")},
{"argescape", PF_argescape, 0, 0, 0, 295, D("string(string s)", "Marks up a string so that it can be reliably tokenized as a single argument later.")},
{"clusterevent", PF_clusterevent, 0, 0, 0, 296, D("void(string dest, string from, string cmd, string info)", "Only functions in mapcluster mode. Sends an event to whichever server the named player is on. The destination server can then dispatch the event to the client or handle it itself via the SV_ParseClusterEvent entrypoint. If dest is empty, the event is broadcast to ALL servers. If the named player can't be found, the event will be returned to this server with the cmd prefixed with 'error:'.")},
{"clearscene", PF_Fixme, 0, 0, 0, 300, D("void()", "Forgets all rentities, polygons, and temporary dlights. Resets all view properties to their default values.")},// (EXT_CSQC)
@ -9431,7 +9466,7 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
{"stringtokeynum_csqc", PF_Fixme,0, 0, 0, 341, D("float(string keyname)", "Looks up the key name in the same way that the bind command would, returning the keycode for that key.")},// (found in menuqc)
{"getkeybind", PF_Fixme, 0, 0, 0, 342, D("string(float keynum)", "Finds the current binding for the given key (ignores modifiers like shift/alt/ctrl).")},// (EXT_CSQC)
{"setcursormode", PF_Fixme, 0, 0, 0, 343, D("void(float usecursor)", "Pass TRUE if you want the engine to release the mouse cursor (absolute input events + touchscreen mode). Pass FALSE if you want the engine to grab the cursor (relative input events + standard looking)")}, // #343 This is a DP extension
{"setcursormode", PF_Fixme, 0, 0, 0, 343, D("void(float usecursor, optional string cursorimage, optional vector hotspot, optional float scale)", "Pass TRUE if you want the engine to release the mouse cursor (absolute input events + touchscreen mode). Pass FALSE if you want the engine to grab the cursor (relative input events + standard looking). If the image name is specified, the engine will use that image for a cursor (use an empty string to clear it again), in a way that will not conflict with the console. Images specified this way will be hardware accelerated, if supported by the platform/port.")},
{"getmousepos", PF_Fixme, 0, 0, 0, 344, D("vector()", "Nasty convoluted DP extension. Typically returns deltas instead of positions. Use CSQC_InputEvent for such things in csqc mods.")}, // #344 This is a DP extension
{"getinputstate", PF_Fixme, 0, 0, 0, 345, D("float(float inputsequencenum)", "Looks up an input frame from the log, setting the input_* globals accordingly.\nThe sequence number range used for prediction should normally be servercommandframe < sequence <= clientcommandframe.\nThe sequence equal to clientcommandframe will change between input frames.")},// (EXT_CSQC)
@ -10077,7 +10112,7 @@ typedef struct
char *desc;
int value;
float value;
char *valuestr;
qboolean misc;
} knowndef_t;
@ -10279,15 +10314,16 @@ void PR_DumpPlatform_f(void)
{"SpectatorDisconnect", "noref void()", QW|NQ, "Called when a spectator disconnects from the game."},
{"SpectatorThink", "noref void()", QW|NQ, "Called each frame for each spectator."},
{"SV_ParseClientCommand", "noref void(string cmd)", QW|NQ, "Provides QC with a way to intercept 'cmd foo' commands from the client. Very handy. Self will be set to the sending client, while the 'cmd' argument can be tokenize()d and each element retrieved via argv(argno). Unrecognised cmds MUST be passed on to the clientcommand builtin."},
{"SV_ParseClusterEvent", "noref void(string dest, string from, string cmd, string info)", QW|NQ, "Part of cluster mode. Handles cross-node events that were sent via clusterevent, on behalf of the named client."},
{"SV_ParseConnectionlessPacket", "noref float(string sender, string body)", QW|NQ, "Provides QC with a way to communicate between servers, or with client server browsers. Sender is the sender's ip. Body is the body of the message. You'll need to add your own password/etc support as required. Self is not valid."},
{"SV_PausedTic", "noref void(float pauseduration)", QW|NQ, "For each frame that the server is paused, this function will be called to give the gamecode a chance to unpause the server again. the pauseduration argument says how long the server has been paused for (the time global is frozen and will not increment while paused). Self is not valid."},
{"SV_ShouldPause", "noref float(float newstatus)", QW|NQ, "Called to give the qc a change to block pause/unpause requests. Return false for the pause request to be ignored. newstatus is 1 if the user is trying to pause the game. For the duration of the call, self will be set to the player who tried to pause, or to world if it was triggered by a server-side event."},
{"ClassChangeWeapon", "noref void()", H2, "Hexen2 support. Called when cl_playerclass changes. Self is set to the player who is changing class."},
{"SV_RunClientCommand", "noref void()", QW|NQ, "Called each time a player movement packet was received from a client. Self is set to the player entity which should be updated, while the input_* globals specify the various properties stored within the input packet. The contents of this function should be somewaht identical to the equivelent function in CSQC, or prediction misses will occur. If you're feeling lazy, you can simply call 'runstandardplayerphysics' after modifying the inputs."},
{"SV_AddDebugPolygons", "noref void()", QW|NQ, "Called each video frame. This is the only place where ssqc is allowed to call the R_BeginPolygon/R_PolygonVertex/R_EndPolygon builtins. This is exclusively for debugging, and will break in anything but single player as it will not be called if the engine is not running both a client and a server."},
{"SV_PlayerPhysics", "noref void()", QW|NQ, "Legacy method to tweak player input that does not reliably work with prediction (prediction WILL break). Mods that care about prediction should use SV_RunClientCommand instead. If pr_no_playerphysics is set to 1, this function will never be called, which will either fix prediction or completely break player movement depending on whether the feature was even useful."},
{"EndFrame", "noref void()", QW|NQ, "Called after non-player entities have been run at the end of the physics frame. Player physics is performed out of order and can/will still occur between EndFrame and BeginFrame."},
{"SV_CheckRejectConnection","noref string(string addr, string uinfo, string features) ", QW|NQ, "Called to give the mod a chance to ignore connection requests based upon client protocol support or other properties. Use infoget to read the uinfo and features arguments."},
{"ClassChangeWeapon", "noref void()", H2, "Hexen2 support. Called when cl_playerclass changes. Self is set to the player who is changing class."},
/* //mvdsv compat
{"UserInfo_Changed", "//noref void()", QW},
{"localinfoChanged", "//noref void()", QW},
@ -10928,9 +10964,9 @@ void PR_DumpPlatform_f(void)
if (!strcmp(knowndefs[i].type, "const float"))
{
if (defines)
VFS_PRINTF(f, "#define %s %i%s\n", knowndefs[i].name, knowndefs[i].value, comment);
VFS_PRINTF(f, "#define %s %g%s\n", knowndefs[i].name, knowndefs[i].value, comment);
else
VFS_PRINTF(f, "%s %s = %i;%s\n", knowndefs[i].type, knowndefs[i].name, knowndefs[i].value, comment);
VFS_PRINTF(f, "%s %s = %g;%s\n", knowndefs[i].type, knowndefs[i].name, knowndefs[i].value, comment);
}
else if (!strcmp(knowndefs[i].type, "const string"))
{
@ -10945,7 +10981,7 @@ void PR_DumpPlatform_f(void)
}
else if (knowndefs[i].value)
{
VFS_PRINTF(f, "%s %s = %i;%s\n", knowndefs[i].type, knowndefs[i].name, knowndefs[i].value, comment);
VFS_PRINTF(f, "%s %s = %g;%s\n", knowndefs[i].type, knowndefs[i].name, knowndefs[i].value, comment);
}
else
VFS_PRINTF(f, "%s %s;%s\n", knowndefs[i].type, knowndefs[i].name, comment);

View file

@ -38,6 +38,7 @@ void PR_Init(void);
void QDECL ED_Spawned (struct edict_s *ent, int loading);
qboolean SV_RunFullQCMovement(struct client_s *client, usercmd_t *ucmd);
qboolean PR_KrimzonParseCommand(char *s);
qboolean PR_ParseClusterEvent(char *dest, char *source, char *cmd, char *info);
qboolean PR_UserCmd(char *cmd);
qboolean PR_ConsoleCmd(const char *cmd);

View file

@ -163,6 +163,7 @@ void SV_Loadgame_Legacy(char *filename, vfsfile_t *f, int version)
cl->state = cs_loadzombie;
cl->connection_started = realtime+20;
cl->istobeloaded = true;
cl->userid = 0;
//probably should be 32, rather than NUM_SPAWN_PARMS(64)
for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
@ -1218,6 +1219,7 @@ void SV_Loadgame_f (void)
cl->state = cs_loadzombie;
cl->connection_started = realtime+20;
cl->istobeloaded = true;
cl->userid = 0;
loadzombies++;
memset(&cl->netchan, 0, sizeof(cl->netchan));

View file

@ -378,9 +378,6 @@ typedef struct client_s
int challenge;
int userid; // identifying number
char userinfo[EXTENDED_INFO_STRING]; // infostring
#ifdef SUBSERVERS
unsigned int previousserver;
#endif
usercmd_t lastcmd; // for filling in big drops and partial predictions
double localtime; // of last message
@ -1024,13 +1021,22 @@ void SSV_PollSlaves(void);
void SSV_InstructMaster(sizebuf_t *cmd);
void SSV_PrintToMaster(char *s);
void SSV_ReadFromControlServer(void);
void SSV_SavePlayerStats(client_t *cl, unsigned int previousserver);
void SSV_SavePlayerStats(client_t *cl, int reason); //initial, periodic (in case of node crashes), part
void Sys_InstructSlave(pubsubserver_t *s, sizebuf_t *cmd);
int Sys_SubServerRead(pubsubserver_t *s); //1: yes. 0: no. -1: error
pubsubserver_t *Sys_ForkServer(void);
#define SSV_IsSubServer() isClusterSlave
void MSV_SubServerCommand_f(void);
void MSV_SubServerCommand_f(void);
void MSV_MapCluster_f(void);
void SSV_Send(const char *dest, const char *src, const char *cmd, const char *msg);
qboolean MSV_ClusterLogin(char *guid, char *userinfo, size_t userinfosize);
void MSV_PollSlaves(void);
void MSV_Status(void);
#else
#define SSV_UpdateAddresses() false
#define MSV_ClusterLogin(guid,info,infosize) false
@ -1040,7 +1046,6 @@ pubsubserver_t *Sys_ForkServer(void);
//
// sv_init.c
//
void SV_SpawnClusterMode(void);
void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean usecinematic);
void SV_UnspawnServer (void);
void SV_FlushSignon (void);

View file

@ -1708,8 +1708,15 @@ static void SV_Status_f (void)
if (NET_GetRates(svs.sockets, &pi, &po, &bi, &bo))
Con_Printf("packets,bytes/sec: in: %g %g out: %g %g\n", pi, bi, po, bo); //not relevent as a limit.
Con_Printf("server uptime : %s\n", ShowTime(realtime));
Con_Printf("public : %s\n", sv_public.value?"yes":"no");
Con_Printf("client types :%s%s%s%s\n", sv_listen_qw.ival?" QW":"", sv_listen_nq.ival?" NQ":"", sv_listen_dp.ival?" DP":"", sv_listen_q3.ival?" Q3":"");
#ifdef SUBSERVERS
if (sv.state == ss_clustermode)
{
MSV_Status();
return;
}
#endif
Con_Printf("map uptime : %s\n", ShowTime(sv.world.physicstime));
//show the current map+name (but hide name if its too long or would be ugly)
if (columns >= 80 && *sv.mapname && strlen(sv.mapname) < 45 && !strchr(sv.mapname, '\n'))
@ -1735,8 +1742,6 @@ static void SV_Status_f (void)
Con_Printf("csqc debug : true\n");
if (sv.mvdrecording)
Con_Printf("recording : %s\n", SV_Demo_CurrentOutput());
Con_Printf("public : %s\n", sv_public.value?"yes":"no");
Con_Printf("client types :%s%s%s%s\n", sv_listen_qw.ival?" QW":"", sv_listen_nq.ival?" NQ":"", sv_listen_dp.ival?" DP":"", sv_listen_q3.ival?" Q3":"");
// min fps lat drp
if (columns < 80)

1088
engine/server/sv_cluster.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -664,7 +664,7 @@ void SV_UpdateMaxPlayers(int newmax)
sv.allocated_client_slots = svs.allocated_client_slots;
}
static void SV_SetupNetworkBuffers(qboolean bigcoords)
void SV_SetupNetworkBuffers(qboolean bigcoords)
{
int i;
@ -741,31 +741,6 @@ static void SV_SetupNetworkBuffers(qboolean bigcoords)
sv.num_signon_buffers = 1;
}
#ifdef SUBSERVERS
void SV_SpawnClusterMode(void)
{
char *sqlparams[] =
{
"",
"",
"",
"login",
};
if (sv.state)
SV_UnspawnServer();
NET_InitServer();
//child processes return 0 and fall through
memset(&sv, 0, sizeof(sv));
sv.state = ss_clustermode;
sv.logindatabase = -1;//SQL_NewServer("sqlite", sqlparams);
//and for legacy clients, we need some server stuff inited.
SV_SetupNetworkBuffers(false);
SV_UpdateMaxPlayers(32);
}
#endif
/*
================
SV_SpawnServer

View file

@ -247,7 +247,8 @@ void SV_Shutdown (void)
sv_fraglogfile = NULL;
}
PR_Shutdown();
SV_UnspawnServer();
#ifdef USEODE
World_ODE_Shutdown();
#endif
@ -494,11 +495,11 @@ void SV_DropClient (client_t *drop)
Rank_SetPlayerStats(drop->rankid, &rs);
}
}
#endif
#ifdef SUBSERVERS
SSV_SavePlayerStats(drop, false);
#endif
}
#ifdef SUBSERVERS
SSV_SavePlayerStats(drop, 2);
#endif
#ifdef SVCHAT
SV_WipeChat(drop);
#endif
@ -1854,798 +1855,7 @@ void SV_ClientProtocolExtensionsChanged(client_t *client)
}
}
#ifdef SUBSERVERS
void MSV_UpdatePlayerStats(qboolean initial, unsigned int playerid, unsigned int serverid, int numstats, float *stats);
static char *knownmaps[] =
{
"",
"start"
};
static pubsubserver_t *subservers;
qboolean isClusterSlave;
unsigned int nextserverid;
pubsubserver_t *MSV_StartSubServer(unsigned int id, const char *mapname)
{
sizebuf_t send;
char send_buf[64];
pubsubserver_t *s = Sys_ForkServer();
if (s)
{
if (!id)
{
if (nextserverid < sizeof(knownmaps)/sizeof(knownmaps[0]))
nextserverid = sizeof(knownmaps)/sizeof(knownmaps[0]);
id = nextserverid++;
}
s->id = id;
s->next = subservers;
subservers = s;
Q_strncpyz(s->name, mapname, sizeof(s->name));
memset(&send, 0, sizeof(send));
send.data = send_buf;
send.maxsize = sizeof(send_buf);
send.cursize = 2;
MSG_WriteByte(&send, ccmd_acceptserver);
MSG_WriteLong(&send, s->id);
MSG_WriteString(&send, s->name);
Sys_InstructSlave(s, &send);
}
return s;
}
pubsubserver_t *MSV_FindSubServer(unsigned int id)
{
pubsubserver_t *s;
for (s = subservers; s; s = s->next)
{
if (id == s->id)
return s;
}
if (!s && id >= 1 && id < sizeof(knownmaps)/sizeof(knownmaps[0]))
s = MSV_StartSubServer(id, knownmaps[id]);
return s;
}
pubsubserver_t *MSV_FindSubServerName(const char *mapname)
{
pubsubserver_t *s;
unsigned int to;
for (to = 1; to < sizeof(knownmaps)/sizeof(knownmaps[0]); to++)
{
if (!strcmp(knownmaps[to], mapname))
return MSV_FindSubServer(to);
}
for (s = subservers; s; s = s->next)
{
if (!strcmp(s->name, mapname))
return s;
}
return MSV_StartSubServer(0, mapname);
}
qboolean MSV_AddressForMap(netadr_t *ret, int natype, int serverid)
{
pubsubserver_t *s = MSV_FindSubServer(serverid);
if (s)
{
if (natype == s->addrv6.type)
*ret = s->addrv6;
else
*ret = s->addrv4;
return true;
}
return false;
}
void MSV_InstructSlave(unsigned int id, sizebuf_t *cmd)
{
pubsubserver_t *s;
if (!id)
{
for (s = subservers; s; s = s->next)
Sys_InstructSlave(s, cmd);
}
else
{
s = MSV_FindSubServer(id);
if (s)
Sys_InstructSlave(s, cmd);
}
}
void MSV_MapCluster_f(void)
{
SV_SpawnClusterMode();
}
void SSV_PrintToMaster(char *s)
{
sizebuf_t send;
char send_buf[8192];
memset(&send, 0, sizeof(send));
send.data = send_buf;
send.maxsize = sizeof(send_buf);
send.cursize = 2;
MSG_WriteByte(&send, ccmd_print);
MSG_WriteString(&send, s);
SSV_InstructMaster(&send);
}
void MSV_SubServerCommand_f(void)
{
sizebuf_t buf;
char bufmem[1024];
pubsubserver_t *s;
int id;
char *c;
if (Cmd_Argc() == 1)
{
Con_Printf("Active servers on this cluster:\n");
for (s = subservers; s; s = s->next)
{
Con_Printf("%i: %s", s->id, s->name);
if (s->addrv4.type != NA_INVALID)
Con_Printf(" %s", NET_AdrToString(bufmem, sizeof(bufmem), &s->addrv4));
if (s->addrv6.type != NA_INVALID)
Con_Printf(" %s", NET_AdrToString(bufmem, sizeof(bufmem), &s->addrv6));
Con_Printf("\n");
}
return;
}
if (!strcmp(Cmd_Argv(0), "ssv_all"))
id = 0;
else
{
id = atoi(Cmd_Argv(1));
Cmd_ShiftArgs(1, false);
}
buf.data = bufmem;
buf.maxsize = sizeof(bufmem);
buf.cursize = 2;
buf.packing = SZ_RAWBYTES;
c = Cmd_Args();
MSG_WriteByte(&buf, ccmd_stuffcmd);
MSG_WriteString(&buf, c);
buf.data[0] = buf.cursize & 0xff;
buf.data[1] = (buf.cursize>>8) & 0xff;
MSV_InstructSlave(id, &buf);
}
void MSV_ReadFromSubServer(pubsubserver_t *s)
{
sizebuf_t send;
qbyte send_buf[MAX_QWMSGLEN];
netadr_t adr;
char *str;
int c;
c = MSG_ReadByte();
switch(c)
{
default:
case ccmd_bad:
Sys_Error("Corrupt message (%i) from SubServer %i:%s", c, s->id, s->name);
break;
case ccmd_print:
Con_Printf("%s", MSG_ReadString());
break;
case ccmd_saveplayer:
{
float stats[NUM_SPAWN_PARMS];
int i, numstats;
unsigned int lastserver = MSG_ReadLong();
int plid = MSG_ReadLong();
numstats = MSG_ReadByte();
for (i = 0; i < numstats; i++)
stats[i] = MSG_ReadFloat();
MSV_UpdatePlayerStats(lastserver, plid, s->id, numstats, stats);
}
break;
case ccmd_transferplayer:
{
char guid[64];
char mapname[64];
int plid = MSG_ReadLong();
char *newmap = MSG_ReadStringBuffer(mapname, sizeof(mapname));
char *claddr = MSG_ReadString();
char *clguid = MSG_ReadStringBuffer(guid, sizeof(guid));
pubsubserver_t *toptr;
memset(&send, 0, sizeof(send));
send.data = send_buf;
send.maxsize = sizeof(send_buf);
send.cursize = 2;
if (NULL!=(toptr=MSV_FindSubServerName(newmap)))
{
Con_Printf("Transfer to %i:%s\n", toptr->id, toptr->name);
MSG_WriteByte(&send, ccmd_takeplayer);
MSG_WriteLong(&send, plid);
MSG_WriteLong(&send, s->id);
MSG_WriteString(&send, claddr);
MSG_WriteString(&send, clguid);
c = MSG_ReadByte();
MSG_WriteByte(&send, c);
Con_Printf("Transfer %i stats\n", c);
while(c--)
MSG_WriteFloat(&send, MSG_ReadFloat());
Sys_InstructSlave(toptr, &send);
}
else
{
//suck up the stats
c = MSG_ReadByte();
while(c--)
MSG_ReadFloat();
Con_Printf("Transfer abort\n");
MSG_WriteByte(&send, ccmd_tookplayer);
MSG_WriteLong(&send, s->id);
MSG_WriteLong(&send, plid);
MSG_WriteString(&send, "");
Sys_InstructSlave(s, &send);
}
}
break;
case ccmd_tookplayer:
{
int to = MSG_ReadLong();
int plid = MSG_ReadLong();
char *claddr = MSG_ReadString();
char *rmsg;
netadr_t cladr;
netadr_t svadr;
char adrbuf[256];
Con_Printf("Took player\n");
memset(&send, 0, sizeof(send));
send.data = send_buf;
send.maxsize = sizeof(send_buf);
send.cursize = 2;
NET_StringToAdr(claddr, 0, &cladr);
MSV_AddressForMap(&svadr, cladr.type, s->id);
if (!to)
{
if (svadr.type != NA_INVALID)
{
rmsg = va("fredir\n%s", NET_AdrToString(adrbuf, sizeof(adrbuf), &svadr));
Netchan_OutOfBand (NS_SERVER, &cladr, strlen(rmsg), (qbyte *)rmsg);
}
}
else
{
MSG_WriteByte(&send, ccmd_tookplayer);
MSG_WriteLong(&send, s->id);
MSG_WriteLong(&send, plid);
MSG_WriteString(&send, NET_AdrToString(adrbuf, sizeof(adrbuf), &svadr));
MSV_InstructSlave(to, &send);
}
}
break;
case ccmd_serveraddress:
s->addrv4.type = NA_INVALID;
s->addrv6.type = NA_INVALID;
str = MSG_ReadString();
Q_strncpyz(s->name, str, sizeof(s->name));
for (;;)
{
str = MSG_ReadString();
if (!*str)
break;
if (NET_StringToAdr(str, 0, &adr))
{
if (adr.type == NA_IP && s->addrv4.type == NA_INVALID)
s->addrv4 = adr;
if (adr.type == NA_IPV6 && s->addrv6.type == NA_INVALID)
s->addrv6 = adr;
}
}
Con_Printf("%i:%s: restarted\n", s->id, s->name);
break;
}
if (msg_readcount != net_message.cursize || msg_badread)
Sys_Error("Master: Readcount isn't right (%i)\n", net_message.data[0]);
}
void MSV_PollSlaves(void)
{
pubsubserver_t **link, *s;
for (link = &subservers; (s=*link); )
{
switch(Sys_SubServerRead(s))
{
case -1:
//error - server is dead and needs to be freed.
*link = s->next;
Z_Free(s);
break;
case 0:
//no messages
link = &s->next;
break;
case 1:
//got a message. read it and see if there's more.
MSV_ReadFromSubServer(s);
break;
}
}
}
void SSV_ReadFromControlServer(void)
{
int c;
char *s;
c = MSG_ReadByte();
switch(c)
{
case ccmd_bad:
default:
SV_Error("Invalid message from cluster (%i)\n", c);
break;
case ccmd_stuffcmd:
s = MSG_ReadString();
SV_BeginRedirect(RD_MASTER, 0);
Cmd_ExecuteString(s, RESTRICT_LOCAL);
SV_EndRedirect();
break;
case ccmd_acceptserver:
svs.clusterserverid = MSG_ReadLong();
s = MSG_ReadString();
if (*s && !strchr(s, ';') && !strchr(s, '\n') && !strchr(s, '\"')) //sanity check the argument
Cmd_ExecuteString(va("map \"%s\"", s), RESTRICT_LOCAL);
if (svprogfuncs && pr_global_ptrs->serverid)
*pr_global_ptrs->serverid = svs.clusterserverid;
break;
case ccmd_tookplayer:
{
client_t *cl = NULL;
int to = MSG_ReadLong();
int plid = MSG_ReadLong();
char *addr = MSG_ReadString();
int i;
Con_Printf("%s: got tookplayer\n", sv.name);
for (i = 0; i < svs.allocated_client_slots; i++)
{
if (svs.clients[i].state && svs.clients[i].userid == plid)
{
cl = &svs.clients[i];
break;
}
}
if (cl)
{
if (!*addr)
{
Con_Printf("%s: tookplayer: failed\n", sv.name);
Info_SetValueForStarKey(cl->userinfo, "*transfer", "", sizeof(cl->userinfo));
}
else
{
Con_Printf("%s: tookplayer: do transfer\n", sv.name);
// SV_StuffcmdToClient(cl, va("connect \"%s\"\n", addr));
SV_StuffcmdToClient(cl, va("cl_transfer \"%s\"\n", addr));
cl->redirect = 2;
}
}
else
Con_Printf("%s: tookplayer: invalid player.\n", sv.name);
}
break;
case ccmd_transferedplayer:
{
client_t *cl;
char *to;
int toserver = MSG_ReadLong();
int playerid = MSG_ReadLong();
int i;
for (i = 0; i < svs.allocated_client_slots; i++)
{
if (svs.clients[i].userid == playerid && svs.clients[i].state >= cs_loadzombie)
{
cl = &svs.clients[i];
cl->drop = true;
to = Info_ValueForKey(cl->userinfo, "*transfer");
Con_Printf("%s transfered to %s\n", cl->name, to);
break;
}
}
}
break;
case ccmd_takeplayer:
{
client_t *cl = NULL;
int i, j;
float stat;
char guid[64];
int plid = MSG_ReadLong();
int fromsv = MSG_ReadLong();
char *claddr = MSG_ReadString();
char *clguid = MSG_ReadStringBuffer(guid, sizeof(guid));
if (sv.state >= ss_active)
{
for (i = 0; i < svs.allocated_client_slots; i++)
{
if (!svs.clients[i].state || (svs.clients[i].userid == plid && svs.clients[i].state >= cs_loadzombie))
{
cl = &svs.clients[i];
break;
}
}
}
Con_Printf("%s: takeplayer\n", sv.name);
if (cl)
{
cl->userid = plid;
if (cl->state == cs_loadzombie && cl->istobeloaded)
cl->connection_started = realtime+20; //renew the slot
else if (!cl->state)
{ //allocate a new pending player.
cl->previousserver = fromsv;
cl->state = cs_loadzombie;
cl->connection_started = realtime+20;
Q_strncpyz(cl->guid, clguid, sizeof(cl->guid));
sv.spawned_client_slots++;
memset(&cl->netchan, 0, sizeof(cl->netchan));
SV_GetNewSpawnParms(cl);
}
}
j = MSG_ReadByte();
Con_Printf("%s: %i stats\n", sv.name, j);
for (i = 0; i < j; i++)
{
stat = MSG_ReadFloat();
if (cl && cl->state == cs_loadzombie && i < NUM_SPAWN_PARMS)
cl->spawn_parms[i] = stat;
}
{
sizebuf_t send;
qbyte send_buf[MAX_QWMSGLEN];
if (fromsv)
Con_Printf("%s: send tookplayer\n", sv.name);
else
Con_Printf("%s: from master\n", sv.name);
memset(&send, 0, sizeof(send));
send.data = send_buf;
send.maxsize = sizeof(send_buf);
send.cursize = 2;
if (cl)
{
MSG_WriteByte(&send, ccmd_tookplayer);
MSG_WriteLong(&send, fromsv);
MSG_WriteLong(&send, plid);
MSG_WriteString(&send, claddr);
SSV_InstructMaster(&send);
}
}
}
break;
}
if (msg_readcount != net_message.cursize || msg_badread)
Sys_Error("Subserver: Readcount isn't right (%i)\n", net_message.data[0]);
}
void SSV_UpdateAddresses(void)
{
char buf[256];
netadr_t addr[64];
struct ftenet_generic_connection_s *con[sizeof(addr)/sizeof(addr[0])];
int flags[sizeof(addr)/sizeof(addr[0])];
int count;
sizebuf_t send;
qbyte send_buf[MAX_QWMSGLEN];
int i;
if (!SSV_IsSubServer())
return;
count = NET_EnumerateAddresses(svs.sockets, con, flags, addr, sizeof(addr)/sizeof(addr[0]));
if (*sv_serverip.string)
{
for (i = 0; i < count; i++)
{
if (addr[i].type == NA_IP)
{
NET_StringToAdr(sv_serverip.string, BigShort(addr[i].port), &addr[0]);
count = 1;
break;
}
}
}
memset(&send, 0, sizeof(send));
send.data = send_buf;
send.maxsize = sizeof(send_buf);
send.cursize = 2;
MSG_WriteByte(&send, ccmd_serveraddress);
MSG_WriteString(&send, sv.name);
for (i = 0; i < count; i++)
MSG_WriteString(&send, NET_AdrToString(buf, sizeof(buf), &addr[i]));
MSG_WriteByte(&send, 0);
SSV_InstructMaster(&send);
}
void SSV_SavePlayerStats(client_t *cl, unsigned int previousserver)
{
//called when the *transfer userinfo gets set to the new map
sizebuf_t send;
qbyte send_buf[MAX_QWMSGLEN];
int i;
if (!SSV_IsSubServer())
return;
if (!previousserver)
SV_SaveSpawnparmsClient(cl, NULL);
memset(&send, 0, sizeof(send));
send.data = send_buf;
send.maxsize = sizeof(send_buf);
send.cursize = 2;
MSG_WriteByte(&send, ccmd_saveplayer);
MSG_WriteLong(&send, previousserver);
MSG_WriteLong(&send, cl->userid);
MSG_WriteByte(&send, NUM_SPAWN_PARMS);
for (i = 0; i < NUM_SPAWN_PARMS; i++)
{
MSG_WriteFloat(&send, cl->spawn_parms[i]);
}
SSV_InstructMaster(&send);
}
void SSV_InitiatePlayerTransfer(client_t *cl, const char *newserver)
{
//called when the *transfer userinfo gets set to the new map
sizebuf_t send;
qbyte send_buf[MAX_QWMSGLEN];
int i;
char tmpbuf[256];
float parms[NUM_SPAWN_PARMS];
SV_SaveSpawnparmsClient(cl, parms);
memset(&send, 0, sizeof(send));
send.data = send_buf;
send.maxsize = sizeof(send_buf);
send.cursize = 2;
MSG_WriteByte(&send, ccmd_transferplayer);
MSG_WriteLong(&send, cl->userid);
MSG_WriteString(&send, newserver);
MSG_WriteString(&send, NET_AdrToString(tmpbuf, sizeof(tmpbuf), &cl->netchan.remote_address));
MSG_WriteString(&send, cl->guid);
//stats
MSG_WriteByte(&send, NUM_SPAWN_PARMS);
for (i = 0; i < NUM_SPAWN_PARMS; i++)
{
MSG_WriteFloat(&send, parms[i]);
}
SSV_InstructMaster(&send);
}
#ifdef SQL
#include "sv_sql.h"
int pendinglookups = 0;
struct logininfo_s
{
netadr_t clientaddr;
char guid[64];
};
#endif
qboolean SV_IgnoreSQLResult(queryrequest_t *req, int firstrow, int numrows, int numcols, qboolean eof)
{
return false;
}
void MSV_UpdatePlayerStats(unsigned int lastserver, unsigned int playerid, unsigned int serverid, int numstats, float *stats)
{
queryrequest_t *req;
sqlserver_t *srv;
static char hex[16] = "0123456789abcdef";
char sql[2048], *sqle;
union{float *f;qbyte *b;} blob;
Q_snprintfz(sql, sizeof(sql), "UPDATE accounts SET stats=x'");
sqle = sql+strlen(sql);
for (blob.f = stats, numstats*=4; numstats--; blob.b++)
{
*sqle++ = hex[*blob.b>>4];
*sqle++ = hex[*blob.b&15];
}
if (lastserver)
Q_snprintfz(sqle, sizeof(sql)-(sqle-sql), "', serverid=%u WHERE playerid = %u;", serverid, playerid);
else
Q_snprintfz(sqle, sizeof(sql)-(sqle-sql), "' WHERE playerid = %u AND serverid = %u;", playerid, serverid);
srv = SQL_GetServer(sv.logindatabase, false);
if (srv)
SQL_NewQuery(srv, SV_IgnoreSQLResult, sql, &req);
if (lastserver)
{
sizebuf_t send;
qbyte send_buf[64];
memset(&send, 0, sizeof(send));
send.data = send_buf;
send.maxsize = sizeof(send_buf);
send.cursize = 2;
MSG_WriteByte(&send, ccmd_transferedplayer);
MSG_WriteLong(&send, serverid);
MSG_WriteLong(&send, playerid);
MSV_InstructSlave(lastserver, &send);
}
}
qboolean MSV_ClusterLoginReply(netadr_t *legacyclientredirect, unsigned int serverid, unsigned int playerid, char *clientguid, netadr_t *clientaddr, void *statsblob, size_t statsblobsize)
{
char tmpbuf[256];
netadr_t serveraddr;
if (!serverid)
serverid = 1;
if (!MSV_AddressForMap(&serveraddr, clientaddr->type, serverid) && !MSV_AddressForMap(&serveraddr, clientaddr->type, serverid=1))
SV_RejectMessage(SCP_QUAKEWORLD, "Unable to find lobby.\n");
else
{
sizebuf_t send;
qbyte send_buf[MAX_QWMSGLEN];
memset(&send, 0, sizeof(send));
send.data = send_buf;
send.maxsize = sizeof(send_buf);
send.cursize = 2;
MSG_WriteByte(&send, ccmd_takeplayer);
MSG_WriteLong(&send, playerid);
MSG_WriteLong(&send, 0); //from server
MSG_WriteString(&send, NET_AdrToString(tmpbuf, sizeof(tmpbuf), &net_from));
MSG_WriteString(&send, clientguid);
MSG_WriteByte(&send, statsblobsize/4);
SZ_Write(&send, statsblob, statsblobsize&~3);
MSV_InstructSlave(serverid, &send);
if (serveraddr.type == NA_INVALID)
{
if (net_from.type != NA_LOOPBACK)
SV_RejectMessage(SCP_QUAKEWORLD, "Starting instance.\n");
}
else if (legacyclientredirect)
{
*legacyclientredirect = serveraddr;
return true;
}
else
{
char *s = va("fredir\n%s", NET_AdrToString(tmpbuf, sizeof(tmpbuf), &serveraddr));
Netchan_OutOfBand (NS_SERVER, clientaddr, strlen(s), (qbyte *)s);
return true;
}
}
return false;
}
qboolean MSV_ClusterLoginSQLResult(queryrequest_t *req, int firstrow, int numrows, int numcols, qboolean eof)
{
sqlserver_t *sql = SQL_GetServer(req->srvid, true);
queryresult_t *res = SQL_GetQueryResult(sql, req->num, 0);
struct logininfo_s *info = req->user.thread;
char *s;
int playerid, serverid;
char *statsblob;
size_t blobsize;
res = SQL_GetQueryResult(sql, req->num, 0);
if (!res)
{
playerid = 0;
statsblob = NULL;
blobsize = 0;
serverid = 0;
}
else
{
s = SQL_ReadField(sql, res, 0, 0, true, NULL);
playerid = atoi(s);
statsblob = SQL_ReadField(sql, res, 0, 2, true, &blobsize);
s = SQL_ReadField(sql, res, 0, 1, true, NULL);
serverid = s?atoi(s):0;
}
net_from = info->clientaddr; //okay, that's a bit stupid, rewrite rejectmessage to accept an arg?
if (!playerid)
SV_RejectMessage(SCP_QUAKEWORLD, "Bad username or password.\n");
else
MSV_ClusterLoginReply(NULL, serverid, playerid, info->guid, &info->clientaddr, statsblob, blobsize);
Z_Free(info);
pendinglookups--;
return false;
}
//returns true to block entry to this server.
qboolean MSV_ClusterLogin(char *guid, char *userinfo, size_t userinfosize)
{
char escname[64], escpasswd[64];
sqlserver_t *sql;
queryrequest_t *req;
struct logininfo_s *info;
char *sqlparams[] =
{
"",
"",
"",
"login",
};
if (sv.state != ss_clustermode)
return false;
if (sv.logindatabase != -1)
{
if (pendinglookups > 10)
return true;
sql = SQL_GetServer(sv.logindatabase, false);
if (!sql)
return true;
SQL_Escape(sql, Info_ValueForKey(userinfo, "name"), escname, sizeof(escname));
SQL_Escape(sql, Info_ValueForKey(userinfo, "password"), escpasswd, sizeof(escpasswd));
if (SQL_NewQuery(sql, MSV_ClusterLoginSQLResult, va("SELECT playerid,serverid,stats FROM accounts WHERE name='%s' AND password='%s';", escname, escpasswd), &req) != -1)
{
pendinglookups++;
req->user.thread = info = Z_Malloc(sizeof(*info));
Q_strncpyz(info->guid, guid, sizeof(info->guid));
info->clientaddr = net_from;
}
}
else if (0)
{
char tmpbuf[256];
netadr_t redir;
if (MSV_ClusterLoginReply(&redir, 0, nextuserid++, guid, &net_from, NULL, 0))
{
Info_SetValueForStarKey(userinfo, "*redirect", NET_AdrToString(tmpbuf, sizeof(tmpbuf), &redir), userinfosize);
return false;
}
return true;
}
else
MSV_ClusterLoginReply(NULL, 0, nextuserid++, guid, &net_from, NULL, 0);
return true;
}
#endif
/*
==================
@ -3045,7 +2255,7 @@ client_t *SVC_DirectConnect(void)
// if there is already a slot for this ip, drop it
for (i=0,cl=svs.clients ; i<svs.allocated_client_slots ; i++,cl++)
{
if (cl->state == cs_free)
if (cl->state == cs_free || cl->state == cs_loadzombie)
continue;
if (NET_CompareBaseAdr (&adr, &cl->netchan.remote_address)
&& ( cl->netchan.qport == qport
@ -3142,9 +2352,8 @@ client_t *SVC_DirectConnect(void)
preserveparms = true;
temp.istobeloaded = cl->istobeloaded;
memcpy(temp.spawn_parms, cl->spawn_parms, sizeof(temp.spawn_parms));
#ifdef SUBSERVERS
temp.previousserver = cl->previousserver;
#endif
if (cl->userid)
temp.userid = cl->userid;
break;
}
}
@ -3643,8 +2852,7 @@ client_t *SVC_DirectConnect(void)
newcl->redirect = redirect;
#ifdef SUBSERVERS
SSV_SavePlayerStats(newcl, newcl->previousserver);
newcl->previousserver = 0;
SSV_SavePlayerStats(newcl, 0);
#endif
return newcl;
@ -4043,7 +3251,7 @@ qboolean SVNQ_ConnectionlessPacket(void)
if (net_from.type == NA_LOOPBACK)
return false;
if (!sv_listen_nq.value)
if (!sv_listen_nq.value || SSV_IsSubServer())
return false;
MSG_BeginReading(svs.netprim);
@ -4681,7 +3889,7 @@ void SV_CheckTimeouts (void)
if (*cl->name)
SV_BroadcastTPrintf (PRINT_HIGH, "LoadZombie %s timed out\n", cl->name);
else
SV_BroadcastTPrintf (PRINT_HIGH, "LoadZombie timed out\n", cl->name);
SV_BroadcastTPrintf (PRINT_HIGH, "LoadZombie timed out\n");
}
sv.spawned_client_slots--;
@ -4694,7 +3902,11 @@ void SV_CheckTimeouts (void)
else
{
//no entity, just free them.
#ifdef SUBSERVERS
SSV_SavePlayerStats(cl, 3);
#endif
cl->state = cs_free;
SV_BroadcastTPrintf (PRINT_HIGH, "TransferZombie %s timed out\n", cl->name);
}
cl->netchan.remote_address.type = NA_INVALID; //don't mess up from not knowing their address.
}
@ -5397,7 +4609,7 @@ void Master_Heartbeat (void)
qboolean madeqwstring = false;
char adr[MAX_ADR_SIZE];
if (!sv_public.ival)
if (!sv_public.ival || SSV_IsSubServer())
return;
if (realtime-HEARTBEAT_SECONDS - svs.last_heartbeat < HEARTBEAT_SECONDS)

View file

@ -60,8 +60,6 @@ void SV_FlushRedirect (void)
if (!*outputbuf)
return;
Log_String(LOG_CONSOLE, va("{\n%s}\n", outputbuf));
if (sv_redirected == RD_PACKET || sv_redirected == RD_PACKET_LOG)
{
//log it to the rcon log if its not just a status response

View file

@ -41,11 +41,9 @@ static HANDLE hconsoleout;
qboolean WinNT; //if true, use utf-16 file paths. if false, hope that paths are in ascii.
#ifdef _DEBUG
#if _MSC_VER >= 1300
#if defined(_DEBUG) || defined(DEBUG)
#define CATCHCRASH
#endif
#endif
#ifdef CATCHCRASH
@ -71,18 +69,197 @@ DWORD CrashExceptionHandler (DWORD exceptionCode, LPEXCEPTION_POINTERS exception
HMODULE hKernel;
BOOL (WINAPI *pIsDebuggerPresent)(void);
DWORD (WINAPI *pSymSetOptions)(DWORD SymOptions);
BOOL (WINAPI *pSymInitialize)(HANDLE hProcess, PSTR UserSearchPath, BOOL fInvadeProcess);
BOOL (WINAPI *pSymFromAddr)(HANDLE hProcess, DWORD64 Address, PDWORD64 Displacement, PSYMBOL_INFO Symbol);
#ifdef _WIN64
#define DBGHELP_POSTFIX "64"
BOOL (WINAPI *pStackWalkX)(DWORD MachineType, HANDLE hProcess, HANDLE hThread, LPSTACKFRAME64 StackFrame, PVOID ContextRecord, PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine, PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine, PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine, PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress);
PVOID (WINAPI *pSymFunctionTableAccessX)(HANDLE hProcess, DWORD64 AddrBase);
DWORD64 (WINAPI *pSymGetModuleBaseX)(HANDLE hProcess, DWORD64 qwAddr);
BOOL (WINAPI *pSymGetLineFromAddrX)(HANDLE hProcess, DWORD64 qwAddr, PDWORD pdwDisplacement, PIMAGEHLP_LINE64 Line64);
BOOL (WINAPI *pSymGetModuleInfoX)(HANDLE hProcess, DWORD64 qwAddr, PIMAGEHLP_MODULE64 ModuleInfo);
#define STACKFRAMEX STACKFRAME64
#define IMAGEHLP_LINEX IMAGEHLP_LINE64
#define IMAGEHLP_MODULEX IMAGEHLP_MODULE64
#else
#define DBGHELP_POSTFIX ""
BOOL (WINAPI *pStackWalkX)(DWORD MachineType, HANDLE hProcess, HANDLE hThread, LPSTACKFRAME StackFrame, PVOID ContextRecord, PREAD_PROCESS_MEMORY_ROUTINE ReadMemoryRoutine, PFUNCTION_TABLE_ACCESS_ROUTINE FunctionTableAccessRoutine, PGET_MODULE_BASE_ROUTINE GetModuleBaseRoutine, PTRANSLATE_ADDRESS_ROUTINE TranslateAddress);
PVOID (WINAPI *pSymFunctionTableAccessX)(HANDLE hProcess, DWORD AddrBase);
DWORD (WINAPI *pSymGetModuleBaseX)(HANDLE hProcess, DWORD dwAddr);
BOOL (WINAPI *pSymGetLineFromAddrX)(HANDLE hProcess, DWORD dwAddr, PDWORD pdwDisplacement, PIMAGEHLP_LINE Line);
BOOL (WINAPI *pSymGetModuleInfoX)(HANDLE hProcess, DWORD dwAddr, PIMAGEHLP_MODULE ModuleInfo);
#define STACKFRAMEX STACKFRAME
#define IMAGEHLP_LINEX IMAGEHLP_LINE
#define IMAGEHLP_MODULEX IMAGEHLP_MODULE
#endif
dllfunction_t debughelpfuncs[] =
{
{(void*)&pSymFromAddr, "SymFromAddr"},
{(void*)&pSymSetOptions, "SymSetOptions"},
{(void*)&pSymInitialize, "SymInitialize"},
{(void*)&pStackWalkX, "StackWalk"DBGHELP_POSTFIX},
{(void*)&pSymFunctionTableAccessX, "SymFunctionTableAccess"DBGHELP_POSTFIX},
{(void*)&pSymGetModuleBaseX, "SymGetModuleBase"DBGHELP_POSTFIX},
{(void*)&pSymGetLineFromAddrX, "SymGetLineFromAddr"DBGHELP_POSTFIX},
{(void*)&pSymGetModuleInfoX, "SymGetModuleInfo"DBGHELP_POSTFIX},
{NULL, NULL}
};
switch(exceptionCode)
{
case EXCEPTION_ACCESS_VIOLATION:
case EXCEPTION_DATATYPE_MISALIGNMENT:
case EXCEPTION_BREAKPOINT:
case EXCEPTION_SINGLE_STEP:
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
case EXCEPTION_FLT_DENORMAL_OPERAND:
case EXCEPTION_FLT_DIVIDE_BY_ZERO:
case EXCEPTION_FLT_INEXACT_RESULT:
case EXCEPTION_FLT_INVALID_OPERATION:
case EXCEPTION_FLT_OVERFLOW:
case EXCEPTION_FLT_STACK_CHECK:
case EXCEPTION_FLT_UNDERFLOW:
case EXCEPTION_INT_DIVIDE_BY_ZERO:
case EXCEPTION_INT_OVERFLOW:
case EXCEPTION_PRIV_INSTRUCTION:
case EXCEPTION_IN_PAGE_ERROR:
case EXCEPTION_ILLEGAL_INSTRUCTION:
case EXCEPTION_NONCONTINUABLE_EXCEPTION:
case EXCEPTION_STACK_OVERFLOW:
case EXCEPTION_INVALID_DISPOSITION:
case EXCEPTION_GUARD_PAGE:
case EXCEPTION_INVALID_HANDLE:
// case EXCEPTION_POSSIBLE_DEADLOCK:
break;
default:
//because windows is a steaming pile of shite, we have to ignore any software-generated exceptions, because most of them are not in fact fatal, *EVEN IF THEY CLAIM TO BE NON-CONTINUABLE*
return exceptionCode;
}
hKernel = LoadLibrary ("kernel32");
pIsDebuggerPresent = (void*)GetProcAddress(hKernel, "IsDebuggerPresent");
if (pIsDebuggerPresent && pIsDebuggerPresent())
return EXCEPTION_CONTINUE_SEARCH;
#ifdef GLQUAKE
GLVID_Crashed();
#endif
if (pIsDebuggerPresent ())
#if 1//ndef _MSC_VER
{
/*if we have a current window, minimize it to bring us out of fullscreen*/
return EXCEPTION_CONTINUE_SEARCH;
if (Sys_LoadLibrary("DBGHELP", debughelpfuncs))
{
STACKFRAMEX stack;
CONTEXT *pcontext = exceptionInfo->ContextRecord;
IMAGEHLP_LINEX line;
IMAGEHLP_MODULEX module;
struct
{
SYMBOL_INFO sym;
char name[1024];
} sym;
int frameno;
char stacklog[8192];
int logpos, logstart;
char *logline;
stacklog[logpos=0] = 0;
pSymInitialize(hProc, NULL, TRUE);
pSymSetOptions(SYMOPT_LOAD_LINES);
memset(&stack, 0, sizeof(stack));
#ifdef _WIN64
#define IMAGE_FILE_MACHINE_THIS IMAGE_FILE_MACHINE_AMD64
stack.AddrPC.Mode = AddrModeFlat;
stack.AddrPC.Offset = pcontext->Rip;
stack.AddrFrame.Mode = AddrModeFlat;
stack.AddrFrame.Offset = pcontext->Rbp;
stack.AddrStack.Mode = AddrModeFlat;
stack.AddrStack.Offset = pcontext->Rsp;
#else
#define IMAGE_FILE_MACHINE_THIS IMAGE_FILE_MACHINE_I386
stack.AddrPC.Mode = AddrModeFlat;
stack.AddrPC.Offset = pcontext->Eip;
stack.AddrFrame.Mode = AddrModeFlat;
stack.AddrFrame.Offset = pcontext->Ebp;
stack.AddrStack.Mode = AddrModeFlat;
stack.AddrStack.Offset = pcontext->Esp;
#endif
Q_strncpyz(stacklog+logpos, FULLENGINENAME " or dependancy has crashed. The following stack dump been copied to your windows clipboard.\n"
#ifdef _MSC_VER
"Would you like to generate a core dump too?\n"
#endif
"\n", sizeof(stacklog)-logpos);
logstart = logpos += strlen(stacklog+logpos);
//so I know which one it is
#if defined(DEBUG) || defined(_DEBUG)
#define BUILDDEBUGREL "Debug"
#else
#define BUILDDEBUGREL "Optimised"
#endif
#ifdef MINIMAL
#define BUILDMINIMAL "Min"
#else
#define BUILDMINIMAL ""
#endif
#if defined(GLQUAKE) && !defined(D3DQUAKE)
#define BUILDTYPE "GL"
#elif !defined(GLQUAKE) && defined(D3DQUAKE)
#define BUILDTYPE "D3D"
#else
#define BUILDTYPE "Merged"
#endif
Q_snprintfz(stacklog+logpos, sizeof(stacklog)-logpos, "Build: %s %s %s: %s\r\n", BUILDDEBUGREL, PLATFORM, BUILDMINIMAL BUILDTYPE, version_string());
logpos += strlen(stacklog+logpos);
for(frameno = 0; ; frameno++)
{
DWORD64 symdisp;
DWORD linedisp;
DWORD_PTR symaddr;
if (!pStackWalkX(IMAGE_FILE_MACHINE_THIS, hProc, GetCurrentThread(), &stack, pcontext, NULL, pSymFunctionTableAccessX, pSymGetModuleBaseX, NULL))
break;
memset(&module, 0, sizeof(module));
module.SizeOfStruct = sizeof(module);
pSymGetModuleInfoX(hProc, stack.AddrPC.Offset, &module);
memset(&line, 0, sizeof(line));
line.SizeOfStruct = sizeof(line);
symdisp = 0;
memset(&sym, 0, sizeof(sym));
sym.sym.MaxNameLen = sizeof(sym.name);
symaddr = stack.AddrPC.Offset;
sym.sym.SizeOfStruct = sizeof(sym.sym);
if (pSymFromAddr(hProc, symaddr, &symdisp, &sym.sym))
{
if (pSymGetLineFromAddrX(hProc, stack.AddrPC.Offset, &linedisp, &line))
logline = va("%-20s - %s:%i (%s)\r\n", sym.sym.Name, line.FileName, (int)line.LineNumber, module.LoadedImageName);
else
logline = va("%-20s+%#x (%s)\r\n", sym.sym.Name, (unsigned int)symdisp, module.LoadedImageName);
}
else
logline = va("0x%p (%s)\r\n", (void*)(DWORD_PTR)stack.AddrPC.Offset, module.LoadedImageName);
Q_strncpyz(stacklog+logpos, logline, sizeof(stacklog)-logpos);
logpos += strlen(stacklog+logpos);
if (logpos+1 >= sizeof(stacklog))
break;
}
Sys_Printf("%s", stacklog+logstart);
return EXCEPTION_EXECUTE_HANDLER;
}
else
{
Sys_Printf("We crashed.\nUnable to load dbghelp library. Stack info is not available\n");
return EXCEPTION_EXECUTE_HANDLER;
}
}
#endif
hDbgHelp = LoadLibrary ("DBGHELP");
if (hDbgHelp)
@ -124,6 +301,16 @@ DWORD CrashExceptionHandler (DWORD exceptionCode, LPEXCEPTION_POINTERS exception
MessageBox(NULL, "Kaboom! Sorry. No MiniDumpWriteDump function.", DISTRIBUTION " Sucks", 0);
return EXCEPTION_EXECUTE_HANDLER;
}
LONG CALLBACK nonmsvc_CrashExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo)
{
DWORD foo = EXCEPTION_CONTINUE_SEARCH;
foo = CrashExceptionHandler(/*false, */ExceptionInfo->ExceptionRecord->ExceptionCode, ExceptionInfo);
//we have no handler. thus we handle it by exiting.
if (foo == EXCEPTION_EXECUTE_HANDLER)
exit(1);
return foo;
}
#endif
@ -584,7 +771,10 @@ void Sys_Error (const char *error, ...)
#endif
if (COM_CheckParm("-noreset"))
{
Sys_Quit();
exit(1);
}
Sys_Printf ("A new server will be started in 10 seconds unless you press a key\n");
@ -595,7 +785,10 @@ void Sys_Error (const char *error, ...)
{
Sleep(500); // don't burn up CPU with polling
if (_kbhit())
{
Sys_Quit();
exit(1);
}
}
Sys_Printf("\nLoading new instance of FTE...\n\n\n");
@ -1332,18 +1525,26 @@ SERVICE_TABLE_ENTRY DispatchTable[] =
int main (int argc, char **argv)
{
#ifdef USESERVICE
if (StartServiceCtrlDispatcher( DispatchTable))
{
return true;
}
#endif
#ifdef CATCHCRASH
#ifdef _MSC_VER
__try
#else
AddVectoredExceptionHandler(true, nonmsvc_CrashExceptionHandler);
#endif
#endif
{
COM_InitArgv (argc, (const char **)argv);
#ifdef SUBSERVERS
isClusterSlave = COM_CheckParm("-clusterslave");
#endif
#ifdef USESERVICE
if (!SSV_IsSubServer() && StartServiceCtrlDispatcher( DispatchTable))
{
return true;
}
#endif
#ifdef USESERVICE
if (COM_CheckParm("-register"))
{
@ -1366,18 +1567,17 @@ int main (int argc, char **argv)
}
#endif
#ifdef SUBSERVERS
isClusterSlave = COM_CheckParm("-clusterslave");
#endif
StartQuakeServer();
ServerMainLoop();
}
#ifdef CATCHCRASH
#ifdef _MSC_VER
__except (CrashExceptionHandler(GetExceptionCode(), GetExceptionInformation()))
{
return 1;
}
#endif
#endif
return true;

View file

@ -4282,6 +4282,20 @@ void Cmd_Fly_f (void)
}
}
#ifdef SUBSERVERS
void Cmd_Transfer_f(void)
{
char *dest = Cmd_Argv(1);
if (!SV_MayCheat())
{
SV_TPrintToClient(host_client, PRINT_HIGH, "Cheats are not allowed on this server\n");
return;
}
SSV_InitiatePlayerTransfer(host_client, dest);
}
#endif
/*
====================
Host_SetPos_f UDC
@ -5186,6 +5200,9 @@ ucmd_t ucmds[] =
{"fly", Cmd_Fly_f},
{"notarget", Cmd_Notarget_f},
{"setpos", Cmd_SetPos_f},
#ifdef SUBSERVERS
{"transfer", Cmd_Transfer_f}, //transfer the player to a different map/server
#endif
#ifdef NQPROT
{"name", SVNQ_NQInfo_f},

View file

@ -1043,6 +1043,9 @@ rendererinfo_t swrendererinfo =
SW_VID_DeInit,
SW_VID_SwapBuffers,
SW_VID_ApplyGammaRamps,
NULL,
NULL,
NULL,
SW_VID_SetWindowCaption,
SW_VID_GetRGBInfo,

View file

@ -9,8 +9,29 @@ mergeInto(LibraryManager.library,
f: {}
},
//FIXME: split+merge by \n
emscriptenfte_print : function(msg)
{
FTEC.linebuffer += Pointer_stringify(msg);
for(;;)
{
nl = FTEC.linebuffer.indexOf("\n");
if (nl == -1)
break;
console.log(FTEC.linebuffer.substring(0, nl));
FTEC.linebuffer = FTEC.linebuffer.substring(nl+1);
}
},
emscriptenfte_alert : function(msg)
{
msg = Pointer_stringify(msg);
console.log(msg);
alert(msg);
},
$FTEC:
{
ctxwarned:0,
linebuffer:'',
w: -1,
h: -1,
@ -127,9 +148,20 @@ mergeInto(LibraryManager.library,
});
});
}
var ctx = Browser.createContext(Module['canvas'], true, true);
if (!ctx)
if (Module.print === undefined)
Module.print = function(msg){console.log(msg);};
var ctx = Browser.createContext(Module['canvas'], true, true);
if (ctx == null)
{
var msg = "Unable to set up webgl context.\n\nPlease use a browser that supports it and has it enabled\nYour graphics drivers may also be blacklisted, so try updating those too. woo, might as well update your entire operating system while you're at it.\nIt'll be expensive, but hey, its YOUR money, not mine.\nYou can probably just disable the blacklist, but please don't moan at me when your computer blows up, seriously, make sure those drivers are not too buggy.\nI knew a guy once. True story. Boring, but true.\nYou're probably missing out on something right now. Don't you just hate it when that happens?\nMeh, its probably just tinkertoys, right?\n\nYou know, you could always try Internet Explorer, you never know, hell might have frozen over.\nDon't worry, I wasn't serious.\n\nTum te tum. Did you get it working yet?\nDude, fix it already.\n\nThis message was brought to you by Sleep Deprivation, sponsoring quake since I don't know when";
if (FTEC.ctxwarned == 0)
{
FTEC.ctxwarned = 1;
console.log(msg);
alert(msg);
}
return 0;
}
// Browser.setCanvasSize(nw, nh, false);
window.onresize = function()
@ -168,26 +200,7 @@ mergeInto(LibraryManager.library,
msg = Pointer_stringify(msg);
throw 'oh noes! something bad happened in ' + msg + '!';
},
emscriptenfte_alert : function(msg)
{
msg = Pointer_stringify(msg);
console.log(msg);
alert(msg);
},
//FIXME: split+merge by \n
emscriptenfte_print : function(msg)
{
FTEC.linebuffer += Pointer_stringify(msg);
for(;;)
{
nl = FTEC.linebuffer.indexOf("\n");
if (nl == -1)
break;
console.log(FTEC.linebuffer.substring(0, nl));
FTEC.linebuffer = FTEC.linebuffer.substring(nl+1);
}
},
emscriptenfte_ticks_ms : function()
{
return Date.now();
@ -231,7 +244,7 @@ mergeInto(LibraryManager.library,
var str = window.localStorage.getItem(name);
if (str != null)
{
console.log('read file '+name+': ' + str);
// console.log('read file '+name+': ' + str);
var len = str.length;
var buf = new Uint8Array(len);
@ -289,7 +302,6 @@ mergeInto(LibraryManager.library,
delete FTEH.f[name];
f.n = null;
emscriptenfte_buf_release(f.h);
console.log('deleted '+name);
return 1;
}
return 0;
@ -313,7 +325,6 @@ console.log('deleted '+name);
for (var i = 0; i < len; i++)
foo += String.fromCharCode(data[i]);
window.localStorage.setItem(b.n, foo);
console.log('saved '+b.n+' persistantly: '+foo);
}
else
console.log('local storage not supported');