Misc tweaks.

Fix potentially serious crash with sprites+csqc tracelines.
Reworked fallback mouse cursor.
Fix decals on q3 bmodels.
Double-click to select a work to copy is now implemented.


git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5323 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2018-10-23 07:09:06 +00:00
parent 4ae635bc7b
commit 2bedc32ff9
49 changed files with 968 additions and 520 deletions

View File

@ -195,6 +195,7 @@ ELSEIF(${UNIX}) #linux(ish)
engine/client/sys_linux.c
engine/common/sys_linux_threads.c
engine/common/net_ssl_gnutls.c
# engine/common/net_ssl_openssl.c
engine/client/snd_al.c
engine/client/snd_alsa.c
@ -241,8 +242,14 @@ ELSEIF(${UNIX}) #linux(ish)
engine/server/sv_sys_unix.c
engine/common/sys_linux_threads.c
engine/common/net_ssl_gnutls.c
# engine/common/net_ssl_openssl.c
)
SET(FTESV_LIBS ${ZLIB_LIBRARIES} m ${CMAKE_DL_LIBS} pthread)
# SET(FTE_DEFINES ${FTE_DEFINES};HAVE_OPENSSL)
# SET(FTESV_DEFINES ${FTESV_DEFINES};HAVE_OPENSSL)
# SET(FTE_LIBS ${FTE_LIBS} ssl crypto)
# SET(FTESV_LIBS ${FTE_LIBS} ssl crypto)
ELSEIF(1) #SDL
# FIND_PACKAGE(Freetype REQUIRED)
# INCLUDE_DIRECTORIES(engine/libs engine/libs/freetype2/include)

View File

@ -1638,8 +1638,8 @@ BASELDFLAGS:=-L$(ARCHLIBS) $(BASELDFLAGS)
.default: help
all: rel
rel: sv-rel m-rel mingl-rel qcc-rel
dbg: sv-dbg m-dbg mingl-dbg qcc-dbg
rel: sv-rel m-rel qcc-rel
dbg: sv-dbg m-dbg qcc-dbg
relcl: glcl-rel mcl-rel
profile: sv-profile gl-profile mingl-profile

View File

@ -5496,7 +5496,7 @@ void CL_SetSolidEntities (void)
so we need to make sure that item pickups are not erroneously considered solid, but doors etc are.
yes, this probably means that externally loaded models will be predicted non-solid - you'll need to upgrade your network protocol for the gamecode to be able to specify solidity.
*/
if (!(cls.fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS) && !((*cl.model_precache[state->modelindex]->name == '*' || cl.model_precache[state->modelindex]->numsubmodels) && cl.model_precache[state->modelindex]->hulls[1].firstclipnode))
if (!(cls.fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS) && !((*cl.model_precache[state->modelindex]->name == '*' || cl.model_precache[state->modelindex]->numsubmodels) && cl.model_precache[state->modelindex]->funcs.NativeTrace))
continue;
pent = &pmove.physents[pmove.numphysent];

View File

@ -2973,7 +2973,7 @@ void CL_ConnectionlessPacket (void)
unsigned int curtime = Sys_Milliseconds();
unsigned long pext = 0, pext2 = 0, huffcrc=0, mtu=0;
#ifdef HAVE_DTLS
qboolean candtls = false;
int candtls = 0; //0=no,1=optional,2=mandatory
#endif
char guidhash[256];
@ -3183,6 +3183,10 @@ void CL_ConnectionlessPacket (void)
//c2s DTLS(getchallenge)
//DTLS(etc)
//getchallenge has to be done twice, with the outer one only reporting whether dtls can/should be used.
//this means the actual connect packet is already over dtls, which protects the user's userinfo.
//FIXME: do rcon via dtls too, but requires tracking pending rcon packets until the handshake completes.
//server says it can do tls.
char *pkt = va("%c%c%c%cdtlsconnect %i", 255, 255, 255, 255, connectinfo.challenge);
NET_SendPacket (NS_CLIENT, strlen(pkt), pkt, &net_from);
@ -3440,9 +3444,9 @@ client_connect: //fixme: make function
if (cls.netchan.remote_address.type != NA_LOOPBACK)
{
if (cls.netchan.remote_address.prot == NP_DTLS || cls.netchan.remote_address.prot == NP_TLS || cls.netchan.remote_address.prot == NP_WSS)
Con_TPrintf ("Connected (encrypted).\n");
Con_TPrintf ("Connected (^2encrypted^7).\n");
else
Con_TPrintf ("Connected (plain-text).\n");
Con_TPrintf ("Connected (^1plain-text^7).\n");
}
#ifdef QUAKESPYAPI
allowremotecmd = false; // localid required now for remote cmds
@ -5666,12 +5670,12 @@ double Host_Frame (double time)
if (cl.paused)
cl.gametimemark += time;
idle = (cls.state == ca_disconnected) ||
idle = (cls.state == ca_disconnected) ||
#ifdef VM_UI
UI_MenuState() != 0 ||
UI_MenuState() != 0 ||
#endif
Key_Dest_Has(kdm_gmenu) ||
Key_Dest_Has(kdm_emenu) ||
Key_Dest_Has(kdm_gmenu) ||
Key_Dest_Has(kdm_emenu) ||
Key_Dest_Has(kdm_editor) ||
!vid.activeapp ||
cl.paused
@ -5724,7 +5728,7 @@ double Host_Frame (double time)
if (sv.state && cls.state != ca_active)
{
maxfpsignoreserver = false;
maxfps = 0;
maxfps = cl_maxfps.ival;
}
else
#endif
@ -6042,9 +6046,6 @@ void CL_StartCinematicOrMenu(void)
Con_ClearNotify();
TP_ExecTrigger("f_startup", true);
Cbuf_Execute ();
if (com_installer)
{
com_installer = false;
@ -6055,12 +6056,15 @@ void CL_StartCinematicOrMenu(void)
#endif
}
if (!sv_state && !cls.demoinfile && !cls.state && !*cls.servername && !Media_PlayingFullScreen())
{
TP_ExecTrigger("f_startup", true);
Cbuf_Execute ();
}
//and any startup cinematics
#ifdef HAVE_MEDIA_DECODER
#ifndef CLIENTONLY
if (!sv.state)
#endif
if (!cls.demoinfile && !cls.state && !*cls.servername && !Media_PlayingFullScreen())
if (!sv_state && !cls.demoinfile && !cls.state && !*cls.servername && !Media_PlayingFullScreen())
{
int ol_depth;
int idcin_depth;
@ -6091,30 +6095,25 @@ void CL_StartCinematicOrMenu(void)
}
#endif
if (!cls.demoinfile && !cls.state && !*cls.servername && !Media_PlayingFullScreen())
if (!sv_state && !cls.demoinfile && !cls.state && !*cls.servername && !Media_PlayingFullScreen())
{
#ifndef CLIENTONLY
if (!sv.state)
#endif
if (qrenderer > QR_NONE && !Key_Dest_Has(kdm_emenu))
{
if (qrenderer > QR_NONE && !Key_Dest_Has(kdm_emenu))
{
#ifndef NOBUILTINMENUS
if (!cls.state && !Key_Dest_Has(kdm_emenu) && !*FS_GetGamedir(false))
M_Menu_Mods_f();
if (!cls.state && !Key_Dest_Has(kdm_emenu) && !*FS_GetGamedir(false))
M_Menu_Mods_f();
#endif
if (!cls.state && !Key_Dest_Has(kdm_emenu) && cl_demoreel.ival)
{
cls.demonum = 0;
CL_NextDemo();
}
if (!cls.state && !Key_Dest_Has(kdm_emenu))
//if we're (now) meant to be using csqc for menus, make sure that its running.
if (!CSQC_UnconnectedInit())
M_ToggleMenu_f();
if (!cls.state && !Key_Dest_Has(kdm_emenu) && cl_demoreel.ival)
{
cls.demonum = 0;
CL_NextDemo();
}
//Con_ForceActiveNow();
if (!cls.state && !Key_Dest_Has(kdm_emenu))
//if we're (now) meant to be using csqc for menus, make sure that its running.
if (!CSQC_UnconnectedInit())
M_ToggleMenu_f();
}
//Con_ForceActiveNow();
}
}
@ -6367,6 +6366,7 @@ void Host_Init (quakeparms_t *parms)
Sys_Quit();
return;
}
PM_Shutdown(); //will restart later as needed, but we need to be sure that no files are open or anything.
}
V_Init ();
NET_Init ();

View File

@ -1166,6 +1166,7 @@ void CL_PredictMovePNum (int seat)
}
if (i == pe->num_entities && pv->nolocalplayer)
{
return;
fromstate = &nullstate;
nopred = true;
}

View File

@ -991,27 +991,104 @@ void SCR_DrawCursor(void)
oldcurs = key_customcursor[cmod].handle;
if (rf->VID_CreateCursor && strcmp(key_customcursor[cmod].name, "none"))
{
image_t dummytex;
flocation_t loc;
char bestname[MAX_QPATH];
unsigned int bestflags;
qbyte *rgbadata;
uploadfmt_t format;
void *filedata = NULL;
int filelen = 0, width, height;
key_customcursor[cmod].handle = NULL;
if (!key_customcursor[cmod].handle && *key_customcursor[cmod].name)
memset(&dummytex, 0, sizeof(dummytex));
dummytex.flags = IF_NOREPLACE; //no dds files
*bestname = 0;
//first try the named image, if possible
if (!filedata && *key_customcursor[cmod].name)
{
image_t dummytex;
flocation_t loc;
char bestname[MAX_QPATH];
unsigned int bestflags;
memset(&dummytex, 0, sizeof(dummytex));
dummytex.ident = key_customcursor[cmod].name;
dummytex.flags = IF_NOREPLACE; //no dds files
if (Image_LocateHighResTexture(&dummytex, &loc, bestname, sizeof(bestname), &bestflags))
key_customcursor[cmod].handle = rf->VID_CreateCursor(bestname, key_customcursor[cmod].hotspot[0], key_customcursor[cmod].hotspot[1], key_customcursor[cmod].scale);
else
key_customcursor[cmod].handle = rf->VID_CreateCursor(key_customcursor[cmod].name, key_customcursor[cmod].hotspot[0], key_customcursor[cmod].hotspot[1], key_customcursor[cmod].scale);
filelen = FS_LoadFile(bestname, &filedata);
}
if (!filedata)
{
dummytex.ident = "gfx/cursor.lmp";
if (Image_LocateHighResTexture(&dummytex, &loc, bestname, sizeof(bestname), &bestflags))
filelen = FS_LoadFile(bestname, &filedata);
}
if (!filedata)
{
static qbyte lamecursor[] =
{
#define W 0x8f,0x8f,0x8f,0xff,
#define B 0x00,0x00,0x00,0xff,
#define T 0x00,0x00,0x00,0x00,
W T T T T T T T
W W T T T T T T
W B W T T T T T
W B B W T T T T
W B B B W T T T
W B B B B W T T
W B B B B B W T
W B B B B B B W
W B B B B W W W
W B W B B W T T
W W T W B B W T
W T T W B B W T
T T T T W B B W
T T T T W B B W
T T T T T W W T
#undef W
#undef B
};
key_customcursor[cmod].handle = rf->VID_CreateCursor(lamecursor, 8, 15, PTI_LLLA8, 0, 0, 1); //try the fallback
}
else if (!filedata)
FS_FreeFile(filedata); //format not okay, just free it.
else
{ //raw file loaded.
rgbadata = ReadRawImageFile(filedata, filelen, &width, &height, &format, true, bestname);
FS_FreeFile(filedata);
if (rgbadata)
{ //image loaded properly, yay
if ((format==PTI_RGBX8 || format==PTI_LLLX8) && !strchr(bestname, ':'))
{ //people seem to insist on using jpgs, which don't have alpha.
//so screw over the alpha channel if needed.
unsigned int alpha_width, alpha_height, p;
char aname[MAX_QPATH];
unsigned char *alphadata;
char *alph;
size_t alphsize;
char ext[8];
COM_StripExtension(bestname, aname, sizeof(aname));
COM_FileExtension(bestname, ext, sizeof(ext));
Q_strncatz(aname, "_alpha.", sizeof(aname));
Q_strncatz(aname, ext, sizeof(aname));
alphsize = FS_LoadFile(aname, (void**)&alph);
if (alph)
{
if ((alphadata = ReadRawImageFile(alph, alphsize, &alpha_width, &alpha_height, &format, true, aname)))
{
if (alpha_width == width && alpha_height == height)
for (p = 0; p < alpha_width*alpha_height; p++)
rgbadata[(p<<2) + 3] = (alphadata[(p<<2) + 0] + alphadata[(p<<2) + 1] + alphadata[(p<<2) + 2])/3;
BZ_Free(alphadata);
}
FS_FreeFile(alph);
}
format = (format==PTI_LLLX8)?PTI_LLLA8:PTI_RGBA8;
}
key_customcursor[cmod].handle = rf->VID_CreateCursor(rgbadata, width, height, format, key_customcursor[cmod].hotspot[0], key_customcursor[cmod].hotspot[1], key_customcursor[cmod].scale); //try the fallback
BZ_Free(rgbadata);
}
}
if (!key_customcursor[cmod].handle)
key_customcursor[cmod].handle = rf->VID_CreateCursor("gfx/cursor.tga", key_customcursor[cmod].hotspot[0], key_customcursor[cmod].hotspot[1], key_customcursor[cmod].scale); //try the fallback
if (!key_customcursor[cmod].handle)
key_customcursor[cmod].handle = rf->VID_CreateCursor("gfx/cursor.png", key_customcursor[cmod].hotspot[0], key_customcursor[cmod].hotspot[1], key_customcursor[cmod].scale); //try the fallback
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], key_customcursor[cmod].scale); //try the fallback
}
else
key_customcursor[cmod].handle = NULL;

View File

