lerpfrac3 fixes. unix sockets for the luls (disabled). some misc tweaks for xonotic.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5309 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2018-09-23 19:35:24 +00:00
parent fe885985ec
commit 5159a801ff
71 changed files with 1863 additions and 805 deletions

View File

@ -473,7 +473,7 @@ ALL_CXXFLAGS=$(subst -Wno-pointer-sign,,$(ALL_CFLAGS))
#cheap compile-everything-in-one-unit (compile becomes preprocess only)
ifneq ($(WPO),)
LTO_CC= -E
LTO_LD= -combine -fwhole-program -x c
LTO_LD= -flto -fwhole-program -x c
LTO_END=ltoxnone
LTO_START=ltoxc
endif

View File

@ -706,14 +706,11 @@ void CL_BaseMove (usercmd_t *cmd, int pnum, float priortime, float extratime)
CL_GatherButtons(cmd, pnum);
}
void CL_ClampPitch (int pnum)
static void CL_ClampPitch (int pnum, float frametime)
{
float mat[16];
float roll;
static float oldtime;
float timestep = realtime - oldtime;
playerview_t *pv = &cl.playerview[pnum];
oldtime = realtime;
if (cl.intermissionmode != IM_NONE)
{
@ -819,17 +816,17 @@ void CL_ClampPitch (int pnum)
}
else
{
if (fabs(vang[ROLL]) < host_frametime*180)
if (fabs(vang[ROLL]) < frametime*180)
vang[ROLL] = 0;
else if (vang[ROLL] > 0)
{
// Con_Printf("Roll %f\n", vang[ROLL]);
vang[ROLL] -= host_frametime*180;
vang[ROLL] -= frametime*180;
}
else
{
// Con_Printf("Roll %f\n", vang[ROLL]);
vang[ROLL] += host_frametime*180;
vang[ROLL] += frametime*180;
}
}
VectorClear(pv->viewanglechange);
@ -904,11 +901,11 @@ void CL_ClampPitch (int pnum)
// cl.viewangles[pnum][ROLL] = 50;
// if (cl.viewangles[pnum][ROLL] < -50)
// cl.viewangles[pnum][ROLL] = -50;
roll = timestep*pv->viewangles[ROLL]*30;
roll = frametime*pv->viewangles[ROLL]*30;
if ((pv->viewangles[ROLL]-roll < 0) != (pv->viewangles[ROLL]<0))
pv->viewangles[ROLL] = 0;
else
pv->viewangles[ROLL] -= timestep*pv->viewangles[ROLL]*3;
pv->viewangles[ROLL] -= frametime*pv->viewangles[ROLL]*3;
}
/*
@ -920,7 +917,7 @@ static void CL_FinishMove (usercmd_t *cmd, int pnum)
{
int i;
CL_ClampPitch(pnum);
CL_ClampPitch(pnum, 0);
//
// always dump the first two message, because it may contain leftover inputs
@ -1869,6 +1866,7 @@ void CL_SendCmd (double frametime, qboolean mainloop)
cl_pendingcmd[plnum].forwardmove += mousemovements[0];
cl_pendingcmd[plnum].sidemove += mousemovements[1];
cl_pendingcmd[plnum].upmove += mousemovements[2];
CL_ClampPitch(plnum, frametime);
// if we are spectator, try autocam
if (pv->spectator)
@ -2021,7 +2019,7 @@ void CL_SendCmd (double frametime, qboolean mainloop)
CL_AdjustAngles (plnum, frametime);
VectorClear(mousemovements);
IN_Move (mousemovements, plnum, frametime);
CL_ClampPitch(plnum);
CL_ClampPitch(plnum, frametime);
cl_pendingcmd[plnum].forwardmove += mousemovements[0]; //FIXME: this will get nuked by CL_BaseMove.
cl_pendingcmd[plnum].sidemove += mousemovements[1];
cl_pendingcmd[plnum].upmove += mousemovements[2];

View File

@ -1026,7 +1026,7 @@ void CL_CheckForResend (void)
t1 = Sys_DoubleTime ();
if (!connectinfo.istransfer)
{
host = strrchr(cls.servername, '@');
host = strrchr(cls.servername+1, '@');
if (host)
host++;
else
@ -1087,7 +1087,7 @@ void CL_CheckForResend (void)
Con_TPrintf ("Connecting to %s...\n", cls.servername);
if (connectinfo.tries == 0)
if (!NET_EnsureRoute(cls.sockets, "conn", cls.servername))
if (!NET_EnsureRoute(cls.sockets, "conn", cls.servername, &connectinfo.adr))
{
Con_Printf ("Unable to establish connection to %s\n", cls.servername);
connectinfo.trying = false;
@ -1564,12 +1564,14 @@ void CL_ResetFog(int ftype)
=====================
CL_ClearState
gamestart==true says that we're changing map, as opposed to servers.
=====================
*/
void CL_ClearState (void)
void CL_ClearState (qboolean gamestart)
{
extern cvar_t cfg_save_auto;
int i, j;
downloadlist_t *pendingdownloads, *faileddownloads;
#ifndef CLIENTONLY
#define serverrunning (sv.state != ss_dead)
#define tolocalserver NET_IsLoopBackAddress(&cls.netchan.remote_address)
@ -1655,6 +1657,7 @@ void CL_ClearState (void)
Z_Free(t);
}
if (!gamestart)
{
downloadlist_t *next;
while(cl.downloadlist)
@ -1670,6 +1673,8 @@ void CL_ClearState (void)
cl.faileddownloads = next;
}
}
pendingdownloads = cl.downloadlist;
faileddownloads = cl.faileddownloads;
#ifdef Q2CLIENT
for (i = 0; i < countof(cl.configstring_general); i++)
@ -1741,6 +1746,8 @@ void CL_ClearState (void)
cl.splitclients = 1;
cl.autotrack_hint = -1;
cl.autotrack_killer = -1;
cl.downloadlist = pendingdownloads;
cl.faileddownloads = faileddownloads;
if (cfg_save_auto.ival && Cvar_UnsavedArchive())
Cmd_ExecuteString("cfg_save\n", RESTRICT_LOCAL);
@ -1879,7 +1886,7 @@ void CL_Disconnect (void)
Cvar_ForceSet(&cl_servername, "none");
CL_ClearState();
CL_ClearState(false);
FS_PureMode(0, NULL, NULL, NULL, NULL, 0);
@ -3779,7 +3786,7 @@ void CL_ReadPackets (void)
//=============================================================================
qboolean CL_AllowArbitaryDownload(char *oldname, char *localfile)
qboolean CL_AllowArbitaryDownload(const char *oldname, const char *localfile)
{
int allow;
//never allow certain (native code) arbitary downloads.
@ -3813,6 +3820,114 @@ qboolean CL_AllowArbitaryDownload(char *oldname, char *localfile)
return false;
}
#if defined(NQPROT) && !defined(NOLEGACY)
//this is for DP compat.
static void CL_Curl_f(void)
{
//curl --args url
int i, argc = Cmd_Argc();
const char *arg, *gamedir, *localterse/*no dlcache*/= NULL;
char localname[MAX_QPATH];
int usage = 0;
qboolean alreadyhave = false;
extern char cl_dp_packagenames[4096];
unsigned int dlflags = DLLF_VERBOSE;
if (argc < 2)
{
Con_Printf("%s: No args\n", Cmd_Argv(0));
return;
}
// Con_Printf("%s %s\n", Cmd_Argv(0), Cmd_Args());
for (i = 1; i < argc; i++)
{
arg = Cmd_Argv(i);
if (!strcmp(arg, "--info"))
{
Con_Printf("%s %s: not implemented\n", Cmd_Argv(0), arg);
return;
}
else if (!strcmp(arg, "--cancel"))
{
Con_Printf("%s %s: not implemented\n", Cmd_Argv(0), arg);
return;
}
else if (!strcmp(arg, "--pak"))
usage |= 1;
else if (!strcmp(arg, "--cachepic"))
usage |= 2;
else if (!strcmp(arg, "--skinframe"))
usage |= 4;
else if (!strcmp(arg, "--for"))
{
alreadyhave = true; //assume we have it.
for (i++; i < argc-1; i++)
{
arg = Cmd_Argv(i);
if (!CL_CheckDLFile(arg))
{
alreadyhave = false;
break;
}
}
}
else if (!strcmp(arg, "--forthismap"))
{
//'don't reconnect on failure'
//though I'm guessing its better expressed as just flagging it as mandatory.
dlflags |= DLLF_REQUIRED;
}
else if (!strcmp(arg, "--as"))
{
//explicit local filename
localterse = Cmd_Argv(++i);
}
else if (!strcmp(arg, "--clear_autodownload"))
{
*cl_dp_packagenames = 0;
return;
}
else if (!strcmp(arg, "--finish_autodownload"))
{
//not really sure why this is needed
// Con_Printf("%s %s: not implemented\n", Cmd_Argv(0), arg);
return;
}
else if (!strcmp(arg, "--maxspeed="))
;
else if (*arg == '-')
Con_Printf("%s: Unknown option %s\n", Cmd_Argv(0), arg);
else
; //usually just the last arg, but may also be some parameter for an unknown arg.
}
arg = Cmd_Argv(argc-1);
if (!localterse)
{
//for compat, we should look for the last / and truncate on a ?.
Con_Printf("%s: skipping download of %s, as the local name was not explicitly given\n", Cmd_Argv(0), arg);
return;
}
if (usage == 1)
{
dlflags |= DLLF_NONGAME;
gamedir = FS_GetGamedir(true);
FS_GenCachedPakName(va("%s/%s", gamedir, localterse), NULL, localname, sizeof(localname));
if (!alreadyhave)
if (!CL_CheckOrEnqueDownloadFile(arg, localname, dlflags))
Con_Printf("Downloading %s to %s\n", arg, localname);
if (*cl_dp_packagenames)
Q_strncatz(cl_dp_packagenames, " ", sizeof(cl_dp_packagenames));
Q_strncatz(cl_dp_packagenames, va("%s/%s", gamedir, localterse), sizeof(cl_dp_packagenames));
}
else
{
Con_Printf("%s: %s: non-package downloads are not supported\n", Cmd_Argv(0), arg);
return;
}
}
#endif
/*
=====================
CL_Download_f
@ -4518,6 +4633,9 @@ void CL_Init (void)
Cmd_AddCommand ("fullinfo", CL_FullInfo_f);
Cmd_AddCommand ("color", CL_Color_f);
#if defined(NQPROT) && !defined(NOLEGACY)
Cmd_AddCommand ("curl", CL_Curl_f);
#endif
Cmd_AddCommand ("download", CL_Download_f);
Cmd_AddCommandD ("dlsize", CL_DownloadSize_f, "For internal use");
Cmd_AddCommandD ("nextul", CL_NextUpload, "For internal use");
@ -4566,7 +4684,7 @@ void CL_Init (void)
#ifdef QUAKEHUD
Stats_Init();
#endif
CL_ClearState(); //make sure the cl.* fields are set properly if there's no ssqc or whatever.
CL_ClearState(false); //make sure the cl.* fields are set properly if there's no ssqc or whatever.
}

View File

@ -36,6 +36,7 @@ static void DLC_Poll(qdownload_t *dl);
static void CL_ProcessUserInfo (int slot, player_info_t *player);
#ifdef NQPROT
char cl_dp_packagenames[4096];
static char cl_dp_csqc_progsname[128];
static int cl_dp_csqc_progssize;
static int cl_dp_csqc_progscrc;
@ -712,27 +713,35 @@ static void CL_SendDownloadStartRequest(char *filename, char *localname, unsigne
static int dlsequence;
qdownload_t *dl;
//don't download multiple things at once... its leaky if nothing else.
if (cls.download)
return;
#ifdef WEBCLIENT
if (!strncmp(filename, "http://", 7) || !strncmp(filename, "https://", 8))
{
if (!cls.download || !(cls.download->flags & DLLF_ALLOWWEB))
struct dl_download *wdl = HTTP_CL_Get(filename, localname, CL_WebDownloadFinished);
if (wdl)
{
struct dl_download *wdl = HTTP_CL_Get(filename, localname, CL_WebDownloadFinished);
if (wdl)
if (flags & DLLF_NONGAME)
{
if (!(flags & DLLF_TEMPORARY))
Con_TPrintf ("Downloading %s to %s...\n", wdl->url, wdl->localname);
wdl->qdownload.flags = flags;
cls.download = &wdl->qdownload;
wdl->fsroot = FS_ROOT;
if (!strncmp(localname, "package/", 8))
Q_strncpyz(wdl->localname, localname+8, sizeof(wdl->localname));
}
else
CL_DownloadFailed(filename, NULL);
if (!(flags & DLLF_TEMPORARY))
Con_TPrintf ("Downloading %s to %s...\n", wdl->url, wdl->localname);
wdl->qdownload.flags = flags;
CL_DisenqueDownload(filename);
cls.download = &wdl->qdownload;
}
else
CL_DownloadFailed(filename, NULL);
return;
}
#endif
if (cls.download)
return; //no!
dl = Z_Malloc(sizeof(*dl));
dl->filesequence = ++dlsequence;
@ -785,7 +794,7 @@ void CL_DownloadFinished(qdownload_t *dl)
//should probably ask the filesytem code if its a package format instead.
if (!strncmp(filename, "package/", 8) || !strncmp(ext, "pk4", 3) || !strncmp(ext, "pk3", 3) || !strncmp(ext, "pak", 3))
if (!strncmp(filename, "package/", 8) || !strncmp(ext, "pk4", 3) || !strncmp(ext, "pk3", 3) || !strncmp(ext, "pak", 3) || (dl->fsroot == FS_ROOT))
{
FS_ReloadPackFiles();
CL_CheckServerInfo();
@ -815,7 +824,9 @@ void CL_DownloadFinished(qdownload_t *dl)
{
if (!strcmp(cl.model_name[i], filename))
{
cl.model_precache[i] = Mod_ForName(cl.model_name[i], MLV_WARN); //throw away result.
if (cl.model_precache[i] && cl.model_precache[i]->loadstate == MLS_FAILED)
cl.model_precache[i]->loadstate = MLS_NOTLOADED;
cl.model_precache[i] = Mod_ForName(cl.model_name[i], MLV_WARN);
if (i == 1)
cl.worldmodel = cl.model_precache[i];
break;
@ -825,7 +836,9 @@ void CL_DownloadFinished(qdownload_t *dl)
{
if (!strcmp(cl.model_csqcname[i], filename))
{
cl.model_csqcprecache[i] = Mod_ForName(cl.model_csqcname[i], MLV_WARN); //throw away result.
if (cl.model_csqcprecache[i] && cl.model_csqcprecache[i]->loadstate == MLS_FAILED)
cl.model_csqcprecache[i]->loadstate = MLS_NOTLOADED;
cl.model_csqcprecache[i] = Mod_ForName(cl.model_csqcname[i], MLV_WARN);
break;
}
}
@ -834,6 +847,8 @@ void CL_DownloadFinished(qdownload_t *dl)
{
if (!strcmp(cl.model_name_vwep[i], filename))
{
if (cl.model_precache_vwep[i] && cl.model_precache_vwep[i]->loadstate == MLS_FAILED)
cl.model_precache_vwep[i]->loadstate = MLS_NOTLOADED;
cl.model_precache_vwep[i] = Mod_ForName(cl.model_name_vwep[i], MLV_WARN);
break;
}
@ -1194,34 +1209,42 @@ static int CL_LoadModels(int stage, qboolean dontactuallyload)
pmove.numphysent = 0;
pmove.physents[0].model = NULL;
/*#ifdef CSQC_DAT
if (atstage())
{
#if defined(CSQC_DAT) && defined(NQPROT)
if (cls.protocol == CP_NETQUAKE && atstage())
{ //we only need this for nq. for qw we checked for downloads with the other stuff.
//there are also too many possible names to load... :(
extern cvar_t cl_nocsqc;
if (cls.protocol == CP_NETQUAKE && !cl_nocsqc.ival && !cls.demoplayback)
if (!cl_nocsqc.ival && !cls.demoplayback)
{
char *s;
const char *cscrc = InfoBuf_ValueForKey(&cl.serverinfo, "*csprogs");
const char *cssize = InfoBuf_ValueForKey(&cl.serverinfo, "*csprogssize");
const char *csname = InfoBuf_ValueForKey(&cl.serverinfo, "*csprogsname");
unsigned int chksum = strtoul(cscrc, NULL, 0);
size_t chksize = strtoul(cssize, NULL, 0);
SCR_SetLoadingFile("csprogs");
s = Info_ValueForKey(cl.serverinfo, "*csprogs");
if (*s) //only allow csqc if the server says so, and the 'checksum' matches.
if (!*csname)
csname = "csprogs.dat";
if (*cscrc && !CSQC_CheckDownload(csname, chksum, chksize)) //only allow csqc if the server says so, and the 'checksum' matches.
{
extern cvar_t cl_download_csprogs;
unsigned int chksum = strtoul(s, NULL, 0);
unsigned int chksum = strtoul(cscrc, NULL, 0);
if (cl_download_csprogs.ival)
{
char *str = va("csprogsvers/%x.dat", chksum);
if (CL_CheckOrEnqueDownloadFile("csprogs.dat", str, DLLF_REQUIRED))
return stage; //its kinda required
if (CL_IsDownloading(str))
return -1; //don't progress to loading it while we're still downloading it.
if (CL_CheckOrEnqueDownloadFile(csname, str, DLLF_REQUIRED))
return -1; //its kinda required
}
else
{
Con_Printf("Not downloading csprogs.dat due to allow_download_csprogs\n");
Con_Printf("Not downloading csprogs.dat due to %s\n", cl_download_csprogs.name);
}
}
}
endstage();
}
#endif*/
#endif
#ifdef HLCLIENT
if (atstage())
@ -1239,19 +1262,25 @@ static int CL_LoadModels(int stage, qboolean dontactuallyload)
qboolean anycsqc;
char *endptr;
unsigned int chksum;
size_t progsize;
const char *progsname;
anycsqc = atoi(InfoBuf_ValueForKey(&cl.serverinfo, "anycsqc"));
if (cls.demoplayback)
anycsqc = true;
s = InfoBuf_ValueForKey(&cl.serverinfo, "*csprogssize");
progsize = strtoul(s, NULL, 0);
s = InfoBuf_ValueForKey(&cl.serverinfo, "*csprogs");
chksum = strtoul(s, &endptr, 0);
progsname = InfoBuf_ValueForKey(&cl.serverinfo, "*csprogsname");
if (*endptr)
{
Con_Printf("corrupt *csprogs key in serverinfo\n");
anycsqc = true;
chksum = 0;
}
progsname = *s?InfoBuf_ValueForKey(&cl.serverinfo, "*csprogsname"):NULL;
SCR_SetLoadingFile("csprogs");
if (!CSQC_Init(anycsqc, *s?true:false, chksum))
if (!CSQC_Init(anycsqc, progsname, chksum, progsize))
{
Sbar_Start(); //try and start this before we're actually on the server,
//this'll stop the mod from sending so much stuffed data at us, whilst we're frozen while trying to load.
@ -2700,13 +2729,25 @@ static void CLDP_ParseDownloadData(void)
if (dl->file)
{
VFS_SEEK(dl->file, start);
VFS_WRITE(dl->file, buffer, size);
if (start > dl->completedbytes)
; //this protocol cannot deal with gaps. we might as well wait until its repeated later.
else if (start+size < dl->completedbytes)
; //already completed this data
else
{
int offset = dl->completedbytes-start; //we may already have completed some chunk already
dl->percent = (start+size) / (float)VFS_GETLEN(dl->file) * 100;
VFS_WRITE(dl->file, buffer+offset, size-offset);
dl->completedbytes += size-offset;
dl->ratebytes += size-offset; //for download rate calcs
}
dl->percent = (start+size) / (float)dl->size * 100;
}
//this is only reliable because I'm lazy
//we need to ack in order.
//the server doesn't actually track packets, only position, however there's no way to tell it that we already have a chunk
//we could send the acks unreliably, but any cl->sv loss would involve a sv->cl resend (because we can't dupe).
MSG_WriteByte(&cls.netchan.message, clcdp_ackdownloaddata);
MSG_WriteLong(&cls.netchan.message, start);
MSG_WriteShort(&cls.netchan.message, size);
@ -3133,7 +3174,7 @@ static void CLQW_ParseServerData (void)
#endif
}
CL_ClearState ();
CL_ClearState (true);
#ifdef QUAKEHUD
Stats_NewMap();
#endif
@ -3408,7 +3449,7 @@ static void CLQ2_ParseServerData (void)
//FTE doesn't actually have a timescale cvar, so create one to 'fool' q2admin.
//I can't really blame q2admin for rejecting engines that don't have this cvar, as it could have been renamed via a hex-edit.
CL_ClearState ();
CL_ClearState (true);
CLQ2_ClearState ();
cl.minpitch = -89;
cl.maxpitch = 89;
@ -3504,7 +3545,9 @@ static void CLQ2_ParseServerData (void)
void CL_ParseEstablished(void)
{
#ifdef NQPROT
*cl_dp_packagenames = 0;
cl_dp_serverextension_download = false;
*cl_dp_csqc_progsname = 0;
cl_dp_csqc_progscrc = 0;
cl_dp_csqc_progssize = 0;
#endif
@ -3671,7 +3714,7 @@ static void CLNQ_ParseServerData(void) //Doesn't change gamedir - use with caut
int gametype;
Con_DPrintf ("Serverdata packet %s.\n", cls.demoplayback?"read":"received");
SCR_SetLoadingStage(LS_CLIENT);
CL_ClearState ();
CL_ClearState (true);
#ifdef QUAKEHUD
Stats_NewMap();
#endif
@ -3776,6 +3819,24 @@ static void CLNQ_ParseServerData(void) //Doesn't change gamedir - use with caut
InfoBuf_SetStarKey(&cl.serverinfo, "*csprogsname", va("%s", cl_dp_csqc_progsname));
}
if (*cl_dp_packagenames)
{
char *in = cl_dp_packagenames;
while (*in)
{
in = COM_Parse(in);
if (*cl.serverpaknames)
Q_strncatz(cl.serverpaknames, " ", sizeof(cl.serverpaknames));
Q_strncatz(cl.serverpaknames, com_token, sizeof(cl.serverpaknames));
if (*cl.serverpakcrcs)
Q_strncatz(cl.serverpakcrcs, " ", sizeof(cl.serverpakcrcs));
Q_strncatz(cl.serverpakcrcs, "-", sizeof(cl.serverpakcrcs)); //we don't have any crc info. we'll instead need this info as part of the filename.
cl.serverpakschanged = true;
}
}
//update gamemode
if (gametype != GAME_COOP)
InfoBuf_SetKey(&cl.serverinfo, "deathmatch", "1");

View File

@ -396,9 +396,9 @@ typedef struct qdownload_s
unsigned int filesequence; //unique file id.
enum fs_relative fsroot; //where the local+temp file is meant to be relative to.
double ratetime;
int rate;
int ratebytes;
double ratetime; //periodically updated
int rate; //ratebytes/ratetimedelta
int ratebytes; //updated by download reception code, and cleared when ratetime is bumped
unsigned int flags;
//chunked downloads uses this
@ -425,7 +425,7 @@ enum qdlabort
};
qboolean DL_Begun(qdownload_t *dl);
void DL_Abort(qdownload_t *dl, enum qdlabort aborttype); //just frees the download's resources. does not delete the temp file.
qboolean CL_AllowArbitaryDownload(char *oldname, char *localfile);
qboolean CL_AllowArbitaryDownload(const char *oldname, const char *localfile);
//
@ -1185,11 +1185,10 @@ enum beamtype_e
typedef struct beam_s beam_t;
beam_t *CL_AddBeam (enum beamtype_e tent, int ent, vec3_t start, vec3_t end);
void CL_ClearState (void);
void CL_ClearState (qboolean gamestart);
void CLQ2_ClearState(void);
void CL_ReadPackets (void);
void CL_ClampPitch (int pnum);
int CL_ReadFromServer (void);
void CL_WriteToServer (usercmd_t *cmd);
@ -1398,7 +1397,8 @@ qboolean CSQC_Inited(void);
void CSQC_RendererRestarted(void);
qboolean CSQC_UnconnectedOkay(qboolean inprinciple);
qboolean CSQC_UnconnectedInit(void);
qboolean CSQC_Init (qboolean anycsqc, qboolean csdatenabled, unsigned int checksum);
qboolean CSQC_CheckDownload(const char *name, unsigned int checksum, size_t checksize); //reports whether we already have a usable csprogs.dat
qboolean CSQC_Init (qboolean anycsqc, const char *csprogsname, unsigned int checksum, size_t progssize);
qboolean CSQC_ConsoleLink(char *text, char *info);
void CSQC_RegisterCvarsAndThings(void);
qboolean CSQC_SetupToRenderPortal(int entnum);