@ -697,6 +697,11 @@ void Con_Init (void)
con_main.linebuffered = Con_ExecuteLine;
con_main.commandcompletion = true;
// con_main.flags |= CONF_ISWINDOW;
con_main.wnd_w = 640;
con_main.wnd_h = 480;
con_main.wnd_x = 0;
con_main.wnd_y = 0;
Q_strncpyz(con_main.title, "MAIN", sizeof(con_main.title));
Q_strncpyz(con_main.prompt, "]", sizeof(con_main.prompt));
@ -2571,7 +2576,7 @@ void Con_DrawConsole (int lines, qboolean noback)
}
//draw main console...
if (lines > 0)
if (lines > 0 && !(con_current->flags & CONF_ISWINDOW))
{
int top;
#ifdef QTERM
@ -2935,18 +2940,106 @@ static qbyte Con_IsTokenChar(unsigned int chr)
return true;
if (chr == '(' || chr == ')' || chr == '{' || chr == '}')
return false;
if (chr == '.' || chr == '/' || chr == '\\')
return 2;
if (chr == '/' || chr == '\\')
return 2; //on left only
if (chr == '.' || chr == ':')
return 3; //disallow only if followed by whitespace
if (chr >= 'a' && chr <= 'z')
return true;
if (chr >= 'A' && chr <= 'Z')
return true;
if (chr >= '0' && chr <= '9')
return true;
if (chr == '[' || chr == ']' || chr == '_' || chr == ':')
if (chr == '[' || chr == ']' || chr == '_')
return true;
return false;
}
void Con_ExpandConsoleSelection(console_t *con)
{
conchar_t *cur, *n;
conline_t *l;
conchar_t *lstart;
conchar_t *lend;
unsigned int cf, uc;
//no selection to expand...
if (!con->selstartline || !con->selendline)
return;
l = con->selstartline;
lstart = (conchar_t*)(l+1);
cur = lstart + con->selstartoffset;
if (con->selstartline == con->selendline)
{
if (con->selstartoffset+1 == con->selendoffset)
{
//they only selected a single char?
//fix that up to select the entire token
while (cur > lstart)
{
cur--;
uc = (*cur & CON_CHARMASK);
if (!Con_IsTokenChar(uc))
{
cur++;
break;
}
if (*cur == CON_LINKSTART)
break;
}
for (n = lstart+con->selendoffset; con->selendoffset < l->length; )
{
n = Font_Decode(n, &cf, &uc);
if (Con_IsTokenChar(uc)==3)
continue;
if (Con_IsTokenChar(uc)==1 && lstart[con->selendoffset] != CON_LINKEND)
con->selendoffset = n-lstart;
else
break;
}
/*while (con->selendoffset > l->length)
{
uc = (((conchar_t*)(l+1))[con->selendoffset] & CON_CHARMASK);
if (Con_IsTokenChar(uc) == 2)
con->selendoffset--;
else
break;
}*/
}
}
//scan backwards to find any link enclosure
for(lend = cur-1; lend >= (conchar_t*)(l+1); lend--)
{
if (*lend == CON_LINKSTART)
{
//found one
cur = lend;
break;
}
if (*lend == CON_LINKEND)
{
//some other link ended here. don't use its start.
break;
}
}
//scan forwards to find the end of the selected link
if (l->length && cur < (conchar_t*)(l+1)+l->length && *cur == CON_LINKSTART)
{
for(lend = (conchar_t*)(con->selendline+1) + con->selendoffset; lend < (conchar_t*)(con->selendline+1) + con->selendline->length; lend++)
{
if (*lend == CON_LINKEND)
{
con->selendoffset = lend+1 - (conchar_t*)(con->selendline+1);
break;
}
}
}
con->selstartoffset = cur-(conchar_t*)(l+1);
}
char *Con_CopyConsole(console_t *con, qboolean nomarkup, qboolean onlyiflink)
{
conchar_t *cur;

View File

@ -5358,7 +5358,7 @@ static pixel32_t *Image_Block_Decode(qbyte *fte_restrict in, size_t insize, int
sizediff = insize - blockbytes*((w+blockwidth-1)/blockwidth)*((h+blockheight-1)/blockheight);
if (sizediff)
{
Con_Printf("Image_Block_Decode: %s data size is %u, expected %u\n\n", Image_FormatName(encoding), insize, insize-sizediff);
Con_Printf("Image_Block_Decode: %s data size is %u, expected %u\n\n", Image_FormatName(encoding), (unsigned int)insize, (unsigned int)(insize-sizediff));
if (sizediff < 0)
return NULL;
}

View File

@ -162,7 +162,7 @@ qboolean mouseactive;
static cvar_t in_joystick = CVARAF("joystick","0", "in_joystick", CVAR_ARCHIVE);
static qboolean joy_advancedinit;
static DWORD joy_flags;
static DWORD joy_flags = JOY_RETURNALL|JOY_RETURNCENTERED;
#define MAX_JOYSTICKS 8
static struct wjoy_s {
qboolean isxinput; //xinput device

View File

@ -671,7 +671,7 @@ qboolean Key_GetConsoleSelectionBox(console_t *con, int *sx, int *sy, int *ex, i
{
*sx = *sy = *ex = *ey = 0;
if (con->buttonsdown == CB_SCROLL)
if (con->buttonsdown == CB_SCROLL || con->buttonsdown == CB_SCROLL_R)
{
//left-mouse.
//scroll the console with the mouse. trigger links on release.
@ -1071,6 +1071,52 @@ void Key_DefaultLinkClicked(console_t *con, char *text, char *info)
}
}
void Key_HandleConsoleLink(console_t *con, char *buffer)
{
if (!buffer)
return;
if (buffer[0] == '^' && buffer[1] == '[')
{
//looks like it might be a link!
char *end = NULL;
char *info;
for (info = buffer + 2; *info; )
{
if (info[0] == '^' && info[1] == ']')
break; //end of tag, with no actual info, apparently
if (*info == '\\')
break;
else if (info[0] == '^' && info[1] == '^')
info+=2;
else
info++;
}
for(end = info; *end; )
{
if (end[0] == '^' && end[1] == ']')
{
//okay, its a valid link that they clicked
*end = 0;
#ifdef PLUGINS
if (!Plug_ConsoleLink(buffer+2, info, con->name))
#endif
#ifdef CSQC_DAT
if (!CSQC_ConsoleLink(buffer+2, info))
#endif
{
Key_DefaultLinkClicked(con, buffer+2, info);
}
break;
}
if (end[0] == '^' && end[1] == '^')
end+=2;
else
end++;
}
}
}
#define Key_IsTouchScreen() false
void Key_ConsoleRelease(console_t *con, int key, unsigned int unicode)
{
@ -1083,33 +1129,48 @@ void Key_ConsoleRelease(console_t *con, int key, unsigned int unicode)
if (con->selstartline)
{
if (con->selstartline == con->selendline && con->selendoffset <= con->selstartoffset+1)
con->flags &= ~CONF_KEEPSELECTION;
else
con->flags |= CONF_KEEPSELECTION;
if (con->userdata)
{
if (con->flags & CONF_BACKSELECTION)
{
con->userline = con->selendline;
con->useroffset = con->selendoffset;
}
con->flags &= ~CONF_KEEPSELECTION;
if (keydown[K_LSHIFT] || keydown[K_RSHIFT])
;
else
{
con->userline = con->selstartline;
con->useroffset = con->selstartoffset;
buffer = Con_CopyConsole(con, false, true);
if (buffer)
{
Key_HandleConsoleLink(con, buffer);
Z_Free(buffer);
}
}
}
else
{
con->flags |= CONF_KEEPSELECTION;
if (con->userdata)
{
if (con->flags & CONF_BACKSELECTION)
{
con->userline = con->selendline;
con->useroffset = con->selendoffset;
}
else
{
con->userline = con->selstartline;
con->useroffset = con->selstartoffset;
}
}
buffer = Con_CopyConsole(con, true, false); //don't keep markup if we're copying to the clipboard
if (buffer)
{
Sys_SaveClipboard(CBT_SELECTION, buffer);
Z_Free(buffer);
}
}
}
con->buttonsdown = CB_NONE;
buffer = Con_CopyConsole(con, true, false); //don't keep markup if we're copying to the clipboard
if (buffer)
{
Sys_SaveClipboard(CBT_SELECTION, buffer);
Z_Free(buffer);
}
}
if (key == K_MOUSE1 && con->buttonsdown == CB_SCROLL)
if ((key == K_MOUSE1 && con->buttonsdown == CB_SCROLL) || (key == K_MOUSE2 && con->buttonsdown == CB_SCROLL_R))
{
con->buttonsdown = CB_NONE;
if (abs(con->mousedown[0] - con->mousecursor[0]) < 5 && abs(con->mousedown[1] - con->mousecursor[1]) < 5)
@ -1138,48 +1199,7 @@ void Key_ConsoleRelease(console_t *con, int key, unsigned int unicode)
Key_ConsoleInsert(buffer);
}
else
{
if (buffer[0] == '^' && buffer[1] == '[')
{
//looks like it might be a link!
char *end = NULL;
char *info;
for (info = buffer + 2; *info; )
{
if (info[0] == '^' && info[1] == ']')
break; //end of tag, with no actual info, apparently
if (*info == '\\')
break;
else if (info[0] == '^' && info[1] == '^')
info+=2;
else
info++;
}
for(end = info; *end; )
{
if (end[0] == '^' && end[1] == ']')
{
//okay, its a valid link that they clicked
*end = 0;
#ifdef PLUGINS
if (!Plug_ConsoleLink(buffer+2, info, con->name))
#endif
#ifdef CSQC_DAT
if (!CSQC_ConsoleLink(buffer+2, info))
#endif
{
Key_DefaultLinkClicked(con, buffer+2, info);
}
break;
}
if (end[0] == '^' && end[1] == '^')
end+=2;
else
end++;
}
}
}
Key_HandleConsoleLink(con, buffer);
Z_Free(buffer);
}
else
@ -1553,6 +1573,7 @@ qboolean Key_Console (console_t *con, int key, unsigned int unicode)
qboolean ctrl = keydown[K_LCTRL] || keydown[K_RCTRL];
qboolean shift = keydown[K_LSHIFT] || keydown[K_RSHIFT];
int rkey = key;
char *buffer;
//weirdness for the keypad.
if ((unicode >= '0' && unicode <= '9') || unicode == '.' || key < 0)
@ -1576,6 +1597,7 @@ qboolean Key_Console (console_t *con, int key, unsigned int unicode)
if ((key == K_MOUSE1 || key == K_MOUSE2))
{
int olddown[2] = {con->mousedown[0],con->mousedown[1]};
if (con->flags & CONF_ISWINDOW)
if (con->mousecursor[0] < -8 || con->mousecursor[1] < 0 || con->mousecursor[0] > con->wnd_w || con->mousecursor[1] > con->wnd_h)
return true;
@ -1609,8 +1631,12 @@ qboolean Key_Console (console_t *con, int key, unsigned int unicode)
{
if (con->redirect && con->redirect(con, unicode, key))
return true;
con->buttonsdown = CB_COPY;
con->flags &= ~CONF_KEEPSELECTION;
if (Key_IsTouchScreen()) //o.O mouse2+touchscreen? really?
con->buttonsdown = CB_COPY;
else
con->buttonsdown = CB_SCROLL_R;
}
else
{
@ -1625,13 +1651,38 @@ qboolean Key_Console (console_t *con, int key, unsigned int unicode)
{
if (con->redirect && con->redirect(con, unicode, key))
return true;
if (Key_IsTouchScreen())
if (Key_IsTouchScreen() || con->mousecursor[0] > ((con->flags & CONF_ISWINDOW)?con->wnd_w-16:vid.width)-8)
{ //just scroll the console up/down
con->buttonsdown = CB_SCROLL;
}
else
{ //selecting text. woo.
if (realtime < con->mousedowntime + 0.4
&& con->mousecursor[0] >= olddown[0]-3 && con->mousecursor[0] <= olddown[0]+3
&& con->mousecursor[1] >= olddown[1]-3 && con->mousecursor[1] <= olddown[1]+3
)
{ //this was a double-click... expand the selection to the entire word
//FIXME: detect tripple-clicks to select the entire line
Con_ExpandConsoleSelection(con);
con->flags |= CONF_KEEPSELECTION;
buffer = Con_CopyConsole(con, true, false); //don't keep markup if we're copying to the clipboard
if (buffer)
{
Sys_SaveClipboard(CBT_SELECTION, buffer);
Z_Free(buffer);
}
return true;
}
con->mousedowntime = realtime;
con->buttonsdown = CB_SELECT;
if (shift)
{
con->mousedown[0] = olddown[0];
con->mousedown[1] = olddown[1];
}
}
con->flags &= ~CONF_KEEPSELECTION;
}

View File

@ -424,7 +424,7 @@ typedef struct rendererinfo_s {
void (*VID_SwapBuffers) (void); //force a buffer swap, regardless of what's displayed.
qboolean (*VID_ApplyGammaRamps) (unsigned int size, unsigned short *ramps);
void *(*VID_CreateCursor) (const char *filename, float hotx, float hoty, float scale); //may be null, stub returns null
void *(*VID_CreateCursor) (const qbyte *imagedata, int width, int height, uploadfmt_t format, float hotx, float hoty, float scale); //may be null, stub returns null
qboolean (*VID_SetCursor) (void *cursor); //may be null
void (*VID_DestroyCursor) (void *cursor); //may be null

View File

@ -2467,8 +2467,8 @@ static void QCBUILTIN PF_cs_getstati(pubprogfuncs_t *prinst, struct globalvars_s
int stnum = G_FLOAT(OFS_PARM0);
if (stnum < 0 || stnum >= MAX_CL_STATS)
{
G_FLOAT(OFS_RETURN) = 0;
PR_RunWarning(prinst, "invalid stat index");
G_INT(OFS_RETURN) = 0;
PR_RunWarning(prinst, "PF_cs_getstati: invalid stat index (%i)\n", stnum);
}
else if (stnum >= 128 && csqc_isdarkplaces && cls.protocol != CP_NETQUAKE && !CPNQ_IS_DP)
{ //dpp7 stats are fucked.
@ -2486,7 +2486,7 @@ static void QCBUILTIN PF_cs_getstatbits(pubprogfuncs_t *prinst, struct globalvar
if (stnum < 0 || stnum >= MAX_CL_STATS)
{
G_FLOAT(OFS_RETURN) = 0;
PR_RunWarning(prinst, "invalid stat index");
PR_RunWarning(prinst, "PF_cs_getstatbits: invalid stat index (%i)\n", stnum);
}
else if (prinst->callargc > 1)
{
@ -2515,14 +2515,14 @@ static void QCBUILTIN PF_cs_getstats(pubprogfuncs_t *prinst, struct globalvars_s
if (stnum < 0 || stnum >= MAX_CL_STATS)
{
G_INT(OFS_RETURN) = 0;
PR_RunWarning(prinst, "invalid stat index");
PR_RunWarning(prinst, "PF_cs_getstats: invalid stat index (%i)\n", stnum);
}
else if (cls.fteprotocolextensions & PEXT_CSQC)
RETURN_TSTRING(csqc_playerview->statsstr[stnum]);
else if (stnum >= MAX_CL_STATS-3)
else if (stnum >= MAX_CL_STATS-3) //we'll be reading the following 3 extra stats too.
{
G_INT(OFS_RETURN) = 0;
PR_RunWarning(prinst, "invalid stat index");
PR_RunWarning(prinst, "PF_cs_getstats: invalid packed-string stat index (%i)\n", stnum);
}
else
{
@ -5751,7 +5751,7 @@ static void QCBUILTIN PF_cs_getplayerstat(pubprogfuncs_t *prinst, struct globalv
}
}
void CL_CalcCrouch (playerview_t *pv);
static void QCBUILTIN PF_V_CalcRefdef(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{ //this function is essentially an overcomplicated way to shirk from defining your own view bobbing.
csqcedict_t *ent = (csqcedict_t*)G_EDICT(prinst, OFS_PARM0);
@ -5777,7 +5777,7 @@ static void QCBUILTIN PF_V_CalcRefdef(pubprogfuncs_t *prinst, struct globalvars_
CL_DecayLights ();
CL_ClearEntityLists();
// CL_ClearEntityLists();
V_ClearRefdef(csqc_playerview);
r_refdef.drawsbar = false; //csqc defaults to no sbar.
@ -5787,6 +5787,7 @@ static void QCBUILTIN PF_V_CalcRefdef(pubprogfuncs_t *prinst, struct globalvars_
VectorCopy(ent->v->origin, csqc_playerview->simorg);
VectorCopy (ent->v->velocity, csqc_playerview->simvel);
csqc_playerview->onground = !!((int)ent->v->flags & FL_ONGROUND);
CL_CalcCrouch (csqc_playerview);
V_CalcRefdef(csqc_playerview); //set up the defaults
VectorCopy(savedvel, csqc_playerview->simvel);
@ -7094,32 +7095,42 @@ static void *CSQC_FindMainProgs(size_t *sz, const char *name, unsigned int check
if (!file)
{
const char *progsname = InfoBuf_ValueForKey(&cl.serverinfo, "*csprogsname");
if (*progsname && cls.state)
file = COM_LoadTempFile (progsname, FSLF_IGNOREPURE, sz);
if (!file && strcmp(progsname, "csprogs.dat"))
file = COM_LoadTempFile ("csprogs.dat", FSLF_IGNOREPURE, sz);
if (file && !cls.demoplayback) //allow them to use csprogs.dat if playing a demo, and don't care about the checksum
flocation_t loc={0};
vfsfile_t *f;
qboolean found = false;
if (!found && *progsname && cls.state)
found = FS_FLocateFile(progsname, FSLF_IGNOREPURE, &loc);
if (!found && strcmp(progsname, "csprogs.dat"))
found = FS_FLocateFile("csprogs.dat", FSLF_IGNOREPURE, &loc);
if (found && (f=FS_OpenReadLocation(&loc)))
{
if (checksum && !csprogs_promiscuous)
{
if (!CSQC_ValidateMainCSProgs(file, *sz, checksum, checksize))
file = NULL;
*sz = VFS_GETLEN(f);
file = Hunk_TempAlloc (*sz);
VFS_READ(f, file, *sz);
VFS_CLOSE(f);
//we write the csprogs into our archive if it was loaded from outside of there.
//this is to ensure that demos will play on the same machine later on...
//this is unreliable though, and redundant if we're writing the csqc into the demos themselves.
//also kinda irrelevant with sv_pure.
//FIXME: don't back up if it was in a package.
if (file && !cls.demoplayback) //allow them to use csprogs.dat if playing a demo, and don't care about the checksum
{
if (checksum && !csprogs_promiscuous)
{
if (!CSQC_ValidateMainCSProgs(file, *sz, checksum, checksize))
file = NULL;
//we write the csprogs into our archive if it was loaded from outside of there.
//this is to ensure that demos will play on the same machine later on...
//this is unreliable though, and redundant if we're writing the csqc into the demos themselves.
//also kinda irrelevant with sv_pure.
//FIXME: don't back up if it was in a package.
#ifndef FTE_TARGET_WEB
if (file
if (file && !sv_state && !FS_WhichPackForLocation(&loc, false)
#if !defined(CLIENTONLY) && defined(MVD_RECORDING)
&& !sv_demo_write_csqc.ival
&& !sv_demo_write_csqc.ival
#endif
)
//back it up
COM_WriteFile(newname, FS_GAMEONLY, file, *sz);
)
//back it up
COM_WriteFile(newname, FS_GAMEONLY, file, *sz);
#endif
}
}
}
}

View File

@ -1294,7 +1294,7 @@ void R2D_PolyBlend (void)
return;
if (bordersize && bordersize < r_refdef.vrect.width && bordersize < r_refdef.vrect.height)
if (r_refdef.playerview->bordertint[3])
{
vec2_t points[4];
vec2_t tcoords[4];

View File

@ -4228,6 +4228,11 @@ static void Sys_QueryDesktopParameters(void)
void Sys_Sleep (double seconds)
{
if (seconds < 0)
seconds = 0;
if (seconds > 1)
seconds = 1;
Con_Printf("Sys_Sleep%g\n", seconds);
Sleep(seconds * 1000);
}
@ -4235,57 +4240,19 @@ void Sys_Sleep (double seconds)
HCURSOR hArrowCursor, hCustomCursor;
void *WIN_CreateCursor(const char *filename, float hotx, float hoty, float scale)
void *WIN_CreateCursor(const qbyte *imagedata, int width, int height, uploadfmt_t format, float hotx, float hoty, float scale)
{
int width, height;
BITMAPV4HEADER bi;
DWORD x,y;
HCURSOR hAlphaCursor = NULL;
ICONINFO ii;
HDC maindc;
qbyte *rgbadata, *rgbadata_start, *bgradata, *bgradata_start;
uploadfmt_t format;
void *filedata;
int filelen;
if (!filename || !*filename)
const qbyte *rgbadata;
qbyte *bgradata, *bgradata_start;
void *scaled = NULL;
if (!imagedata)
return NULL;
filelen = FS_LoadFile(filename, &filedata);
if (!filedata)
return NULL;
rgbadata_start = ReadRawImageFile(filedata, filelen, &width, &height, &format, true, "cursor");
FS_FreeFile(filedata);
if (!rgbadata_start)
return NULL;
if ((format==PTI_RGBX8 || format==PTI_LLLX8) && !strchr(filename, ':'))
{ //people seem to insist on using jpgs, which don't have alpha.
//screw over the alpha channel if needed.
unsigned int alpha_width, alpha_height, p;
char aname[MAX_QPATH];
unsigned char *alphadata;
char *alph;
size_t alphsize;
char ext[8];
uploadfmt_t alphaformat;
COM_StripExtension(filename, aname, sizeof(aname));
COM_FileExtension(filename, ext, sizeof(ext));
Q_strncatz(aname, "_alpha.", sizeof(aname));
Q_strncatz(aname, ext, sizeof(aname));
alphsize = FS_LoadFile(filename, (void**)&alph);
if (alph)
{
if ((alphadata = ReadRawImageFile(alph, alphsize, &alpha_width, &alpha_height, &alphaformat, true, aname)))
{
if (alpha_width == width && alpha_height == height)
for (p = 0; p < alpha_width*alpha_height; p++)
rgbadata_start[(p<<2) + 3] = (alphadata[(p<<2) + 0] + alphadata[(p<<2) + 1] + alphadata[(p<<2) + 2])/3;
BZ_Free(alphadata);
}
FS_FreeFile(alph);
}
}
// FIXME: CreateIconIndirect does NOT understand DPI scaling, and will show a tiny cursor in such cases.
// we should rescale scale by vid_conautoscale etc.
@ -4298,11 +4265,10 @@ void *WIN_CreateCursor(const char *filename, float hotx, float hoty, float scale
if (nw <= 0 || nh <= 0 || nw > 128 || nh > 128) //don't go crazy.
return NULL;
nd = BZ_Malloc(nw*nh*4);
Image_ResampleTexture((unsigned int*)rgbadata_start, width, height, (unsigned int*)nd, nw, nh);
Image_ResampleTexture((unsigned int*)imagedata, width, height, (unsigned int*)nd, nw, nh);
width = nw;
height = nh;
BZ_Free(rgbadata_start);
rgbadata_start = nd;
imagedata = scaled = nd;
}
memset(&bi,0, sizeof(bi));
@ -4327,11 +4293,11 @@ void *WIN_CreateCursor(const char *filename, float hotx, float hoty, float scale
if (!ii.hbmColor)
{
BZ_Free(rgbadata_start);
BZ_Free(scaled);
return NULL;
}
for (rgbadata=rgbadata_start,y=0;y<height;y++)
for (rgbadata=imagedata,y=0;y<height;y++)
{
bgradata = bgradata_start + (height-1-y)*width*4;
for (x=0;x<width;x++)
@ -4345,7 +4311,7 @@ void *WIN_CreateCursor(const char *filename, float hotx, float hoty, float scale
}
}
BZ_Free(rgbadata_start);
BZ_Free(scaled);
ii.fIcon = FALSE; // Change fIcon to TRUE to create an alpha icon
ii.xHotspot = hotx;

View File

@ -784,7 +784,7 @@ void V_CalcBlend (float *hw_blend)
if (j == CSHIFT_SERVER)
{
/*server blend always goes into sw, ALWAYS*/
/*server blend always goes into sw, ALWAYS. hardware is too unreliable.*/
blend = pv->screentint;
}
else
@ -792,7 +792,7 @@ void V_CalcBlend (float *hw_blend)
/*flashing things should not change hardware gamma ramps - windows is too slow*/
/*splitscreen should only use hw gamma ramps if they're all equal, and they're probably not*/
/*hw blends may also not be supported or may be disabled*/
if (gl_cshiftenabled.value)
if (gl_cshiftenabled.ival == 2)
blend = pv->bordertint; //show the colours only on the borders so we don't blind ourselves
else if (j == CSHIFT_BONUS || j == CSHIFT_DAMAGE || gl_nohwblend.ival || !r2d_canhwgamma || cl.splitclients > 1)
blend = pv->screentint;

View File

@ -27,7 +27,7 @@ void *wadmutex;
void Wads_Flush (void){}
qboolean Wad_NextDownload (void){return true;}
void *W_GetLumpName (const char *name, size_t *size, qbyte *type) {return NULL;}
qbyte *W_GetTexture(const char *name, int *width, int *height, qboolean *usesalpha){return NULL;}
qbyte *W_GetTexture(const char *name, int *width, int *height, uploadfmt_t *format){return NULL;}
void W_LoadWadFile (char *filename){}
void W_Shutdown (void){}
void CL_Skygroup_f(void){}

View File

@ -128,7 +128,7 @@ extern qboolean mouseinitialized;
//extern HANDLE hinput, houtput;
extern HCURSOR hArrowCursor, hCustomCursor;
void *WIN_CreateCursor(const char *filename, float hotx, float hoty, float scale);
void *WIN_CreateCursor(const qbyte *imagedata, int width, int height, uploadfmt_t format, float hotx, float hoty, float scale);
qboolean WIN_SetCursor(void *cursor);
void WIN_DestroyCursor(void *cursor);
void WIN_WindowCreated(HWND window);

View File

@ -368,6 +368,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define HAVE_CLIENT
#endif
#ifndef HAVE_SERVER
#undef MVD_RECORDING
#endif
//software rendering is just too glitchy, don't use it - unless its the only choice.
#if defined(SWQUAKE) && !defined(_DEBUG) && !defined(__DJGPP__)
#undef SWQUAKE
@ -620,10 +624,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#undef USE_EGL
#endif
#if defined(HAVE_WINSSPI) || defined(HAVE_GNUTLS)
#if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL) || defined(HAVE_WINSSPI)
#define HAVE_SSL
#endif
#if defined(HAVE_GNUTLS) || defined(HAVE_WINSSPI)
#if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL) || defined(HAVE_WINSSPI)
//FIXME: HAVE_WINSSPI does not work as a server.
//FIXME: advertising dtls without a valid certificate will probably bug out if a client tries to auto-upgrade.
//FIXME: we don't cache server certs

View File

@ -534,7 +534,7 @@ void FS_ReferenceControl(unsigned int refflag, unsigned int resetflags);
typedef struct vfsfile_s
{
int (QDECL *ReadBytes) (struct vfsfile_s *file, void *buffer, int bytestoread);
int (QDECL *WriteBytes) (struct vfsfile_s *file, const void *buffer, int bytestoread);
int (QDECL *WriteBytes) (struct vfsfile_s *file, const void *buffer, int bytestowrite);
qboolean (QDECL *Seek) (struct vfsfile_s *file, qofs_t pos); //returns false for error
qofs_t (QDECL *Tell) (struct vfsfile_s *file);
qofs_t (QDECL *GetLen) (struct vfsfile_s *file); //could give some lag
@ -812,6 +812,8 @@ qbyte COM_BlockSequenceCRCByte (qbyte *base, int length, int sequence);
qbyte Q2COM_BlockSequenceCRCByte (qbyte *base, int length, int sequence);
typedef size_t hashfunc_t(unsigned char *digest, size_t maxdigestsize, size_t numstrings, const unsigned char **strings, size_t *stringlens);
#define SHA1 SHA1_quake
#define HMAC HMAC_quake
hashfunc_t SHA1_m;
//int SHA1_m(char *digest, size_t maxdigestsize, size_t numstrings, const char **strings, size_t *stringlens);
//#define SHA1(digest,maxdigestsize,string,stringlen) SHA1_m(digest, maxdigestsize, 1, &string, &stringlen)

View File

@ -119,6 +119,7 @@
#define HAVE_PACKET //we can send unreliable messages!
#define HAVE_TCP //we can create/accept TCP connections.
#define HAVE_GNUTLS //on linux
//#define HAVE_OPENSSL //on linux. hardlinked, so typically set only via the makefile.
#define HAVE_WINSSPI //on windows
#define FTPSERVER //sv_ftp cvar.
#define WEBCLIENT //uri_get+any internal downloads etc

View File

@ -113,26 +113,35 @@ typedef struct conline_s {
} conline_t;
//majority of these are mututally exclusive. the bits allow multiple.
#define CB_NONE 0
#define CB_SCROLL 1
#define CB_COPY 2
#define CB_CLOSE 3
#define CB_MOVE 4
#define CB_ACTIONBAR 5
#define CB_SELECT 6
#define CB_SIZELEFT (1u<<29)
#define CB_SIZERIGHT (1u<<30)
#define CB_SIZEBOTTOM (1u<<31)
#define CONF_HIDDEN 1 /*do not show in the console list (unless active)*/
#define CONF_NOTIFY 2 /*text printed to console also appears as notify lines*/
#define CONF_NOTIFY_BOTTOM 4 /*align the bottom*/
#define CONF_NOTIFY_RIGHT 8
//#define CONF_NOTIMES 16
#define CONF_KEYFOCUSED 32
#define CONF_ISWINDOW 64
#define CONF_NOWRAP 128
#define CONF_KEEPSELECTION 256 //there's text selected, keep it selected.
#define CONF_BACKSELECTION 512 //a hint that the text was selected from the end
enum
{
CB_NONE = 0,
CB_SCROLL = 1,
CB_COPY = 2,
CB_CLOSE = 3,
CB_MOVE = 4,
CB_ACTIONBAR = 5,
CB_SELECT = 6,
CB_SCROLL_R = 7,
//the flags part
CB_SIZELEFT = (1u<<29),
CB_SIZERIGHT = (1u<<30),
CB_SIZEBOTTOM = (1u<<31),
};
enum
{
CONF_HIDDEN = 1u<<0, /*do not show in the console list (unless active)*/
CONF_NOTIFY = 1u<<1, /*text printed to console also appears as notify lines*/
CONF_NOTIFY_BOTTOM = 1u<<2, /*align the bottom*/
CONF_NOTIFY_RIGHT = 1u<<3,
//CONF_NOTIMES = 1u<<4,
CONF_KEYFOCUSED = 1u<<5,
CONF_ISWINDOW = 1u<<6,
CONF_NOWRAP = 1u<<7,
CONF_KEEPSELECTION = 1u<<8, //there's text selected, keep it selected.
CONF_BACKSELECTION = 1u<<9, //a hint that the text was selected from the end
};
typedef struct console_s
{
int id;
@ -186,6 +195,7 @@ typedef struct console_s
int mousedown[2]; //x,y position that the current buttons were clicked.
unsigned int buttonsdown;
int mousecursor[2]; //x,y
float mousedowntime; //time mouse1 last went down, to detect double-clicks
struct console_s *next;
} console_t;
@ -220,6 +230,7 @@ void Con_History_Load(void);
struct font_s;
void Con_DrawOneConsole(console_t *con, qboolean focused, struct font_s *font, float fx, float fy, float fsx, float fsy, float lineagelimit);
void Con_DrawConsole (int lines, qboolean noback);
void Con_ExpandConsoleSelection(console_t *con);
char *Con_CopyConsole(console_t *con, qboolean nomarkup, qboolean onlyiflink);
void Con_Print (const char *txt);
void Con_CenterPrint(const char *txt);

View File

@ -14,6 +14,7 @@
void FS_BeginManifestUpdates(void);
static void QDECL fs_game_callback(cvar_t *var, char *oldvalue);
static void COM_InitHomedir(ftemanifest_t *man);
hashtable_t filesystemhash;
qboolean com_fschanged = true;
qboolean com_installer = false;
@ -550,7 +551,7 @@ static qboolean FS_Manifest_ParseTokens(ftemanifest_t *man)
Z_Free(man->defaultexec);
man->defaultexec = Z_StrDup(Cmd_Argv(1));
}
else if (!Q_strcasecmp(cmd, "bind") || !Q_strcasecmp(cmd, "set") || !Q_strcasecmp(cmd, "seta"))
else if (!Q_strcasecmp(cmd, "bind") || !Q_strcasecmp(cmd, "set") || !Q_strcasecmp(cmd, "seta") || !Q_strcasecmp(cmd, "alias"))
{
Z_StrCat(&man->defaultoverrides, va("%s %s\n", Cmd_Argv(0), Cmd_Args()));
}
@ -5607,6 +5608,7 @@ qboolean FS_ChangeGame(ftemanifest_t *man, qboolean allowreloadconfigs, qboolean
{
qboolean oldhome = com_homepathenabled;
COM_InitHomedir(man);
com_homepathenabled = com_homepathusable;
if (man->disablehomedir && !COM_CheckParm("-usehome"))
@ -6145,56 +6147,21 @@ void FS_ArbitraryFile_c(int argn, const char *partial, struct xcommandargcomplet
}
}
/*
================
COM_InitFilesystem
note: does not actually load any packs, just makes sure the basedir+cvars+etc is set up. vfs_fopens will still fail.
================
*/
void COM_InitFilesystem (void)
static void COM_InitHomedir(ftemanifest_t *man)
{
int i;
int i;
char *ev;
qboolean usehome;
FS_RegisterDefaultFileSystems();
Cmd_AddCommand("fs_restart", FS_ReloadPackFiles_f);
Cmd_AddCommandD("fs_changegame", FS_ChangeGame_f, "Switch between different manifests (or registered games)");
Cmd_AddCommandD("fs_changemod", FS_ChangeMod_f, "Provides the backend functionality of a transient online installer. Eg, for quaddicted's map/mod database.");
Cmd_AddCommand("fs_showmanifest", FS_ShowManifest_f);
Cmd_AddCommand ("fs_flush", COM_RefreshFSCache_f);
Cmd_AddCommandAD("dir", COM_Dir_f, FS_ArbitraryFile_c, "Displays filesystem listings. Accepts wildcards."); //q3 like
Cmd_AddCommandD("path", COM_Path_f, "prints a list of current search paths.");
Cmd_AddCommandAD("flocate", COM_Locate_f, FS_ArbitraryFile_c, "Searches for a named file, and displays where it can be found in the OS's filesystem"); //prints the pak or whatever where this file can be found.
//
// -basedir <path>
// Overrides the system supplied base directory (under id1)
//
i = COM_CheckParm ("-basedir");
if (i && i < com_argc-1)
strcpy (com_gamepath, com_argv[i+1]);
else
strcpy (com_gamepath, host_parms.basedir);
FS_CleanDir(com_gamepath, sizeof(com_gamepath));
Cvar_Register(&cfg_reload_on_gamedir, "Filesystem");
Cvar_Register(&com_fs_cache, "Filesystem");
Cvar_Register(&fs_gamename, "Filesystem");
Cvar_Register(&pm_downloads_url, "Filesystem");
Cvar_Register(&pm_autoupdate, "Filesystem");
Cvar_Register(&com_protocolname, "Server Info");
Cvar_Register(&com_protocolversion, "Server Info");
Cvar_Register(&fs_game, "Filesystem");
#ifdef Q2SERVER
Cvar_Register(&fs_gamedir, "Filesystem");
Cvar_Register(&fs_basedir, "Filesystem");
//FIXME: this should come from the manifest, as fte_GAME or something
#ifdef _WIN32
#define HOMESUBDIR FULLENGINENAME
#else
#ifdef GAME_SHORTNAME
#define HOMESUBDIR GAME_SHORTNAME
#else
#define HOMESUBDIR "fte"
#endif
#endif
usehome = false;
@ -6221,7 +6188,7 @@ void COM_InitFilesystem (void)
if (dSHGetFolderPathW(NULL, 0x5, NULL, 0, wfolder) == S_OK)
{
narrowen(folder, sizeof(folder), wfolder);
Q_snprintfz(com_homepath, sizeof(com_homepath), "%s/My Games/%s/", folder, FULLENGINENAME);
Q_snprintfz(com_homepath, sizeof(com_homepath), "%s/My Games/%s/", folder, HOMESUBDIR);
}
}
// if (shfolder)
@ -6231,12 +6198,12 @@ void COM_InitFilesystem (void)
{
ev = getenv("USERPROFILE");
if (ev)
Q_snprintfz(com_homepath, sizeof(com_homepath), "%s/My Documents/My Games/%s/", ev, FULLENGINENAME);
Q_snprintfz(com_homepath, sizeof(com_homepath), "%s/My Documents/My Games/%s/", ev, HOMESUBDIR);
}
#ifdef NPFTE
if (!*com_homepath)
Q_snprintfz(com_homepath, sizeof(com_homepath), "/%s/", FULLENGINENAME);
Q_snprintfz(com_homepath, sizeof(com_homepath), "/%s/", HOMESUBDIR);
//as a browser plugin, always use their home directory
usehome = true;
#else
@ -6319,29 +6286,33 @@ void COM_InitFilesystem (void)
char newhome[MAX_OSPATH];
struct stat s;
#ifdef GAME_SHORTNAME
#define HOMESUBDIR GAME_SHORTNAME
#else
#define HOMESUBDIR "fte" //FIXME: this should come from the manifest, as fte_GAME or something
#endif
if (ev[strlen(ev)-1] == '/')
Q_snprintfz(oldhome, sizeof(oldhome), "%s."HOMESUBDIR"/", ev);
else
Q_snprintfz(oldhome, sizeof(oldhome), "%s/."HOMESUBDIR"/", ev);
xdghome = getenv("XDG_DATA_HOME");
if (!xdghome || !*xdghome)
xdghome = va("%s/.local/share", ev);
if (xdghome[strlen(xdghome)-1] == '/')
Q_snprintfz(newhome, sizeof(newhome), "%s"HOMESUBDIR"/", xdghome);
if (man && man->installation)
{
if (xdghome[strlen(xdghome)-1] == '/')
Q_snprintfz(com_homepath, sizeof(com_homepath), "%s%s/", xdghome, *man->installation?man->installation:HOMESUBDIR);
else
Q_snprintfz(com_homepath, sizeof(com_homepath), "%s/%s/", xdghome, *man->installation?man->installation:HOMESUBDIR);
}
else
Q_snprintfz(newhome, sizeof(newhome), "%s/"HOMESUBDIR"/", xdghome);
{
if (xdghome[strlen(xdghome)-1] == '/')
Q_snprintfz(newhome, sizeof(newhome), "%s%s/", xdghome, HOMESUBDIR);
else
Q_snprintfz(newhome, sizeof(newhome), "%s/%s/", xdghome, HOMESUBDIR);
if (stat(newhome, &s) == -1 && stat(oldhome, &s) != -1)
Q_strncpyz(com_homepath, oldhome, sizeof(com_homepath));
else
Q_strncpyz(com_homepath, newhome, sizeof(com_homepath));
if (ev[strlen(ev)-1] == '/')
Q_snprintfz(oldhome, sizeof(oldhome), "%s.%s/", ev, HOMESUBDIR);
else
Q_snprintfz(oldhome, sizeof(oldhome), "%s/.%s/", ev, HOMESUBDIR);
if (stat(newhome, &s) == -1 && stat(oldhome, &s) != -1)
Q_strncpyz(com_homepath, oldhome, sizeof(com_homepath));
else
Q_strncpyz(com_homepath, newhome, sizeof(com_homepath));
}
usehome = true; // always use home on unix unless told not to
}
#endif
@ -6364,6 +6335,60 @@ void COM_InitFilesystem (void)
com_homepathenabled = com_homepathusable;
}
/*
================
COM_InitFilesystem
note: does not actually load any packs, just makes sure the basedir+cvars+etc is set up. vfs_fopens will still fail.
================
*/
void COM_InitFilesystem (void)
{
int i;
FS_RegisterDefaultFileSystems();
Cmd_AddCommand("fs_restart", FS_ReloadPackFiles_f);
Cmd_AddCommandD("fs_changegame", FS_ChangeGame_f, "Switch between different manifests (or registered games)");
Cmd_AddCommandD("fs_changemod", FS_ChangeMod_f, "Provides the backend functionality of a transient online installer. Eg, for quaddicted's map/mod database.");
Cmd_AddCommand("fs_showmanifest", FS_ShowManifest_f);
Cmd_AddCommand ("fs_flush", COM_RefreshFSCache_f);
Cmd_AddCommandAD("dir", COM_Dir_f, FS_ArbitraryFile_c, "Displays filesystem listings. Accepts wildcards."); //q3 like
Cmd_AddCommandD("path", COM_Path_f, "prints a list of current search paths.");
Cmd_AddCommandAD("flocate", COM_Locate_f, FS_ArbitraryFile_c, "Searches for a named file, and displays where it can be found in the OS's filesystem"); //prints the pak or whatever where this file can be found.
//
// -basedir <path>
// Overrides the system supplied base directory (under id1)
//
i = COM_CheckParm ("-basedir");
if (i && i < com_argc-1)
strcpy (com_gamepath, com_argv[i+1]);
else
strcpy (com_gamepath, host_parms.basedir);
FS_CleanDir(com_gamepath, sizeof(com_gamepath));
Cvar_Register(&cfg_reload_on_gamedir, "Filesystem");
Cvar_Register(&com_fs_cache, "Filesystem");
Cvar_Register(&fs_gamename, "Filesystem");
Cvar_Register(&pm_downloads_url, "Filesystem");
Cvar_Register(&pm_autoupdate, "Filesystem");
Cvar_Register(&com_protocolname, "Server Info");
Cvar_Register(&com_protocolversion, "Server Info");
Cvar_Register(&fs_game, "Filesystem");
#ifdef Q2SERVER
Cvar_Register(&fs_gamedir, "Filesystem");
Cvar_Register(&fs_basedir, "Filesystem");
#endif
COM_InitHomedir(NULL);
fs_readonly = COM_CheckParm("-readonly");
fs_thread_mutex = Sys_CreateMutex();

View File

@ -183,6 +183,7 @@ qboolean NET_DTLS_Decode(struct ftenet_connections_s *col);
qboolean NET_DTLS_Disconnect(struct ftenet_connections_s *col, netadr_t *to);
void NET_DTLS_Timeouts(struct ftenet_connections_s *col);
#endif
extern cvar_t timeout;
//============================================================================

View File

@ -1087,7 +1087,7 @@ static qboolean SSL_InitConnection(gnutlsfile_t *newf, qboolean isserver, qboole
return true;
}
vfsfile_t *FS_OpenSSL(const char *hostname, vfsfile_t *source, qboolean isserver)
vfsfile_t *GNUTLS_OpenVFS(const char *hostname, vfsfile_t *source, qboolean isserver)
{
gnutlsfile_t *newf;
@ -1127,7 +1127,7 @@ vfsfile_t *FS_OpenSSL(const char *hostname, vfsfile_t *source, qboolean isserver
return &newf->funcs;
}
int TLS_GetChannelBinding(vfsfile_t *vf, qbyte *binddata, size_t *bindsize)
int GNUTLS_GetChannelBinding(vfsfile_t *vf, qbyte *binddata, size_t *bindsize)
{
gnutls_datum_t cb;
gnutlsfile_t *f = (gnutlsfile_t*)vf;
@ -1337,7 +1337,7 @@ const dtlsfuncs_t *GNUDTLS_InitClient(void)
qboolean SSL_InitGlobal(qboolean isserver) {return false;}
vfsfile_t *FS_OpenSSL(const char *hostname, vfsfile_t *source, qboolean isserver) {return NULL;}
int TLS_GetChannelBinding(vfsfile_t *vf, qbyte *binddata, size_t *bindsize) {return -1;}
int GNUTLS_GetChannelBinding(vfsfile_t *vf, qbyte *binddata, size_t *bindsize) {return -1;}
const dtlsfuncs_t *GNUDTLS_InitClient(void) {return NULL;}
const dtlsfuncs_t *GNUDTLS_InitServer(void) {return NULL;}
#endif

View File

@ -1012,7 +1012,7 @@ static qboolean QDECL SSPI_Close (struct vfsfile_s *file)
}
#include <wchar.h>
vfsfile_t *FS_OpenSSL(const char *servername, vfsfile_t *source, qboolean server)
vfsfile_t *SSPI_OpenVFS(const char *servername, vfsfile_t *source, qboolean server)
{
sslfile_t *newf;
int i = 0;
@ -1095,7 +1095,7 @@ typedef struct _SecPkgContext_Bindings
SEC_CHANNEL_BINDINGS *Bindings;
} SecPkgContext_Bindings, *PSecPkgContext_Bindings;
#endif
int TLS_GetChannelBinding(vfsfile_t *vf, qbyte *binddata, size_t *bindsize)
int SSPI_GetChannelBinding(vfsfile_t *vf, qbyte *binddata, size_t *bindsize)
{
int ret;
sslfile_t *f = (sslfile_t*)vf;

View File

@ -120,13 +120,16 @@ int UDP6_OpenSocket (int port);
#ifdef HAVE_IPX
void IPX_CloseSocket (int socket);
#endif
cvar_t timeout = CVARD("timeout","65", "Connections will time out if no packets are received for this duration of time."); // seconds without any message
cvar_t net_hybriddualstack = CVARD("net_hybriddualstack", "1", "Uses hybrid ipv4+ipv6 sockets where possible. Not supported on xp or below.");
cvar_t net_fakeloss = CVARFD("net_fakeloss", "0", CVAR_CHEAT, "Simulates packetloss in both receiving and sending, on a scale from 0 to 1.");
cvar_t net_enabled = CVARD("net_enabled", "1", "If 0, disables all network access, including name resolution and socket creation. Does not affect loopback/internal connections.");
#if defined(TCPCONNECT) && !defined(CLIENTONLY)
cvar_t net_enable_qizmo = CVARD("net_enable_qizmo", "1", "Enables compatibility with qizmo's tcp connections serverside. Frankly, using sv_port_tcp without this is a bit pointless.");
cvar_t net_enable_qtv = CVARD("net_enable_qtv", "1", "Listens for qtv proxies, or clients using the qtvplay command.");
#if defined(HAVE_SSL)
cvar_t net_enable_tls = CVARD("net_enable_tls", "1", "If enabled, binary data sent to a non-tls tcp port will be interpretted as a tls handshake (enabling https or wss over the same tcp port.");
#endif
cvar_t net_enable_http = CVARD("net_enable_http", "0", "If enabled, tcp ports will accept http clients, potentially serving large files which could distrupt gameplay.");
cvar_t net_enable_websockets = CVARD("net_enable_websockets", "1", "If enabled, tcp ports will accept websocket game clients.");
cvar_t net_enable_webrtcbroker = CVARD("net_enable_webrtcbroker", "0", "If 1, tcp ports will accept websocket connections from clients trying to broker direct webrtc connections. This should be low traffic, but might involve a lot of mostly-idle connections.");
@ -2035,6 +2038,44 @@ qboolean NET_IsLoopBackAddress (netadr_t *adr)
return adr->type == NA_LOOPBACK;
}
#ifdef HAVE_SSL
vfsfile_t *FS_OpenSSL(const char *hostname, vfsfile_t *source, qboolean isserver)
{
vfsfile_t *f = NULL;
#ifdef HAVE_GNUTLS
if (!f)
f = GNUTLS_OpenVFS(hostname, source, isserver);
#endif
#ifdef HAVE_OPENSSL
if (!f)
f = OSSL_OpenVFS(hostname, source, isserver);
#endif
#ifdef HAVE_WINSSPI
if (!f)
f = SSPI_OpenVFS(hostname, source, isserver);
#endif
return f;
}
int TLS_GetChannelBinding(vfsfile_t *stream, qbyte *data, size_t *datasize)
{
int r = -1;
#ifdef HAVE_GNUTLS
if (r == -1)
r = GNUTLS_GetChannelBinding(stream, data, datasize);
#endif
#ifdef HAVE_OPENSSL
if (r == -1)
r = OSSL_GetChannelBinding(stream, data, datasize);
#endif
#ifdef HAVE_WINSSPI
if (r == -1)
r = SSPI_GetChannelBinding(stream, data, datasize);
#endif
return r;
}
#endif
/////////////////////////////////////////////
//loopback stuff
@ -2495,34 +2536,56 @@ struct dtlspeer_s
void NET_DTLS_Timeouts(ftenet_connections_t *col)
{
struct dtlspeer_s *peer;
struct dtlspeer_s *peer, **link;
if (!col)
return;
for (peer = col->dtls; peer; peer = peer->next)
for (link = &col->dtls; (peer=*link); )
{
if (peer->timeout < realtime)
{
peer->funcs->DestroyContext(peer->dtlsstate);
*link = peer->next;
continue;
}
peer->funcs->Timeouts(peer->dtlsstate);
link = &peer->next;
}
}
const dtlsfuncs_t *DTLS_InitServer(void)
{
#if defined(HAVE_GNUTLS)
return GNUDTLS_InitServer();
#elif defined(HAVE_WINSSPI)
return SSPI_DTLS_InitServer();
#else
return NULL;
const dtlsfuncs_t *f = NULL;
#ifdef HAVE_GNUTLS
if (!f)
f = GNUDTLS_InitServer();
#endif
#ifdef HAVE_OPENSSL
if (!f)
f = OSSL_InitServer();
#endif
#ifdef HAVE_WINSSPI
if (!f)
f = SSPI_DTLS_InitServer();
#endif
return f;
}
const dtlsfuncs_t *DTLS_InitClient(void)
{
const dtlsfuncs_t *f = NULL;
#ifdef HAVE_WINSSPI
return SSPI_DTLS_InitClient();
#elif defined(HAVE_GNUTLS)
return GNUDTLS_InitClient();
#else
return NULL;
if (!f)
f = SSPI_DTLS_InitClient();
#endif
#ifdef HAVE_GNUTLS
if (!f)
f = GNUDTLS_InitClient();
#endif
#ifdef HAVE_OPENSSL
if (!f)
f = OSSL_InitClient();
#endif
return f;
}
static neterr_t NET_SendPacketCol (ftenet_connections_t *collection, int length, const void *data, netadr_t *to);
@ -2533,6 +2596,7 @@ static neterr_t FTENET_DTLS_DoSendPacket(void *cbctx, const qbyte *data, size_t
}
qboolean NET_DTLS_Create(ftenet_connections_t *col, netadr_t *to)
{
extern cvar_t timeout;
struct dtlspeer_s *peer;
if (to->prot != NP_DGRAM)
return false;
@ -2554,6 +2618,8 @@ qboolean NET_DTLS_Create(ftenet_connections_t *col, netadr_t *to)
peer->funcs = DTLS_InitClient();
if (peer->funcs)
peer->dtlsstate = peer->funcs->CreateContext(NET_BaseAdrToString(hostname, sizeof(hostname), to), peer, FTENET_DTLS_DoSendPacket, col->islisten);
peer->timeout = realtime+timeout.value;
if (peer->dtlsstate)
{
if (peer->next)
@ -2616,11 +2682,13 @@ static neterr_t FTENET_DTLS_SendPacket(ftenet_connections_t *col, int length, co
qboolean NET_DTLS_Decode(ftenet_connections_t *col)
{
extern cvar_t timeout;
struct dtlspeer_s *peer;
for (peer = col->dtls; peer; peer = peer->next)
{
if (NET_CompareAdr(&peer->addr, &net_from))
{
peer->timeout = realtime+timeout.value; //refresh the timeout if our peer is still alive.
switch(peer->funcs->Received(peer->dtlsstate, net_message.data, net_message.cursize))
{
case NETERR_DISCONNECTED:
@ -7137,12 +7205,22 @@ void NET_PrintConnectionsStatus(ftenet_connections_t *collection)
}
#ifdef HAVE_DTLS
if (developer.ival)
{
struct dtlspeer_s *dtls;
char adr[64];
for (dtls = collection->dtls; dtls; dtls = dtls->next)
Con_Printf("dtls: %s\n", NET_AdrToString(adr, sizeof(adr), &dtls->addr));
}
else
{
struct dtlspeer_s *dtls;
int c = 0;
for (dtls = collection->dtls; dtls; dtls = dtls->next)
c++;
if (c)
Con_Printf("dtls connections : %i\n", c);
}
#endif
}
@ -7720,6 +7798,7 @@ void NET_Init (void)
#endif
}
Cvar_Register(&timeout, "networking");
Cvar_Register(&net_hybriddualstack, "networking");
Cvar_Register(&net_fakeloss, "networking");
@ -7912,7 +7991,9 @@ void SVNET_RegisterCvars(void)
#if defined(TCPCONNECT) && !defined(CLIENTONLY)
Cvar_Register (&net_enable_qizmo, "networking");
Cvar_Register (&net_enable_qtv, "networking");
#if defined(HAVE_SSL)
Cvar_Register (&net_enable_tls, "networking");
#endif
Cvar_Register (&net_enable_http, "networking");
Cvar_Register (&net_enable_websockets, "networking");
Cvar_Register (&net_enable_webrtcbroker, "networking");

View File

@ -311,14 +311,24 @@ typedef struct dtlsfuncs_s
} dtlsfuncs_t;
const dtlsfuncs_t *DTLS_InitServer(void);
const dtlsfuncs_t *DTLS_InitClient(void);
#endif
#ifdef HAVE_WINSSPI
vfsfile_t *SSPI_OpenVFS(const char *hostname, vfsfile_t *source, qboolean isserver);
int SSPI_GetChannelBinding(vfsfile_t *vf, qbyte *binddata, size_t *bindsize);
const dtlsfuncs_t *SSPI_DTLS_InitServer(void); //returns NULL if there's no cert available.
const dtlsfuncs_t *SSPI_DTLS_InitClient(void); //should always return something, if implemented.
#endif
#ifdef HAVE_GNUTLS
vfsfile_t *GNUTLS_OpenVFS(const char *hostname, vfsfile_t *source, qboolean isserver);
int GNUTLS_GetChannelBinding(vfsfile_t *vf, qbyte *binddata, size_t *bindsize);
const dtlsfuncs_t *GNUDTLS_InitServer(void); //returns NULL if there's no cert available.
const dtlsfuncs_t *GNUDTLS_InitClient(void); //should always return something, if implemented.
#endif
#ifdef HAVE_OPENSSL
vfsfile_t *OSSL_OpenVFS(const char *hostname, vfsfile_t *source, qboolean isserver);
int OSSL_GetChannelBinding(vfsfile_t *vf, qbyte *binddata, size_t *bindsize);
const dtlsfuncs_t *OSSL_InitServer(void); //returns NULL if there's no cert available.
const dtlsfuncs_t *OSSL_InitClient(void); //should always return something, if implemented.
#endif

View File

@ -380,7 +380,10 @@ int QDECL QCEditor (pubprogfuncs_t *prinst, const char *filename, int *line, int
return DEBUG_TRACE_ABORT;
if (!*filename || !line || !*line) //don't try editing an empty line, it won't work
{
Con_Printf("Unable to debug, please disable optimisations\n");
if (!*filename)
Con_Printf("Unable to debug, please disable optimisations\n");
else
Con_Printf("Unable to debug, please provide line number info\n");
if (fatal)
return DEBUG_TRACE_ABORT;
return DEBUG_TRACE_OFF;
@ -5724,8 +5727,8 @@ void QCBUILTIN PF_gettime (pubprogfuncs_t *prinst, struct globalvars_s *pr_globa
case 0: //cached time at start of frame
G_FLOAT(OFS_RETURN) = realtime;
break;
case 1: //actual time
G_FLOAT(OFS_RETURN) = Sys_DoubleTime();
case 1: //actual time, ish. we round to milliseconds to reduce spectre exposure
G_FLOAT(OFS_RETURN) = (qint64_t)(Sys_DoubleTime()*1000) / 1000.0;
break;
//case 2: //highres.. looks like time into the frame
//case 3: //uptime

View File

@ -627,7 +627,16 @@ void Mod_ClipDecal(struct model_s *mod, vec3_t center, vec3_t normal, vec3_t tan
#endif
#ifdef Q3BSPS
else if (cl.worldmodel->fromgame == fg_quake3)
Q3BSP_ClipDecalToNodes(&dec, mod->rootnode);
{
if (mod->submodelof)
{
msurface_t *surf;
for (surf = mod->surfaces+mod->firstmodelsurface, p = 0; p < mod->nummodelsurfaces; p++, surf++)
Fragment_Mesh(&dec, surf->mesh, surf->texinfo);
}
else
Q3BSP_ClipDecalToNodes(&dec, mod->rootnode);
}
#endif
#ifdef TERRAIN

View File

@ -16,7 +16,7 @@ This file came to FTE via EzQuake.
/* #define SHA1HANDSOFF * Copies data before messing with it. */
#define SHA1HANDSOFF
//#include "quakedef.h"
#include "quakedef.h"
#include <string.h>
#define BigLong(l) (((unsigned char*)&l)[0]<<24) | (((unsigned char*)&l)[1]<<16) | (((unsigned char*)&l)[2]<<8) | (((unsigned char*)&l)[3]<<0)

View File

@ -1528,6 +1528,8 @@ qboolean Font_LoadFreeTypeFont(struct font_s *f, int height, const char *fontfil
error = pFT_New_Face(fontlib, va("/usr/share/fonts/%s", fontfilename), 0, &face);
if (error)
error = pFT_New_Face(fontlib, va("/usr/share/fonts/truetype/%s.ttf", fontfilename), 0, &face);
if (error) //just to give a chance of the same names working on more than one os, with the right package installed.
error = pFT_New_Face(fontlib, va("/usr/share/fonts/truetype/msttcorefonts/%s.ttf", fontfilename), 0, &face);
}
#endif
if (!error)

View File

@ -172,7 +172,7 @@ m*_t structures are in-memory
#define EF_BLUE (1<<6)
#define EF_RED (1<<7)
#define H2EF_NODRAW (1<<7) //this is going to get complicated... emulated server side.
#define DPEF_NOGUNBOB (1<<8) //viewmodel attachment does not bob
#define DPEF_NOGUNBOB (1<<8) //viewmodel attachment does not bob. only applies to viewmodelforclient/RF_WEAPONMODEL
#define EF_FULLBRIGHT (1<<9) //abslight=1
#define DPEF_FLAME (1<<10) //'onfire'
#define DPEF_STARDUST (1<<11) //'showering sparks'

View File

@ -7273,6 +7273,8 @@ char *Shader_GetShaderBody(shader_t *s, char *fname, size_t fnamesize)
if (fnamesize)
{
*fname = 0;
if (parsename)
{
unsigned int key;
@ -7297,8 +7299,24 @@ char *Shader_GetShaderBody(shader_t *s, char *fname, size_t fnamesize)
}
}
}
else
*fname = 0;
if (!strchr(parsename, ':'))
{
//if the named shader is a .shader file then just directly load it.
const char *token = COM_GetFileExtension(parsename, NULL);
if (!strcmp(token, ".shader") || !*token)
{
char shaderfile[MAX_QPATH];
if (!*token)
{
Q_snprintfz(shaderfile, sizeof(shaderfile), "%s.shader", parsename);
if (COM_FCheckExists(shaderfile))
Q_snprintfz(fname, fnamesize, "%s:%i", shaderfile, 1);
}
else if (COM_FCheckExists(parsename))
Q_snprintfz(fname, fnamesize, "%s:%i", parsename, 1);
}
}
}
#ifdef _DEBUG

View File

@ -2744,50 +2744,11 @@ static void *X11VID_CreateCursorRGBA(const qbyte *rgbacursor, size_t w, size_t h
Z_Free(cursor);
return NULL;
}
static void *X11VID_CreateCursor(const char *filename, float hotx, float hoty, float scale)
static void *X11VID_CreateCursor(const qbyte *imagedata, int width, int height, uploadfmt_t format, float hotx, float hoty, float scale)
{
void *r;
qbyte *rgbadata;
uploadfmt_t format;
void *filedata;
int filelen, width, height;
if (!filename || !*filename)
if (!imagedata)
return NULL;
filelen = FS_LoadFile(filename, &filedata);
if (!filedata)
return NULL;
rgbadata = ReadRawImageFile(filedata, filelen, &width, &height, &format, true, filename);
FS_FreeFile(filedata);
if (!rgbadata)
return NULL;
if ((format==PTI_RGBX8 || format==PTI_LLLX8) && !strchr(filename, ':'))
{ //people seem to insist on using jpgs, which don't have alpha.
//so screw over the alpha channel if needed.
unsigned int alpha_width, alpha_height, p;
char aname[MAX_QPATH];
unsigned char *alphadata;
char *alph;
size_t alphsize;
char ext[8];
COM_StripExtension(filename, aname, sizeof(aname));
COM_FileExtension(filename, ext, sizeof(ext));
Q_strncatz(aname, "_alpha.", sizeof(aname));
Q_strncatz(aname, ext, sizeof(aname));
alphsize = FS_LoadFile(filename, (void**)&alph);
if (alph)
{
if ((alphadata = ReadRawImageFile(alph, alphsize, &alpha_width, &alpha_height, &format, true, aname)))
{
if (alpha_width == width && alpha_height == height)
for (p = 0; p < alpha_width*alpha_height; p++)
rgbadata[(p<<2) + 3] = (alphadata[(p<<2) + 0] + alphadata[(p<<2) + 1] + alphadata[(p<<2) + 2])/3;
BZ_Free(alphadata);
}
FS_FreeFile(alph);
}
}
if (scale != 1)
{
@ -2798,15 +2759,14 @@ static void *X11VID_CreateCursor(const char *filename, float hotx, float hoty, f
if (nw <= 0 || nh <= 0 || nw > 128 || nh > 128) //don't go crazy.
return NULL;
nd = BZ_Malloc(nw*nh*4);
Image_ResampleTexture((unsigned int*)rgbadata, width, height, (unsigned int*)nd, nw, nh);
Image_ResampleTexture((unsigned int*)imagedata, width, height, (unsigned int*)nd, nw, nh);
width = nw;
height = nh;
BZ_Free(rgbadata);
rgbadata = nd;
r = X11VID_CreateCursorRGBA(nd, width, height, hotx, hoty);
BZ_Free(nd);
}
r = X11VID_CreateCursorRGBA(rgbadata, width, height, hotx, hoty);
BZ_Free(rgbadata);
else
r = X11VID_CreateCursorRGBA(imagedata, width, height, hotx, hoty);
return r;
}

View File

@ -60,25 +60,11 @@ static void *GLVID_getsdlglfunction(char *functionname)
#endif
#if SDL_MAJOR_VERSION >= 2
void *GLVID_CreateCursor (const char *filename, float hotx, float hoty, float scale)
void *GLVID_CreateCursor (const qbyte *imagedata, int width, int height, uploadfmt_t format, float hotx, float hoty, float scale)
{
int width;
int height;
SDL_Cursor *curs;
SDL_Surface *surf;
qbyte *rgbadata_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)
if (!imagedata)
return NULL;
if (scale != 1)
@ -90,17 +76,20 @@ void *GLVID_CreateCursor (const char *filename, float hotx, float hoty, float
if (nw <= 0 || nh <= 0 || nw > 128 || nh > 128) //don't go crazy.
return NULL;
nd = BZ_Malloc(nw*nh*4);
Image_ResampleTexture((unsigned int*)rgbadata_start, width, height, (unsigned int*)nd, nw, nh);
width = nw;
height = nh;
BZ_Free(rgbadata_start);
rgbadata_start = nd;
}
Image_ResampleTexture((unsigned int*)imagedata, width, height, (unsigned int*)nd, nw, nh);
surf = SDL_CreateRGBSurfaceFrom(rgbadata_start, width, height, 32, width*4, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);
curs = SDL_CreateColorCursor(surf, hotx, hoty);
SDL_FreeSurface(surf);
BZ_Free(rgbadata_start);
surf = SDL_CreateRGBSurfaceFrom(nd, nw, nh, 32, nw*4, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);
curs = SDL_CreateColorCursor(surf, hotx, hoty);
SDL_FreeSurface(surf);
BZ_Free(nd);
}
else
{
surf = SDL_CreateRGBSurfaceFrom((void*)imagedata, width, height, 32, width*4, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);
curs = SDL_CreateColorCursor(surf, hotx, hoty);
SDL_FreeSurface(surf);
}
return curs;
}
qboolean GLVID_SetCursor (void *cursor)

View File

@ -375,7 +375,7 @@ void Cookie_Monster(void)
//path) I'm going to call this an optimisation feature and not bother with it... hopefully there won't be too many sites that have sub-paths or third-party stuff... gah.
//httponly) irrelevant until we support javascript... which we don't.
//secure) assumed to be true. https:// vs http:// are thus completely independant. sorry.
//expires) gah, parsing time values sucks! plus we don't have persistent storage.
//expires) gah, parsing time values sucks! plus we don't have persistent storage. All cookies are session cookies.
void Cookie_Parse(char *domain, int secure, char *line, char *end)
{
char *e;

View File

@ -706,6 +706,7 @@ QCC_type_t *QCC_PR_GenFunctionType (QCC_type_t *rettype, struct QCC_typeparam_s
char *QCC_PR_ParseName (void);
CompilerConstant_t *QCC_PR_DefineName(char *name);
struct QCC_typeparam_s *QCC_PR_FindStructMember(QCC_type_t *t, const char *membername, unsigned int *out_ofs);
QCC_type_t *QCC_PR_PointerType (QCC_type_t *pointsto);
const char *QCC_VarAtOffset(QCC_sref_t ref);
@ -730,6 +731,8 @@ void QCC_PR_ParsePrintSRef (int warningtype, QCC_sref_t sref);
void VARGS QCC_PR_ParseErrorPrintDef (int errortype, QCC_def_t *def, const char *error, ...);
void VARGS QCC_PR_ParseErrorPrintSRef (int errortype, QCC_sref_t sref, const char *error, ...);
QCC_type_t *QCC_PR_MakeThiscall(QCC_type_t *orig, QCC_type_t *thistype);
int QCC_WarningForName(const char *name);
char *QCC_NameForWarning(int idx);

View File

@ -9,6 +9,14 @@
#include <alloca.h>
#endif
#ifdef _MSC_VER
#define longlong __int64
#define LL(x) x##i64
#else
#define longlong long long
#define LL(x) x##ll
#endif
/*
TODO:
*foo++ = 5;
@ -236,7 +244,8 @@ QCC_sref_t QCC_MakeTranslateStringConst(const char *value);
QCC_sref_t QCC_MakeStringConst(const char *value);
QCC_sref_t QCC_MakeStringConstLength(const char *value, int length);
QCC_sref_t QCC_MakeFloatConst(float value);
QCC_sref_t QCC_MakeIntConst(int value);
QCC_sref_t QCC_MakeFloatConstFromInt(longlong llvalue);
QCC_sref_t QCC_MakeIntConst(longlong llvalue);
QCC_sref_t QCC_MakeVectorConst(float a, float b, float c);
enum
@ -2181,7 +2190,7 @@ static int QCC_PR_RoundFloatConst(const QCC_eval_t *eval)
float val = eval->_float;
int ival = val;
if (val != (float)ival)
QCC_PR_ParseWarning(WARN_OVERFLOW, "Constant float operand not an integer value");
QCC_PR_ParseWarning(WARN_OVERFLOW, "Constant float operand %f will be truncated to %i", val, ival);
return ival;
}
@ -4553,7 +4562,7 @@ static void QCC_VerifyFormatString (const char *funcname, QCC_ref_t **arglist, u
{
case 0:
if (argpos < argcount && argn_last < argcount)
QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: surplus trailing arguments for format", funcname);
QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: surplus trailing %s%s%s argument(s) for format %s\"%s\"%s", funcname, col_symbol, TypeName(ARGCTYPE(argpos), temp, sizeof(temp)), col_none, col_name, strings + formatstring->string, col_none);
return;
case '%':
if(*++s == '%')
@ -4575,7 +4584,7 @@ static void QCC_VerifyFormatString (const char *funcname, QCC_ref_t **arglist, u
width = strtol(s, &err, 10);
if(!err)
{
QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: bad format string: %s", funcname, s0);
QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: bad format string: %s%s%s", funcname, col_name, s0, col_none);
return;
}
if(*err == '$')
@ -4621,7 +4630,7 @@ noflags:
arg = strtol(s, &err, 10);
if(!err || *err != '$')
{
QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: invalid format string: %s", funcname, s0);
QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: invalid format string: %s%s%s", funcname, col_name, s0, col_none);
return;
}
s = err + 1;
@ -4636,7 +4645,7 @@ noflags:
strtol(s, &err, 10);
if(!err)
{
QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: invalid format string: %s", funcname, s0);
QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: invalid format string: %s%s%s", funcname, col_name, s0, col_none);
return;
}
s = err;
@ -4656,7 +4665,7 @@ noflags:
arg = strtol(s, &err, 10);
if(!err || *err != '$')
{
QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: invalid format string: %s", funcname, s0);
QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: invalid format string: %s%s%s", funcname, col_name, s0, col_none);
return;
}
s = err + 1;
@ -4672,14 +4681,14 @@ noflags:
strtol(s, &err, 10);
if(!err)
{
QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: invalid format string: %s", funcname, s0);
QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: invalid format string: %s%s%s", funcname, col_name, s0, col_none);
return;
}
s = err;
}
else
{
QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: invalid format string: %s", funcname, s0);
QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: invalid format string: %s%s%s", funcname, col_name, s0, col_none);
return;
}
}
@ -4744,7 +4753,7 @@ nolength:
break;
default:
{
QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: %s requires float at arg %i (got %s)", funcname, formatbuf, thisarg+1, TypeName(ARGCTYPE(thisarg), temp, sizeof(temp)));
QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: %s%s%s requires float at arg %i (got %s%s%s)", funcname, col_name, formatbuf, col_none, thisarg+1, col_symbol, TypeName(ARGCTYPE(thisarg), temp, sizeof(temp)), col_none);
}
break;
}
@ -4759,7 +4768,7 @@ nolength:
case ev_variant:
break;
default:
QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: %s requires pointer at arg %i (got %s)", funcname, formatbuf, thisarg+1, TypeName(ARGCTYPE(thisarg), temp, sizeof(temp)));
QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: %s%s%s requires pointer at arg %i (got %s%s%s)", funcname, col_name, formatbuf, col_none, thisarg+1, col_symbol, TypeName(ARGCTYPE(thisarg), temp, sizeof(temp)), col_none);
break;
}
}
@ -4775,7 +4784,7 @@ nolength:
break;
//fallthrough
default:
QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: %s requires int at arg %i (got %s)", funcname, formatbuf, thisarg+1, TypeName(ARGCTYPE(thisarg), temp, sizeof(temp)));
QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: %s%s%s requires int at arg %i (got %s%s%s)", funcname, col_name, formatbuf, col_none, thisarg+1, col_symbol, TypeName(ARGCTYPE(thisarg), temp, sizeof(temp)), col_none);
break;
}
}
@ -4790,12 +4799,12 @@ nolength:
case ev_variant:
break;
default:
QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: %s requires vector at arg %i (got %s)", funcname, formatbuf, thisarg+1, TypeName(ARGCTYPE(thisarg), temp, sizeof(temp)));
QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: %s%s%s requires vector at arg %i (got %s%s%s)", funcname, col_name, formatbuf, col_none, thisarg+1, col_symbol, TypeName(ARGCTYPE(thisarg), temp, sizeof(temp)), col_none);
break;
}
}
else
QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: %s requires intvector at arg %i (got %s)", funcname, formatbuf, thisarg+1, TypeName(ARGCTYPE(thisarg), temp, sizeof(temp)));
QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: %s%s%s requires intvector at arg %i (got %s%s%s)", funcname, col_name, formatbuf, col_none, thisarg+1, col_symbol, TypeName(ARGCTYPE(thisarg), temp, sizeof(temp)), col_none);
break;
case 's':
case 'S':
@ -4805,12 +4814,12 @@ nolength:
case ev_variant:
break;
default:
QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: %s requires string at arg %i", funcname, formatbuf, thisarg+1, TypeName(ARGCTYPE(thisarg), temp, sizeof(temp)));
QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: %s%s%s requires string at arg %i (got %s%s%s)", funcname, col_name, formatbuf, col_none, thisarg+1, col_symbol, TypeName(ARGCTYPE(thisarg), temp, sizeof(temp)), col_none);
break;
}
break;
default:
QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: invalid format string: %s", funcname, s0);
QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: invalid format string: %s%s%s", funcname, col_name, s0, col_none);
return;
}
s++;
@ -5877,7 +5886,7 @@ static QCC_sref_t QCC_PR_ParseFunctionCall (QCC_ref_t *funcref) //warning, the f
if (t)
{
QCC_PR_Expect(")");
return QCC_MakeIntConst(t->size * 4);
return QCC_PR_Statement(&pr_opcodes[OP_ADD_PIW], QCC_MakeIntConst(0), QCC_MakeIntConst(t->size), NULL);
}
else
{
@ -6523,9 +6532,13 @@ QCC_sref_t QCC_MakeSRef(QCC_def_t *def, unsigned int ofs, QCC_type_t *type)
//int varchecks;
//int typechecks;
extern hashtable_t floatconstdefstable;
QCC_sref_t QCC_MakeIntConst(int value)
QCC_sref_t QCC_MakeIntConst(longlong llvalue)
{
QCC_def_t *cn;
int value = llvalue;
if (value != llvalue)
QCC_PR_ParseWarning(WARN_OVERFLOW, "Constant int operand %lld will be truncated to %i", llvalue, value);
cn = Hash_GetKey(&floatconstdefstable, value);
if (cn)
@ -7806,17 +7819,40 @@ QCC_ref_t *QCC_PR_ParseRefValue (QCC_ref_t *refbuf, QCC_type_t *assumeclass, pbo
if (assumeclass && assumeclass->parentclass)
{ //try getting a member.
QCC_type_t *type;
for(type = assumeclass; type && !d.cast; type = type->parentclass)
if (assumeclass->type == ev_struct)
{
//look for virtual things
QC_snprintfz(membername, sizeof(membername), "%s::"MEMBERFIELDNAME, type->name, name);
d = QCC_PR_GetSRef (NULL, membername, pr_scope, false, 0, false);
unsigned int ofs;
struct QCC_typeparam_s *p = QCC_PR_FindStructMember(assumeclass, name, &ofs);
if (p)
{
QCC_sref_t ths;
ths = QCC_PR_GetSRef(QCC_PR_PointerType(pr_classtype), "this", pr_scope, false, 0, false);
if (ths.cast)
{
ths.cast = QCC_PR_PointerType(p->type);
if (d.sym->arraysize)
{
//FIXME: this should result in a pointer type, and not this->member[0]
}
return QCC_PR_ParseRefArrayPointer(refbuf, QCC_PR_BuildRef(refbuf, REF_POINTER, ths, QCC_MakeIntConst(ofs), p->type, false), allowarrayassign, makearraypointers);
}
}
}
for(type = assumeclass; type && !d.cast; type = type->parentclass)
else
{
//look for non-virtual things (functions: after virtual stuff, because this will find the actual function def too)
QC_snprintfz(membername, sizeof(membername), "%s::%s", type->name, name);
d = QCC_PR_GetSRef (NULL, membername, pr_scope, false, 0, false);
for(type = assumeclass; type && !d.cast; type = type->parentclass)
{
//look for virtual things
QC_snprintfz(membername, sizeof(membername), "%s::"MEMBERFIELDNAME, type->name, name);
d = QCC_PR_GetSRef (NULL, membername, pr_scope, false, 0, false);
}
for(type = assumeclass; type && !d.cast; type = type->parentclass)
{
//look for non-virtual things (functions: after virtual stuff, because this will find the actual function def too)
QC_snprintfz(membername, sizeof(membername), "%s::%s", type->name, name);
d = QCC_PR_GetSRef (NULL, membername, pr_scope, false, 0, false);
}
}
}
if (!d.cast)
@ -15452,6 +15488,8 @@ void QCC_PR_ParseDefs (char *classname, pbool fatal)
allocatenew = true;
if (classname)
{
unsigned int ofs;
struct QCC_typeparam_s *p;
char *membername = name;
name = qccHunkAlloc(strlen(classname) + strlen(name) + 3);
sprintf(name, "%s::%s", classname, membername);
@ -15460,6 +15498,13 @@ void QCC_PR_ParseDefs (char *classname, pbool fatal)
allocatenew = false;
else if (!defclass || !defclass->parentclass)
QCC_PR_ParseError(ERR_NOTANAME, "%s is not a class\n", classname);
if (defclass->type == ev_struct)
{
p = QCC_PR_FindStructMember(defclass, membername, &ofs);
if (p && p->isvirtual)
type = QCC_PR_MakeThiscall(type, defclass);
}
}
else
defclass = NULL;

View File

@ -2081,13 +2081,13 @@ static void QCC_PR_LexNumber (void)
num*=base;
num += c-'0';
}
else if (c >= 'a' && c <= 'f' && base > 10)
else if (c >= 'a' && c <= 'z' && c < 'a'+base-10)
{
pr_token[tokenlen++] = c;
num*=base;
num += c -'a'+10;
}
else if (c >= 'A' && c <= 'F' && base > 10)
else if (c >= 'A' && c <= 'Z' && c < 'A'+base-10)
{
pr_token[tokenlen++] = c;
num*=base;
@ -2145,7 +2145,7 @@ static void QCC_PR_LexNumber (void)
if ((longlong)pr_immediate._int != (longlong)num)
{
if (((longlong)pr_immediate._int & LL(0xffffffff80000000)) != LL(0xffffffff80000000))
QCC_PR_ParseWarning(WARN_OVERFLOW, "numerical overflow");
QCC_PR_ParseWarning(WARN_OVERFLOW, "numerical overflow");
}
return;
}
@ -4797,7 +4797,7 @@ char *pr_parm_argcount_name;
int recursivefunctiontype;
static QCC_type_t *QCC_PR_MakeThiscall(QCC_type_t *orig, QCC_type_t *thistype)
QCC_type_t *QCC_PR_MakeThiscall(QCC_type_t *orig, QCC_type_t *thistype)
{
QCC_type_t ftype = *orig;
@ -4807,9 +4807,12 @@ static QCC_type_t *QCC_PR_MakeThiscall(QCC_type_t *orig, QCC_type_t *thistype)
ftype.params = qccHunkAlloc(sizeof(*ftype.params) * ftype.num_parms);
memcpy(ftype.params+1, orig->params, sizeof(*ftype.params) * orig->num_parms);
ftype.params[0].paramname = "this";
ftype.params[0].type = QCC_PointerTypeTo(thistype);
ftype.params[0].type = QCC_PR_PointerType(thistype);
ftype.params[0].isvirtual = true;
memmove(&pr_parm_names[1], &pr_parm_names[0], sizeof(*pr_parm_names)*orig->num_parms);
strcpy(pr_parm_names[0], "this");
orig = QCC_PR_FindType (&ftype);
if (!orig)
{
@ -5869,6 +5872,8 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
newt = QCC_PR_NewType(tname, ev_struct, true);
newt->parentclass = parenttype;
}
else if (!newt->size && !newt->parentclass)
newt->parentclass = parenttype;
else if (parenttype && newt->parentclass != parenttype)
QCC_PR_ParseError(ERR_NOTANAME, "Redeclaration of struct with different parent type", tname, parenttype->name);
@ -5992,7 +5997,12 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
QC_snprintfz(membername, sizeof(membername), "%s::%s", newt->name, parmname);
d = QCC_PR_GetDef(type, membername, NULL, true, 0, (type->type==ev_function)?GDF_CONST:0);
if (QCC_PR_CheckToken("=") || (type->type == ev_function && QCC_PR_PeekToken("{")))
{
//FIXME: methods cannot be compiled yet, as none of the fields are not actually defined yet.
pr_classtype = newt;
QCC_PR_ParseInitializerDef(d, 0);
pr_classtype = NULL;
}
QCC_FreeDef(d);
if (!QCC_PR_PeekToken(","))
newparm = NULL;

View File

@ -4175,13 +4175,19 @@ static void QCC_PR_CommandLinePrecompilerOptions (void)
{
flag_ifvector = flag_vectorlogic = true;
flag_dblstarexp = flag_attributes = flag_assumevar = pr_subscopedlocals = flag_cpriority = flag_allowuninit = true;
flag_boundchecks = false; //gmqcc doesn't support these, so xonotic is buggy shite.
flag_boundchecks = false; //gmqcc doesn't support dynamic bound checks, so xonotic is buggy shite. we don't want to generate code that will crash.
opt_logicops = true;
qccwarningaction[WARN_CONSTANTCOMPARISON] = WA_IGNORE;
qccwarningaction[WARN_POINTLESSSTATEMENT] = WA_IGNORE;
qccwarningaction[WARN_OVERFLOW] = WA_IGNORE;
qccwarningaction[WARN_STRICTTYPEMISMATCH] = WA_IGNORE;
qccwarningaction[WARN_PARAMWITHNONAME] = WA_IGNORE;
//we have to disable some of these warnings, because xonotic insists on using -Werror. use -Wextra to override.
qccwarningaction[WARN_NOTREFERENCEDCONST] = WA_IGNORE; //gmqcc doesn't warn about function prototypes without any names
qccwarningaction[WARN_CONSTANTCOMPARISON] = WA_IGNORE; //xonotic abuses this, and gmqcc doesn't warn.
qccwarningaction[WARN_POINTLESSSTATEMENT] = WA_IGNORE; //so many macro expansions that we can't mute because of xonotic using an external preprocessor.
qccwarningaction[WARN_OVERFLOW] = WA_IGNORE; //xonotic has data loss from implicit conversions too.
qccwarningaction[WARN_STRICTTYPEMISMATCH] = WA_IGNORE; //gmqcc doesn't enforce checks on auxilliary types.
qccwarningaction[WARN_PARAMWITHNONAME] = WA_IGNORE; //nor does it care if a parameter isn't named.
qccwarningaction[WARN_IFSTRING_USED] = WA_IGNORE; //and many people would argue that this was a feature rather than a bug
qccwarningaction[WARN_UNINITIALIZED] = WA_IGNORE; //all locals get 0-initialised anyway, and our checks are not quite up to scratch.
qccwarningaction[WARN_GMQCC_SPECIFIC] = WA_IGNORE; //we shouldn't warn about gmqcc syntax when we're trying to be compatible with it. there's always -Wextra.
keyword_asm = false;
keyword_inout = keyword_optional = keyword_state = keyword_inline = keyword_nosave = keyword_extern = keyword_shared = keyword_unused = keyword_used = keyword_nonstatic = keyword_ignore = keyword_strip = false;
@ -4284,10 +4290,30 @@ static void QCC_PR_CommandLinePrecompilerOptions (void)
for (j = 0; j < ERR_PARSEERRORS; j++)
if (qccwarningaction[j] == WA_IGNORE)
{
if (j != WARN_FTE_SPECIFIC && //kinda annoying when its actually valid code.
j != WARN_NOTREFERENCEDCONST && //warning about every single constant is annoying as heck. note that this includes both stuff like MOVETYPE_ and builtins.
j != WARN_EXTRAPRECACHE) //we can't guarentee that we can parse this correctly. this warning is thus a common false positive. its available with -Wextra, and there's intrinsics to reduce false positives.
switch(j)
{
//these warnings do not get switched on with -Wall when using -std=gmqcc, because mods that use -Werror would screw up too much
case WARN_CONSTANTCOMPARISON:
case WARN_POINTLESSSTATEMENT:
case WARN_OVERFLOW:
case WARN_STRICTTYPEMISMATCH:
case WARN_PARAMWITHNONAME:
case WARN_IFSTRING_USED:
case WARN_UNINITIALIZED:
case WARN_GMQCC_SPECIFIC:
qccwarningaction[j] = qccwarningaction[WARN_GMQCC_SPECIFIC];
break;
//these warnings require -Wextra to enable, as they're too annoying to have to fix
case WARN_NOTREFERENCEDCONST: //warning about every single constant is annoying as heck. note that this includes both stuff like MOVETYPE_ and builtins.
case WARN_EXTRAPRECACHE: //we can't guarentee that we can parse this correctly. this warning is thus a common false positive. its available with -Wextra, and there's intrinsics to reduce false positives.
case WARN_FTE_SPECIFIC: //kinda annoying when its actually valid code.
break;
default:
qccwarningaction[j] = WA_WARN;
break;
}
}
}
else if (!stricmp(a, "extra"))

View File

@ -828,16 +828,20 @@ void NPP_NQFlush(void)
break;
case svcfte_cgamepacket:
if (sv.csqcdebug)
if (writedest != &sv.multicast)
{
/*shift the data up by two bytes*/
memmove(buffer+3, buffer+1, bufferlen-1);
Con_Printf(CON_WARNING"Warning: svc_cgamepacket used outside of a multicast\n");
if (sv.csqcdebug)
{
/*shift the data up by two bytes*/
memmove(buffer+3, buffer+1, bufferlen-1);
/*add a length in the 2nd/3rd bytes*/
buffer[1] = (bufferlen-1);
buffer[2] = (bufferlen-1) >> 8;
/*add a length in the 2nd/3rd bytes*/
buffer[1] = (bufferlen-1);
buffer[2] = (bufferlen-1) >> 8;
bufferlen += 2;
bufferlen += 2;
}
}
break;
case svc_temp_entity:
@ -846,16 +850,20 @@ void NPP_NQFlush(void)
default:
if (te_515sevilhackworkaround)
{
if (sv.csqcdebug)
if (writedest != &sv.multicast)
{
/*shift the data up by two bytes, but don't care about the first byte*/
memmove(buffer+3, buffer+1, bufferlen-1);
Con_Printf(CON_WARNING"Warning: unknown svc_temp_entity used outside of a multicast\n");
if (sv.csqcdebug)
{
/*shift the data up by two bytes, but don't care about the first byte*/
memmove(buffer+3, buffer+1, bufferlen-1);
/*add a length in the 2nd/3rd bytes, if needed*/
buffer[1] = (bufferlen-1) & 0xff;
buffer[2] = (bufferlen-1) >> 8;
/*add a length in the 2nd/3rd bytes, if needed*/
buffer[1] = (bufferlen-1) & 0xff;
buffer[2] = (bufferlen-1) >> 8;
bufferlen += 2;
bufferlen += 2;
}
}
/*replace the svc itself*/
buffer[0] = svcfte_cgamepacket;
@ -1870,16 +1878,20 @@ void NPP_QWFlush(void)
break;
case svcfte_cgamepacket:
if (sv.csqcdebug)
if (writedest != &sv.nqmulticast)
{
/*shift the data up by two bytes*/
memmove(buffer+3, buffer+1, bufferlen-1);
Con_Printf(CON_WARNING"Warning: svc_cgamepacket used outside of a multicast\n");
if (sv.csqcdebug)
{
/*shift the data up by two bytes*/
memmove(buffer+3, buffer+1, bufferlen-1);
/*add a length in the 2nd/3rd bytes*/
buffer[1] = (bufferlen-1);
buffer[2] = (bufferlen-1) >> 8;
/*add a length in the 2nd/3rd bytes*/
buffer[1] = (bufferlen-1);
buffer[2] = (bufferlen-1) >> 8;
bufferlen += 2;
bufferlen += 2;
}
}
break;
case svc_temp_entity:
@ -1888,16 +1900,20 @@ void NPP_QWFlush(void)
default:
if (te_515sevilhackworkaround)
{
if (sv.csqcdebug)
if (writedest != &sv.nqmulticast)
{
/*shift the data up by two bytes*/
memmove(buffer+3, buffer+1, bufferlen-1);
Con_Printf(CON_WARNING"Warning: unknown svc_temp_entity used outside of a multicast\n");
if (sv.csqcdebug)
{
/*shift the data up by two bytes*/
memmove(buffer+3, buffer+1, bufferlen-1);
/*add a length in the 2nd/3rd bytes*/
buffer[1] = (bufferlen-1);
buffer[2] = (bufferlen-1) >> 8;
/*add a length in the 2nd/3rd bytes*/
buffer[1] = (bufferlen-1);
buffer[2] = (bufferlen-1) >> 8;
bufferlen += 2;
bufferlen += 2;
}
}
/*replace the svc itself*/
buffer[0] = svcfte_cgamepacket;

View File

@ -6255,6 +6255,44 @@ void QCBUILTIN PF_multicast (pubprogfuncs_t *prinst, struct globalvars_s *pr_glo
NPP_Flush();
#endif
if (sv.csqcdebug)
{
#ifdef NQPROT
if (sv.nqmulticast.cursize && sv.nqmulticast.data[0] == svcfte_cgamepacket)
{
if (sv.nqmulticast.cursize + 2 > sv.nqmulticast.maxsize)
sv.nqmulticast.cursize = 0;
else
{
/*shift the data up by two bytes*/
memmove(sv.nqmulticast.data+3, sv.nqmulticast.data+1, sv.nqmulticast.cursize-1);
/*add a length in the 2nd/3rd bytes*/
sv.nqmulticast.data[1] = (sv.nqmulticast.cursize-1);
sv.nqmulticast.data[2] = (sv.nqmulticast.cursize-1) >> 8;
sv.nqmulticast.cursize += 2;
}
}
#endif
if (sv.multicast.cursize)
{
if (sv.multicast.cursize + 2 > sv.multicast.maxsize)
sv.multicast.cursize = 0;
else
{
/*shift the data up by two bytes*/
memmove(sv.multicast.data+3, sv.multicast.data+1, sv.multicast.cursize-1);
/*add a length in the 2nd/3rd bytes*/
sv.multicast.data[1] = (sv.multicast.cursize-1);
sv.multicast.data[2] = (sv.multicast.cursize-1) >> 8;
sv.multicast.cursize += 2;
}
}
}
SV_MulticastProtExt(o, to, pr_global_struct->dimension_send, 0, 0);
}

View File

@ -130,7 +130,7 @@ typedef struct
PAUSE_EXPLICIT = 1, //someone hit pause
PAUSE_SERVICE = 2, //we're running as a service and someone paused us rather than killing us.
PAUSE_AUTO = 4 //console is down in a singleplayer game.
} paused;
} paused, oldpaused;
float pausedstart;
//check player/eyes models for hacks

View File

@ -1902,7 +1902,10 @@ static void SV_Status_f (void)
int columns = 80;
extern cvar_t sv_listen_qw;
#if defined(TCPCONNECT) && !defined(CLIENTONLY)
extern cvar_t net_enable_tls, net_enable_http, net_enable_webrtcbroker, net_enable_websockets, net_enable_qizmo, net_enable_qtv;
#if defined(HAVE_SSL)
extern cvar_t net_enable_tls;
#endif
extern cvar_t net_enable_http, net_enable_webrtcbroker, net_enable_websockets, net_enable_qizmo, net_enable_qtv;
#endif
#ifdef NQPROT
extern cvar_t sv_listen_nq, sv_listen_dp;
@ -1978,8 +1981,10 @@ static void SV_Status_f (void)
Con_Printf(" DTLS");
#endif
#if defined(TCPCONNECT) && !defined(CLIENTONLY)
#if defined(HAVE_SSL)
if (net_enable_tls.ival)
Con_Printf(" TLS");
#endif
if (net_enable_http.ival)
Con_Printf(" HTTP");
if (net_enable_webrtcbroker.ival)

View File

@ -3893,8 +3893,7 @@ void SV_WriteEntitiesToClient (client_t *client, sizebuf_t *msg, qboolean ignore
// this is the frame we are creating
frame = &client->frameunion.frames[client->netchan.incoming_sequence & UPDATE_MASK];
if (!sv.paused)
memset(frame->playerpresent, 0, sizeof(frame->playerpresent));
memset(frame->playerpresent, 0, sizeof(frame->playerpresent));
// find the client's PVS
if (ignorepvs)

View File

@ -58,8 +58,7 @@ cvar_t sv_nopvs = CVARD("sv_nopvs", "0", "Set to 1 to ignore pvs on the serv
cvar_t fraglog_public = CVARD("fraglog_public", "1", "Enables support for connectionless fraglog requests");
cvar_t fraglog_details = CVARD("fraglog_details", "1", "Bitmask\n1: killer+killee names.\n2: killer+killee teams\n4:timestamp.\n8:killer weapon\n16:killer+killee guid.\nFor compatibility, use 1(vanilla) or 7(mvdsv).");
cvar_t timeout = CVAR("timeout","65"); // seconds without any message
cvar_t zombietime = CVAR("zombietime", "2"); // seconds to sink messages
cvar_t zombietime = CVARD("zombietime", "2", "Client slots will not be reused for this number of seconds."); // seconds to sink messages
cvar_t sv_crypt_rcon = CVARFD("sv_crypt_rcon", "", CVAR_ARCHIVE, "Controls whether the rcon password must be hashed or not. Hashed passwords also partially prevent replay attacks, but does NOT prevent malicious actors from reading the commands/results.\n0: completely insecure. ONLY allows plain-text passwords. Do not use.\n1: Mandatory hashing (recommended).\nEmpty: Allow either, whether the password is secure or not is purely the client's responsibility/fault. Only use this for comptibility with old clients.");
cvar_t sv_crypt_rcon_clockskew = CVARFD("sv_timestamplen", "60", CVAR_ARCHIVE, "Limits clock skew to reduce (delayed) replay attacks");
@ -4780,7 +4779,6 @@ float SV_Frame (void)
static int oldpackets;
float oldtime;
qboolean isidle;
static int oldpaused;
float timedelta;
float delay;
@ -4820,10 +4818,10 @@ float SV_Frame (void)
sv.paused ^= PAUSE_AUTO;
#endif
if (oldpaused != sv.paused)
if (sv.oldpaused != sv.paused)
{
sv.oldpaused = sv.paused;
SV_PauseChanged();
oldpaused = sv.paused;
}
@ -5084,7 +5082,7 @@ static void SV_InfoChanged(void *context, const char *key)
#endif
for (i = 0; i < svs.allocated_client_slots; i++)
{
if (svs.clients[i].state >= cs_connected)
if (svs.clients[i].state >= cs_connected && !svs.clients[i].controller)
{
InfoSync_Add(&svs.clients[i].infosync, context, key);
}
@ -5155,7 +5153,6 @@ void SV_InitLocal (void)
Cvar_Register (&sv_allow_splitscreen, cvargroup_serverinfo);
Cvar_Register (&fbskins, cvargroup_serverinfo);
Cvar_Register (&timeout, cvargroup_servercontrol);
Cvar_Register (&zombietime, cvargroup_servercontrol);
Cvar_Register (&sv_pupglow, cvargroup_serverinfo);
@ -5615,8 +5612,10 @@ void SV_ExtractFromUserinfo (client_t *cl, qboolean verbose)
cl->playercolor = top*16 + bottom;
if (svs.gametype == GT_PROGS || svs.gametype == GT_Q1QVM)
{
#ifndef NOLEGACY
if (cl->edict)
cl->edict->xv->clientcolors = cl->playercolor;
#endif
MSG_WriteByte (&sv.nqreliable_datagram, svc_updatecolors);
MSG_WriteByte (&sv.nqreliable_datagram, cl-svs.clients);
MSG_WriteByte (&sv.nqreliable_datagram, cl->playercolor);

View File

@ -53,6 +53,7 @@ cvar_t sv_airaccelerate = CVAR( "sv_airaccelerate", "0.7");
cvar_t sv_wateraccelerate = CVAR( "sv_wateraccelerate", "10");
cvar_t sv_friction = CVAR( "sv_friction", "4");
cvar_t sv_waterfriction = CVAR( "sv_waterfriction", "4");
cvar_t sv_wallfriction = CVARD( "sv_wallfriction", "1", "Additional friction when running into walls");
cvar_t sv_gameplayfix_noairborncorpse = CVAR( "sv_gameplayfix_noairborncorpse", "0");
cvar_t sv_gameplayfix_multiplethinks = CVARD( "sv_gameplayfix_multiplethinks", "1", "Enables multiple thinks per entity per frame so small nextthink times are accurate. QuakeWorld mods expect a value of 1.");
cvar_t sv_gameplayfix_stepdown = CVARD( "sv_gameplayfix_stepdown", "0", "Attempt to step down steps, instead of only up them. Affects non-predicted movetype_walk.");
@ -87,6 +88,7 @@ void WPhys_Init(void)
Cvar_Register (&sv_wateraccelerate, cvargroup_serverphysics);
Cvar_Register (&sv_friction, cvargroup_serverphysics);
Cvar_Register (&sv_waterfriction, cvargroup_serverphysics);
Cvar_Register (&sv_wallfriction, cvargroup_serverphysics);
Cvar_Register (&sv_sound_watersplash, cvargroup_serverphysics);
Cvar_Register (&sv_sound_land, cvargroup_serverphysics);
Cvar_Register (&sv_stepheight, cvargroup_serverphysics);
@ -1887,7 +1889,7 @@ static void SV_WalkMove (edict_t *ent)
#else
// 1/32 epsilon to keep floating point happy
#define DIST_EPSILON (0.03125)
/*#define DIST_EPSILON (0.03125)
static int WPhys_SetOnGround (world_t *w, wedict_t *ent, const float *gravitydir)
{
vec3_t end;
@ -1896,6 +1898,8 @@ static int WPhys_SetOnGround (world_t *w, wedict_t *ent, const float *gravitydir
return 1;
VectorMA(ent->v->origin, 1, gravitydir, end);
trace = World_Move(w, ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, (wedict_t*)ent);
if (DotProduct(trace.plane.normal, ent->v->velocity) > 0)
return 0; //velocity is away from the plane normal, so this does not count as a contact.
if (trace.fraction <= DIST_EPSILON && -DotProduct(gravitydir, trace.plane.normal) >= 0.7)
{
ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
@ -1903,7 +1907,7 @@ static int WPhys_SetOnGround (world_t *w, wedict_t *ent, const float *gravitydir
return 1;
}
return 0;
}
}*/
static void WPhys_WalkMove (world_t *w, wedict_t *ent, const float *gravitydir)
{
//int originalmove_clip;
@ -1922,7 +1926,7 @@ static void WPhys_WalkMove (world_t *w, wedict_t *ent, const float *gravitydir)
clip = WPhys_FlyMove (w, ent, gravitydir, host_frametime, NULL);
WPhys_SetOnGround (w, ent, gravitydir);
// WPhys_SetOnGround (w, ent, gravitydir);
WPhys_CheckVelocity(w, ent);
VectorCopy(ent->v->origin, originalmove_origin);
@ -1951,7 +1955,7 @@ static void WPhys_WalkMove (world_t *w, wedict_t *ent, const float *gravitydir)
return;
// only step up while jumping if that is enabled
if (!pm_airstep.value)
if (!pm_airstep.value)
if (!oldonground && ent->v->waterlevel == 0)
return;
}
@ -1967,9 +1971,9 @@ static void WPhys_WalkMove (world_t *w, wedict_t *ent, const float *gravitydir)
WPhys_PushEntity(w, ent, upmove, MOVE_NORMAL);
// move forward
ent->v->velocity[2] = 0;
VectorMA(ent->v->velocity, -DotProduct(gravitydir, ent->v->velocity), gravitydir, ent->v->velocity); //ent->v->velocity[2] = 0;
clip = WPhys_FlyMove (w, ent, gravitydir, host_frametime, &steptrace);
ent->v->velocity[2] += start_velocity[2];
VectorMA(ent->v->velocity, DotProduct(gravitydir, start_velocity), gravitydir, ent->v->velocity); //ent->v->velocity[2] += start_velocity[2];
WPhys_CheckVelocity(w, ent);
@ -1994,22 +1998,23 @@ static void WPhys_WalkMove (world_t *w, wedict_t *ent, const float *gravitydir)
//Con_Printf("step - ");
// extra friction based on view angle
if (clip & 2)// && sv_wallfriction.value)
if ((clip & 2) && sv_wallfriction.value)
{
// Con_Printf("wall\n");
WPhys_WallFriction (ent, &steptrace);
}
}
else if (!sv_gameplayfix_stepdown.ival || !oldonground || start_velocity[2] > 0 || ((int)ent->v->flags & FL_ONGROUND) || ent->v->waterlevel >= 2)
else if (!sv_gameplayfix_stepdown.ival || !oldonground || -DotProduct(gravitydir,start_velocity) > 0 || ((int)ent->v->flags & FL_ONGROUND) || ent->v->waterlevel >= 2)
return;
// move down
VectorScale(gravitydir, -(-movevars.stepheight + start_velocity[2]*host_frametime), downmove);
VectorScale(gravitydir, movevars.stepheight + (1/32.0) - DotProduct(gravitydir,start_velocity)*host_frametime, downmove);
// FIXME: don't link?
downtrace = WPhys_PushEntity (w, ent, downmove, MOVE_NORMAL);
if (downtrace.fraction < 1 && -DotProduct(gravitydir, downtrace.plane.normal) > 0.7)
{
if (DotProduct(downtrace.plane.normal, ent->v->velocity)<=0) //Spike: moving away from the surface should not count as onground.
// LordHavoc: disabled this check so you can walk on monsters/players
//if (ent->v->solid == SOLID_BSP)
{
@ -2031,7 +2036,7 @@ static void WPhys_WalkMove (world_t *w, wedict_t *ent, const float *gravitydir)
ent->v->groundentity = originalmove_groundentity;
}
WPhys_SetOnGround (w, ent, gravitydir);
// WPhys_SetOnGround (w, ent, gravitydir);
WPhys_CheckVelocity(w, ent);
}
#endif
@ -2142,9 +2147,9 @@ void WPhys_RunEntity (world_t *w, wedict_t *ent)
if (ent->lastruntime == w->framenum)
return;
ent->lastruntime = w->framenum;
if (progstype == PROG_QW) //we don't use the field any more, but qw mods might.
ent->v->lastruntime = w->physicstime;
#ifndef CLIENTONLY
if (progstype == PROG_QW && w == &sv.world) //we don't use the field any more, but qw mods might.
ent->v->lastruntime = w->physicstime;
svent = NULL;
#endif
}
@ -2233,9 +2238,9 @@ void WPhys_RunEntity (world_t *w, wedict_t *ent)
WPhys_WalkMove (w, ent, gravitydir);
#ifndef CLIENTONLY
if (!(ent->entnum > 0 && ent->entnum <= sv.allocated_client_slots) && w == &sv.world)
World_LinkEdict (w, ent, true);
if (!svent)
#endif
World_LinkEdict (w, ent, true);
break;
#ifdef USERBE
case MOVETYPE_PHYSICS:
@ -2257,7 +2262,7 @@ void WPhys_RunEntity (world_t *w, wedict_t *ent)
#ifndef CLIENTONLY
if (svent)
{
World_LinkEdict (w, (wedict_t*)svent, true);
World_LinkEdict (w, ent, true);
if (!host_client->spectator)
{
@ -2416,7 +2421,6 @@ void World_Physics_Frame(world_t *w)
host_client = &svs.clients[i-1];
sv_player = svs.clients[i-1].edict;
host_client->lastruncmd = newt;
SV_PreRunCmd();
#ifndef NEWSPEEDCHEATPROT
svs.clients[i-1].last_check = 0;

View File

@ -1081,7 +1081,10 @@ void SV_SendClientPrespawnInfo(client_t *client)
else if (client->prespawn_idx == 5)
{
ClientReliableWrite_Begin(client, svc_setpause, 2);
ClientReliableWrite_Byte (client, sv.paused!=0);
ClientReliableWrite_Byte (client, sv.oldpaused!=0);
if (sv.oldpaused && sv.oldpaused&~PAUSE_AUTO)
SV_PrintToClient(client, PRINT_HIGH, "server is paused\n");
}
else
{
@ -1796,7 +1799,7 @@ void SVQW_Spawn_f (void)
// send all current names, colors, and frag counts
// FIXME: is this a good thing?
SZ_Clear (&host_client->netchan.message);
// SZ_Clear (&host_client->netchan.message);
// send current status of all other players
@ -2138,6 +2141,8 @@ void SV_Begin_Core(client_t *split)
SV_PostRunCmd();
host_client = oh;
sv_player = oh?oh->edict:NULL;
host_client->lastruncmd = sv.time*1000;
}
}
}
@ -2217,18 +2222,6 @@ void SV_Begin_f (void)
SV_BroadcastTPrintf (PRINT_HIGH, "warning: %s eyes or player model does not match\n", host_client->name);
}
// if we are paused, tell the client
if (sv.paused)
{
if (!ISQ2CLIENT(host_client))
{
ClientReliableWrite_Begin (host_client, svc_setpause, 2);
ClientReliableWrite_Byte (host_client, sv.paused!=0);
}
if (sv.paused&~PAUSE_AUTO)
SV_ClientTPrintf(host_client, PRINT_HIGH, "server is paused\n");
}
if (sendangles)
{
//
@ -5518,7 +5511,7 @@ static void SVNQ_Spawn_f (void)
// send all current names, colors, and frag counts
// FIXME: is this a good thing?
SZ_Clear (&host_client->netchan.message);
// SZ_Clear (&host_client->netchan.message);
// send current status of all other players
@ -5640,19 +5633,6 @@ static void SVNQ_Begin_f (void)
SV_BroadcastTPrintf (PRINT_HIGH, "warning: %s eyes or player model not verified\n", host_client->name);
}
// if we are paused, tell the client
if (sv.paused)
{
if (!ISQ2CLIENT(host_client))
{
ClientReliableWrite_Begin (host_client, svc_setpause, 2);
ClientReliableWrite_Byte (host_client, sv.paused!=0);
}
if (sv.paused&~PAUSE_AUTO)
SV_ClientTPrintf(host_client, PRINT_HIGH, "server is paused\n");
}
if (sendangles)
{
//
@ -6830,6 +6810,7 @@ size_t playertouchmax;
void SV_PreRunCmd(void)
{
size_t max = MAX_EDICTS;//(sv.world.num_edicts+7)&~7;
host_client->lastruncmd = sv.time*1000;
if (max > playertouchmax)
{
playertouchmax = max;

View File

@ -2294,7 +2294,7 @@ static void World_ClipToNetwork (world_t *w, moveclip_t *clip)
if (!((int)clip->passedict->xv->dimension_hit & 1))
continue;
if (!model || model->loadstate != MLS_LOADED)
if (!model || model->loadstate != MLS_LOADED || !model->funcs.NativeTrace)
{
model = NULL;