View File

@ -539,7 +539,7 @@ void CLQ3_ParseGameState(void)
//
// wipe the client_state_t struct
//
CL_ClearState();
CL_ClearState(true);
ccs.firstParseEntity = 0;
memset(ccs.parseEntities, 0, sizeof(ccs.parseEntities));
memset(ccs.baselines, 0, sizeof(ccs.baselines));

View File

@ -1176,6 +1176,27 @@ void VARGS Con_DLPrintf (int level, const char *fmt, ...)
}
}
void VARGS Con_ThrottlePrintf (float *timer, int developerlevel, const char *fmt, ...)
{
va_list argptr;
char msg[MAXPRINTMSG];
float now = realtime;
if (*timer > now)
; //in the future? zomg
else if (*timer > now-1)
return; //within the last second
*timer = now; //in the future? zomg
va_start (argptr,fmt);
vsnprintf (msg,sizeof(msg)-1, fmt,argptr);
va_end (argptr);
if (developerlevel)
Con_DLPrintf(developerlevel, "%s", msg);
else
Con_Printf("%s", msg);
}
/*description text at the bottom of the console*/
void Con_Footerf(console_t *con, qboolean append, const char *fmt, ...)
@ -2640,7 +2661,7 @@ void Con_DrawConsole (int lines, qboolean noback)
key = Info_ValueForKey(info, "tiprawimg");
if (*key)
{
shader = R2D_SafeCachePic("riprawimg");
shader = R2D_SafeCachePic("tiprawimg");
shader->defaulttextures->base = Image_FindTexture(key, NULL, IF_NOREPLACE|IF_PREMULTIPLYALPHA);
if (!shader->defaulttextures->base)
{
@ -2707,6 +2728,16 @@ void Con_DrawConsole (int lines, qboolean noback)
else
shader = NULL;
}
if (iw > (vid.width/4.0))
{
ih *= (vid.width/4.0)/iw;
iw *= (vid.width/4.0)/iw;
}
if (ih > (vid.height/4.0))
{
iw *= (vid.width/4.0)/ih;
ih *= (vid.width/4.0)/ih;
}
if (x + iw/2 + 8 + 256 > vid.width)
x = vid.width - (iw/2 + 8 + 256);

View File

@ -5030,7 +5030,7 @@ typedef struct
#define MPEGLAYER3_ID_MPEG 1
#endif
qboolean QDECL S_LoadMP3Sound (sfx_t *s, qbyte *data, size_t datalen, int sndspeed)
static qboolean QDECL S_LoadMP3Sound (sfx_t *s, qbyte *data, size_t datalen, int sndspeed, qboolean forcedecode)
{
WAVEFORMATEX pcm_format;
MPEGLAYER3WAVEFORMAT mp3format;

View File

@ -2967,7 +2967,7 @@ void M_Menu_Video_f (void)
MC_AddRedText(menu, 200, y, current3dres, false); y+=8;
y+=8;
MC_AddRedText(menu, 0, y, " <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ", false); y+=8;
MC_AddRedText(menu, 0, y, " ^Ue080^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue082 ", false); y+=8;
y+=8;
info->renderer = MC_AddCombo(menu, 16, y, " Renderer", rendererops, i); y+=8;
info->bppcombo = MC_AddCombo(menu, 16, y, " Color Depth", bppnames, currentbpp); y+=8;

View File

@ -385,7 +385,7 @@ void M_Menu_SinglePlayer_f (void)
}
else if (!strncmp(Cmd_Argv(1), "skill", 5))
{
//yes, hexen2 has per-class names for the skill levels. because being weird and obtuse is kinda its forté
//yes, hexen2 has per-class names for the skill levels. because being weird and obtuse is kinda its forte
static char *skillnames[6][4] =
{
{

View File

@ -44,7 +44,12 @@ typedef enum
#define MAX_BONE_CONTROLLERS 5
#endif
#define FRAME_BLENDS 4
#ifdef NOLEGACY
#define FRAME_BLENDS 2
#else
#define FRAME_BLENDS 4 //for compat with DP (for mods that want 4-way blending yet refuse to use framegroups properly). real mods should be using skeletal objects allowing for N-way blending.
#endif
#define FST_BASE 0 //base frames
#define FS_REG 1 //regular frames
#define FS_COUNT 2 //regular frames

View File

@ -368,7 +368,7 @@ void SV_Master_Worker_Resolved(void *ctx, void *data, size_t a, size_t b)
{
//tcp masters require a route
if (NET_AddrIsReliable(na))
NET_EnsureRoute(svs.sockets, master->cv.name, master->cv.string);
NET_EnsureRoute(svs.sockets, master->cv.name, master->cv.string, na);
//q2+qw masters are given a ping to verify that they're still up
switch (master->protocol)
@ -684,14 +684,14 @@ int slist_customkeys;
#define POLLUDP4SOCKETS 64 //it's big so we can have lots of messages when behind a firewall. Basically if a firewall only allows replys, and only remembers 3 servers per socket, we need this big cos it can take a while for a packet to find a fast optimised route and we might be waiting for a few secs for a reply the first time around.
int lastpollsockUDP4;
#ifdef IPPROTO_IPV6
#ifdef HAVE_IPV6
#define POLLUDP6SOCKETS 4 //it's non-zero so we can have lots of messages when behind a firewall. Basically if a firewall only allows replys, and only remembers 3 servers per socket, we need this big cos it can take a while for a packet to find a fast optimised route and we might be waiting for a few secs for a reply the first time around.
int lastpollsockUDP6;
#else
#define POLLUDP6SOCKETS 0
#endif
#ifdef USEIPX
#ifdef HAVE_IPX
#define POLLIPXSOCKETS 2 //ipx isn't used as much. In fact, we only expect local servers to be using it. I'm not sure why I implemented it anyway. You might see a q2 server using it. Rarely.
int lastpollsockIPX;
#else
@ -1800,7 +1800,7 @@ qboolean NET_SendPollPacket(int len, void *data, netadr_t to)
char buf[128];
NetadrToSockadr (&to, &addr);
#ifdef USEIPX
#ifdef HAVE_IPX
if (((struct sockaddr*)&addr)->sa_family == AF_IPX)
{
lastpollsockIPX++;
@ -1923,7 +1923,7 @@ int Master_CheckPollSockets(void)
continue;
if (e == NET_EMSGSIZE)
{
SockadrToNetadr (&from, &net_from);
SockadrToNetadr (&from, fromlen, &net_from);
Con_Printf ("Warning: Oversize packet from %s\n",
NET_AdrToString (adr, sizeof(adr), &net_from));
continue;
@ -1938,7 +1938,7 @@ int Master_CheckPollSockets(void)
Con_Printf ("NET_CheckPollSockets: %i, %s\n", e, strerror(e));
continue;
}
SockadrToNetadr (&from, &net_from);
SockadrToNetadr (&from, fromlen, &net_from);
net_message.cursize = ret;
if (ret >= sizeof(net_message_buffer) )
@ -1968,7 +1968,7 @@ int Master_CheckPollSockets(void)
CL_ReadServerInfo(MSG_ReadString(), MP_QUAKE2, false);
continue;
}
#ifdef IPPROTO_IPV6
#ifdef HAVE_IPV6
if (!strncmp(s, "server6", 7)) //parse a bit more...
{
msg_readcount = c+7;
@ -1991,7 +1991,7 @@ int Master_CheckPollSockets(void)
}
#endif
#ifdef IPPROTO_IPV6
#ifdef HAVE_IPV6
if (!strncmp(s, "getserversResponse6", 19) && (s[19] == '\\' || s[19] == '/')) //parse a bit more...
{
msg_readcount = c+19-1;
@ -2017,7 +2017,7 @@ int Master_CheckPollSockets(void)
continue;
}
#ifdef IPPROTO_IPV6
#ifdef HAVE_IPV6
if (!strncmp(s, "qw_slist6\\", 10)) //parse a bit more...
{
msg_readcount = c+9-1;
@ -2450,7 +2450,6 @@ void MasterInfo_ProcessHTTPJSON(struct dl_download *dl)
//don't try sending to servers we don't support
void MasterInfo_Request(master_t *mast)
{
//static int mastersequence; // warning: unused variable âmastersequenceâ
if (!mast)
return;
@ -2645,21 +2644,21 @@ void MasterInfo_Refresh(qboolean doreset)
Master_AddMaster("255.255.255.255:"STRINGIFY(PORT_DEFAULTSERVER), MT_BCAST, MP_DPMASTER, "Nearby Game Servers.");
#ifndef QUAKETC
Master_AddMaster("255.255.255.255:"STRINGIFY(PORT_QWSERVER), MT_BCAST, MP_QUAKEWORLD, "Nearby QuakeWorld UDP servers.");
Master_AddMasterHTTP("http://www.gameaholic.com/servers/qspy-quakeworld", MT_MASTERHTTP, MP_QUAKEWORLD, "gameaholic's QW master");
// Master_AddMasterHTTP("http://www.gameaholic.com/servers/qspy-quakeworld", MT_MASTERHTTP, MP_QUAKEWORLD, "gameaholic's QW master");
Master_AddMasterHTTP("https://www.quakeservers.net/lists/servers/global.txt",MT_MASTERHTTP, MP_QUAKEWORLD, "QuakeServers.net (http)");
#endif
#ifdef NQPROT
Master_AddMasterHTTP("http://www.gameaholic.com/servers/qspy-quake", MT_MASTERHTTP, MP_NETQUAKE, "gameaholic's NQ master");
// Master_AddMasterHTTP("http://www.gameaholic.com/servers/qspy-quake", MT_MASTERHTTP, MP_NETQUAKE, "gameaholic's NQ master");
// Master_AddMasterHTTP("http://servers.quakeone.com/index.php?format=json", MT_MASTERHTTPJSON, MP_NETQUAKE, "quakeone's server listing");
Master_AddMaster("255.255.255.255:"STRINGIFY(PORT_NQSERVER), MT_BCAST, MP_NETQUAKE, "Nearby Quake1 servers");
Master_AddMaster("255.255.255.255:"STRINGIFY(PORT_NQSERVER), MT_BCAST, MP_DPMASTER, "Nearby DarkPlaces servers");
Master_AddMaster("255.255.255.255:"STRINGIFY(PORT_NQSERVER), MT_BCAST, MP_DPMASTER, "Nearby DarkPlaces servers"); //only responds to one type, depending on active protocol.
#endif
#ifdef Q2CLIENT
Master_AddMasterHTTP("http://www.gameaholic.com/servers/qspy-quake2", MT_MASTERHTTP, MP_QUAKE2, "gameaholic's Q2 master");
// Master_AddMasterHTTP("http://www.gameaholic.com/servers/qspy-quake2", MT_MASTERHTTP, MP_QUAKE2, "gameaholic's Q2 master");
Master_AddMaster("255.255.255.255:27910", MT_BCAST, MP_QUAKE2, "Nearby Quake2 UDP servers.");
#endif
#ifdef Q3CLIENT
Master_AddMasterHTTP("http://www.gameaholic.com/servers/qspy-quake3", MT_MASTERHTTP, MP_QUAKE3, "gameaholic's Q3 master");
// Master_AddMasterHTTP("http://www.gameaholic.com/servers/qspy-quake3", MT_MASTERHTTP, MP_QUAKE3, "gameaholic's Q3 master");
Master_AddMaster("255.255.255.255:"STRINGIFY(PORT_Q3SERVER), MT_BCAST, MP_QUAKE3, "Nearby Quake3 UDP servers.");
#endif

View File

@ -52,6 +52,8 @@ typedef struct csqctreadstate_s {
static qboolean csprogs_promiscuous;
static unsigned int csprogs_checksum;
static size_t csprogs_checksize;
static char csprogs_checkname[MAX_QPATH];
static csqctreadstate_t *csqcthreads;
qboolean csqc_resortfrags;
world_t csqc_world;
@ -584,7 +586,7 @@ static const char *csqcmapentitydata;
static qboolean csqcmapentitydataloaded;
static unsigned int csqc_deprecated_warned;
#define csqc_deprecated(s) do {if (!csqc_deprecated_warned++){Con_Printf("csqc warning: %s\n", s); PR_StackTrace (prinst, false);}}while(0)
#define csqc_deprecated(s) do {if (!csqc_deprecated_warned++){Con_Printf(CON_WARNING"csqc deprecation warning: %s\n", s); PR_StackTrace (prinst, false);}}while(0)
static model_t *CSQC_GetModelForIndex(int index);
@ -600,7 +602,7 @@ static void CS_CheckVelocity(csqcedict_t *ent)
static void cs_getframestate(csqcedict_t *in, unsigned int rflags, framestate_t *out)
static void cs_getframestate(csqcedict_t *in, unsigned int rflags, framestate_t *fte_restrict out)
{
//FTE_CSQC_HALFLIFE_MODELS
#ifdef HALFLIFEMODELS
@ -623,12 +625,18 @@ static void cs_getframestate(csqcedict_t *in, unsigned int rflags, framestate_t
out->g[FST_BASE].frame[0] = in->xv->baseframe;
out->g[FST_BASE].frame[1] = in->xv->baseframe2;
//out->g[FST_BASE].frame[2] = in->xv->baseframe3;
//out->g[FST_BASE].frame[3] = in->xv->baseframe4;
out->g[FST_BASE].lerpweight[1] = in->xv->baselerpfrac;
//out->g[FST_BASE].frame[3] = in->xv->baseframe4;
#if 0//FRAME_BLENDS >= 4
// out->g[FST_BASE].frame[2] = in->xv->baseframe3;
// out->g[FST_BASE].lerpweight[2] = in->xv->baselerpfrac3;
// out->g[FST_BASE].frame[3] = in->xv->baseframe3;
// out->g[FST_BASE].lerpweight[3] = in->xv->baselerpfrac4;
out->g[FST_BASE].lerpweight[0] = 1-(out->g[FST_BASE].lerpweight[1]+out->g[FST_BASE].lerpweight[2]+out->g[FST_BASE].lerpweight[3]);
#else
out->g[FST_BASE].lerpweight[0] = 1-(out->g[FST_BASE].lerpweight[1]);
#endif
if (rflags & CSQCRF_FRAMETIMESARESTARTTIMES)
{
out->g[FST_BASE].frametime[0] = *csqcg.simtime - in->xv->baseframe1time;
@ -649,25 +657,33 @@ static void cs_getframestate(csqcedict_t *in, unsigned int rflags, framestate_t
out->g[FS_REG].endbone = 0x7fffffff;
out->g[FS_REG].frame[0] = in->v->frame;
out->g[FS_REG].frame[1] = in->xv->frame2;
out->g[FS_REG].frame[2] = in->xv->frame3;
out->g[FS_REG].frame[3] = in->xv->frame4;
out->g[FS_REG].lerpweight[1] = in->xv->lerpfrac;
#if FRAME_BLENDS >= 4
out->g[FS_REG].frame[2] = in->xv->frame3;
out->g[FS_REG].lerpweight[2] = in->xv->lerpfrac3;
out->g[FS_REG].frame[3] = in->xv->frame4;
out->g[FS_REG].lerpweight[3] = in->xv->lerpfrac4;
out->g[FS_REG].lerpweight[0] = 1-(out->g[FS_REG].lerpweight[1]+out->g[FS_REG].lerpweight[2]+out->g[FS_REG].lerpweight[3]);
#else
out->g[FS_REG].lerpweight[0] = 1-(out->g[FS_REG].lerpweight[1]);
#endif
if ((rflags & CSQCRF_FRAMETIMESARESTARTTIMES) || csqc_isdarkplaces)
{
out->g[FS_REG].frametime[0] = *csqcg.simtime - in->xv->frame1time;
out->g[FS_REG].frametime[1] = *csqcg.simtime - in->xv->frame2time;
out->g[FS_REG].frametime[2] = 0;//*csqcg.simtime - in->xv->frame3time;
out->g[FS_REG].frametime[3] = 0;//*csqcg.simtime - in->xv->frame4time;
#if FRAME_BLENDS >= 4
out->g[FS_REG].frametime[2] = *csqcg.simtime - in->xv->frame3time;
out->g[FS_REG].frametime[3] = *csqcg.simtime - in->xv->frame4time;
#endif
}
else
{
out->g[FS_REG].frametime[0] = in->xv->frame1time;
out->g[FS_REG].frametime[1] = in->xv->frame2time;
out->g[FS_REG].frametime[2] = 0;//in->xv->frame3time;
out->g[FS_REG].frametime[3] = 0;//in->xv->frame4time;
#if FRAME_BLENDS >= 4
out->g[FS_REG].frametime[2] = in->xv->frame3time;
out->g[FS_REG].frametime[3] = in->xv->frame4time;
#endif
}
@ -728,7 +744,7 @@ static void QCBUILTIN PF_cvar (pubprogfuncs_t *prinst, struct globalvars_s *pr_g
}
else
{
var = Cvar_Get(str, "", 0, "csqc cvars");
var = PF_Cvar_FindOrGet (str);
if (var && !(var->flags & CVAR_NOUNSAFEEXPAND))
G_FLOAT(OFS_RETURN) = var->value;
else
@ -1833,8 +1849,16 @@ static void QCBUILTIN PF_cs_project (pubprogfuncs_t *prinst, struct globalvars_s
out[1] = 1-(1+tempv[1])/2;
out[2] = tempv[2];
out[0] = out[0]*r_refdef.vrect.width + r_refdef.vrect.x;
out[1] = out[1]*r_refdef.vrect.height + r_refdef.vrect.y;
if (csqc_isdarkplaces)
{ /*sigh*/
out[0] = out[0]*vid.width + r_refdef.vrect.x;
out[1] = out[1]*vid.height + r_refdef.vrect.y;
}
else
{
out[0] = out[0]*r_refdef.vrect.width + r_refdef.vrect.x;
out[1] = out[1]*r_refdef.vrect.height + r_refdef.vrect.y;
}
if (tempv[3] < 0)
out[2] *= -1;
@ -1852,8 +1876,16 @@ static void QCBUILTIN PF_cs_unproject (pubprogfuncs_t *prinst, struct globalvars
float v[4], tempv[4];
tx = ((tx-r_refdef.vrect.x)/r_refdef.vrect.width);
ty = ((ty-r_refdef.vrect.y)/r_refdef.vrect.height);
if (csqc_isdarkplaces)
{ /*sigh*/
tx = ((tx-r_refdef.vrect.x)/vid.width);
ty = ((ty-r_refdef.vrect.y)/vid.height);
}
else
{
tx = ((tx-r_refdef.vrect.x)/r_refdef.vrect.width);
ty = ((ty-r_refdef.vrect.y)/r_refdef.vrect.height);
}
ty = 1-ty;
v[0] = tx*2-1;
v[1] = ty*2-1;
@ -2532,7 +2564,7 @@ static void QCBUILTIN PF_cs_SetSize (pubprogfuncs_t *prinst, struct globalvars_s
World_LinkEdict (w, (wedict_t*)e, false);
}
static void cs_settracevars(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals, trace_t *tr)
static void cs_settracevars(pubprogfuncs_t *prinst, trace_t *tr)
{
*csqcg.trace_allsolid = tr->allsolid;
*csqcg.trace_startsolid = tr->startsolid;
@ -2596,7 +2628,7 @@ static void QCBUILTIN PF_cs_traceline(pubprogfuncs_t *prinst, struct globalvars_
trace = World_Move (&csqc_world, v1, mins, maxs, v2, nomonsters|MOVE_IGNOREHULL, (wedict_t*)ent);
cs_settracevars(prinst, pr_globals, &trace);
cs_settracevars(prinst, &trace);
}
static void QCBUILTIN PF_cs_tracebox(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
@ -2614,7 +2646,7 @@ static void QCBUILTIN PF_cs_tracebox(pubprogfuncs_t *prinst, struct globalvars_s
trace = World_Move (&csqc_world, v1, mins, maxs, v2, nomonsters|MOVE_IGNOREHULL, (wedict_t*)ent);
cs_settracevars(prinst, pr_globals, &trace);
cs_settracevars(prinst, &trace);
}
static trace_t CS_Trace_Toss (csqcedict_t *tossent, csqcedict_t *ignore)
@ -2668,7 +2700,7 @@ static void QCBUILTIN PF_cs_tracetoss (pubprogfuncs_t *prinst, struct globalvars
trace = CS_Trace_Toss (ent, ignore);
cs_settracevars(prinst, pr_globals, &trace);
cs_settracevars(prinst, &trace);
}
static void QCBUILTIN PF_cs_pointcontents(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
@ -3116,7 +3148,29 @@ static void QCBUILTIN PF_cs_boxparticles(pubprogfuncs_t *prinst, struct globalva
float count = G_FLOAT(OFS_PARM6);
int flags = (prinst->callargc < 7)?0:G_FLOAT(OFS_PARM7);
if (flags & 128)
/* if (flags & 1) //PARTICLES_USEALPHA
{
float *alphamin = (float*)PR_FindGlobal(csqcprogs, "particles_alphamin", 0, NULL);
float *alphamax = (float*)PR_FindGlobal(csqcprogs, "particles_alphamax", 0, NULL);
if (alphamin && alphamax)
;
}
if (flags & 2) //PARTICLES_USECOLOR
{ //rgb vectors
float *colourmin = (float*)PR_FindGlobal(csqcprogs, "particles_colormin", 0, NULL);
float *colourmax = (float*)PR_FindGlobal(csqcprogs, "particles_colormax", 0, NULL);
if (colourmin && colourmax)
;
}
if (flags & 4) //PARTICLES_USEFADE
{
float *fade = (float*)PR_FindGlobal(csqcprogs, "particles_fade", 0, NULL);
if (fade)
;
}
*/
if (flags & 128) //PARTICLES_DRAWASTRAIL
{
flags &= ~128;
P_ParticleTrail(org_from, org_to, effectnum, 0, NULL, NULL);
@ -3126,8 +3180,11 @@ static void QCBUILTIN PF_cs_boxparticles(pubprogfuncs_t *prinst, struct globalva
P_RunParticleCube(effectnum, org_from, org_to, vel_from, vel_to, count, 0, true, 0);
}
if (flags)
Con_DPrintf("PF_cs_boxparticles: flags & %x is not supported\n", flags);
if (flags & ~128)
{
static float throttletimer;
Con_ThrottlePrintf(&throttletimer, 1, "PF_cs_boxparticles: flags & %x is not supported\n", flags);
}
}
static void QCBUILTIN PF_cs_pointparticles (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
@ -4852,7 +4909,7 @@ static void QCBUILTIN PF_cs_walkmove (pubprogfuncs_t *prinst, struct globalvars_
// save program state, because CS_movestep may call other progs
oldself = *csqcg.self;
G_FLOAT(OFS_RETURN) = World_movestep(&csqc_world, (wedict_t*)ent, move, axis, true, false, settrace?cs_settracevars:NULL, pr_globals);
G_FLOAT(OFS_RETURN) = World_movestep(&csqc_world, (wedict_t*)ent, move, axis, true, false, settrace?cs_settracevars:NULL);
// restore program state
*csqcg.self = oldself;
@ -5935,7 +5992,7 @@ static void QCBUILTIN PF_resourcestatus(pubprogfuncs_t *prinst, struct globalvar
else
{
if (doload && sfx->loadstate == SLS_NOTLOADED)
S_LoadSound(sfx);
S_LoadSound(sfx, true);
switch(sfx->loadstate)
{
case SLS_NOTLOADED:
@ -6805,6 +6862,8 @@ static void PDECL CSQC_EntSpawn (struct edict_s *e, int loading)
// ent->xv->dimension_ghost = 0;
ent->xv->dimension_solid = *csqcg.dimension_default;
ent->xv->dimension_hit = *csqcg.dimension_default;
ent->xv->drawflags = SCALE_ORIGIN_ORIGIN;
}
}
@ -6835,7 +6894,7 @@ static pbool QDECL CSQC_EntFree (struct edict_s *e)
return true;
}
static void QDECL CSQC_Event_Touch(world_t *w, wedict_t *s, wedict_t *o)
static void QDECL CSQC_Event_Touch(world_t *w, wedict_t *s, wedict_t *o, trace_t *trace)
{
int oself = *csqcg.self;
int oother = *csqcg.other;
@ -6968,73 +7027,91 @@ void CSQC_Shutdown(void)
}
}
//when the qclib needs a file, it calls out to this function.
void *PDECL CSQC_PRLoadFile (const char *path, unsigned char *(PDECL *buf_get)(void *ctx, size_t len), void *buf_ctx, size_t *sz, pbool issource)
static qboolean CSQC_ValidateMainCSProgs(void *file, size_t filesize, unsigned int checksum, size_t checksize)
{
if (!file)
return false;
if (checksize && filesize != checksize)
return false;
if (cls.protocol == CP_NETQUAKE && !(cls.fteprotocolextensions2 & PEXT2_PREDINFO))
{ //DP uses really lame checksums.
if (QCRC_Block(file, filesize) != checksum)
return false;
}
else
{ //FTE uses folded-md4. yeah, its broken but at least its still more awkward
if (LittleLong(Com_BlockChecksum(file, filesize)) != checksum)
return false;
}
return true;
}
static void *CSQC_FindMainProgs(size_t *sz, const char *name, unsigned int checksum, size_t checksize)
{ //returns a TempFile
char newname[MAX_QPATH];
extern cvar_t sv_demo_write_csqc;
qbyte *file = NULL;
void *file = NULL;
if (!strcmp(path, "csprogs.dat"))
//the filename we'll cache to
snprintf(newname, MAX_QPATH, "csprogsvers/%x.dat", checksum);
//we can use FSLF_IGNOREPURE because we have our own hashes/size checks instead.
//this should make it slightly easier for server admins
if (checksum)
{
char newname[MAX_QPATH];
snprintf(newname, MAX_QPATH, "csprogsvers/%x.dat", csprogs_checksum);
file = COM_LoadTempFile (newname, FSLF_IGNOREPURE, sz);
if (!CSQC_ValidateMainCSProgs(file, *sz, checksum, checksize))
file = NULL;
}
//we can use FSLF_IGNOREPURE because we have our own hashes/size checks instead.
//this should make it slightly easier for server admins
if (csprogs_checksum)
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
{
file = COM_LoadTempFile (newname, FSLF_IGNOREPURE, sz);
if (file)
if (checksum && !csprogs_promiscuous)
{
if (cls.protocol == CP_NETQUAKE && !(cls.fteprotocolextensions2 & PEXT2_PREDINFO))
{
if (QCRC_Block(file, *sz) != csprogs_checksum)
file = NULL;
}
else
{
if (LittleLong(Com_BlockChecksum(file, *sz)) != csprogs_checksum) //and the user wasn't trying to be cunning.
file = NULL;
}
}
}
if (!CSQC_ValidateMainCSProgs(file, *sz, checksum, checksize))
file = NULL;
if (!file)
{
file = COM_LoadTempFile (path, FSLF_IGNOREPURE, sz);
if (file && !cls.demoplayback) //allow them to use csprogs.dat if playing a demo, and don't care about the checksum
{
if (csprogs_checksum && !csprogs_promiscuous)
{
if (cls.protocol == CP_NETQUAKE && !(cls.fteprotocolextensions2 & PEXT2_PREDINFO))
{
if (QCRC_Block(file, *sz) != csprogs_checksum)
file = NULL;
}
else
{
if (LittleLong(Com_BlockChecksum(file, *sz)) != csprogs_checksum)
file = NULL; //not valid
}
//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.
//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
#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
}
}
}
}
return file;
}
qboolean CSQC_CheckDownload(const char *name, unsigned int checksum, size_t checksize)
{
size_t sz;
if (CSQC_FindMainProgs(&sz, name, checksum, checksize))
return true;
return false;
}
//when the qclib needs a file, it calls out to this function.
void *PDECL CSQC_PRLoadFile (const char *path, unsigned char *(PDECL *buf_get)(void *ctx, size_t len), void *buf_ctx, size_t *sz, pbool issource)
{
qbyte *file;
if (!strcmp(path, csprogs_checkname))
file = CSQC_FindMainProgs(sz, csprogs_checkname, csprogs_checksum, csprogs_checksize);
else
file = COM_LoadTempFile (path, 0, sz);
@ -7078,7 +7155,7 @@ qboolean CSQC_UnconnectedInit(void)
if (csqcprogs)
return true;
return CSQC_Init(true, true, 0);
return CSQC_Init(true, "csprogs.dat", 0, 0);
}
void ASMCALL CSQC_StateOp(pubprogfuncs_t *prinst, float var, func_t func)
{
@ -7212,27 +7289,40 @@ pbool PDECL CSQC_CheckHeaderCrc(pubprogfuncs_t *progs, progsnum_t num, int crc)
}
double csqctime;
qboolean CSQC_Init (qboolean anycsqc, qboolean csdatenabled, unsigned int checksum)
qboolean CSQC_Init (qboolean anycsqc, const char *csprogsname, unsigned int checksum, size_t progssize)
{
int i;
string_t *str;
csqcedict_t *worldent;
char *cheats;
if (csprogs_promiscuous != anycsqc || csprogs_checksum != checksum)
qboolean csdatenabled = true;
if (!csprogsname)
{
csdatenabled = false;
csprogsname = "csprogs.dat";
}
if (csprogs_promiscuous != anycsqc || csprogs_checksum != checksum || csprogs_checksize != progssize || strcmp(csprogs_checkname,csprogsname))
CSQC_Shutdown();
csprogs_promiscuous = anycsqc;
csprogs_checksum = checksum;
csprogs_checksize = progssize;
Q_strncpyz(csprogs_checkname, csprogsname, sizeof(csprogs_checkname));
csqc_mayread = false;
csqc_singlecheats = cls.demoplayback;
cheats = InfoBuf_ValueForKey(&cl.serverinfo, "*cheats");
#ifdef HAVE_SERVER
if (sv.state == ss_active)
{
cheats = InfoBuf_ValueForKey(&svs.info, "*cheats");
if (!*cheats && sv.allocated_client_slots == 1)
cheats = "ON";
}
else
#endif
cheats = InfoBuf_ValueForKey(&cl.serverinfo, "*cheats");
if (!Q_strcasecmp(cheats, "ON") || atoi(cheats))
csqc_singlecheats = true;
#ifndef CLIENTONLY
else if (sv.state == ss_active && sv.allocated_client_slots == 1)
csqc_singlecheats = true;
#endif
//its already running...
if (csqcprogs)
@ -7352,7 +7442,7 @@ qboolean CSQC_Init (qboolean anycsqc, qboolean csdatenabled, unsigned int checks
if (!csqc_nogameaccess)
{ //only load csprogs if its expected to be able to work without failing for game access reasons
csprogsnum = PR_LoadProgs(csqcprogs, "csprogs.dat");
csprogsnum = PR_LoadProgs(csqcprogs, csprogs_checkname);
if (csprogsnum >= 0)
Con_DPrintf("Loaded csprogs.dat\n");
}

View File

@ -1279,7 +1279,7 @@ void R2D_PolyBlend (void)
if (r_refdef.flags & RDF_NOWORLDMODEL)
return;
R2D_ImageColours (r_refdef.playerview->screentint[0], r_refdef.playerview->screentint[1], r_refdef.playerview->screentint[2], r_refdef.playerview->screentint[3]);
R2D_ImageColours (SRGBA(r_refdef.playerview->screentint[0], r_refdef.playerview->screentint[1], r_refdef.playerview->screentint[2], r_refdef.playerview->screentint[3]));
R2D_ScalePic(r_refdef.vrect.x, r_refdef.vrect.y, r_refdef.vrect.width, r_refdef.vrect.height, shader_polyblend);
R2D_ImageColours (1, 1, 1, 1);
}

View File

@ -405,7 +405,6 @@ static void Surf_AddDynamicLights (msurface_t *surf)
}
}
// warning: Surf_AddDynamicLightNorms defined but not used
/*
static void Surf_AddDynamicLightNorms (msurface_t *surf)
{
@ -1571,8 +1570,6 @@ static void Surf_BuildLightMap_Worker (model_t *wmodel, msurface_t *surf, qbyte
static vec3_t *blocknormals;
static unsigned int *blocklights;
//int stride = LMBLOCK_WIDTH*lightmap_bytes; //warning: unused variable stride
shift += 7; // increase to base value
surf->cached_dlight = false;

View File

@ -694,7 +694,7 @@ static void OpenAL_ChannelUpdate(soundcardinfo_t *sc, channel_t *chan, unsigned
{
if (!sfx->openal_buffer)
{
if (!S_LoadSound(sfx))
if (!S_LoadSound(sfx, false))
return; //can't load it
if (sfx->loadstate != SLS_LOADED)
{
@ -1110,24 +1110,24 @@ static void QDECL OnChangeALSettings (cvar_t *var, char *value)
switch ((enum distancemodel_e)s_al_distancemodel.ival)
{
case DM_INVERSE:
//gain = AL_REFERENCE_DISTANCE / (AL_REFERENCE_DISTANCE + AL_ROLLOFF_FACTOR * (distance AL_REFERENCE_DISTANCE) )
//gain = AL_REFERENCE_DISTANCE / (AL_REFERENCE_DISTANCE + AL_ROLLOFF_FACTOR * (distance - AL_REFERENCE_DISTANCE) )
palDistanceModel(AL_INVERSE_DISTANCE);
break;
case DM_INVERSE_CLAMPED: //openal's default mode
//istance = max(distance,AL_REFERENCE_DISTANCE);
//distance = min(distance,AL_MAX_DISTANCE);
//gain = AL_REFERENCE_DISTANCE / (AL_REFERENCE_DISTANCE + AL_ROLLOFF_FACTOR * (distance AL_REFERENCE_DISTANCE) )
//gain = AL_REFERENCE_DISTANCE / (AL_REFERENCE_DISTANCE + AL_ROLLOFF_FACTOR * (distance - AL_REFERENCE_DISTANCE) )
palDistanceModel(AL_INVERSE_DISTANCE_CLAMPED);
break;
case DM_LINEAR: //most quake-like. linear
//distance = min(distance, AL_MAX_DISTANCE) // avoid negative gain
//gain = ( 1 AL_ROLLOFF_FACTOR * (distance AL_REFERENCE_DISTANCE) / (AL_MAX_DISTANCE AL_REFERENCE_DISTANCE) )
//gain = ( 1 - AL_ROLLOFF_FACTOR * (distance - AL_REFERENCE_DISTANCE) / (AL_MAX_DISTANCE - AL_REFERENCE_DISTANCE) )
palDistanceModel(AL_LINEAR_DISTANCE);
break;
case DM_LINEAR_CLAMPED: //linear, with near stuff clamped to further away
//distance = max(distance, AL_REFERENCE_DISTANCE)
//distance = min(distance, AL_MAX_DISTANCE)
//gain = ( 1 AL_ROLLOFF_FACTOR * (distance AL_REFERENCE_DISTANCE) / (AL_MAX_DISTANCE AL_REFERENCE_DISTANCE) )
//gain = ( 1 - AL_ROLLOFF_FACTOR * (distance - AL_REFERENCE_DISTANCE) / (AL_MAX_DISTANCE - AL_REFERENCE_DISTANCE) )
palDistanceModel(AL_LINEAR_DISTANCE_CLAMPED);
break;
case DM_EXPONENT:

View File

@ -2485,7 +2485,7 @@ sfx_t *S_PrecacheSound2 (const char *name, qboolean syspath)
// cache it in
if (precache.ival && sndcardinfo)
S_LoadSound (sfx);
S_LoadSound (sfx, true);
return sfx;
}
@ -2829,7 +2829,7 @@ static void S_UpdateSoundCard(soundcardinfo_t *sc, qboolean updateonly, channel_
target_chan->entchannel = entchannel;
SND_Spatialize(sc, target_chan);
if (!S_LoadSound (sfx))
if (!S_LoadSound (sfx, false))
{
target_chan->sfx = NULL;
return; // couldn't load the sound's data
@ -3156,7 +3156,7 @@ void S_StaticSound (sfx_t *sfx, vec3_t origin, float vol, float attenuation)
}
}
if (!S_LoadSound (sfx))
if (!S_LoadSound (sfx, true))
break;
ss = &scard->channel[scard->total_chans];
@ -3476,7 +3476,7 @@ static void S_Q2_AddEntitySounds(soundcardinfo_t *sc)
if (!sfx)
continue;
if (sfx->loadstate == SLS_NOTLOADED)
S_LoadSound(sfx);
S_LoadSound(sfx, true);
if (sfx->loadstate != SLS_LOADED)
continue; //not ready yet

View File

@ -613,7 +613,7 @@ static qboolean ResampleSfx (sfx_t *sfx, int inrate, int inchannels, int inwidth
#define DSPK_EXP 0.0433
/*
qboolean QDECL S_LoadDoomSpeakerSound (sfx_t *s, qbyte *data, size_t datalen, int sndspeed)
qboolean QDECL S_LoadDoomSpeakerSound (sfx_t *s, qbyte *data, size_t datalen, int sndspeed, qboolean forcedecode)
{
sfxcache_t *sc;
@ -689,7 +689,7 @@ qboolean QDECL S_LoadDoomSpeakerSound (sfx_t *s, qbyte *data, size_t datalen, in
return sc;
}
*/
static qboolean QDECL S_LoadDoomSound (sfx_t *s, qbyte *data, size_t datalen, int sndspeed)
static qboolean QDECL S_LoadDoomSound (sfx_t *s, qbyte *data, size_t datalen, int sndspeed, qboolean forcedecode)
{
// format data from Unofficial Doom Specs v1.6
unsigned short *dataus;
@ -731,7 +731,7 @@ void S_ShortedLittleFloats(void *p, size_t samples)
}
}
static qboolean QDECL S_LoadWavSound (sfx_t *s, qbyte *data, size_t datalen, int sndspeed)
static qboolean QDECL S_LoadWavSound (sfx_t *s, qbyte *data, size_t datalen, int sndspeed, qboolean forcedecode)
{
wavinfo_t info;
@ -772,11 +772,11 @@ static qboolean QDECL S_LoadWavSound (sfx_t *s, qbyte *data, size_t datalen, int
return ResampleSfx (s, info.rate, info.numchannels, info.width, info.samples, info.loopstart, data + info.dataofs);
}
qboolean QDECL S_LoadOVSound (sfx_t *s, qbyte *data, size_t datalen, int sndspeed);
qboolean QDECL S_LoadOVSound (sfx_t *s, qbyte *data, size_t datalen, int sndspeed, qboolean forcedecode);
#ifdef FTE_TARGET_WEB
//web browsers contain their own decoding libraries that our openal stuff can use.
static qboolean QDECL S_LoadBrowserFile (sfx_t *s, qbyte *data, size_t datalen, int sndspeed)
static qboolean QDECL S_LoadBrowserFile (sfx_t *s, qbyte *data, size_t datalen, int sndspeed, qboolean forcedecode)
{
sfxcache_t *sc;
s->decoder.buf = sc = BZ_Malloc(sizeof(sfxcache_t) + datalen);
@ -834,7 +834,7 @@ S_LoadSound
==============
*/
static void S_LoadSoundWorker (void *ctx, void *ctxdata, size_t a, size_t b)
static void S_LoadSoundWorker (void *ctx, void *ctxdata, size_t forcedecode, size_t b)
{
sfx_t *s = ctx;
char namebuffer[256];
@ -920,7 +920,7 @@ static void S_LoadSoundWorker (void *ctx, void *ctxdata, size_t a, size_t b)
data = FS_LoadMallocFile(namebuffer, &filesize);
if (data)
{
Con_DPrintf("found a mangled name: %s\n", namebuffer);
Con_DPrintf("S_LoadSound: %s%s requested, but could only find %s\n", prefixes[pre], name, namebuffer);
break;
}
}
@ -942,7 +942,7 @@ static void S_LoadSoundWorker (void *ctx, void *ctxdata, size_t a, size_t b)
{
if (AudioInputPlugins[i])
{
if (AudioInputPlugins[i](s, data, filesize, snd_speed))
if (AudioInputPlugins[i](s, data, filesize, snd_speed, forcedecode))
{
//wake up the main thread in case it decided to wait for us.
COM_AddWork(WG_MAIN, S_LoadedOrFailed, s, NULL, SLS_LOADED, 0);
@ -960,12 +960,12 @@ static void S_LoadSoundWorker (void *ctx, void *ctxdata, size_t a, size_t b)
return;
}
qboolean S_LoadSound (sfx_t *s)
qboolean S_LoadSound (sfx_t *s, qboolean force)
{
if (s->loadstate == SLS_NOTLOADED && sndcardinfo)
{
s->loadstate = SLS_LOADING;
COM_AddWork(WG_LOADER, S_LoadSoundWorker, s, NULL, 0, 0);
COM_AddWork(WG_LOADER, S_LoadSoundWorker, s, NULL, force, 0);
}
if (s->loadstate == SLS_FAILED)
return false; //it failed to load once before, don't bother trying again.

View File

@ -62,6 +62,7 @@ typedef struct {
int srcspeed;
int srcchannels;
qboolean nopurge;
qboolean failed;
char *tempbuffer;
@ -79,52 +80,7 @@ typedef struct {
sfx_t *s;
} ovdecoderbuffer_t;
float QDECL OV_Query(struct sfx_s *sfx, struct sfxcache_s *buf, char *name, size_t namesize);
static sfxcache_t *QDECL OV_DecodeSome(struct sfx_s *sfx, struct sfxcache_s *buf, ssamplepos_t start, int length);
static void QDECL OV_CancelDecoder(sfx_t *s);
static qboolean OV_StartDecode(unsigned char *start, unsigned long length, ovdecoderbuffer_t *buffer);
qboolean QDECL S_LoadOVSound (sfx_t *s, qbyte *data, size_t datalen, int sndspeed)
{
ovdecoderbuffer_t *buffer;
if (datalen < 4 || strncmp(data, "OggS", 4))
return false;
buffer = Z_Malloc(sizeof(ovdecoderbuffer_t));
buffer->decodedbytestart = 0;
buffer->decodedbytecount = 0;
buffer->s = s;
s->decoder.buf = buffer;
s->loopstart = -1;
if (!OV_StartDecode(data, datalen, buffer))
{
if (buffer->decodedbuffer)
{
BZ_Free(buffer->decodedbuffer);
buffer->decodedbuffer = NULL;
}
buffer->decodedbufferbytes = 0;
buffer->decodedbytestart = 0;
buffer->decodedbytecount = 0;
Z_Free(s->decoder.buf);
s->decoder.buf = NULL;
s->loadstate = SLS_FAILED; //failed!
return false;
}
s->decoder.decodedata = OV_DecodeSome;
s->decoder.querydata = OV_Query;
s->decoder.purge = OV_CancelDecoder;
s->decoder.ended = OV_CancelDecoder;
s->decoder.decodedata(s, NULL, 0, 100);
return true;
}
float QDECL OV_Query(struct sfx_s *sfx, struct sfxcache_s *buf, char *name, size_t namesize)
static float QDECL OV_Query(struct sfx_s *sfx, struct sfxcache_s *buf, char *name, size_t namesize)
{
ovdecoderbuffer_t *dec = sfx->decoder.buf;
if (!dec)
@ -206,7 +162,7 @@ static sfxcache_t *QDECL OV_DecodeSome(struct sfx_s *sfx, struct sfxcache_s *buf
p_ov_pcm_seek(&dec->vf, (dec->decodedbytestart * dec->srcspeed) / outspeed);
}
*/
if (dec->decodedbytecount > outspeed*8)
if (dec->decodedbytecount > outspeed*8 && !dec->nopurge)
{
/*everything is okay, but our buffer is getting needlessly large.
keep anything after the 'new' position, but discard all before that
@ -329,7 +285,7 @@ static sfxcache_t *QDECL OV_DecodeSome(struct sfx_s *sfx, struct sfxcache_s *buf
s->loadstate = SLS_NOTLOADED;
}*/
static void QDECL OV_CancelDecoder(sfx_t *s)
{
{ //called when the sound is unloaded. the entire thing is going away.
ovdecoderbuffer_t *dec;
s->loadstate = SLS_FAILED;
@ -358,6 +314,26 @@ static void QDECL OV_CancelDecoder(sfx_t *s)
// COM_AddWork(WG_MAIN, OV_CanceledDecoder, s, NULL, SLS_NOTLOADED, 0);
s->loadstate = SLS_NOTLOADED;
}
static void QDECL OV_ClearDecoder(sfx_t *s)
{ //called when the sound is no longer playing.
ovdecoderbuffer_t *dec;
dec = s->decoder.buf;
if (dec->nopurge)
{
/* BZ_Free(dec->tempbuffer);
dec->tempbuffer = NULL;
dec->tempbufferbytes = 0;
BZ_Free(dec->decodedbuffer);
dec->decodedbuffer = NULL;
dec->decodedbufferbytes = 0;
dec->decodedbytestart = 0;
dec->decodedbytecount = 0;
*/
return;
}
OV_CancelDecoder(s);
}
static size_t VARGS read_func (void *ptr, size_t size, size_t nmemb, void *datasource)
{
@ -515,5 +491,48 @@ static qboolean OV_StartDecode(unsigned char *start, unsigned long length, ovdec
return true;
}
qboolean QDECL S_LoadOVSound (sfx_t *s, qbyte *data, size_t datalen, int sndspeed, qboolean forcedecode)
{
ovdecoderbuffer_t *buffer;
if (datalen < 4 || strncmp(data, "OggS", 4))
return false;
buffer = Z_Malloc(sizeof(ovdecoderbuffer_t));
buffer->decodedbytestart = 0;
buffer->decodedbytecount = 0;
buffer->nopurge = forcedecode;
buffer->s = s;
s->decoder.buf = buffer;
s->loopstart = -1;
if (!OV_StartDecode(data, datalen, buffer))
{
if (buffer->decodedbuffer)
{
BZ_Free(buffer->decodedbuffer);
buffer->decodedbuffer = NULL;
}
buffer->decodedbufferbytes = 0;
buffer->decodedbytestart = 0;
buffer->decodedbytecount = 0;
Z_Free(s->decoder.buf);
s->decoder.buf = NULL;
s->loadstate = SLS_FAILED; //failed!
return false;
}
s->decoder.decodedata = OV_DecodeSome;
s->decoder.querydata = OV_Query;
s->decoder.purge = OV_CancelDecoder;
s->decoder.ended = OV_ClearDecoder;
s->decoder.decodedata(s, NULL, 0, 100);
return true;
}
#endif

View File

@ -326,9 +326,9 @@ extern int snd_blocked;
void S_LocalSound (const char *s);
void S_LocalSound2 (const char *sound, int channel, float volume);
qboolean S_LoadSound (sfx_t *s);
qboolean S_LoadSound (sfx_t *s, qboolean forcedecode);
typedef qboolean (QDECL *S_LoadSound_t) (sfx_t *s, qbyte *data, size_t datalen, int sndspeed);
typedef qboolean (QDECL *S_LoadSound_t) (sfx_t *s, qbyte *data, size_t datalen, int sndspeed, qboolean forcedecode);
qboolean S_RegisterSoundInputPlugin(S_LoadSound_t loadfnc); //called to register additional sound input plugins
void S_AmbientOff (void);

View File

@ -548,6 +548,10 @@ int Sys_EnumerateFiles2 (const char *truepath, int apathofs, const char *match,
break;
if (*ent->d_name != '.')
{
#ifdef _DIRENT_HAVE_D_TYPE
if (ent->d_type != DT_DIR && ent->d_type != DT_UNKNOWN)
continue;
#endif
if (wildcmp(subdir, ent->d_name))
{
memcpy(file, truepath, wild-truepath);

View File

@ -204,30 +204,33 @@ static void Con_Editor_DeleteSelection(console_t *con)
{
conline_t *n;
con->flags &= ~CONF_KEEPSELECTION;
if (con->selstartline == con->selendline)
if (con->selstartline)
{
memmove((conchar_t*)(con->selstartline+1)+con->selstartoffset, (conchar_t*)(con->selendline+1)+con->selendoffset, sizeof(conchar_t)*(con->selendline->length - con->selendoffset));
con->selendline->length = con->selstartoffset + (con->selendline->length - con->selendoffset);
}
else
{
con->selstartline->length = con->selstartoffset;
for(n = con->selstartline;;)
if (con->selstartline == con->selendline)
{
n = n->newer;
if (!n)
break; //shouldn't happen
if (n == con->selendline)
memmove((conchar_t*)(con->selstartline+1)+con->selstartoffset, (conchar_t*)(con->selendline+1)+con->selendoffset, sizeof(conchar_t)*(con->selendline->length - con->selendoffset));
con->selendline->length = con->selstartoffset + (con->selendline->length - con->selendoffset);
}
else
{
con->selstartline->length = con->selstartoffset;
for(n = con->selstartline;;)
{
//this is the last line, we need to keep the end of the string but not the start.
memmove(n+1, (conchar_t*)(n+1)+con->selendoffset, sizeof(conchar_t)*(n->length - con->selendoffset));
n->length = n->length - con->selendoffset;
n = n->newer;
if (!n)
break; //shouldn't happen
if (n == con->selendline)
{
//this is the last line, we need to keep the end of the string but not the start.
memmove(n+1, (conchar_t*)(n+1)+con->selendoffset, sizeof(conchar_t)*(n->length - con->selendoffset));
n->length = n->length - con->selendoffset;
n = Con_EditorMerge(con, con->selstartline, n);
break;
}
//truncate and merge
n->length = 0;
n = Con_EditorMerge(con, con->selstartline, n);
break;
}
//truncate and merge
n->length = 0;
n = Con_EditorMerge(con, con->selstartline, n);
}
}
con->userline = con->selstartline;

View File

@ -745,8 +745,6 @@ static char *Macro_demoplayback (void)
{
switch (cls.demoplayback)
{
case DPB_EZTV: // warning: enumeration value DPB_EZTV not handled in switch
break;
case DPB_NONE:
return "0";
case DPB_QUAKEWORLD:
@ -761,7 +759,10 @@ static char *Macro_demoplayback (void)
case DPB_QUAKE2:
return "dm2playback";
#endif
//gcc will warn if we add annother playback and forget here, otherwise I'd use a default.
case DPB_EZTV:
break;
}
return "1"; //unknown.
}

View File

@ -361,6 +361,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#if defined(SERVERONLY) && defined(CLIENTONLY)
#undef CLIENTONLY //impossible build. assume the config had CLIENTONLY and they tried building a dedicated server
#endif
#ifndef CLIENTONLY
#define HAVE_SERVER
#endif
#ifndef SERVERONLY
#define HAVE_CLIENT
#endif
//software rendering is just too glitchy, don't use it - unless its the only choice.
#if defined(SWQUAKE) && !defined(_DEBUG) && !defined(__DJGPP__)
@ -1067,6 +1073,7 @@ STAT_PUNCHVECTOR_X = 29,
STAT_PUNCHVECTOR_Y = 30,
STAT_PUNCHVECTOR_Z = 31,
#ifdef HEXEN2
//these stats are used only when running a hexen2 mod/hud, and will never be used for a quake mod/hud/generic code.
STAT_H2_LEVEL = 32, // changes stat bar
STAT_H2_INTELLIGENCE, // changes stat bar
@ -1123,7 +1130,7 @@ STAT_H2_PLAYERCLASS,
STAT_H2_OBJECTIVE1, //integer
STAT_H2_OBJECTIVE2, //integer
#endif
STAT_MOVEVARS_AIRACCEL_QW_STRETCHFACTOR = 220, // DP
STAT_MOVEVARS_AIRCONTROL_PENALTY = 221, // DP

View File

@ -369,7 +369,7 @@ typedef struct q2miptex_s
// upper design bounds
// leaffaces, leafbrushes, planes, and verts are still bounded by
// 16 bit short limits
#define SANITY_MAX_Q2MAP_MODELS 1024
#define SANITY_MAX_Q2MAP_MODELS MAX_PRECACHE_MODELS
//#define MAX_Q2MAP_ENTITIES 2048
#define SANITY_MAX_MAP_BRUSHES (~0u/sizeof(*out))
#define SANITY_MAX_MAP_LEAFFACES 262144 //sanity only
@ -378,11 +378,7 @@ typedef struct q2miptex_s
#define MAX_Q2MAP_AREAPORTALS 1024
//#define MAX_Q2MAP_VERTS MAX_MAP_VERTS
//#define MAX_Q2MAP_FACES MAX_MAP_FACES
#ifdef FTE_TARGET_WEB
#define MAX_Q2MAP_LEAFBRUSHES (32768) //used in an array
#else
#define MAX_Q2MAP_LEAFBRUSHES (65536*2) //used in an array
#endif
#define SANITY_MAX_MAP_LEAFBRUSHES (65536*64) //used in an array
//#define MAX_Q2MAP_PORTALS 65536 //unused
//#define MAX_Q2MAP_EDGES 128000 //unused
//#define MAX_Q2MAP_SURFEDGES 256000 //unused

View File

@ -707,7 +707,7 @@ void Cmd_Exec_f (void)
return;
}
if (!FS_FLocateFile(name, FSLF_IFFOUND, &loc) && !FS_FLocateFile(va("%s.cfg", name), FSLF_IFFOUND, &loc))
if (!FS_FLocateFile(name, FSLF_IFFOUND|FSLF_IGNOREPURE, &loc) && !FS_FLocateFile(va("%s.cfg", name), FSLF_IFFOUND, &loc))
{
Con_TPrintf ("couldn't exec %s\n", name);
return;
@ -721,9 +721,9 @@ void Cmd_Exec_f (void)
if (cl_warncmd.ival || developer.ival || cvar_watched)
{
if (loc.search)
Con_TPrintf ("execing %s/%s\n",name, loc.search->logicalpath);
Con_TPrintf ("execing ^[^7%s\\tip\\from %s/%s^]\n", name, loc.search->logicalpath, name);
else
Con_TPrintf ("execing %s\n",name);
Con_TPrintf ("execing %s\n", name);
}
l = VFS_GETLEN(file);

View File

@ -1002,8 +1002,8 @@ typedef struct
skeltype_t skeltype; //the skeletal type of this bone block. all blocks should have the same result or the whole thing is unusable or whatever.
int firstbone; //first bone of interest
int endbone; //the first bone of the next group (ie: if first is 0, this is the count)
float frac[8]; //weight of this animation (1 if lerpcount is 1)
float *pose[8]; //pointer to the raw frame data for bone 0.
float frac[FRAME_BLENDS*2]; //weight of this animation (1 if lerpcount is 1)
float *pose[FRAME_BLENDS*2]; //pointer to the raw frame data for bone 0.
int lerpcount; //number of pose+frac entries.
} skellerps_t;
static qboolean Alias_BuildSkelLerps(skellerps_t *lerps, struct framestateregion_s *fs, int numbones, galiasinfo_t *inf)
@ -1249,9 +1249,6 @@ const float *Alias_GetBoneInformation(galiasinfo_t *inf, framestate_t *framestat
endbone = lerp->endbone;
switch(lerp->lerpcount)
{
case 1://no blend required, data can be used as-is, once merged with the other bone groups, anyway.
memcpy(targetbuffer+bone*12, lerp->pose[0]+bone*12, (endbone-bone)*12*sizeof(float));
break;
case 2:
{
int k;
@ -1291,6 +1288,32 @@ const float *Alias_GetBoneInformation(galiasinfo_t *inf, framestate_t *framestat
}
}
break;
case 0:
case 1: //the weight will usually be 1, which won't take this path.
default:
{ //the generic slow path.
int k, i, b;
float *out, *pose, frac;
for (i = 0; i < lerp->lerpcount; i++)
{
out = targetbuffer + bone*12;
pose = lerp->pose[i] + bone*12;
frac = lerp->frac[i];
if (!i)
{ //first influence shouldn't add, saving us a memcpy.
for (b = bone; b < endbone; b++, out+=12, pose+=12)
for (k = 0; k < 12; k++)
out[k] = (pose[k]*frac);
}
else
{
for (b = bone; b < endbone; b++, out+=12, pose+=12)
for (k = 0; k < 12; k++)
out[k] += (pose[k]*frac);
}
}
}
break;
}
}
@ -1681,7 +1704,7 @@ qboolean Alias_GAliasBuildMesh(mesh_t *mesh, vbo_t **vbop, galiasinfo_t *inf, in
meshcache.ent = e;
#ifdef _DEBUG
#if defined(_DEBUG) && FRAME_BLENDS == 4
if (!e->framestate.g[FS_REG].lerpweight[0] && !e->framestate.g[FS_REG].lerpweight[1] && !e->framestate.g[FS_REG].lerpweight[2] && !e->framestate.g[FS_REG].lerpweight[3])
Con_Printf("Entity with no lerp info\n");
#endif
@ -1817,6 +1840,12 @@ qboolean Alias_GAliasBuildMesh(mesh_t *mesh, vbo_t **vbop, galiasinfo_t *inf, in
float lerp;
float fg1time;
//float fg2time;
static float printtimer;
#if FRAME_BLENDS != 2
if (e->framestate.g[FS_REG].lerpweight[2] || e->framestate.g[FS_REG].lerpweight[3])
Con_ThrottlePrintf(&printtimer, 1, "Alias_GAliasBuildMesh(%s): non-skeletal animation only supports two animations\n", e->model->name);
#endif
//FIXME: replace most of this logic with Alias_BuildSkelLerps
@ -1828,22 +1857,22 @@ qboolean Alias_GAliasBuildMesh(mesh_t *mesh, vbo_t **vbop, galiasinfo_t *inf, in
if (frame1 < 0)
{
Con_DPrintf("Negative frame (%s)\n", e->model->name);
Con_ThrottlePrintf(&printtimer, 1, "Negative frame (%s)\n", e->model->name);
frame1 = 0;
}
if (frame2 < 0)
{
Con_DPrintf("Negative frame (%s)\n", e->model->name);
Con_ThrottlePrintf(&printtimer, 1, "Negative frame (%s)\n", e->model->name);
frame2 = frame1;
}
if (frame1 >= inf->numanimations)
{
Con_DPrintf("Too high frame %i (%s)\n", frame1, e->model->name);
Con_ThrottlePrintf(&printtimer, 1, "Too high frame %i (%s)\n", frame1, e->model->name);
frame1 %= inf->numanimations;
}
if (frame2 >= inf->numanimations)
{
Con_DPrintf("Too high frame %i (%s)\n", frame2, e->model->name);
Con_ThrottlePrintf(&printtimer, 1, "Too high frame %i (%s)\n", frame2, e->model->name);
frame2 %= inf->numanimations;
}
@ -1857,7 +1886,7 @@ qboolean Alias_GAliasBuildMesh(mesh_t *mesh, vbo_t **vbop, galiasinfo_t *inf, in
if (!inf->numanimations || !g1->numposes || !g2->numposes)
{
Con_Printf("Invalid animation data on entity with model %s\n", e->model->name);
Con_ThrottlePrintf(&printtimer, 1, "Invalid animation data on entity with model %s\n", e->model->name);
//no animation data. panic!
memset(mesh, 0, sizeof(*mesh));
*vbop = NULL;
@ -4508,6 +4537,14 @@ qboolean Mod_GetTag(model_t *model, int tagnum, framestate_t *fstate, float *res
//float f1time, f2time; //tags/md3s don't support framegroups.
float f2ness;
#if FRAME_BLENDS != 2
if (fstate->g[FS_REG].lerpweight[2] || fstate->g[FS_REG].lerpweight[3])
{
static float printtimer;
Con_ThrottlePrintf(&printtimer, 1, "Mod_GetTag(%s): non-skeletal animation only supports two animations\n", model->name);
}
#endif
frame1 = fstate->g[FS_REG].frame[0];
frame2 = fstate->g[FS_REG].frame[1];
//f1time = fstate->g[FS_REG].frametime[0];

View File

@ -227,6 +227,7 @@ void VARGS Con_Printf (const char *fmt, ...) LIKEPRINTF(1);
void VARGS Con_TPrintf (translation_t text, ...);
void VARGS Con_DPrintf (const char *fmt, ...) LIKEPRINTF(1); //developer>=1, for stuff that's probably actually slightly useful
void VARGS Con_DLPrintf (int level, const char *fmt, ...) LIKEPRINTF(2); //developer>=2, for spammy stuff
void VARGS Con_ThrottlePrintf (float *timer, int developerlevel, const char *fmt, ...); //for spammed warnings, so they don't spam prints with every single frame/call. the timer arg should be a static local.
void VARGS Con_SafePrintf (const char *fmt, ...) LIKEPRINTF(1);
void Con_Footerf(console_t *con, qboolean append, const char *fmt, ...) LIKEPRINTF(3);
void Con_Clear_f (void);

View File

@ -3201,6 +3201,8 @@ void QDECL Q_strnlowercatz(char *d, const char *s, int n)
*d = 0;
}
//pname must be of the form "gamedir/foo.pk3"
//as a special exception, we allow "downloads/*.pk3 too"
qboolean FS_GenCachedPakName(const char *pname, const char *crc, char *local, int llen)
{
const char *fn;
@ -3227,7 +3229,7 @@ qboolean FS_GenCachedPakName(const char *pname, const char *crc, char *local, in
}
}
// fn = COM_SkipPath(pname);
if (fn == pname)
if (fn == pname || !*fn)
{ //only allow it if it has some game path first.
*local = 0;
return false;
@ -3531,6 +3533,7 @@ void FS_PureMode(int puremode, char *purenamelist, char *purecrclist, char *refn
#ifndef SERVERONLY
int FS_PureOkay(void)
{
qboolean ret = true;
//returns true if all pure packages that we're meant to need could load.
//if they couldn't then they won't override things, or the game will just be completely screwed due to having absolutely no game data
if (fs_puremode == 1 && fs_purenames && *fs_purenames && fs_purecrcs && *fs_purecrcs)
@ -3595,14 +3598,13 @@ int FS_PureOkay(void)
if (!CL_CheckDLFile(va("package/%s", pname)))
if (CL_CheckOrEnqueDownloadFile(va("package/%s", pname), va("%s.%i", pname, crc), DLLF_NONGAME))
return -1;
Con_Printf(CON_ERROR"Pure package %s:%i missing.\n", pname, crc);
return false;
Con_Printf(CON_ERROR"Pure package %s:%08x missing.\n", pname, crc);
ret = false;
}
}
return true;
}
return true;
return ret;
}
#endif
@ -3825,8 +3827,10 @@ void FS_ReloadPackFilesFlags(unsigned int reloadflags)
names = COM_ParseOut(names, nametok, sizeof(nametok));
crc = strtoul(crctok, NULL, 0);
if (!crc)
if (!*crctok)
continue;
if (!strcmp(crctok, "-"))
*crctok = 0;
pname = nametok;
@ -3855,7 +3859,8 @@ void FS_ReloadPackFilesFlags(unsigned int reloadflags)
for (sp = com_searchpaths; sp; sp = sp->next)
{
if (sp->nextpure == (void*)0x1) //don't add twice.
if (sp->crc_check == crc)
if ((*crctok && sp->crc_check == crc) ||
(!*crctok && !strcmp(COM_SkipPath(sp->purepath), COM_SkipPath(pname))))
{
if (fs_puremode)
{
@ -3888,14 +3893,19 @@ void FS_ReloadPackFilesFlags(unsigned int reloadflags)
int i;
COM_FileExtension(pname, ext, sizeof(ext));
if (FS_GenCachedPakName(pname, va("%i", crc), local, sizeof(local)))
if (FS_GenCachedPakName(pname, crctok, local, sizeof(local)))
{
unsigned int keptflags;
handle = FS_GetOldPath(&oldpaths, local, &keptflags);
if (handle)
{
sp = FS_AddPathHandle(&oldpaths, pname, local, handle, "", SPF_COPYPROTECTED|SPF_UNTRUSTED|SPF_TEMPORARY|keptflags, (unsigned int)-1);
if (sp->crc_check == crc)
if (sp->handle->GeneratePureCRC)
{
sp->crc_check = sp->handle->GeneratePureCRC(sp->handle, fs_pureseed, 0);
sp->crc_reply = sp->handle->GeneratePureCRC(sp->handle, fs_pureseed, 1);
}
if (sp->crc_check == crc || !*crctok)
{
if (fs_puremode)
{
@ -3925,11 +3935,13 @@ void FS_ReloadPackFilesFlags(unsigned int reloadflags)
if (!handle)
break;
sp = FS_AddPathHandle(&oldpaths, pname, local, handle, "", SPF_COPYPROTECTED|SPF_UNTRUSTED|SPF_TEMPORARY, (unsigned int)-1);
if (sp->handle->GeneratePureCRC)
{
sp->crc_check = sp->handle->GeneratePureCRC(sp->handle, fs_pureseed, 0);
sp->crc_reply = sp->handle->GeneratePureCRC(sp->handle, fs_pureseed, 1);
}
sp->crc_check = sp->handle->GeneratePureCRC(sp->handle, fs_pureseed, 0);
sp->crc_reply = sp->handle->GeneratePureCRC(sp->handle, fs_pureseed, 1);
if (sp->crc_check == crc)
if (!*crctok)
{
if (fs_puremode)
{
@ -3947,7 +3959,7 @@ void FS_ReloadPackFilesFlags(unsigned int reloadflags)
}
if (!sp)
Con_DPrintf("Pure package %s:%i wasn't found\n", pname, crc);
Con_DPrintf("Pure package %s:%08x wasn't found\n", pname, crc);
}
}
}
@ -5198,11 +5210,10 @@ void FS_BeginManifestUpdates(void)
qboolean FS_FoundManifest(void *usr, ftemanifest_t *man)
{
if (!*(ftemanifest_t**)usr)
{
*(ftemanifest_t**)usr = man;
return true;
}
return false;
else
FS_Manifest_Free(man);
return true;
}
//reads the default manifest based upon the basedir, the commandline arguments, the name of the exe, etc.
@ -5366,7 +5377,7 @@ qboolean FS_ChangeGame(ftemanifest_t *man, qboolean allowreloadconfigs, qboolean
{
if (allowreloadconfigs)
{
FS_FLocateFile(conffile[i], FSLF_IFFOUND, &loc); //q1
FS_FLocateFile(conffile[i], FSLF_IFFOUND|FSLF_IGNOREPURE, &loc); //q1
confpath[i] = loc.search?loc.search->handle:NULL;
}
else
@ -5409,9 +5420,12 @@ qboolean FS_ChangeGame(ftemanifest_t *man, qboolean allowreloadconfigs, qboolean
//if we're a client, display a menu to pick between them (or display an error)
//servers can just use the first they find, they'd effectively just crash otherwise, but still give a warning.
if (!isDedicated)
{
FS_Manifest_Free(man);
man = NULL;
}
else if (found)
Con_Printf(CON_WARNING "Warning: found multiple possible games. Using the first found.\n");
Con_Printf(CON_WARNING "Warning: found multiple possible games. Using the first found (%s).\n", man->formalname);
else
Con_Printf(CON_ERROR "Error: unable to determine correct game/basedir.\n");
}
@ -5610,7 +5624,7 @@ qboolean FS_ChangeGame(ftemanifest_t *man, qboolean allowreloadconfigs, qboolean
{
for (i = 0; i < countof(conffile); i++)
{
FS_FLocateFile(conffile[i], FSLF_IFFOUND, &loc);
FS_FLocateFile(conffile[i], FSLF_IFFOUND|FSLF_IGNOREPURE, &loc);
if (confpath[i] != (loc.search?loc.search->handle:NULL))
{
reloadconfigs = true;
@ -5756,6 +5770,7 @@ static int QDECL FS_EnumerateFMFs(const char *fname, qofs_t fsize, time_t mtime,
return true;
}
//callback must call FS_Manifest_Free.
int FS_EnumerateKnownGames(qboolean (*callback)(void *usr, ftemanifest_t *man), void *usr)
{
int i;
@ -5787,6 +5802,15 @@ int FS_EnumerateKnownGames(qboolean (*callback)(void *usr, ftemanifest_t *man),
if (!e.found)
Sys_EnumerateFiles(host_parms.basedir, "*.fmf", FS_EnumerateFMFs, &e, NULL);
if (!e.found)
{
if (*com_homepath)
Sys_EnumerateFiles(NULL, va("%s/*.fmf", com_homepath), FS_EnumerateFMFs, &e, NULL);
#ifdef __linux__
Sys_EnumerateFiles(NULL, "/etc/fte/*.fmf", FS_EnumerateFMFs, &e, NULL);
#endif
}
//right, no fmf files anywhere.
//just make stuff up from whatever games they may have installed on their system.
if (!e.found)
@ -6251,6 +6275,12 @@ void COM_InitFilesystem (void)
com_homepathusable = usehome;
com_homepathenabled = false;
i = COM_CheckParm("-homedir");
if (i && i+1<com_argc)
{ //explicitly override the homedir.
Q_strncpyz(com_homepath, com_argv[i+1], sizeof(com_homepath));
com_homepathusable = true;
}
if (COM_CheckParm("-usehome"))
com_homepathusable = true;
if (COM_CheckParm("-nohome"))

View File

@ -339,7 +339,7 @@ typedef struct cminfo_s
q2mapsurface_t *surfaces;
int numleafbrushes;
q2cbrush_t *leafbrushes[MAX_Q2MAP_LEAFBRUSHES];
q2cbrush_t **leafbrushes;
int numcmodels;
cmodel_t *cmodels;
@ -1865,13 +1865,14 @@ static qboolean CModQ2_LoadLeafBrushes (model_t *mod, qbyte *mod_base, lump_t *l
return false;
}
// need to save space for box planes
if (count > MAX_Q2MAP_LEAFBRUSHES)
if (count > SANITY_MAX_MAP_LEAFBRUSHES)
{
Con_Printf (CON_ERROR "Map has too many leafbrushes\n");
return false;
}
out = prv->leafbrushes;
//prv->numbrushes is because of submodels being weird.
out = prv->leafbrushes = ZG_Malloc(&mod->memgroup, sizeof(*out) * (count+prv->numbrushes));
prv->numleafbrushes = count;
for ( i=0 ; i<count ; i++, in++, out++)
@ -3206,7 +3207,7 @@ static qboolean CModQ3_LoadLeafs (model_t *mod, qbyte *mod_base, lump_t *l)
mleaf_t *out;
q3dleaf_t *in;
int count;
q2cbrush_t *brush;
q2cbrush_t **brush;
in = (void *)(mod_base + l->fileofs);
if (l->filelen % sizeof(*in))
@ -3258,10 +3259,10 @@ static qboolean CModQ3_LoadLeafs (model_t *mod, qbyte *mod_base, lump_t *l)
out->nummarksurfaces = 0;
}
brush = &prv->leafbrushes[out->firstleafbrush];
for (j=0 ; j<out->numleafbrushes ; j++)
{
brush = prv->leafbrushes[out->firstleafbrush + j];
out->contents |= brush->contents;
out->contents |= brush[j]->contents;
}
if (out->area >= prv->numareas)
@ -3333,17 +3334,18 @@ static qboolean CModQ3_LoadLeafBrushes (model_t *mod, qbyte *mod_base, lump_t *l
return false;
}
// need to save space for box planes
if (count > MAX_Q2MAP_LEAFBRUSHES)
if (count > SANITY_MAX_MAP_LEAFBRUSHES)
{
Con_Printf (CON_ERROR "Map has too many leafbrushes\n");
return false;
}
out = prv->leafbrushes;
//prv->numbrushes is because of submodels being weird.
out = prv->leafbrushes = ZG_Malloc(&mod->memgroup, sizeof(*out) * (count+prv->numbrushes));
prv->numleafbrushes = count;
for ( i=0 ; i<count ; i++, in++, out++)
*out = prv->brushes + LittleLong (*in);
*out = prv->brushes + (unsigned int)LittleLong (*in);
return true;
}

View File

@ -25,6 +25,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define HAVE_WEBSOCKCL
#endif
#ifdef __linux__
//#define UNIXSOCKETS
#endif
//FIXME: should split this into loopback/dgram/stream/dtls/tls/irc
//with the ipv4/v6/x as a separate parameter
typedef enum {
@ -34,6 +38,9 @@ typedef enum {
NA_IP,
NA_IPV6,
NA_IPX,
#ifdef UNIXSOCKETS
NA_UNIX,
#endif
#ifdef IRCCONNECT
NA_IRC/*remove!*/,
#endif
@ -48,7 +55,9 @@ typedef enum {
NP_TLS,
NP_WS,
NP_WSS,
NP_NATPMP
NP_NATPMP, //server-only scheme for registering public ports.
NP_INVALID
} netproto_t;
typedef enum {NS_CLIENT, NS_SERVER} netsrc_t;
@ -71,6 +80,13 @@ typedef struct
#endif
#ifdef HAVE_WEBSOCKCL
char websocketurl[64];
#endif
#ifdef UNIXSOCKETS
struct
{
int len; //abstract addresses contain nulls, so this is needed.
char path[108];
} un;
#endif
} address;
@ -126,7 +142,7 @@ neterr_t NET_SendPacket (netsrc_t socket, int length, const void *data, netadr_t
int NET_LocalAddressForRemote(struct ftenet_connections_s *collection, netadr_t *remote, netadr_t *local, int idx);
void NET_PrintAddresses(struct ftenet_connections_s *collection);
qboolean NET_AddressSmellsFunny(netadr_t *a);
qboolean NET_EnsureRoute(struct ftenet_connections_s *collection, char *routename, char *host);
qboolean NET_EnsureRoute(struct ftenet_connections_s *collection, char *routename, char *host, netadr_t *adr);
void NET_PrintConnectionsStatus(struct ftenet_connections_s *collection);
enum addressscope_e
@ -143,10 +159,10 @@ qboolean NET_CompareAdr (netadr_t *a, netadr_t *b);
qboolean NET_CompareBaseAdr (netadr_t *a, netadr_t *b);
void NET_AdrToStringResolve (netadr_t *adr, void (*resolved)(void *ctx, void *data, size_t a, size_t b), void *ctx, size_t a, size_t b);
char *NET_AdrToString (char *s, int len, netadr_t *a);
char *NET_SockadrToString (char *s, int len, struct sockaddr_qstorage *a);
char *NET_SockadrToString (char *s, int len, struct sockaddr_qstorage *a, size_t sizeofa);
char *NET_BaseAdrToString (char *s, int len, netadr_t *a);
size_t NET_StringToSockaddr2 (const char *s, int defaultport, struct sockaddr_qstorage *sadr, int *addrfamily, int *addrsize, size_t addrcount);
#define NET_StringToSockaddr(s,p,a,f,z) (NET_StringToSockaddr2(s,p,a,f,z,1)>0)
size_t NET_StringToSockaddr2 (const char *s, int defaultport, netadrtype_t afhint, struct sockaddr_qstorage *sadr, int *addrfamily, int *addrsize, size_t addrcount);
#define NET_StringToSockaddr(s,p,a,f,z) (NET_StringToSockaddr2(s,p,NA_INVALID,a,f,z,1)>0)
size_t NET_StringToAdr2 (const char *s, int defaultport, netadr_t *a, size_t addrcount);
#define NET_StringToAdr(s,p,a) NET_StringToAdr2(s,p,a,1)
qboolean NET_PortToAdr (netadrtype_t adrfamily, netproto_t adrprot, const char *s, netadr_t *a);
@ -344,5 +360,5 @@ int UDP_OpenSocket (int port);
int UDP6_OpenSocket (int port);
int IPX_OpenSocket (int port);
int NetadrToSockadr (netadr_t *a, struct sockaddr_qstorage *s);
void SockadrToNetadr (struct sockaddr_qstorage *s, netadr_t *a);
void SockadrToNetadr (struct sockaddr_qstorage *s, int sizeofsockaddr, netadr_t *a);
qboolean NET_Sleep(float seconds, qboolean stdinissocket);

File diff suppressed because it is too large Load Diff

View File

@ -41,13 +41,13 @@
#include <xtl.h>
#include <WinSockX.h>
#else
#ifdef _MSC_VER
#define USEIPX
#if defined(_MSC_VER) && !defined(NOLEGACY)
#define HAVE_IPX
#endif
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock2.h>
#ifdef USEIPX
#ifdef HAVE_IPX
#include "wsipx.h"
#endif
#include <ws2tcpip.h>
@ -130,6 +130,9 @@
#ifdef sun
#include <sys/filio.h>
#endif
#ifdef UNIXSOCKETS
#include <sys/un.h>
#endif
#ifdef NeXT
#include <libc.h>
@ -143,17 +146,18 @@
#define ioctlsocket ioctl
#endif
#if defined(AF_INET6) && !defined(IPPROTO_IPV6)
#define IPPROTO_IPV6 IPPROTO_IPV6 //fte often just checks to see if IPPROTO_IPV6 is defined or not, which doesn't work if its an enum value or somesuch...
#endif
#if defined(AF_INET)
#define HAVE_IPV4
#endif
#ifdef IPPROTO_IPV6
#if defined(AF_INET6)
#define HAVE_IPV6
#endif
// #if defined(AF_IPX) && !defined(NOLEGACY)
// #include <netipx/ipx.h>
// #define HAVE_IPX
// #endif
#define SOCKET int
#endif
@ -204,7 +208,9 @@
#endif
#if defined(FTE_TARGET_WEB)
#undef IPPROTO_IPV6
#undef HAVE_IPV4
#undef HAVE_IPV6
#undef HAVE_IPX
#endif
#if 1//def SUPPORT_ICE

View File

@ -960,26 +960,13 @@ static qintptr_t VARGS Plug_Net_TCPListen(void *offset, quintptr_t mask, const q
if (!currentplug)
return -3; //streams depend upon current plugin context. which isn't valid in a thread.
if (!localip)
localip = "0.0.0.0"; //pass "[::]" for ipv6
localip = "tcp://0.0.0.0"; //pass "[::]" for ipv6
if (!NET_StringToAdr(localip, localport, &a))
return -1;
NetadrToSockadr(&a, &address);
switch(((struct sockaddr*)&address)->sa_family)
{
case AF_INET:
alen = sizeof(struct sockaddr_in);
break;
#ifdef IPPROTO_IPV6
case AF_INET6:
alen = sizeof(struct sockaddr_in6);
break;
#endif
default:
return -2;
}
if (a.prot != NP_STREAM && a.prot != NP_DGRAM)
return -1;
alen = NetadrToSockadr(&a, &address);
if ((sock = socket(((struct sockaddr*)&address)->sa_family, SOCK_STREAM, 0)) == -1)
{
@ -1041,7 +1028,7 @@ static qintptr_t VARGS Plug_Net_Accept(void *offset, quintptr_t mask, const qint
{
netadr_t a;
char *s;
SockadrToNetadr((struct sockaddr_qstorage *)&address, &a);
SockadrToNetadr((struct sockaddr_qstorage *)&address, addrlen, &a);
s = NET_AdrToString(adr, sizeof(adr), &a);
Q_strncpyz(VM_POINTER(arg[1]), s, addrlen);
}

View File

@ -8,18 +8,20 @@
#include <ctype.h>
#define VMUTF8 0
#define VMUTF8 utf8_enable.ival
#define VMUTF8MARKUP false
static char *cvargroup_progs = "Progs variables";
cvar_t utf8_enable = CVARD("utf8_enable", "0", "When 1, changes the qc builtins to act upon codepoints instead of bytes. Do not use unless com_parseutf8 is also set.");
cvar_t sv_gameplayfix_nolinknonsolid = CVARD("sv_gameplayfix_nolinknonsolid", "1", "When 0, setorigin et al will not link the entity into the collision nodes (which is faster, especially if you have a lot of non-solid entities. When 1, allows entities to freely switch between .solid values (except for SOLID_BSP) without relinking. A lot of DP mods assume a value of 1 and will bug out otherwise, while 0 will restore a bugs present in various mods.");
cvar_t sv_gameplayfix_blowupfallenzombies = CVARD("sv_gameplayfix_blowupfallenzombies", "0", "Allow findradius to find non-solid entities. This may break certain mods. It is better for mods to use FL_FINDABLE_NONSOLID instead.");
cvar_t dpcompat_findradiusarealinks = CVARD("dpcompat_findradiusarealinks", "0", "Use the world collision info to accelerate findradius instead of looping through every single entity. May actually be slower for large radiuses, or fail to find entities which have not been linked properly with setorigin.");
#ifndef NOLEGACY
cvar_t dpcompat_strcat_limit = CVARD("dpcompat_strcat_limit", "", "When set, cripples strcat (and related function) string lengths to the value specified.\nSet to 16383 to replicate DP's limit, otherwise leave as 0 to avoid limits.");
#endif
cvar_t pr_autocreatecvars = CVARD("pr_autocreatecvars", "1", "Implicitly create any cvars that don't exist when read.");
cvar_t pr_droptofloorunits = CVARD("pr_droptofloorunits", "256", "Distance that droptofloor is allowed to drop to be considered successul.");
cvar_t pr_brokenfloatconvert = CVAR("pr_brokenfloatconvert", "0");
cvar_t pr_fixbrokenqccarrays = CVARFD("pr_fixbrokenqccarrays", "0", CVAR_LATCH, "As part of its nq/qw/h2/csqc support, FTE remaps QC fields to match an internal order. This is a faster way to handle extended fields. However, some QCCs are buggy and don't report all field defs.\n0: do nothing. QCC must be well behaved.\n1: Duplicate engine fields, remap the ones we can to known offsets. This is sufficient for QCCX/FrikQCC mods that use hardcoded or even occasional calculated offsets (fixes ktpro).\n2: Scan the mod for field accessing instructions, and assume those are the fields (and that they don't alias non-fields). This can be used to work around gmqcc's WTFs (fixes xonotic).");
@ -85,6 +87,8 @@ void PF_Common_RegisterCvars(void)
Cvar_Register (&pr_enable_profiling, cvargroup_progs);
Cvar_Register (&pr_sourcedir, cvargroup_progs);
Cvar_Register (&pr_fixbrokenqccarrays, cvargroup_progs);
Cvar_Register (&utf8_enable, cvargroup_progs);
Cvar_Register (&pr_autocreatecvars, cvargroup_progs);
#ifdef RAGDOLL
Cmd_AddCommand("skel_info", skel_info_f);
@ -102,6 +106,16 @@ qofs_t PR_ReadBytesString(char *str)
{
//use doubles, so we can cope with eg "5.3mb" or much larger values
double d = strtod(str, &str);
if (d < 0)
{
#if defined(_WIN64) && !defined(WINRT)
return 0x80000000; //use of virtual address space rather than physical memory means we can just go crazy and use the max of 2gb.
#elif defined(FTE_TARGET_WEB)
return 8*1024*1024;
#else
return 32*1024*1024;
#endif
}
if (*str == 'g')
d *= 1024*1024*1024;
if (*str == 'm')
@ -1411,11 +1425,37 @@ void QCBUILTIN PF_FindString (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl
////////////////////////////////////////////////////
//Cvars
cvar_t *PF_Cvar_FindOrGet(const char *var_name)
{
const char *def;
cvar_t *var;
var = Cvar_FindVar(var_name);
if (!var && pr_autocreatecvars.ival)
{
//this little chunk is so cvars dp creates are created with meaningful values
def = "";
if (!strcmp(var_name, "sv_maxairspeed"))
def = "30";
else if (!strcmp(var_name, "sv_jumpvelocity"))
def = "270";
else
def = "";
var = Cvar_Get(var_name, def, 0, "Implicit QC variables");
if (var)
Con_Printf("^3Created QC Cvar %s\n", var_name);
else
Con_Printf(CON_ERROR"Unable to create QC Cvar %s\n", var_name);
}
return var;
}
//string(string cvarname) cvar_string
void QCBUILTIN PF_cvar_string (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
const char *str = PR_GetStringOfs(prinst, OFS_PARM0);
cvar_t *cv = Cvar_Get(str, "", 0, "QC variables");
cvar_t *cv = PF_Cvar_FindOrGet(str);
if (cv && !(cv->flags & CVAR_NOUNSAFEEXPAND))
{
if(cv->latched_string)
@ -1436,7 +1476,7 @@ void QCBUILTIN PF_cvars_haveunsaved (pubprogfuncs_t *prinst, struct globalvars_s
void QCBUILTIN PF_cvar_defstring (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
const char *str = PR_GetStringOfs(prinst, OFS_PARM0);
cvar_t *cv = Cvar_Get(str, "", 0, "QC variables");
cvar_t *cv = PF_Cvar_FindOrGet(str);
if (cv && !(cv->flags & CVAR_NOUNSAFEEXPAND))
RETURN_CSTRING(cv->defaultstr);
else
@ -1447,7 +1487,7 @@ void QCBUILTIN PF_cvar_defstring (pubprogfuncs_t *prinst, struct globalvars_s *p
void QCBUILTIN PF_cvar_description (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
const char *str = PR_GetStringOfs(prinst, OFS_PARM0);
cvar_t *cv = Cvar_Get(str, "", 0, "QC variables");
cvar_t *cv = PF_Cvar_FindOrGet(str);
if (cv && !(cv->flags & CVAR_NOUNSAFEEXPAND))
RETURN_CSTRING(cv->description);
else
@ -1461,7 +1501,7 @@ void QCBUILTIN PF_cvar_type (pubprogfuncs_t *prinst, struct globalvars_s *pr_glo
int ret = 0;
cvar_t *v;
v = Cvar_FindVar(str);
v = Cvar_FindVar(str); //this builtin MUST NOT create cvars implicitly, otherwise there would be no way to test if it exists.
if (v && !(v->flags & CVAR_NOUNSAFEEXPAND))
{
ret |= 1; // CVAR_EXISTS
@ -1486,7 +1526,7 @@ void QCBUILTIN PF_cvar_set (pubprogfuncs_t *prinst, struct globalvars_s *pr_glob
var_name = PR_GetStringOfs(prinst, OFS_PARM0);
val = PR_GetStringOfs(prinst, OFS_PARM1);
var = Cvar_Get(var_name, val, 0, "QC variables");
var = PF_Cvar_FindOrGet(var_name);
if (!var || (var->flags & CVAR_NOTFROMSERVER))
return;
Cvar_Set (var, val);
@ -1500,7 +1540,7 @@ void QCBUILTIN PF_cvar_setlatch (pubprogfuncs_t *prinst, struct globalvars_s *pr
var_name = PR_GetStringOfs(prinst, OFS_PARM0);
val = PR_GetStringOfs(prinst, OFS_PARM1);
var = Cvar_Get(var_name, val, 0, "QC variables");
var = PF_Cvar_FindOrGet(var_name);
if (!var || (var->flags & CVAR_NOTFROMSERVER))
return;
Cvar_LockFromServer(var, val);
@ -1515,7 +1555,7 @@ void QCBUILTIN PF_cvar_setf (pubprogfuncs_t *prinst, struct globalvars_s *pr_glo
var_name = PR_GetStringOfs(prinst, OFS_PARM0);
val = G_FLOAT(OFS_PARM1);
var = Cvar_FindVar(var_name);
var = PF_Cvar_FindOrGet(var_name);
if (!var || (var->flags & CVAR_NOTFROMSERVER))
return;
Cvar_SetValue (var, val);
@ -6553,7 +6593,6 @@ lh_extension_t QSG_Extensions[] = {
{"DP_INPUTBUTTONS"},
{"DP_LIGHTSTYLE_STATICVALUE"},
{"DP_LITSUPPORT"},
{"DP_MD3_TAGSINFO", 2, NULL, {"gettagindex", "gettaginfo"}},
{"DP_MONSTERWALK", 0, NULL, {NULL}, "MOVETYPE_WALK is valid on non-player entities. Note that only players receive acceleration etc in line with none/bounce/fly/noclip movetypes on the player, thus you will have to provide your own accelerations (incluing gravity) yourself."},
{"DP_MOVETYPEBOUNCEMISSILE"}, //I added the code for hexen2 support.
{"DP_MOVETYPEFOLLOW"},
@ -6575,6 +6614,7 @@ lh_extension_t QSG_Extensions[] = {
{"DP_QC_FS_SEARCH", 4, NULL, {"search_begin", "search_end", "search_getsize", "search_getfilename"}},
{"DP_QC_GETSURFACE", 6, NULL, {"getsurfacenumpoints", "getsurfacepoint", "getsurfacenormal", "getsurfacetexture", "getsurfacenearpoint", "getsurfaceclippedpoint"}},
{"DP_QC_GETSURFACEPOINTATTRIBUTE", 1, NULL, {"getsurfacepointattribute"}},
{"DP_QC_GETTAGINFO", 2, NULL, {"gettagindex", "gettaginfo"}},
{"DP_QC_MINMAXBOUND", 3, NULL, {"min", "max", "bound"}},
{"DP_QC_MULTIPLETEMPSTRINGS", 0, NULL, {NULL}, "Superseded by DP_QC_UNLIMITEDTEMPSTRINGS. Functions that return a temporary string will not overwrite/destroy previous temporary strings until at least 16 strings are returned (or control returns to the engine)."},
{"DP_QC_RANDOMVEC", 1, NULL, {"randomvec"}},

View File

@ -300,7 +300,7 @@ void QCBUILTIN PF_setattachment(pubprogfuncs_t *prinst, struct globalvars_s *pr_
#endif
#if defined(SKELETALOBJECTS) || defined(RAGDOLL)
void skel_lookup(world_t *prinst, int skelidx, framestate_t *out);
void skel_lookup(world_t *prinst, int skelidx, framestate_t *fte_restrict out);
void skel_dodelete(world_t *world);
void skel_reset(world_t *world);
void skel_reload(void);
@ -328,6 +328,7 @@ void QCBUILTIN PF_touchtriggers(pubprogfuncs_t *prinst, struct globalvars_s *pr_
//pr_cmds.c builtins that need to be moved to a common.
void VARGS PR_BIError(pubprogfuncs_t *progfuncs, char *format, ...) LIKEPRINTF(2);
cvar_t *PF_Cvar_FindOrGet(const char *var_name);
void QCBUILTIN PF_cvar_string (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_cvars_haveunsaved (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_cvar_set (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);

View File

@ -76,7 +76,7 @@ struct vm_s {
qboolean QVM_LoadDLL(vm_t *vm, const char *name, qboolean binroot, void **vmMain, sys_calldll_t syscall)
{
void (EXPORT_FN *dllEntry)(sys_calldll_t syscall);
char dllname_arch[MAX_OSPATH]; //id compatible
char dllname_arch[MAX_OSPATH]; //id compatiblehttps://slashdot.org/
char dllname_anycpu[MAX_OSPATH];//simple
dllhandle_t *hVM;
@ -526,7 +526,7 @@ do{ \
**
** calls function
*/
static void inline QVM_Call(qvm_t *vm, int addr)
inline static void QVM_Call(qvm_t *vm, int addr)
{
vm->sp--;
if (vm->sp < vm->min_sp) Sys_Error("QVM Stack underflow");
@ -558,7 +558,7 @@ static void inline QVM_Call(qvm_t *vm, int addr)
** [oPC][0][.......]| <- oldBP
** ^BP
*/
static void inline QVM_Enter(qvm_t *vm, int size)
inline static void QVM_Enter(qvm_t *vm, int size)
{
int *fp;
@ -575,8 +575,9 @@ static void inline QVM_Enter(qvm_t *vm, int size)
/*
** QVM_Return
** returns failure when returning to the engine.
*/
static void inline QVM_Return(qvm_t *vm, int size)
inline static qboolean QVM_Return(qvm_t *vm, int size)
{
int *fp;
@ -586,16 +587,17 @@ static void inline QVM_Return(qvm_t *vm, int size)
if(vm->bp>vm->max_bp)
Sys_Error("VM run time error: freed too much stack\n");
if(fp[1]>=vm->len_cs*2)
if ((size_t)(vm->cs+fp[1]) != (size_t)RETURNOFFSETMARKER) //this being false causes the program to quit.
Sys_Error("VM run time error: program returned to hyperspace (%p, %#x)\n", (char*)vm->cs, fp[1]);
if(fp[1]<0)
if ((size_t)(vm->cs+fp[1]) != (size_t)RETURNOFFSETMARKER)
Sys_Error("VM run time error: program returned to negative hyperspace\n");
if (vm->sp-vm->max_sp != fp[0])
Sys_Error("VM run time error: stack push/pop mismatch \n");
vm->pc=vm->cs+fp[1]; // restore PC
if((unsigned int)fp[1]>=(unsigned int)(vm->len_cs*2)) //explicit casts to make sure the C compiler can't make assumptions about overflows.
{
if (fp[1] == -1)
return false; //return to engine.
Sys_Error("VM run time error: program returned to hyperspace (%p, %#x)\n", (char*)vm->cs, fp[1]);
}
return true;
}
// ------------------------- * execution * -------------------------
@ -622,7 +624,7 @@ int QVM_ExecVM(register qvm_t *qvm, int command, int arg0, int arg1, int arg2, i
oldpc = qvm->pc;
// setup execution environment
qvm->pc=RETURNOFFSETMARKER;
qvm->pc=qvm->cs-1;
// qvm->cycles=0;
// prepare local stack
qvm->bp -= 15*4; //we have to do this each call for the sake of (reliable) recursion.
@ -669,11 +671,9 @@ int QVM_ExecVM(register qvm_t *qvm, int command, int arg0, int arg1, int arg2, i
QVM_Enter(qvm, param);
break;
case OP_LEAVE:
QVM_Return(qvm, param);
if ((size_t)qvm->pc == (size_t)RETURNOFFSETMARKER)
if (!QVM_Return(qvm, param))
{
// pick return value from stack
// pick return value from C stack
qvm->pc = oldpc;
qvm->bp += 15*4;

View File

@ -58,10 +58,10 @@ typedef struct {
int (*func)(void *);
void *args;
} qthread_t;
static int Sys_CreatedThread(void *v)
static void *Sys_CreatedThread(void *v)
{
qthread_t *qthread = v;
int r;
qintptr_t r;
#ifdef ANDROID
JNIEnv* env;
@ -74,7 +74,7 @@ static int Sys_CreatedThread(void *v)
(*sys_jvm)->DetachCurrentThread(sys_jvm);
#endif
return r;
return (void*)r;
}
void *Sys_CreateThread(char *name, int (*func)(void *), void *args, int priority, int stacksize)

View File

@ -198,7 +198,7 @@ typedef struct
struct world_s
{
void (QDECL *Event_Touch)(struct world_s *w, wedict_t *s, wedict_t *o);
void (QDECL *Event_Touch)(struct world_s *w, wedict_t *s, wedict_t *o, trace_t *trace);
void (QDECL *Event_Think)(struct world_s *w, wedict_t *s);
void (QDECL *Event_Sound) (float *origin, wedict_t *entity, int channel, const char *sample, int volume, float attenuation, float pitchadj, float timeoffset, unsigned int flags);
qboolean (QDECL *Event_ContentsTransition) (struct world_s *w, wedict_t *ent, int oldwatertype, int newwatertype);
@ -370,7 +370,7 @@ void Q23BSP_FindTouchedLeafs(model_t *mod, struct pvscache_s *ent, float *mins,
/*sv_move.c*/
#if defined(CSQC_DAT) || !defined(CLIENTONLY)
qboolean World_CheckBottom (world_t *world, wedict_t *ent, vec3_t up);
qboolean World_movestep (world_t *world, wedict_t *ent, vec3_t move, vec3_t axis[3], qboolean relink, qboolean noenemy, void (*set_move_trace)(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals, trace_t *trace), struct globalvars_s *set_trace_globs);
qboolean World_movestep (world_t *world, wedict_t *ent, vec3_t move, vec3_t axis[3], qboolean relink, qboolean noenemy, void (*set_move_trace)(pubprogfuncs_t *prinst, trace_t *trace));
qboolean World_MoveToGoal (world_t *world, wedict_t *ent, float dist);
qboolean World_GetEntGravityAxis(wedict_t *ent, vec3_t axis[3]);
#endif

View File

@ -1505,7 +1505,7 @@ qboolean R_CalcModelLighting(entity_t *e, model_t *clmodel)
case PTI_RGBA16F:
case PTI_RGBA32F:
break;
default:
default: //non-hdr lightmap format. clamp model lighting to match the lightmap's clamps.
m = max(max(ambientlight[0], ambientlight[1]), ambientlight[2]);
if (m > 255)
{
@ -2860,7 +2860,6 @@ void BE_GenModelBatches(batch_t **batches, const dlight_t *dl, unsigned int bemo
R_HalfLife_GenerateBatches(ent, batches);
#endif
break;
// warning: enumeration value mod_* not handled in switch
case mod_dummy:
case mod_heightmap:
#if defined(TERRAIN)

View File

@ -275,13 +275,16 @@ typedef struct font_s
unsigned char advance; //how wide this char is, when drawn
unsigned short block; //to quickly find the char again
//glyph offset+sizes. I guess these are not strictly needed, but whatever
//texture offsets.
unsigned short bmx;
unsigned short bmy;
//texture/screen pixel sizes.
unsigned char bmw;
unsigned char bmh;
//unsigned short pad;
//positions inside the atlas
//screen offsets.
short top;
short left;
} *chars[FONTBLOCKS];

View File

@ -7911,6 +7911,61 @@ void *Mod_LoadTerrainInfo(model_t *mod, char *loadname, qboolean force)
}
#ifndef SERVERONLY
struct ted_import_s
{
int x, y;
int width;
int height;
unsigned short *data;
};
//static void ted_itterate(heightmap_t *hm, int distribution, float *pos, float radius, float strength, int steps,
void ted_import_heights(void *vctx, hmsection_t *s, int idx, float wx, float wy, float strength)
{
struct ted_import_s *ctx = vctx;
unsigned int y = idx/SECTHEIGHTSIZE;
unsigned int x = idx%SECTHEIGHTSIZE;
x += s->sx*(SECTHEIGHTSIZE-1) - ctx->x;
y += s->sy*(SECTHEIGHTSIZE-1) - ctx->y;
if (x < 0 || x >= ctx->width || y < 0 || y >= ctx->height)
return;
s->flags |= TSF_NOTIFY|TSF_EDITED|TSF_DIRTY|TSF_RELIGHT;
s->heights[idx] = ctx->data[x + y*ctx->width] * (8192.0/(1<<16));
}
void Mod_Terrain_Import_f(void)
{
model_t *mod;
struct ted_import_s ctx;
const char *mapname = Cmd_Argv(1);
size_t fsize;
heightmap_t *hm;
vec3_t pos = {0};
if (Cmd_IsInsecure())
{
Con_Printf("Please use this command via the console\n");
return;
}
if (*mapname)
mod = NULL;//Mod_FindName(va("maps/%s", mapname));
else
mod = cl.worldmodel;
if (!mod || mod->type == mod_dummy)
return;
hm = mod->terrain;
if (!hm)
return;
fsize = 0;
ctx.data = (void*)FS_LoadMallocFile("quake8km/height8km.r16", &fsize);
ctx.width = ctx.height = sqrt(fsize/2);
ctx.x = 0;
ctx.y = 0;
pos[0] += hm->sectionsize * CHUNKBIAS;
pos[1] += hm->sectionsize * CHUNKBIAS;
if (fsize == ctx.width*ctx.height*2)
ted_itterate(hm, tid_flat, pos, max(ctx.width, ctx.height), 1, SECTHEIGHTSIZE, ted_import_heights, &ctx);
FS_FreeFile(ctx.data);
}
void Mod_Terrain_Create_f(void)
{
int x,y;
@ -7932,7 +7987,6 @@ void Mod_Terrain_Create_f(void)
Con_Printf("%s: NAME \"DESCRIPTION\" SKYNAME DEFAULTGROUNDTEX DEFAULTHEIGHT DEFAULTWATER DEFAULTWATERHEIGHT seed\nGenerates a fresh maps/foo.hmp file. You may wish to edit it with notepad later to customise it. You will need csaddon.dat in order to edit the actual terrain.\n", Cmd_Argv(0));
return;
}
mname = va("maps/%s.hmp", Cmd_Argv(1));
mapdesc = Cmd_Argv(2); if (!*mapdesc) mapdesc = Cmd_Argv(1);
skyname = Cmd_Argv(3);
@ -7999,6 +8053,7 @@ void Mod_Terrain_Create_f(void)
}
}
mname = va("maps/%s.hmp", Cmd_Argv(1));
if (COM_FCheckExists(mname))
{
Con_Printf("%s: already exists, not overwriting.\n", mname);
@ -8154,6 +8209,7 @@ void Terr_Init(void)
Cmd_AddCommand("mod_terrain_save", Mod_Terrain_Save_f);
Cmd_AddCommand("mod_terrain_reload", Mod_Terrain_Reload_f);
#ifndef SERVERONLY
Cmd_AddCommandD("mod_terrain_import", Mod_Terrain_Import_f, "Import a raw heightmap");
Cmd_AddCommand("mod_terrain_create", Mod_Terrain_Create_f);
Cmd_AddCommandD("mod_terrain_convert", Mod_Terrain_Convert_f, "mod_terrain_convert [mapname] [texkill]\nConvert a terrain to the current format. If texkill is specified, only tiles with the named texture will be converted, and tiles with that texture will be stripped. This is a slow operation.");
#endif

View File

@ -825,11 +825,11 @@ void Mod_Init (qboolean initial)
#ifdef Q1BSPS
//q1-based formats
Mod_RegisterModelFormatMagic(NULL, "Quake1 2PSB Map(bsp)", BSPVERSION_LONG1, Mod_LoadBrushModel);
Mod_RegisterModelFormatMagic(NULL, "Quake1 BSP2 Map(bsp)", BSPVERSION_LONG2, Mod_LoadBrushModel);
Mod_RegisterModelFormatMagic(NULL, "Half-Life Map (bsp)", 30, Mod_LoadBrushModel);
Mod_RegisterModelFormatMagic(NULL, "Quake1 Map (bsp)", 29, Mod_LoadBrushModel);
Mod_RegisterModelFormatMagic(NULL, "Quake1 Prerelease Map (bsp)", 28, Mod_LoadBrushModel);
Mod_RegisterModelFormatMagic(NULL, "Quake1 2PSB Map (bsp)", BSPVERSION_LONG1, Mod_LoadBrushModel);
Mod_RegisterModelFormatMagic(NULL, "Quake1 BSP2 Map (bsp)", BSPVERSION_LONG2, Mod_LoadBrushModel);
Mod_RegisterModelFormatMagic(NULL, "Half-Life Map (bsp)", BSPVERSIONHL, Mod_LoadBrushModel);
Mod_RegisterModelFormatMagic(NULL, "Quake1 Map (bsp)", BSPVERSION, Mod_LoadBrushModel);
Mod_RegisterModelFormatMagic(NULL, "Quake1 Prerelease Map (bsp)", BSPVERSIONPREREL, Mod_LoadBrushModel);
#endif
}
}

View File

@ -428,15 +428,6 @@ void R_MakeTexWad_f(void)
}
#endif
void GLR_TimeRefresh_f (void);
extern cvar_t v_contrast, r_drawflat;
extern cvar_t r_stains, r_stainfadetime, r_stainfadeammount;
// callback defines
extern cvar_t gl_font;
extern cvar_t vid_conautoscale, vid_conheight, vid_conwidth;
extern cvar_t crosshair, crosshairimage, crosshaircolor, r_skyboxname;
extern cvar_t r_fastskycolour;
void GLV_Gamma_Callback(struct cvar_s *var, char *oldvalue);
void GLR_DeInit (void)

View File

@ -5535,6 +5535,15 @@ void QDECL R_BuildDefaultTexnums(texnums_t *src, shader_t *shader)
tex->fullbright = R_LoadHiResTexture(va("%s_luma:%s_glow", imagename, imagename), subpath, imageflags);
}
}
//if there's a reflectcube texture specified by the shader, make sure we have a reflectmask to go with it.
if (tex->reflectcube)
{
if (!TEXVALID(tex->reflectmask) && *mapname)
tex->reflectmask = R_LoadHiResTexture(va("%s_reflect", mapname), NULL, imageflags);
if (!TEXVALID(tex->reflectmask))
tex->reflectmask = R_LoadHiResTexture(va("%s_reflect", imagename), subpath, imageflags);
}
}
}
@ -5792,7 +5801,6 @@ void QDECL R_BuildLegacyTexnums(shader_t *shader, const char *fallbackname, cons
if (tex->reflectcube)
{
extern cvar_t r_shadow_bumpscale_basetexture;
if (!TEXVALID(tex->reflectmask) && *mapname)
tex->reflectmask = R_LoadHiResTexture(va("%s_reflect", mapname), NULL, imageflags);
if (!TEXVALID(tex->reflectmask))

View File

@ -3103,10 +3103,14 @@ static void Sh_DrawStencilLightShadows(dlight_t *dl, qbyte *lvis, qbyte *vvis, q
switch (emodel->type)
{
case mod_alias:
if (r_drawentities.ival == 3)
continue;
R_DrawGAliasShadowVolume (ent, dl->origin, dl->radius);
break;
case mod_brush:
if (r_drawentities.ival == 2)
continue;
Sh_DrawBrushModelShadow (dl, ent);
break;

View File

@ -513,7 +513,7 @@ void GL_CheckExtensions (void *(*getglfunction) (char *name))
{
int i;
qglGetIntegerv(GL_NUM_EXTENSIONS, &gl_num_extensions);
if (developer.value)
if (developer.value>1)
{
Con_Printf ("GL_EXTENSIONS:\n");
for (i = 0; i < gl_num_extensions; i++)
@ -2262,7 +2262,7 @@ static GLhandleARB GLSlang_CreateShader (program_t *prog, const char *name, int
GLcharARB *combined;
int totallen = 1;
for (i = 0; i < glsl.strings; i++)
totallen += glsl.len[i] + 64;
totallen += glsl.len[i] + 64 + (glsl.file[i]?strlen(glsl.file[i]):0);
combined = malloc(totallen);
totallen = 0;
combined[totallen] = 0;
@ -2272,12 +2272,18 @@ static GLhandleARB GLSlang_CreateShader (program_t *prog, const char *name, int
; //#version MUST be the first line, don't prefix it with a #line, it'll just break things.
else if (!totallen || combined[totallen-1] == '\n')
{ //last line was a newline, hurrah. safe to insert without breaking anything
Q_snprintfz(combined+totallen, 64, "#line %i %i //%s\n", glsl.line[i], i, glsl.file[i]);
if (glsl.file[i])
Q_snprintfz(combined+totallen, 64+strlen(glsl.file[i]), "#line %i %i //%s\n", glsl.line[i], i, glsl.file[i]);
else
Q_snprintfz(combined+totallen, 64, "#line %i %i\n", glsl.line[i], i);
totallen += strlen(combined+totallen);
}
else if (glsl.len[i] && *glsl.str[i] == '\n')
{ //last line didn't end with a newline, but there is one after. that's okay too, but we need to play it safe.
Q_snprintfz(combined+totallen, 64, "\n#line %i %i //%s\n", glsl.line[i], i, glsl.file[i]);
if (glsl.file[i])
Q_snprintfz(combined+totallen, 64+strlen(glsl.file[i]), "\n#line %i %i //%s\n", glsl.line[i], i, glsl.file[i]);
else
Q_snprintfz(combined+totallen, 64, "\n#line %i %i\n", glsl.line[i], i);
totallen += strlen(combined+totallen);
}
//now shove stuff there.
@ -3367,8 +3373,6 @@ qboolean GL_Init(rendererstate_t *info, void *(*getglfunction) (char *name))
sh_config.env_add = gl_config.env_add;
}
GL_SetupFormats();
return true;
}

View File

@ -50,6 +50,7 @@ none of these issues will be fixed by a compositing window manager, because ther
#include <stdarg.h>
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <dlfcn.h>
@ -1411,7 +1412,7 @@ GLXFBConfig GLX_GetFBConfig(rendererstate_t *info)
int numconfigs;
GLXFBConfig *fbconfigs;
qboolean hassrgb, hasmultisample, hasfloats;
qboolean hassrgb, hasmultisample;//, hasfloats;
if (glx.QueryExtensionsString)
glx.glxextensions = glx.QueryExtensionsString(vid_dpy, scrnum);
@ -1427,9 +1428,9 @@ GLXFBConfig GLX_GetFBConfig(rendererstate_t *info)
return NULL; //don't worry about it
}
hassrgb = GLX_CheckExtension("GLX_ARB_framebuffer_sRGB");
hassrgb = GLX_CheckExtension("GLX_ARB_framebuffer_sRGB") || GLX_CheckExtension("GLX_EXT_framebuffer_sRGB");
hasmultisample = GLX_CheckExtension("GLX_ARB_multisample");
hasfloats = GLX_CheckExtension("GLX_ARB_fbconfig_float");
// hasfloats = GLX_CheckExtension("GLX_ARB_fbconfig_float");
//do it in a loop, mostly to disable extensions that are unlikely to be supported on various glx implementations.
for (i = 0; i < (16<<1); i++)
@ -1452,28 +1453,31 @@ GLXFBConfig GLX_GetFBConfig(rendererstate_t *info)
//attrib[n++] = GLX_AUX_BUFFERS; attrib[n++] = 0;
#if 0
if (!(i&4))
{
if (info->srgb <= 2 || !hasfloats)
{ //unlike on windows, this is explicitly blocked except for pbuffers. ffs.
if (info->srgb < 2 || !hasfloats)
continue; //skip fp16 framebuffers
//unlike on windows, this is explicitly blocked except for pbuffers. ffs.
attrib[n++] = GLX_RENDER_TYPE; attrib[n++] = GLX_RGBA_FLOAT_BIT;
attrib[n++] = GLX_RED_SIZE; attrib[n++] = info->bpp?info->bpp/3:4;
attrib[n++] = GLX_GREEN_SIZE; attrib[n++] = info->bpp?info->bpp/3:4;
attrib[n++] = GLX_BLUE_SIZE; attrib[n++] = info->bpp?info->bpp/3:4;
}
else
#endif
{
if (info->bpp > 24)
{
if (info->bpp == 32)
{ //bpp32 is an alias for 24 (we ignore the alpha channel)
attrib[n++] = GLX_RED_SIZE; attrib[n++] = 8;
attrib[n++] = GLX_GREEN_SIZE; attrib[n++] = 8;
attrib[n++] = GLX_BLUE_SIZE; attrib[n++] = 8;
}
else
{
attrib[n++] = GLX_RED_SIZE; attrib[n++] = info->bpp?info->bpp/3:4;
attrib[n++] = GLX_GREEN_SIZE; attrib[n++] = info->bpp?info->bpp/3:4;
attrib[n++] = GLX_BLUE_SIZE; attrib[n++] = info->bpp?info->bpp/3:4;
{ //clamp requested bitdepth to 8bits on the second pass, so that bpp30 doesn't fail
attrib[n++] = GLX_RED_SIZE; attrib[n++] = bound(1,info->bpp?info->bpp/3:4, (i&4)?8:16);
attrib[n++] = GLX_GREEN_SIZE; attrib[n++] = bound(1,info->bpp?info->bpp/3:4, (i&4)?8:16);
attrib[n++] = GLX_BLUE_SIZE; attrib[n++] = bound(1,info->bpp?info->bpp/3:4, (i&4)?8:16);
}
}
//attrib[n++] = GLX_ALPHA_SIZE; attrib[n++] = GLX_DONT_CARE;
@ -1642,9 +1646,9 @@ qboolean GLX_Init(rendererstate_t *info, GLXFBConfig fbconfig, XVisualInfo *visi
if (glx.GetFBConfigAttrib)
{
if (glx.GetFBConfigAttrib(vid_dpy, fbconfig, GLX_RENDER_TYPE, &val) && val == GLX_RGBA_FLOAT_BIT)
if (!glx.GetFBConfigAttrib(vid_dpy, fbconfig, GLX_RENDER_TYPE, &val) && val == GLX_RGBA_FLOAT_BIT)
vid.flags |= VID_FP16; //other things need to be 16bit too, to avoid loss of precision.
if (glx.GetFBConfigAttrib(vid_dpy, fbconfig, GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB, &val) && val)
if (!glx.GetFBConfigAttrib(vid_dpy, fbconfig, GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB, &val) && val)
vid.flags |= VID_SRGB_CAPABLE; //can use srgb properly, without faking it etc.
}
@ -1958,7 +1962,7 @@ static void install_grabs(void)
{
if (!mouse_grabbed)
{
Con_DPrintf("Grabbing mouse\n");
Con_DLPrintf(2, "Grabbing mouse\n");
mouse_grabbed = true;
//XGrabPointer can cause alt+tab type shortcuts to be skipped by the window manager. This means we don't want to use it unless we have no choice.
//the grab is purely to constrain the pointer to the window
@ -1990,7 +1994,7 @@ static void uninstall_grabs(void)
{
if (mouse_grabbed && vid_dpy)
{
Con_DPrintf("Releasing mouse grab\n");
Con_DLPrintf(2, "Releasing mouse grab\n");
mouse_grabbed = false;
if (x11_input_method == XIM_DGA)
{
@ -2358,7 +2362,12 @@ static void GetEvent(void)
char *protname = x11.pXGetAtomName(vid_dpy, event.xclient.data.l[0]);
if (!strcmp(protname, "WM_DELETE_WINDOW"))
{
Cmd_ExecuteString("menu_quit prompt", RESTRICT_LOCAL);
if (Cmd_Exists("menu_quit") || Cmd_AliasExist("menu_quit", RESTRICT_LOCAL))
Cmd_ExecuteString("menu_quit prompt", RESTRICT_LOCAL);
else if (Cmd_Exists("m_quit") || Cmd_AliasExist("m_quit", RESTRICT_LOCAL))
Cmd_ExecuteString("m_quit", RESTRICT_LOCAL);
else
Cmd_ExecuteString("quit", RESTRICT_LOCAL);
x11.pXSetInputFocus(vid_dpy, vid_window, RevertToParent, CurrentTime);
}
else
@ -2369,14 +2378,24 @@ static void GetEvent(void)
else if (!strcmp(name, "XdndEnter") && event.xclient.format == 32)
{
//check for text/uri-list
x11.dnd.type = None;
int i;
for (i = 2; i < 2+3; i++)
{
if (event.xclient.data.l[i])
{
char *t = x11.pXGetAtomName(vid_dpy, event.xclient.data.l[i]);
#ifdef XDS
//direct-save has no way to deal with multiple files, other than lying about it.
//which is unfortunately what other programs do. we have no real way to tell which file(s) actually got dragged/written.
//we would need to report an empty directory, then scan for new files, then wipe the lot recursively.
if (!strcmp(t, "XdndDirectSave0") && !x11.dnd.type) //single file
x11.dnd.type = event.xclient.data.l[i];
#endif
if (!strcmp(t, "text/uri-list")) //file list
x11.dnd.type = event.xclient.data.l[i];
// else if (!strcmp(t, "application/octet-stream")) //raw file data without a name.
// x11.dnd.type = event.xclient.data.l[i];
x11.pXFree(t);
}
}
@ -2391,7 +2410,7 @@ static void GetEvent(void)
xev.xclient.message_type = x11.pXInternAtom(vid_dpy, "XdndStatus", False);
xev.xclient.format = 32;
xev.xclient.data.l[0] = vid_window; //so source can ignore it if stale
xev.xclient.data.l[1] = 1;
xev.xclient.data.l[1] = x11.dnd.type?1:0;
xev.xclient.data.l[2] = 0; //(x<<16)|y (should be in root coords)
xev.xclient.data.l[3] = 0; //(w<<16)|h
xev.xclient.data.l[4] = x11.pXInternAtom (vid_dpy, "XdndActionCopy", False);
@ -2408,9 +2427,35 @@ static void GetEvent(void)
else if (!strcmp(name, "XdndDrop") && event.xclient.format == 32)
{
Atom xa_XdndSelection = x11.pXInternAtom(vid_dpy, "XdndSelection", False);
Window source = event.xclient.data.l[0];
Time t = CurrentTime;//event.xclient.data.l[2];
#ifdef XDS
char *droptype = x11.dnd.type?x11.pXGetAtomName(vid_dpy, x11.dnd.type):NULL;
if (droptype && !strcmp(droptype, "XdndDirectSave0")) //single file
{
unsigned char *data = NULL;
Atom type;
int fmt;
unsigned long nitems;
unsigned long bytesleft;
if (x11.pXGetWindowProperty(vid_dpy, source, x11.dnd.type, 0, 65536, False, AnyPropertyType, &type, &fmt, &nitems, &bytesleft, &data) == Success && data)
{
char hostname[1024];
if (gethostname(hostname, sizeof(hostname)) < 0)
*hostname = 0; //failed? o.O
char *path = va("file://%s/tmp/%s", hostname, data);
Atom proptype = x11.pXInternAtom(vid_dpy, "text/plain", false);
x11.pXChangeProperty(vid_dpy, source, x11.dnd.type, proptype, 8, PropModeReplace, (void*)path, strlen(path));
Con_Printf("Dropping file %s\n", data);
x11.pXFree(data);
}
}
x11.pXFree(droptype);
#endif
x11.dnd.myprop = x11.pXInternAtom(vid_dpy, "_FTE_dnd", False);
if (x11.pXGetSelectionOwner(vid_dpy, xa_XdndSelection) == event.xclient.data.l[0])
if (x11.pXGetSelectionOwner(vid_dpy, xa_XdndSelection) == source)
{
x11.pXDeleteProperty(vid_dpy, vid_window, x11.dnd.myprop);
x11.pXConvertSelection(vid_dpy, xa_XdndSelection, x11.dnd.type, x11.dnd.myprop, vid_window, t);
@ -2435,7 +2480,8 @@ static void GetEvent(void)
unsigned long bytesleft;
if (x11.pXGetWindowProperty(vid_dpy, vid_window, x11.dnd.myprop, 0, 65536, False, AnyPropertyType, &type, &fmt, &nitems, &bytesleft, &data) == Success && data)
{
if (type == x11.dnd.type)
char *tname = x11.pXGetAtomName(vid_dpy, x11.dnd.type);
if (type == x11.dnd.type && !strcmp(tname, "text/uri-list"))
{
char *start, *end;
for (start = data; *start; )
@ -2449,8 +2495,20 @@ static void GetEvent(void)
start++;
}
okay = true;
x11.pXFree(data);
}
#ifdef XDS
else if (type == x11.dnd.type && !strcmp(tname, "XdndDirectSave0") && nitems == 1)
{
switch(data[0])
{
case 'S': //sender wrote the file
case 'E': //sender failed to generate the data or something
case 'F': //sender failed to write the file. we should use application/octet-stream and write it ourself.
}
}
#endif
x11.pXFree(tname);
x11.pXFree(data);
}
x11.pXDeleteProperty(vid_dpy, vid_window, x11.dnd.myprop); //might be large, so don't force it to hang around.

View File

@ -1478,7 +1478,7 @@ unsigned long _true = true;
closesocket(clientsock); //try to forget this ever happend
return true;
}
NET_SockadrToString(cl->peername, sizeof(cl->peername), &from);
NET_SockadrToString(cl->peername, sizeof(cl->peername), &from, fromlen);
IWebPrintf("%s: New FTP connection\n", cl->peername);
//RFC1700
if (((struct sockaddr *)&from)->sa_family == AF_INET)

View File

@ -38,8 +38,8 @@ static void DL_OnLoad(void *c, int buf)
{
if (*dl->localname)
{
FS_CreatePath(dl->localname, FS_GAMEONLY);
dl->file = FS_OpenVFS(dl->localname, "w+b", FS_GAMEONLY);
FS_CreatePath(dl->localname, dl->fsroot);
dl->file = FS_OpenVFS(dl->localname, "w+b", dl->fsroot);
}
else
{
@ -199,8 +199,8 @@ static void readfinished(void* user_data, int32_t result)
{
if (*f->localname)
{
FS_CreatePath(f->localname, FS_GAME);
f->file = FS_OpenVFS(f->localname, "w+b", FS_GAME);
FS_CreatePath(f->localname, dl->fsroot);
f->file = FS_OpenVFS(f->localname, "w+b", dl->fsroot);
}
else
f->file = FS_OpenTemp();
@ -797,8 +797,8 @@ static qboolean HTTP_DL_Work(struct dl_download *dl)
#ifndef NPFTE
if (*dl->localname)
{
FS_CreatePath(dl->localname, FS_GAME);
dl->file = FS_OpenVFS(dl->localname, "w+b", FS_GAME);
FS_CreatePath(dl->localname, dl->fsroot);
dl->file = FS_OpenVFS(dl->localname, "w+b", dl->fsroot);
}
else
dl->file = FS_OpenTemp();
@ -1332,8 +1332,8 @@ qboolean DataScheme_Decode(struct dl_download *dl)
#ifndef NPFTE
if (*dl->localname)
{
FS_CreatePath(dl->localname, FS_GAME);
dl->file = FS_OpenVFS(dl->localname, "w+b", FS_GAME);
FS_CreatePath(dl->localname, dl->fsroot);
dl->file = FS_OpenVFS(dl->localname, "w+b", dl->fsroot);
}
else
dl->file = FS_OpenTemp();
@ -1485,6 +1485,7 @@ struct dl_download *DL_Create(const char *url)
newdl->url = (char*)(newdl+1);
strcpy(newdl->url, url);
newdl->poll = DL_Decide;
newdl->fsroot = FS_GAMEONLY;
newdl->sizelimit = 0x80000000u; //some sanity limit.
#if !defined(NPFTE) && !defined(SERVERONLY)
newdl->qdownload.method = DL_HTTP;

View File

@ -99,6 +99,7 @@ struct dl_download
char *url; /*original url*/
char redir[MAX_OSPATH]; /*current redirected url*/
char localname[MAX_OSPATH]; /*leave empty for a temp file*/
enum fs_relative fsroot;
struct vfsfile_s *file; /*downloaded to, if not already set when starting will open localname or a temp file*/
char postmimetype[64];

View File

@ -777,12 +777,22 @@ reeval:
break;
case OP_CP_ITOF:
ptr = (eval_t *)(((qbyte *)sv_edicts) + OPA->_int);
i = OPA->_int;
errorif (QCPOINTERREADFAIL(i, sizeof(char)))
{
QCFAULT(&progfuncs->funcs, "bad pointer read in %s (%#x)", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name), OPA->_int);
}
ptr = QCPOINTERM(i);
OPC->_float = (float)ptr->_int;
break;
case OP_CP_FTOI:
ptr = (eval_t *)(((qbyte *)sv_edicts) + OPA->_int);
i = OPA->_int;
errorif (QCPOINTERREADFAIL(i, sizeof(char)))
{
QCFAULT(&progfuncs->funcs, "bad pointer read in %s (%#x)", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name), OPA->_int);
}
ptr = QCPOINTERM(i);
OPC->_int = (int)ptr->_float;
break;

View File

@ -958,7 +958,7 @@ unsigned int utf8_check(const void *in, unsigned int *value)
if ((str[1] & 0xc0) == 0x80)
{
*value = uc = ((str[0] & 0x1f)<<6) | (str[1] & 0x3f);
if (!uc || uc >= (1u<<7)) //allow modified utf-8
if (!uc || uc >= (1u<<7)) //allow modified utf-8 (only for nulls)
return 2;
}
}

View File

@ -9571,6 +9571,23 @@ QCC_opcode_t *QCC_PR_ChooseOpcode(QCC_sref_t lhs, QCC_sref_t rhs, QCC_opcode_t *
return op;
}
//used to optimise logicops slightly.
pbool QCC_OpHasSideEffects(QCC_statement_t *st)
{
//function calls potentially always have side effects (and are expensive)
if ((st->op >= OP_CALL0 && st->op <= OP_CALL8) || (st->op >= OP_CALL1H && st->op <= OP_CALL8H))
return true;
//otherwise if we're assigning to some variable (that isn't a temp) then it has a side effect.
//FIXME: this doesn't catch op_address+op_storep_*, but that should generally not happen as logicops is tied to a single statement.
if (st->c.sym && !st->c.sym->temp && OpAssignsToC(st->op))
return true;
if (st->b.sym && !st->b.sym->temp && OpAssignsToB(st->op))
return true;
if (st->a.sym && !st->a.sym->temp && OpAssignsToA(st->op))
return true;
return false;
}
QCC_ref_t *QCC_PR_RefExpression (QCC_ref_t *retbuf, int priority, int exprflags)
{
QCC_ref_t rhsbuf;
@ -9996,7 +10013,7 @@ QCC_ref_t *QCC_PR_RefExpression (QCC_ref_t *retbuf, int priority, int exprflags)
logicjump->b.ofs = &statements[numstatements] - logicjump;
if (logicjump->b.ofs == 1)
numstatements--; //err, that was pointless.
else if (logicjump->b.ofs == 2 && !(logicjump[1].op >= OP_CALL0 && logicjump[1].op <= OP_CALL8) && !(logicjump[1].op >= OP_CALL1H && logicjump[1].op <= OP_CALL8H))
else if (logicjump->b.ofs == 2 && !QCC_OpHasSideEffects(&logicjump[1]))
{
logicjump[0] = logicjump[1];
numstatements--; //don't bother if the jump is the same cost as the thing we're trying to skip (calls are expensive despite being a single opcode).

View File

@ -1571,12 +1571,16 @@ void QCC_PR_LexString (void)
#else
void QCC_PR_LexString (void)
{
int c;
unsigned int c, t;
int bytecount;
int len = 0;
char *end, *cnst;
int raw;
char rawdelim[64];
unsigned int code;
int stringtype = 0; //0 - quake output, input is 8bit. warnings when its not ascii. \u will still give utf-8 text, other chars as-is. Expect \s to screw everything up with utf-8 output.
//1 - quake output, input is utf-8. due to editors not supporting it, that generally means the input (ab)uses markup.
//2 - utf-8 output, input is utf-8. welcome to the future! unfortunately not the present.
int texttype;
pbool first = true;
@ -1630,6 +1634,22 @@ void QCC_PR_LexString (void)
pr_source_line++;
}
}
else if (*pr_file_p == 'Q' && pr_file_p[1] == '\"')
{ //quake output with utf-8 input (expect to need markup).
stringtype = 1;
pr_file_p+=2;
}
else if ((*pr_file_p == 'U' || *pr_file_p == 'u' || *pr_file_p == 'L') && pr_file_p[1] == '\"')
{ //unicode string, char32_t, char16_t, wchar_t respectively. we spit out utf-8 regardless.
QCC_PR_ParseWarning(WARN_NOTUTF8, "interpretting char32_t/char16_t/wchar_t as utf-8");
stringtype = 2;
pr_file_p+=2;
}
else if (*pr_file_p == 'u' && pr_file_p[1] == '8' && pr_file_p[2] == '\"')
{ //utf-8 string.
stringtype = 2;
pr_file_p+=3;
}
else if (*pr_file_p == '\"')
pr_file_p++;
else if (first)
@ -1687,11 +1707,12 @@ void QCC_PR_LexString (void)
break;
}
//make sure line numbers are correct
//make sure line numbers are correct though.
if (c == '\r' && *pr_file_p != '\n')
pr_source_line++; //mac
if (c == '\n') //dos/unix
pr_source_line++;
goto forcebyte;
}
else
{
@ -1726,9 +1747,9 @@ void QCC_PR_LexString (void)
//else if (c == 'b')
// c = '\b';
else if (c == '[')
c = 16; //quake specific
c = 0xe010; //quake specific
else if (c == ']')
c = 17; //quake specific
c = 0xe011; //quake specific
else if (c == '{')
{
int d;
@ -1741,71 +1762,44 @@ void QCC_PR_LexString (void)
}
}
else if (c == '.')
c = 0x1c | texttype;
c = 0xe01c | texttype;
else if (c == '<')
c = 29;
c = 0xe01d; //separator start
else if (c == '-')
c = 30;
c = 0xe01e; //separator middle
else if (c == '>')
c = 31;
c = 0xe01f; //separator end
else if (c == '(')
c = 128;
c = 0xe080; //slider start
else if (c == '=')
c = 129;
c = 0xe081; //slider middle
else if (c == ')')
c = 130;
c = 0xe082; //slider end
else if (c == '+')
c = 0xe083; //slider box
else if (c == 'u' || c == 'U')
{
//lower case u specifies exactly 4 nibbles.
//upper case U specifies variable length. terminate with a double-doublequote pair, or some other non-hex char.
int count = 0;
unsigned long d;
unsigned long unicode;
unicode = 0;
for(;;)
//upper case U specifies exactly 8 nibbles.
unsigned int nibbles = (c=='u')?4:8;
c = 0;
while (nibbles --> 0)
{
d = (unsigned char)*pr_file_p;
if (d >= '0' && d <= '9')
unicode = (unicode*16) + (d - '0');
else if (d >= 'A' && d <= 'F')
unicode = (unicode*16) + (d - 'A') + 10;
else if (d >= 'a' && d <= 'f')
unicode = (unicode*16) + (d - 'a') + 10;
t = (unsigned char)*pr_file_p;
if (t >= '0' && t <= '9')
c = (c*16) + (t - '0');
else if (t >= 'A' && t <= 'F')
c = (c*16) + (t - 'A') + 10;
else if (t >= 'a' && t <= 'f')
c = (c*16) + (t - 'a') + 10;
else
break;
count++;
pr_file_p++;
}
if (!count || ((c=='u')?(count!=4):(count>8)) || unicode > 0x10FFFFu) //RFC 3629 imposes the same limit as UTF-16 surrogate pairs.
QCC_PR_ParseWarning(ERR_BADCHARACTERCODE, "Bad unicode character code");
if (nibbles)
QCC_PR_ParseWarning(ERR_BADCHARACTERCODE, "Unicode character terminated unexpectedly");
//figure out the count of bytes required to encode this char
count = 1;
d = 0x7f;
while (unicode > d)
{
count++;
d = (d<<5) | 0x1f;
}
//error if needed
if (len+count >= sizeof(pr_token))
QCC_Error(ERR_INVALIDSTRINGIMMEDIATE, "String length exceeds %i", sizeof(pr_token)-1);
//output it.
if (count == 1)
pr_token[len++] = (unsigned char)(c&0x7f);
else
{
c = count*6;
pr_token[len++] = (unsigned char)((unicode>>c)&(0x0000007f>>count)) | (0xffffff00 >> count);
do
{
c = c-6;
pr_token[len++] = (unsigned char)((unicode>>c)&0x3f) | 0x80;
} while(c);
}
continue;
goto forceutf8;
}
else if (c == 'x' || c == 'X')
{
@ -1833,13 +1827,14 @@ void QCC_PR_LexString (void)
c += d - 'a' + 10;
else
QCC_PR_ParseError(ERR_BADCHARACTERCODE, "Bad character code");
goto forcebyte;
}
else if (c == '\\')
c = '\\';
else if (c == '\'')
c = '\'';
else if (c >= '0' && c <= '9') //WARNING: This is not octal, but uses 'yellow' numbers instead (as on hud).
c = 18 + c - '0';
c = 0xe012 + c - '0';
else if (c == '\r')
{ //sigh
c = *pr_file_p++;
@ -1913,13 +1908,82 @@ void QCC_PR_LexString (void)
else if (c == 0x7C && flag_acc) //reacc support... reacc is strange.
c = '\n';
else
c |= texttype;
{
unsigned int cp;
unsigned int len = stringtype?utf8_check(pr_file_p-1, &cp):0;
if (!len)
{ //invalid utf-8 encoding? don't treat it as utf-8!
c |= texttype;
goto forcequake;
}
if (texttype)
{
c = cp;
if (cp < 128)
c |= 0xe080; //FIXME: technically invalid for C0 chars.
else
{
QCC_PR_ParseWarning(ERR_BADCHARACTERCODE, "Unable to mask non-ascii chars. Attempting to mask bytes");
c |= texttype;
goto forcequake;
}
}
else
c = cp;
pr_file_p += len-1;
}
}
if (len >= sizeof(pr_token)-1)
QCC_Error(ERR_INVALIDSTRINGIMMEDIATE, "String length exceeds %i", sizeof(pr_token)-1);
pr_token[len] = c;
len++;
if (stringtype == 2)
{ //we're outputting a utf-8 string.
forceutf8:
if (c > 0x10FFFFu) //RFC 3629 imposes the same limit as UTF-16 surrogate pairs.
QCC_PR_ParseWarning(WARN_NOTUTF8, "Bad unicode character code - codepoint is above 0x10FFFFu");
//figure out the count of bytes required to encode this char
bytecount = 1;
t = 0x7f;
while (c > t)
{
bytecount++;
t = (t<<5) | 0x1f;
}
//error if needed
if (len+bytecount >= sizeof(pr_token))
QCC_Error(ERR_INVALIDSTRINGIMMEDIATE, "String length exceeds %i", sizeof(pr_token)-1);
//output it.
if (bytecount == 1)
pr_token[len++] = (unsigned char)(c&0x7f);
else
{
t = bytecount*6;
pr_token[len++] = (unsigned char)((c>>t)&(0x0000007f>>bytecount)) | (0xffffff00 >> bytecount);
do
{
t = t-6;
pr_token[len++] = (unsigned char)((c>>t)&0x3f) | 0x80;
} while(t);
}
}
else
{
forcequake:
//we need to convert it to a quake char...
if (c >= 0xe000 && c <= 0xe0ff)
c = c & 0xff; //this private use range is commonly used for quake's glyphs.
else if (c >= 0 && c <= 0x7f)
; //FIXME: SOME c0 codes are known to quake, but many got reused for random glyphs. however I'm going to treat quake as full ascii.
else if (c > 0xff)
QCC_PR_ParseWarning(WARN_NOTUTF8, "Cannot convert character to quake's charset");
forcebyte:
if (len >= sizeof(pr_token)-1)
QCC_Error(ERR_INVALIDSTRINGIMMEDIATE, "String length exceeds %i", sizeof(pr_token)-1);
pr_token[len] = c;
len++;
}
}
}
@ -1940,7 +2004,7 @@ void QCC_PR_LexString (void)
len = utf8_check(&pr_token[c], &code);
if (!len || c+len>pr_immediate_strlen)
{
QCC_PR_ParseWarning(WARN_NOTUTF8, "String constant is not valid utf-8");
QCC_PR_ParseWarning(WARN_NOTUTF8, "String literal is not valid utf-8");
break;
}
c += len;
@ -3690,7 +3754,7 @@ void QCC_PR_Lex (void)
}
// handle quoted strings as a unit
if (c == '\"' || (c == 'R' && pr_file_p[1] == '\"'))
if (c == '\"' || ((c == 'R' || c == 'Q' || c == 'u' || c == 'U') && pr_file_p[1] == '\"') || (c == 'u' && pr_file_p[1] == '8' && pr_file_p[2] == '\"'))
{
QCC_PR_LexString ();
return;

View File

@ -62,6 +62,7 @@ cvar_t temp1 = CVARF("temp1", "0", CVAR_ARCHIVE);
cvar_t noexit = CVAR("noexit", "0");
extern cvar_t sv_specprint;
extern cvar_t pr_autocreatecvars;
cvar_t pr_ssqc_memsize = CVARD("pr_ssqc_memsize", "-1", "The ammount of memory available to the QC vm. This has a theoretical maximum of 1gb, but that value can only really be used in 64bit builds. -1 will attempt to use some conservative default, but you may need to increase it. Consider also clearing pr_fixbrokenqccarrays if you need to change this cvar.");
/*cvars purely for compat with others*/
@ -95,6 +96,7 @@ cvar_t sv_gameplayfix_setmodelrealbox = CVARD("sv_gameplayfix_setmodelrealbox",
#endif
cvar_t sv_gameplayfix_setmodelsize_qw = CVARD("sv_gameplayfix_setmodelsize_qw", "0", "The setmodel builtin will act as a setsize for QuakeWorld mods also.");
cvar_t dpcompat_nopreparse = CVARD("dpcompat_nopreparse", "0", "Xonotic uses svc_tempentity with unknowable lengths mixed with other data that needs to be translated. This cvar disables any attempt to translate or pre-parse network messages, including disabling nq/qw cross compatibility. NOTE: because preparsing will be disabled, messages might not get backbuffered correctly if too much reliable data is written.");
cvar_t dpcompat_traceontouch = CVARD("dpcompat_traceontouch", "0", "Report trace plane etc when an entity touches another.");
extern cvar_t sv_listen_dp;
cvar_t sv_addon[MAXADDONS];
@ -590,11 +592,15 @@ static void QDECL SVPR_Get_FrameState(world_t *w, wedict_t *ent, framestate_t *f
#endif
}
static void QDECL SVPR_Event_Touch(world_t *w, wedict_t *s, wedict_t *o)
static void set_trace_globals(pubprogfuncs_t *prinst, trace_t *trace);
static void QDECL SVPR_Event_Touch(world_t *w, wedict_t *s, wedict_t *o, trace_t *trace)
{
int oself = pr_global_struct->self;
int oother = pr_global_struct->other;
if (trace)
set_trace_globals(w->progs, trace);
pr_global_struct->self = EDICT_TO_PROG(w->progs, s);
pr_global_struct->other = EDICT_TO_PROG(w->progs, o);
pr_global_struct->time = w->physicstime;
@ -815,6 +821,8 @@ void PR_LoadGlabalStruct(qboolean muted)
static float svphysicsmode = 2;
static float writeonly;
static int writeonly_int;
static int endcontentsi, surfaceflagsi;
static float endcontentsf, surfaceflagsf;
static float dimension_send_default;
static float dimension_default = 255;
static float zero_default;
@ -938,10 +946,10 @@ void PR_LoadGlabalStruct(qboolean muted)
// make sure these entries are always valid pointers
ensureglobal(dimension_send, dimension_send_default);
ensureglobal(dimension_default, dimension_default);
ensureglobal(trace_endcontentsf, writeonly);
ensureglobal(trace_endcontentsi, writeonly_int);
ensureglobal(trace_surfaceflagsf, writeonly);
ensureglobal(trace_surfaceflagsi, writeonly_int);
ensureglobal(trace_endcontentsf, endcontentsf);
ensureglobal(trace_endcontentsi, endcontentsi);
ensureglobal(trace_surfaceflagsf, surfaceflagsf);
ensureglobal(trace_surfaceflagsi, surfaceflagsi);
ensureglobal(trace_brush_id, writeonly_int);
ensureglobal(trace_brush_faceid, writeonly_int);
ensureglobal(trace_surface_id, writeonly_int);
@ -1223,7 +1231,7 @@ static void PR_Decompile_f(void)
if (!svprogfuncs)
{
Q_SetProgsParms(false);
PR_Configure(svprogfuncs, pr_ssqc_memsize.ival, MAX_PROGS, 0);
PR_Configure(svprogfuncs, PR_ReadBytesString(pr_ssqc_memsize.string), MAX_PROGS, 0);
}
@ -1303,7 +1311,7 @@ static void PR_ApplyCompilation_f (void)
s = PR_SaveEnts(svprogfuncs, NULL, &len, 0, 1);
PR_Configure(svprogfuncs, pr_ssqc_memsize.ival, MAX_PROGS, pr_enable_profiling.ival);
PR_Configure(svprogfuncs, PR_ReadBytesString(pr_ssqc_memsize.string), MAX_PROGS, pr_enable_profiling.ival);
PR_RegisterFields();
sv.world.edict_size=PR_InitEnts(svprogfuncs, sv.world.max_edicts);
@ -1521,12 +1529,12 @@ void SVQ1_CvarChanged(cvar_t *var)
static void QCBUILTIN PF_precache_model (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
static void QCBUILTIN PF_setmodel (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_makestatic (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
static void PR_FallbackSpawn_Misc_Model(pubprogfuncs_t *progfuncs, edict_t *self)
static void PR_FallbackSpawn_Misc_Model(pubprogfuncs_t *progfuncs, edict_t *self, qboolean force)
{
void *pr_globals;
eval_t *val;
if (sv.world.worldmodel && sv.world.worldmodel->type==mod_brush && sv.world.worldmodel->fromgame == fg_quake3)
if (sv.world.worldmodel && sv.world.worldmodel->type==mod_brush && sv.world.worldmodel->fromgame == fg_quake3 && !force)
{ //on q3bsp, these are expected to be handled directly by q3map2, but it doesn't always strip it.
ED_Free(progfuncs, self);
return;
@ -1560,12 +1568,6 @@ static void PR_FallbackSpawn_Func_Detail(pubprogfuncs_t *progfuncs, edict_t *sel
void *pr_globals;
eval_t *val;
if (sv.world.worldmodel && sv.world.worldmodel->type==mod_brush && sv.world.worldmodel->fromgame == fg_quake3)
{ //on q3bsp, these are expected to be handled directly by q3map2, but it doesn't always strip it.
ED_Free(progfuncs, self);
return;
}
if (!self->v->model && (val = progfuncs->GetEdictFieldValue(progfuncs, self, "mdl", ev_string, NULL)))
self->v->model = val->string;
if (!*PR_GetString(progfuncs, self->v->model)) //must have a model, because otherwise various things will assume its not valid at all.
@ -1700,10 +1702,10 @@ static void PDECL PR_DoSpawnInitialEntity(pubprogfuncs_t *progfuncs, struct edic
//the mod is responsible for freeing unrecognised ents.
}
else if (!strcmp(eclassname, "misc_model"))
PR_FallbackSpawn_Misc_Model(progfuncs, ed);
PR_FallbackSpawn_Misc_Model(progfuncs, ed, false);
//func_detail+func_group are for compat with ericw-tools, etc.
else if (!strcmp(eclassname, "func_detail_illusionary"))
PR_FallbackSpawn_Misc_Model(progfuncs, ed);
PR_FallbackSpawn_Misc_Model(progfuncs, ed, true);
else if (!strcmp(eclassname, "func_detail") || !strcmp(eclassname, "func_detail_wall") || !strcmp(eclassname, "func_detail_fence"))
PR_FallbackSpawn_Func_Detail(progfuncs, ed);
else if (!strcmp(eclassname, "func_group"))
@ -3586,7 +3588,7 @@ static void QCBUILTIN PF_ss_LocalSound(pubprogfuncs_t *prinst, struct globalvars
#define PF_ss_LocalSound PF_Fixme
#endif
static void set_trace_globals(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals, trace_t *trace)
static void set_trace_globals(pubprogfuncs_t *prinst, /*struct globalvars_s *pr_globals,*/ trace_t *trace)
{
pr_global_struct->trace_allsolid = trace->allsolid;
pr_global_struct->trace_startsolid = trace->startsolid;
@ -3674,7 +3676,7 @@ void QCBUILTIN PF_svtraceline (pubprogfuncs_t *prinst, struct globalvars_s *pr_g
trace = World_Move (&sv.world, v1, mins, maxs, v2, nomonsters|MOVE_IGNOREHULL, (wedict_t*)ent);
set_trace_globals(prinst, pr_globals, &trace);
set_trace_globals(prinst, &trace);
}
#ifdef HEXEN2
@ -3694,7 +3696,7 @@ static void QCBUILTIN PF_traceboxh2 (pubprogfuncs_t *prinst, struct globalvars_s
trace = World_Move (&sv.world, v1, mins, maxs, v2, nomonsters|MOVE_IGNOREHULL, (wedict_t*)ent);
set_trace_globals(prinst, pr_globals, &trace);
set_trace_globals(prinst, &trace);
}
#endif
@ -3716,7 +3718,7 @@ static void QCBUILTIN PF_traceboxdp (pubprogfuncs_t *prinst, struct globalvars_s
trace = World_Move (&sv.world, v1, mins, maxs, v2, nomonsters|MOVE_IGNOREHULL, (wedict_t*)ent);
set_trace_globals(prinst, pr_globals, &trace);
set_trace_globals(prinst, &trace);
}
static void QCBUILTIN PF_TraceToss (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
@ -3732,7 +3734,7 @@ static void QCBUILTIN PF_TraceToss (pubprogfuncs_t *prinst, struct globalvars_s
trace = WPhys_Trace_Toss (&sv.world, (wedict_t*)ent, (wedict_t*)ignore);
set_trace_globals(prinst, pr_globals, &trace);
set_trace_globals(prinst, &trace);
}
//============================================================================
@ -4100,22 +4102,8 @@ static void QCBUILTIN PF_cvar (pubprogfuncs_t *prinst, struct globalvars_s *pr_g
G_FLOAT(OFS_RETURN) = sv.world.worldmodel->fromgame == fg_halflife;
else
{
cvar_t *cv = Cvar_FindVar(str);
if (!cv)
{
//this little chunk is so cvars dp creates are created with meaningful values
char *def = "";
if (!strcmp(str, "sv_maxairspeed"))
def = "30";
else if (!strcmp(str, "sv_jumpvelocity"))
def = "270";
else
def = "";
cv = Cvar_Get(str, def, 0, "QC variables");
Con_Printf("^3Creating cvar %s\n", str);
}
if (cv->flags & CVAR_NOUNSAFEEXPAND)
cvar_t *cv = PF_Cvar_FindOrGet(str);
if (!cv || (cv->flags & CVAR_NOUNSAFEEXPAND))
G_FLOAT(OFS_RETURN) = 0;
else
G_FLOAT(OFS_RETURN) = cv->value;
@ -4487,7 +4475,6 @@ void QCBUILTIN PF_precache_vwep_model (pubprogfuncs_t *prinst, struct globalvars
}
#endif
// warning: PF_svcoredump defined but not used
/*
static void QCBUILTIN PF_svcoredump (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
@ -4558,7 +4545,7 @@ static void QCBUILTIN PF_walkmove (pubprogfuncs_t *prinst, struct globalvars_s *
// }
// else if (!SV_TestEntityPosition(ent))
// {
G_FLOAT(OFS_RETURN) = World_movestep(&sv.world, (wedict_t*)ent, move, axis, true, false, settrace?set_trace_globals:NULL, pr_globals);
G_FLOAT(OFS_RETURN) = World_movestep(&sv.world, (wedict_t*)ent, move, axis, true, false, settrace?set_trace_globals:NULL);
// if (SV_TestEntityPosition(ent))
// Con_Printf("Entity became stuck\n");
// }
@ -6243,7 +6230,6 @@ static void QCBUILTIN PF_mvdsv_freestring(pubprogfuncs_t *prinst, struct globalv
}
#endif
// warning: PF_strcatp defined but not used
/*
static void QCBUILTIN PF_strcatp(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
@ -6269,7 +6255,6 @@ static void QCBUILTIN PF_strcatp(pubprogfuncs_t *prinst, struct globalvars_s *pr
}
*/
// warning: PF_redstring defined but not used
/*
static void QCBUILTIN PF_redstring(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
@ -7743,7 +7728,7 @@ static void QCBUILTIN PF_h2movestep (pubprogfuncs_t *prinst, struct globalvars_s
// save program state, because SV_movestep may call other progs
oldself = pr_global_struct->self;
G_INT(OFS_RETURN) = World_movestep (&sv.world, (wedict_t*)ent, v, NULL, false, true, set_trace?set_trace_globals:NULL, pr_globals);
G_INT(OFS_RETURN) = World_movestep (&sv.world, (wedict_t*)ent, v, NULL, false, true, set_trace?set_trace_globals:NULL);
// restore program state
pr_global_struct->self = oldself;
@ -9781,7 +9766,7 @@ static void QCBUILTIN PF_runclientphys(pubprogfuncs_t *prinst, struct globalvars
if (!touched->v->touch || n >= playertouchmax || (playertouch[n/8]&(1<<(n%8))))
continue;
sv.world.Event_Touch(&sv.world, (wedict_t*)touched, (wedict_t*)ent);
sv.world.Event_Touch(&sv.world, (wedict_t*)touched, (wedict_t*)ent, NULL);
playertouch[n/8] |= 1 << (n%8);
}
pmove.numtouch = 0;
@ -11839,7 +11824,7 @@ void PR_DumpPlatform_f(void)
{"SV_ShouldPause", "float(float newstatus)", QW|NQ, "Called to give the qc a change to block pause/unpause requests. Return false for the pause request to be ignored. newstatus is 1 if the user is trying to pause the game. For the duration of the call, self will be set to the player who tried to pause, or to world if it was triggered by a server-side event."},
{"SV_RunClientCommand", "void()", QW|NQ, "Called each time a player movement packet was received from a client. Self is set to the player entity which should be updated, while the input_* globals specify the various properties stored within the input packet. The contents of this function should be somewaht identical to the equivelent function in CSQC, or prediction misses will occur. If you're feeling lazy, you can simply call 'runstandardplayerphysics' after modifying the inputs."},
{"SV_AddDebugPolygons", "void()", QW|NQ, "Called each video frame. This is the only place where ssqc is allowed to call the R_BeginPolygon/R_PolygonVertex/R_EndPolygon builtins. This is exclusively for debugging, and will break in anything but single player as it will not be called if the engine is not running both a client and a server."},
{"SV_PlayerPhysics", "void()", QW|NQ, "Legacy method to tweak player input that does not reliably work with prediction (prediction WILL break). Mods that care about prediction should use SV_RunClientCommand instead. If pr_no_playerphysics is set to 1, this function will never be called, which will either fix prediction or completely break player movement depending on whether the feature was even useful."},
{"SV_PlayerPhysics", "void()", QW|NQ, "Compatibility method to tweak player input that does not reliably work with prediction (prediction WILL break). Mods that care about prediction should use SV_RunClientCommand instead. If pr_no_playerphysics is set to 1, this function will never be called, which will either fix prediction or completely break player movement depending on whether the feature was even useful."},
{"EndFrame", "void()", QW|NQ, "Called after non-player entities have been run at the end of the physics frame. Player physics is performed out of order and can/will still occur between EndFrame and BeginFrame."},
{"SV_CheckRejectConnection","string(string addr, string uinfo, string features) ", QW|NQ, "Called to give the mod a chance to ignore connection requests based upon client protocol support or other properties. Use infoget to read the uinfo and features arguments."},
#ifdef HEXEN2

View File

@ -977,7 +977,7 @@ static qintptr_t QVM_WalkMove (void *offset, quintptr_t mask, const qintptr_t *a
move[1] = sin(yaw)*dist;
move[2] = 0;
return World_movestep(&sv.world, (wedict_t*)ed, move, axis, true, false, NULL, NULL);
return World_movestep(&sv.world, (wedict_t*)ed, move, axis, true, false, NULL);
}
static qintptr_t QVM_DropToFloor (void *offset, quintptr_t mask, const qintptr_t *arg)
{
@ -2106,7 +2106,7 @@ static void QDECL Q1QVM_Get_FrameState(world_t *w, wedict_t *ent, framestate_t *
#endif
}
static void QDECL Q1QVM_Event_Touch(world_t *w, wedict_t *s, wedict_t *o)
static void QDECL Q1QVM_Event_Touch(world_t *w, wedict_t *s, wedict_t *o, trace_t *trace)
{
int oself = pr_global_struct->self;
int oother = pr_global_struct->other;

View File

@ -326,17 +326,27 @@ and the extension fields are added on the end and can have extra vm-specific stu
#define HALFLIFEMODEL_FIELDS
#endif
#if FRAME_BLENDS >= 4
#define frame34fields \
comfieldfloat(frame3,"Some people just don't understand how to use framegroups...") /**/\
comfieldfloat(frame3time,".frame3 equivelent of frame1time.") /*EXT_CSQC_1*/\
comfieldfloat(lerpfrac3,"Weight of .frame3 - .frame's weight is automatically calculated as 1-(lerpfrac+lerpfrac3+lerpfrac4), as a result these fields should NEVER add to above 1.") /**/\
comfieldfloat(frame4,NULL) /**/\
comfieldfloat(frame4time,".frame4 equivelent of frame1time.") /*EXT_CSQC_1*/\
comfieldfloat(lerpfrac4,NULL) /**/\
#else
#define frame34fields
#endif
//this is the list for all the csqc fields.
//(the #define is so the list always matches the ones pulled out)
#define csqcextfields \
comfieldfloat(entnum,"This is the number of the entity that the ssqc is using.") \
comfieldfloat(frame2,"This is typically the old frame of the entity. if lerpfrac is 1, .frame will be ignored and .frame2 will be used solely. lerpfrac 0.5 will give an even 50/50 blend.") /*EXT_CSQC_1*/\
comfieldfloat(frame3,"Some people just don't understand how to use framegroups...") /**/\
comfieldfloat(frame4,NULL) /**/\
comfieldfloat(frame2time,".frame2 equivelent of frame1time.") /*EXT_CSQC_1*/\
comfieldfloat(lerpfrac,"The value 0 means the entity will animate using only .frame, which will be jerky. As this value is incremented, more of frame2 will be used. If you wish to use .frame2 as the 'old' frame, it is generally recommended to start this field with the value 1, to decrement it by frametime, and when it drops below 0 add 1 to it and update .frame2 and .frame to lerp into the new frame.") /*EXT_CSQC_1*/\
comfieldfloat(lerpfrac3,NULL) /**/\
comfieldfloat(lerpfrac4,NULL) /**/\
comfieldfloat(lerpfrac,"The weight of .frame2. A value of 0 means the entity will animate using only .frame, while 1 would exclusively be .frame2. As this value is incremented, more of frame2 will be used. If you wish to use .frame2 as the 'old' frame, it is generally recommended to start this field with the value 1, to decrement it by frametime, and when it drops below 0 add 1 to it and update .frame2 and .frame to lerp into the new frame.") /*EXT_CSQC_1*/\
frame34fields \
comfieldfloat(renderflags,NULL)\
comfieldfloat(forceshader,"Contains a shader handle used to replace all surfaces upon the entity.")/*FTE_CSQC_SHADERS*/\
\

View File

@ -12,6 +12,7 @@ extern cvar_t pr_enable_profiling;
cvar_t sv_savefmt = CVARFD("sv_savefmt", "", CVAR_SAVE, "Specifies the format used for the saved game.\n0=legacy.\n1=fte\n2=binary");
cvar_t sv_autosave = CVARFD("sv_autosave", "5", CVAR_SAVE, "Interval for autosaves, in minutes. Set to 0 to disable autosave.");
extern cvar_t pr_ssqc_memsize;
void SV_Savegame_f (void);
@ -379,7 +380,7 @@ static qboolean SV_Loadgame_Legacy(char *filename, vfsfile_t *f, int version)
Q_SetProgsParms(false);
svs.numprogs = 0;
PR_Configure(svprogfuncs, -1, MAX_PROGS, pr_enable_profiling.ival);
PR_Configure(svprogfuncs, PR_ReadBytesString(pr_ssqc_memsize.string), MAX_PROGS, pr_enable_profiling.ival);
PR_RegisterFields();
PR_InitEnts(svprogfuncs, sv.world.max_edicts); //just in case the max edicts isn't set.
progstype = pt; //presumably the progs.dat will be what they were before.
@ -901,7 +902,7 @@ qboolean SV_LoadLevelCache(const char *savename, const char *level, const char *
if (progstype != PROG_H2)
{
Q_SetProgsParms(false);
PR_Configure(svprogfuncs, -1, MAX_PROGS, pr_enable_profiling.ival);
PR_Configure(svprogfuncs, PR_ReadBytesString(pr_ssqc_memsize.string), MAX_PROGS, pr_enable_profiling.ival);
PR_RegisterFields();
PR_InitEnts(svprogfuncs, sv.world.max_edicts);
}

View File

@ -381,10 +381,30 @@ static void SV_Give_f (void)
static int QDECL ShowMapList (const char *name, qofs_t flags, time_t mtime, void *parm, searchpathfuncs_t *spath)
{
const char *levelshots[] =
{
"levelshots/%s.tga",
"levelshots/%s.jpg",
"levelshots/%s.png",
"maps/%s.tga",
"maps/%s.jpg",
"maps/%s.png"
};
size_t u;
char stripped[64];
if (name[5] == 'b' && name[6] == '_') //skip box models
return true;
COM_StripExtension(name+5, stripped, sizeof(stripped));
for (u = 0; u < countof(levelshots); u++)
{
const char *ls = va(levelshots[u], stripped);
if (COM_FCheckExists(ls))
{
Con_Printf("^[\\map\\%s\\img\\%s\\w\\64\\h\\48^]", stripped, ls);
Con_Printf("^[[%s]\\map\\%s\\tipimg\\%s^]\n", stripped, stripped, ls);
return true;
}
}
Con_Printf("^[[%s]\\map\\%s^]\n", stripped, stripped);
return true;
}

View File

@ -852,8 +852,6 @@ void SV_SpawnServer (const char *server, const char *startspot, qboolean noents,
SCR_ImageName(server);
#endif
NET_InitServer();
sv.state = ss_dead;
if (sv.gamedirchanged)
@ -1391,6 +1389,8 @@ void SV_SpawnServer (const char *server, const char *startspot, qboolean noents,
SCR_ImageName(server);
#endif
NET_InitServer();
//
// spawn the rest of the entities on the map
//

View File

@ -110,10 +110,10 @@ cvar_t sv_reconnectlimit = CVARD("sv_reconnectlimit", "0", "Blocks dupe connecti
extern cvar_t net_enable_dtls;
cvar_t sv_reportheartbeats = CVARD("sv_reportheartbeats", "2", "Print a notice each time a heartbeat is sent to a master server. When set to 2, the message will be displayed once.");
cvar_t sv_highchars = CVAR("sv_highchars", "1");
cvar_t sv_maxrate = CVAR("sv_maxrate", "30000");
cvar_t sv_maxdrate = CVARAF("sv_maxdrate", "500000",
"sv_maxdownloadrate", 0);
cvar_t sv_minping = CVARF("sv_minping", "", CVAR_SERVERINFO);
cvar_t sv_maxrate = CVARD("sv_maxrate", "50000", "This controls the maximum number of bytes any indivual player may receive (when not downloading). The individual user's rate will also be controlled by the user's rate cvar.");
cvar_t sv_maxdrate = CVARAFD("sv_maxdrate", "500000",
"sv_maxdownloadrate", 0, "This cvar controls the maximum number of bytes sent to each player per second while that player is downloading.\nIf this cvar is set to 0, there will be NO CAP for download rates (if the user's drate is empty/0 too, then expect really fast+abusive downloads that could potentially be considered denial of service attacks)");
cvar_t sv_minping = CVARFD("sv_minping", "", CVAR_SERVERINFO, "Simulate fake lag for any players with a ping under the value specified here. Value is in milliseconds.");
cvar_t sv_bigcoords = CVARFD("sv_bigcoords", "1", 0, "Uses floats for coordinates instead of 16bit values.\nAlso boosts angle precision, so can be useful even on small maps.\nAffects clients thusly:\nQW: enforces a mandatory protocol extension\nDP: enables DPP7 protocol support\nNQ: uses RMQ protocol (protocol 999).");
cvar_t sv_calcphs = CVARFD("sv_calcphs", "2", CVAR_LATCH, "Enables culling of sound effects. 0=always skip phs. Sounds are globally broadcast. 1=always generate phs. Sounds are always culled. On large maps the phs will be dumped to disk. 2=On large single-player maps, generation of phs is skipped. Otherwise like option 1.");
@ -5546,6 +5546,8 @@ void SV_ExtractFromUserinfo (client_t *cl, qboolean verbose)
}
//make CERTAIN that the name we think they're using is actually the name everyone else sees too.
//bots are allowed empty names. this gives the gamecode a chance to actually assign one.
if (cl->protocol != SCP_BAD)
{
InfoBuf_SetValueForKey (&cl->userinfo, "name", newname);
val = InfoBuf_ValueForKey (&cl->userinfo, "name");

View File

@ -142,7 +142,7 @@ possible, no move is done, false is returned, and
pr_global_struct->trace_normal is set to the normal of the blocking wall
=============
*/
qboolean World_movestep (world_t *world, wedict_t *ent, vec3_t move, vec3_t axis[3], qboolean relink, qboolean noenemy, void (*set_move_trace)(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals, trace_t *trace), struct globalvars_s *set_trace_globs)
qboolean World_movestep (world_t *world, wedict_t *ent, vec3_t move, vec3_t axis[3], qboolean relink, qboolean noenemy, void (*set_move_trace)(pubprogfuncs_t *prinst, trace_t *trace))
{
float dz;
vec3_t oldorg, neworg, end;
@ -192,7 +192,7 @@ qboolean World_movestep (world_t *world, wedict_t *ent, vec3_t move, vec3_t axis
}
trace = World_Move (world, ent->v->origin, ent->v->mins, ent->v->maxs, neworg, false, ent);
if (set_move_trace)
set_move_trace(world->progs, set_trace_globs, &trace);
set_move_trace(world->progs, &trace);
if (trace.fraction == 1)
{
@ -218,7 +218,7 @@ qboolean World_movestep (world_t *world, wedict_t *ent, vec3_t move, vec3_t axis
trace = World_Move (world, neworg, ent->v->mins, ent->v->maxs, end, false, ent);
if (set_move_trace)
set_move_trace(world->progs, set_trace_globs, &trace);
set_move_trace(world->progs, &trace);
if (trace.allsolid)
return false;
@ -229,7 +229,7 @@ qboolean World_movestep (world_t *world, wedict_t *ent, vec3_t move, vec3_t axis
VectorMA(neworg, -movevars.stepheight, axis[2], neworg);
trace = World_Move (world, neworg, ent->v->mins, ent->v->maxs, end, false, ent);
if (set_move_trace)
set_move_trace(world->progs, set_trace_globs, &trace);
set_move_trace(world->progs, &trace);
if (trace.allsolid || trace.startsolid)
return false;
}
@ -448,7 +448,7 @@ qboolean World_StepDirection (world_t *world, wedict_t *ent, float yaw, float di
//FIXME: Hexen2: ent flags & FL_SET_TRACE
VectorCopy (ent->v->origin, oldorigin);
if (World_movestep (world, ent, move, axis, false, false, NULL, NULL))
if (World_movestep (world, ent, move, axis, false, false, NULL))
{
delta = anglemod(delta);
if (delta > 45 && delta < 315)

View File

@ -2659,8 +2659,8 @@ char *SV_MVDName2Txt(char *name)
ext = COM_GetFileExtension(s, ext);
if (!ext || !*ext) //if there's no extension on there, then make sure we're pointing to the end of the string.
ext = s+strlen(s);
if (ext > s+sizeof(s)+4) //make sure we don't overflow the buffer by truncating the base/path, ensuring that we don't write some other type of file.
ext = s+sizeof(s)+4; //should probably make this an error case and abort instead.
if (ext > s+sizeof(s)-4) //make sure we don't overflow the buffer by truncating the base/path, ensuring that we don't write some other type of file.
ext = s+sizeof(s)-4; //should probably make this an error case and abort instead.
strcpy((char*)ext, ".txt");
return va("%s", s);

View File

@ -70,7 +70,7 @@ cvar_t pm_watersinkspeed = CVARFD("pm_watersinkspeed", "", CVAR_SERVERINFO, "Th
cvar_t pm_flyfriction = CVARFD("pm_flyfriction", "", CVAR_SERVERINFO, "Amount of friction that applies in fly or 6dof mode. Empty means 4.");
cvar_t pm_slidefix = CVARF("pm_slidefix", "", CVAR_SERVERINFO);
cvar_t pm_slidyslopes = CVARF("pm_slidyslopes", "", CVAR_SERVERINFO);
cvar_t pm_airstep = CVARF("pm_airstep", "", CVAR_SERVERINFO);
cvar_t pm_airstep = CVARAF("pm_airstep", "", "sv_jumpstep", CVAR_SERVERINFO);
cvar_t pm_stepdown = CVARF("pm_stepdown", "", CVAR_SERVERINFO);
cvar_t pm_walljump = CVARF("pm_walljump", "", CVAR_SERVERINFO);
@ -105,7 +105,6 @@ void WPhys_Init(void)
static void WPhys_Physics_Toss (world_t *w, wedict_t *ent);
// warning: SV_CheckAllEnts defined but not used
/*
================
SV_CheckAllEnts
@ -239,12 +238,12 @@ static void WPhys_Impact (world_t *w, wedict_t *e1, trace_t *trace)
*w->g.time = w->physicstime;
if (e1->v->touch && e1->v->solid != SOLID_NOT)
{
w->Event_Touch(w, e1, e2);
w->Event_Touch(w, e1, e2, trace);
}
if (e2->v->touch && e2->v->solid != SOLID_NOT)
{
w->Event_Touch(w, e2, e1);
w->Event_Touch(w, e2, e1, trace);
}
}
@ -1657,7 +1656,6 @@ static void WPhys_WallFriction (wedict_t *ent, trace_t *trace)
ent->v->velocity[1] = side[1] * (1 + d);
}
// warning: SV_TryUnstick defined but not used
/*
=====================
SV_TryUnstick
@ -1951,7 +1949,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 (!(sv_jumpstep.value && sv_gameplayfix_stepwhilejumping.value))
if (!pm_airstep.value)
if (!oldonground && ent->v->waterlevel == 0)
return;
}
@ -2079,7 +2077,7 @@ void WPhys_RunEntity (world_t *w, wedict_t *ent)
{
#ifdef HEXEN2
wedict_t *movechain;
vec3_t initial_origin = {0},initial_angle = {0}; // warning: initial_?[?] may be used uninitialized in this function
vec3_t initial_origin = {0},initial_angle = {0};
#endif
const float *gravitydir;

View File

@ -329,6 +329,22 @@ void Con_DLPrintf (int level, const char *fmt, ...)
if (log_developer.value)
Con_Log(msg); // log to console
}
//for spammed warnings, so they don't spam prints with every single frame/call. the timer arg should be a static local.
void VARGS Con_ThrottlePrintf (float *timer, int developerlevel, const char *fmt, ...)
{
va_list argptr;
char msg[MAXPRINTMSG];
va_start (argptr,fmt);
vsnprintf (msg,sizeof(msg)-1, fmt,argptr);
va_end (argptr);
if (developerlevel)
Con_DLPrintf (developerlevel, "%s", msg);
else
Con_Printf("%s", msg);
}
#endif
/*

View File

@ -879,10 +879,10 @@ int main(int argc, char *argv[])
#endif
//decide if we should be printing colours to the stdout or not.
if (!COM_CheckParm("-nocolour")||!COM_CheckParm("-nocolor"))
if (COM_CheckParm("-nocolour")||COM_CheckParm("-nocolor"))
useansicolours = false;
else
useansicolours = (isatty(STDOUT_FILENO) || !COM_CheckParm("-colour")||!COM_CheckParm("-color"));
useansicolours = (isatty(STDOUT_FILENO) || COM_CheckParm("-colour") || COM_CheckParm("-color"));
switch(Sys_CheckChRoot())
{

View File

@ -4224,7 +4224,14 @@ void SV_PTrack_f (void)
if (!SV_CanTrack(host_client, i+1))
{
SV_ClientTPrintf (host_client, PRINT_HIGH, "invalid player to track\n");
if (i < 0 || i >= sv.allocated_client_slots)
SV_ClientTPrintf (host_client, PRINT_HIGH, "invalid player to track\n");
else if (svs.clients[i].spectator)
SV_ClientTPrintf (host_client, PRINT_HIGH, "cannot track other spectators\n");
else if (svs.clients[i].state != cs_spawned)
SV_ClientTPrintf (host_client, PRINT_HIGH, "cannot track - player not spawned yet\n");
else
SV_ClientTPrintf (host_client, PRINT_HIGH, "invalid player to track\n");
host_client->spec_track = 0;
ent = EDICT_NUM_PB(svprogfuncs, host_client - svs.clients + 1);
tent = EDICT_NUM_PB(svprogfuncs, 0);
@ -7416,11 +7423,11 @@ if (sv_player->v->health > 0 && before && !after )
VectorCopy(pmove.touchvel[i], old_vel);
VectorCopy(pmove.touchvel[i], sv_player->v->velocity);
}
sv.world.Event_Touch(&sv.world, (wedict_t*)ent, (wedict_t*)sv_player);
sv.world.Event_Touch(&sv.world, (wedict_t*)ent, (wedict_t*)sv_player, NULL);
}
if (sv_player->v->touch && !ED_ISFREE(ent))
sv.world.Event_Touch(&sv.world, (wedict_t*)sv_player, (wedict_t*)ent);
sv.world.Event_Touch(&sv.world, (wedict_t*)sv_player, (wedict_t*)ent, NULL);
}
}

View File

@ -803,7 +803,7 @@ static void QDECL PFQ2_SetAreaPortalState(unsigned int p, qboolean s)
qboolean SVQ2_InitGameProgs(void)
{
extern cvar_t maxclients;
volatile static game_import_t import; //volatile because msvc sucks
static volatile game_import_t import; //volatile because msvc sucks
if (COM_CheckParm("-noq2dll"))
{
SVQ2_ShutdownGameProgs();

View File

@ -1921,7 +1921,7 @@ void World_TouchAllLinks (world_t *w, wedict_t *ent)
if (!((int)ent->xv->dimension_solid & (int)touch->xv->dimension_hit)) //didn't change did it?...
continue;
w->Event_Touch(w, touch, ent);
w->Event_Touch(w, touch, ent, NULL);
if (ED_ISFREE(ent))
break;
@ -2059,7 +2059,7 @@ static void World_ClipToLinks (world_t *w, areagridlink_t *node, moveclip_t *cli
//even if the trace traveled less, we still care if it was in a solid.
clip->trace.startsolid |= trace.startsolid;
clip->trace.allsolid |= trace.allsolid;
if (!clip->trace.ent)
if (!clip->trace.ent || trace.fraction == clip->trace.fraction) //xonotic requires that second test (DP has no check at all, which would end up reporting mismatched fraction/ent results, so yuck).
{
clip->trace.contents = trace.contents;
clip->trace.ent = touch;

View File

@ -138,7 +138,7 @@ static unsigned int domkeytoshift(unsigned int code)
/* 0*/ 0,0,0,0,0,0,0,0, K_BACKSPACE,K_TAB,0,0,0,K_ENTER,0,0,
/* 16*/ K_SHIFT,K_CTRL,K_ALT,K_PAUSE,K_CAPSLOCK,0,0,0,0,0,0,K_ESCAPE,0,0,0,0,
/* 32*/ ' ',K_PGUP,K_PGDN,K_END,K_HOME,K_LEFTARROW,K_UPARROW,K_RIGHTARROW, K_DOWNARROW,0,0,0,K_PRINTSCREEN,K_INS,K_DEL,0,
/* 48*/ ')','!','\"',0/*」*/,'$','%','^','&', '*','(',0,':',0,'+',0,0,
/* 48*/ ')','!','\"',0xA3/*poundsign*/,'$','%','^','&', '*','(',0,':',0,'+',0,0,
/* 64*/ 0,'A','B','C','D','E','F','G', 'H','I','J','K','L','M','N','O',
/* 80*/ 'P','Q','R','S','T','U','V','W', 'X','Y','Z',K_LWIN,K_RWIN,K_APP,0,0,