cl_clock 2; now gives a 12-hour clock.

fix configs not getting execed properly when not run from the automatically detected basedir.
fix some silly bugs.
qcc: remove deprecated %5 support without qccx syntax.
qcc: added -Fembedsrc to embed the sourcecode into the progs in a form that can be read with various standard unzip programs. This works without breaking any engines.
server: fix memory explosion issue with fitz666 clients.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5016 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2016-09-01 14:31:24 +00:00
parent c08a0aa139
commit 57dfaea5fd
25 changed files with 2775 additions and 2529 deletions

View file

@ -775,6 +775,7 @@ ifeq (,$(findstring NO_ZLIB,$(CFLAGS)))
SV_LDFLAGS+=-lz
GL_LDFLAGS+=-lz
M_LDFLAGS+=-lz
QCC_LDFLAGS+=-lz
endif
@ -868,10 +869,12 @@ ifeq (win_SDL,$(findstring win,$(FTE_TARGET))$(findstring _SDL,$(FTE_TARGET)))
GL_LDFLAGS=$(GLLDFLAGS) -lmingw32 -lws2_32 `$(SDLCONFIG) --static-libs`
M_LDFLAGS=$(MLDFLAGS) -lmingw32 -lws2_32 `$(SDLCONFIG) --static-libs`
SV_LDFLAGS=$(MINGW_LIBS_DIR)/libz.a -lm -lmingw32 -lws2_32 -lwinmm `$(SDLCONFIG) --static-libs`
QCC_LDFLAGS=$(MINGW_LIBS_DIR)/libz.a
else
GL_LDFLAGS=$(IMAGELDFLAGS) $(OGGVORBISLDFLAGS) -lws2_32 -lmingw32 $(SDL_LDFLAGS) -mwindows -ldxguid -lwinmm -lole32 $(GLLDFLAGS) `$(SDLCONFIG) --libs`
M_LDFLAGS=$(IMAGELDFLAGS) $(OGGVORBISLDFLAGS) -lws2_32 -lmingw32 -mwindows -ldxguid -lwinmm -lole32 $(MLDFLAGS) `$(SDL_CONFIG) --libs` $(IMAGELDFLAGS)
SV_LDFLAGS=$(MINGW_LIBS_DIR)/libz.a -lm -lmingw32 -lws2_32 -lwinmm `$(SDLCONFIG) --libs`
QCC_LDFLAGS=$(MINGW_LIBS_DIR)/libz.a
endif
GL_CFLAGS=-DFTE_SDL -I$(MINGW_LIBS_DIR)/ -I$(MINGW_LIBS_DIR) -I$(LIBS_DIR) $(GLCFLAGS) -DLIBVORBISFILE_STATIC $(DX7SDK) $(SPEEXCFLAGS)
@ -1039,6 +1042,7 @@ ifeq (win,$(findstring win,$(FTE_TARGET))$(findstring _SDL,$(FTE_TARGET)))
BITS=64
endif
QCC_DIR=winqcc$(BITS)
QCC_LDFLAGS=$(MINGW_LIBS_DIR)/libz.a
BASELDFLAGS=
@ -1625,7 +1629,7 @@ m-profile:
_qcc-tmp: $(REQDIR)
@$(MAKE) $(TYPE) EXE_NAME="$(EXE_NAME)$(EXEPOSTFIX)" PRECOMPHEADERS="" OUT_DIR="$(OUT_DIR)" WCFLAGS="$(CLIENT_ONLY_CFLAGS) $(WCFLAGS)" LDFLAGS="$(LDFLAGS)" OBJS="QCC_OBJS SOBJS"
@$(MAKE) $(TYPE) EXE_NAME="$(EXE_NAME)$(EXEPOSTFIX)" PRECOMPHEADERS="" OUT_DIR="$(OUT_DIR)" WCFLAGS="$(CLIENT_ONLY_CFLAGS) $(WCFLAGS)" LDFLAGS="$(LDFLAGS) $(QCC_LDFLAGS)" OBJS="QCC_OBJS SOBJS"
qcc-rel:
@$(MAKE) _qcc-tmp TYPE=_out-rel REQDIR=reldir EXE_NAME="../fteqcc$(BITS)" OUT_DIR="$(RELEASE_DIR)/$(QCC_DIR)" SOBJS="qcctui.o $(if $(findstring win,$(FTE_TARGET)),fteqcc.o)"
qccgui-rel:

View file

@ -2073,9 +2073,8 @@ void CL_CheckServerInfo(void)
if (cls.protocol == CP_NETQUAKE)
{ //proquake likes spamming us with fixangles
float div = cls.proquake_angles_hack?65536:256;
//should be about 0.5/65536, but there's some precision issues with such small numbers around 80, so we need to bias it more than we ought
cl.maxpitch -= 1.0/2048;
cl.minpitch -= 0.5/div;
}
}
else

View file

@ -1552,7 +1552,10 @@ void SCR_DrawClock(void)
time( &long_time );
newtime = localtime( &long_time );
strftime( str, sizeof(str)-1, "%H:%M ", newtime);
if (show_clock.ival == 2)
strftime( str, sizeof(str)-1, "%I:%M %p ", newtime);
else
strftime( str, sizeof(str)-1, "%H:%M ", newtime);
SCR_StringXY(str, show_clock_x.value, show_clock_y.value);
}

View file

@ -373,8 +373,8 @@ static qboolean PM_MergePackage(package_t *oldp, package_t *newp)
;
for (nm = 0; nm < countof(newp->mirror) && newp->mirror[nm]; nm++)
;
if (oldp->priority != newp->priority)
return false;
// if (oldp->priority != newp->priority)
// return false;
ignorefiles = (oldp->extract==EXTRACT_ZIP); //zips ignore the remote file list, its only important if its already installed (so just keep the old file list and its fine).
if (oldp->extract != newp->extract)
@ -415,6 +415,7 @@ static qboolean PM_MergePackage(package_t *oldp, package_t *newp)
if (newp->license){Z_Free(oldp->license); oldp->license = Z_StrDup(newp->license);}
if (newp->author){Z_Free(oldp->author); oldp->author = Z_StrDup(newp->author);}
if (newp->previewimage){Z_Free(oldp->previewimage); oldp->previewimage = Z_StrDup(newp->previewimage);}
oldp->priority = newp->priority;
if (nm)
{ //copy over the mirrors

View file

@ -2105,34 +2105,28 @@ void M_Menu_Main_f (void)
y = 32;
mainm->selecteditem = (menuoption_t *)
#ifndef CLIENTONLY
MC_AddConsoleCommandQBigFont (mainm, 72, y, "Single ", "menu_single\n"); y += 20;
MC_AddConsoleCommandQBigFont (mainm, 72, y, "Single ", "menu_single\n"); y += 20;
#endif
MC_AddConsoleCommandQBigFont (mainm, 72, y, "Multiplayer ", "menu_multi\n"); y += 20;
MC_AddConsoleCommandQBigFont (mainm, 72, y, "Options ", "menu_options\n"); y += 20;
MC_AddConsoleCommandQBigFont (mainm, 72, y, "Multiplayer ", "menu_multi\n"); y += 20;
MC_AddConsoleCommandQBigFont (mainm, 72, y, "Options ", "menu_options\n"); y += 20;
if (m_helpismedia.value)
{
MC_AddConsoleCommandQBigFont(mainm, 72, y, "Media ", "menu_media\n"); y += 20;
}
{MC_AddConsoleCommandQBigFont(mainm, 72, y, "Media ", "menu_media\n"); y += 20;}
else
{
MC_AddConsoleCommandQBigFont(mainm, 72, y, "Help ", "help\n"); y += 20;
}
{MC_AddConsoleCommandQBigFont(mainm, 72, y, "Help ", "help\n"); y += 20;}
if (Cmd_AliasExist("mod_menu", RESTRICT_LOCAL))
{
MC_AddConsoleCommandQBigFont(mainm, 72, y, va("%-13s", Cvar_Get("mod_menu", "Mod Menu", 0, NULL)->string), "mod_menu\n"); y += 20;
}
{MC_AddConsoleCommandQBigFont(mainm, 72, y, va("%-14s", Cvar_Get("mod_menu", "Mod Menu", 0, NULL)->string), "mod_menu\n"); y += 20;}
if (Cmd_Exists("xmpp"))
{
MC_AddConsoleCommandQBigFont(mainm, 72, y, "Social ", "xmpp\n"); y += 20;
}
{MC_AddConsoleCommandQBigFont(mainm, 72, y, "Social ", "xmpp\n"); y += 20;}
if (Cmd_Exists("irc"))
{
MC_AddConsoleCommandQBigFont(mainm, 72, y, "IRC ", "irc\n"); y += 20;
}
{MC_AddConsoleCommandQBigFont(mainm, 72, y, "IRC ", "irc\n"); y += 20;}
if (Cmd_Exists("qi"))
{MC_AddConsoleCommandQBigFont(mainm, 72, y, "Quake Injector", "qi\n"); y += 20;}
if (Cmd_Exists("menu_download"))
{MC_AddConsoleCommandQBigFont(mainm, 72, y, "Updates ", "menu_download\n"); y += 20;}
#ifdef FTE_TARGET_WEB
MC_AddConsoleCommandQBigFont (mainm, 72, y, "Save Settings", "menu_quit\n"); y += 20;
MC_AddConsoleCommandQBigFont (mainm, 72, y, "Save Settings ", "menu_quit\n"); y += 20;
#else
MC_AddConsoleCommandQBigFont (mainm, 72, y, "Quit ", "menu_quit\n"); y += 20;
MC_AddConsoleCommandQBigFont (mainm, 72, y, "Quit ", "menu_quit\n"); y += 20;
#endif
mainm->cursoritem = (menuoption_t *)MC_AddCursor(mainm, &resel, 54, 32);

View file

@ -3114,7 +3114,8 @@ static void Mods_Draw(int x, int y, struct menucustom_s *c, struct menu_s *m)
if (!mods->nummanifests)
{
Draw_FunString(x, y+0, "No games or mods known");
Draw_FunString(x, y+8, "Consider using -basedir $PATHTOGAME on the commandline");
Draw_FunString(x, y+8, "You may need to use -basedir $PATHTOGAME on the commandline");
return;
}
for (i = 0; y+8 <= ym && i < mods->nummanifests; y+=8, i++)
@ -3132,18 +3133,27 @@ static qboolean Mods_Key(struct menucustom_s *c, struct menu_s *m, int key, unsi
ftemanifest_t *man;
if (key == K_MOUSE1)
{
qboolean wasgameless = !*FS_GetGamedir(false);
i = (mousecursor_y - mods->y)/8;
if (i < 0 || i > mods->nummanifests)
return false;
man = mods->manifests[i];
mods->manifests[i] = NULL;
mods->manifests[i] = NULL; //make sure the manifest survives the menu being closed.
M_RemoveMenu(m);
FS_ChangeGame(man, true, true);
//starting to a blank state generally means that the current config settings are utterly useless and windowed by default.
//so generally when switching to a *real* game, we want to restart video just so things like fullscreen etc are saved+used properly.
//if we're already running a game, this should probably just be a vid_reload instead to ensure that the conback etc is reloaded.
Cbuf_AddText("\nvid_restart\n", RESTRICT_LOCAL);
if (wasgameless && !!*FS_GetGamedir(false))
{
//starting to a blank state generally means that the current(engine-default) config settings are utterly useless and windowed by default.
//so generally when switching to a *real* game, we want to restart video just so things like fullscreen etc are saved+used properly.
Cbuf_AddText("\nvid_restart\n", RESTRICT_LOCAL);
}
else
{
//if we're already running a game, this should probably just be a vid_reload instead to ensure that the conback etc is reloaded.
//(a full restart is annoying)
Cbuf_AddText("\nvid_reload\n", RESTRICT_LOCAL);
}
return true;
}
@ -3184,29 +3194,21 @@ void M_Menu_Mods_f (void)
memset(&mods, 0, sizeof(mods));
FS_EnumerateKnownGames(Mods_AddMod, &mods);
if (mods.nummanifests == 1)
{
FS_ChangeGame(mods.manifests[0], true, true);
Z_Free(mods.manifests);
}
else
{
Key_Dest_Add(kdm_emenu);
Key_Dest_Add(kdm_emenu);
menu = M_CreateMenu(sizeof(modmenu_t));
*(modmenu_t*)menu->data = mods;
if (COM_FCheckExists("gfx/p_option.lmp"))
{
MC_AddPicture(menu, 16, 4, 32, 144, "gfx/qplaque.lmp");
MC_AddCenterPicture(menu, 0, 24, "gfx/p_option.lmp");
}
c = MC_AddCustom(menu, 64, 32, menu->data, 0);
menu->cursoritem = (menuoption_t*)c;
c->draw = Mods_Draw;
c->key = Mods_Key;
menu->remove = Mods_Remove;
menu = M_CreateMenu(sizeof(modmenu_t));
*(modmenu_t*)menu->data = mods;
if (COM_FCheckExists("gfx/p_option.lmp"))
{
MC_AddPicture(menu, 16, 4, 32, 144, "gfx/qplaque.lmp");
MC_AddCenterPicture(menu, 0, 24, "gfx/p_option.lmp");
}
c = MC_AddCustom(menu, 64, 32, menu->data, 0);
menu->cursoritem = (menuoption_t*)c;
c->draw = Mods_Draw;
c->key = Mods_Key;
menu->remove = Mods_Remove;
}
#if 0

View file

@ -473,7 +473,7 @@ void M_Menu_SinglePlayer_f (void)
{
menu = M_CreateMenu(0);
MC_AddPicture(menu, 16, 4, 32, 144, "gfx/qplaque.lmp");
MC_AddCenterPicture(menu, 0, 24, "gfx/ttl_sgl.lmp");
MC_AddCenterPicture(menu, 4, 24, "gfx/ttl_sgl.lmp");
menu->selecteditem = (menuoption_t*)
MC_AddConsoleCommandQBigFont (menu, 72, 32, "New Game", va("closemenu;disconnect;maxclients 1;deathmatch 0;coop %i;startmap_sp\n", cl_splitscreen.ival>0));

View file

@ -2746,6 +2746,38 @@ static void QCBUILTIN PF_ReadAngle(pubprogfuncs_t *prinst, struct globalvars_s *
G_FLOAT(OFS_RETURN) = MSG_ReadAngle();
}
//basically acts as a readstring, but with added precache (and download)
static void QCBUILTIN PF_ReadPicture(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
char *imagename;
unsigned short size;
if (!csqc_mayread)
{
CSQC_Abort("PF_ReadPicture is not valid at this time");
G_INT(OFS_RETURN) = 0;
return;
}
imagename = MSG_ReadString();
size = MSG_ReadShort();
MSG_ReadSkip(size);
//do the precache+download thing
{
shader_t *pic = R2D_SafeCachePic(imagename);
char ext[8];
//fixme: probably shouldn't block here.
if ((!pic || !R_GetShaderSizes(pic, NULL, NULL, true)) && cls.state
#ifndef CLIENTONLY
&& !sv.active
#endif
&& *COM_FileExtension(imagename, ext, sizeof(ext))) //only try to download it if it looks as though it contains a path.
CL_CheckOrEnqueDownloadFile(imagename, imagename, 0);
}
RETURN_TSTRING(imagename);
}
static void QCBUILTIN PF_objerror (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{

View file

@ -99,6 +99,12 @@ static qboolean WASAPI_DetermineFormat(soundcardinfo_t *sc, IAudioClient *dev, q
{
Con_Printf("WASAPI: overriding channels\n");
if (sc->sn.numchannels >= 8)
{
pwfx->nChannels = 8;
if (pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
((WAVEFORMATEXTENSIBLE*)pwfx)->dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_FRONT_LEFT_OF_CENTER | SPEAKER_FRONT_RIGHT_OF_CENTER;
}
if (sc->sn.numchannels >= 6)
{
pwfx->nChannels = 6;

View file

@ -4861,9 +4861,21 @@ qboolean FS_ChangeGame(ftemanifest_t *man, qboolean allowreloadconfigs, qboolean
man = FS_ReadDefaultManifest(newbasedir, sizeof(newbasedir), fixedbasedir);
if (!man && isDedicated)
{ //dedicated servers have no menu code, so just pick the first fmf we could find.
FS_EnumerateKnownGames(FS_FoundManifest, &man);
if (!man)
{
int found = FS_EnumerateKnownGames(FS_FoundManifest, &man);
if (found != 1)
{
//we found more than 1 (or none)
//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)
man = NULL;
else if (found)
Con_Printf(CON_WARNING "Warning: found multiple possible games. Using the first found.\n");
else
Con_Printf(CON_ERROR "Error: unable to determine correct game/basedir.\n");
}
}
if (!man)
{
@ -5183,7 +5195,7 @@ static int QDECL FS_EnumerateFMFs(const char *fname, qofs_t fsize, time_t mtime,
return true;
}
void FS_EnumerateKnownGames(qboolean (*callback)(void *usr, ftemanifest_t *man), void *usr)
int FS_EnumerateKnownGames(qboolean (*callback)(void *usr, ftemanifest_t *man), void *usr)
{
int i;
char basedir[MAX_OSPATH];
@ -5230,6 +5242,7 @@ void FS_EnumerateKnownGames(qboolean (*callback)(void *usr, ftemanifest_t *man),
}
}
}
return e.found;
}
//attempts to find a new basedir for 'input', changing to it as appropriate

View file

@ -70,7 +70,7 @@ void FS_AddHashedPackage(searchpath_t **oldpaths, const char *parent_pure, const
void PM_LoadPackages(searchpath_t **oldpaths, const char *parent_pure, const char *parent_logical, searchpath_t *search, unsigned int loadstuff, int minpri, int maxpri);
void Menu_Download_Update(void);
void FS_EnumerateKnownGames(qboolean (*callback)(void *usr, ftemanifest_t *man), void *usr);
int FS_EnumerateKnownGames(qboolean (*callback)(void *usr, ftemanifest_t *man), void *usr);
#define SPF_REFERENCED 1 //something has been loaded from this path. should filter out client references...
#define SPF_COPYPROTECTED 2 //downloads are not allowed fom here.

View file

@ -2655,7 +2655,9 @@ void QCBUILTIN PF_parseentitydata(pubprogfuncs_t *prinst, struct globalvars_s *p
size_t size;
if (offset)
if (offset < 0)
offset = 0;
else if (offset)
{
int boffset = offset;
if (VMUTF8)
@ -2979,12 +2981,12 @@ void QCBUILTIN PF_strpad (pubprogfuncs_t *prinst, struct globalvars_s *pr_global
if (pad < 0)
{ //pad left
pad = -pad - strlen(src);
if (pad>=MAXTEMPBUFFERLEN)
pad = MAXTEMPBUFFERLEN-1;
if (pad>=sizeof(destbuf))
pad = sizeof(destbuf)-1;
if (pad < 0)
pad = 0;
Q_strncpyz(dest+pad, src, MAXTEMPBUFFERLEN-pad);
Q_strncpyz(dest+pad, src, sizeof(destbuf)-pad);
while(pad)
{
dest[--pad] = ' ';
@ -2992,13 +2994,13 @@ void QCBUILTIN PF_strpad (pubprogfuncs_t *prinst, struct globalvars_s *pr_global
}
else
{ //pad right
if (pad>=MAXTEMPBUFFERLEN)
pad = MAXTEMPBUFFERLEN-1;
if (pad>=sizeof(destbuf))
pad = sizeof(destbuf)-1;
pad -= strlen(src);
if (pad < 0)
pad = 0;
Q_strncpyz(dest, src, MAXTEMPBUFFERLEN);
Q_strncpyz(dest, src, sizeof(destbuf));
dest+=strlen(dest);
while(pad-->0)
@ -4116,7 +4118,11 @@ void QCBUILTIN PF_buf_writefile (pubprogfuncs_t *prinst, struct globalvars_s *p
midx = min(midx, strbuflist[bufno].used);
for(strings = strbuflist[bufno].strings; idx < midx; idx++)
{
PF_fwrite_internal (prinst, fnum, strings[idx], strlen(strings[idx]));
if (strings[idx])
{
PF_fwrite_internal (prinst, fnum, strings[idx], strlen(strings[idx]));
PF_fwrite_internal (prinst, fnum, "\n", 1);
}
}
G_FLOAT(OFS_RETURN) = 1;
}
@ -4211,7 +4217,7 @@ void QCBUILTIN PF_uri_unescape (pubprogfuncs_t *prinst, struct globalvars_s *pr
unsigned char *i, *o;
unsigned char hex;
i = s; o = resultbuf;
while (*i)
while (*i && o < resultbuf+sizeof(resultbuf)-2)
{
if (*i == '%')
{

View file

@ -45,9 +45,6 @@ struct wedict_s
#define PF_drawline PF_Fixme
#define PF_WritePicture PF_Fixme
#define PF_ReadPicture PF_Fixme
#define G_PROG G_FLOAT
//the lh extension system asks for a name for the extension.

File diff suppressed because it is too large Load diff

View file

@ -5095,6 +5095,7 @@ static void * Mod_LoadSpriteGroup (model_t *mod, void * pin, void *pend, msprite
dspriteinterval_t *pin_intervals;
float *poutintervals;
void *ptemp;
float prevtime;
pingroup = (dspritegroup_t *)pin;
@ -5112,7 +5113,7 @@ static void * Mod_LoadSpriteGroup (model_t *mod, void * pin, void *pend, msprite
pspritegroup->intervals = poutintervals;
for (i=0 ; i<numframes ; i++)
for (i=0, prevtime=0 ; i<numframes ; i++)
{
*poutintervals = LittleFloat (pin_intervals->interval);
if (*poutintervals <= 0.0)
@ -5120,6 +5121,7 @@ static void * Mod_LoadSpriteGroup (model_t *mod, void * pin, void *pend, msprite
Con_Printf (CON_ERROR "Mod_LoadSpriteGroup: interval<=0\n");
return NULL;
}
prevtime = *poutintervals = prevtime+*poutintervals;
poutintervals++;
pin_intervals++;

View file

@ -595,6 +595,7 @@ extern pbool flag_brokenarrays;
extern pbool flag_rootconstructor;
extern pbool flag_guiannotate;
extern pbool flag_qccx;
extern pbool flag_embedsrc;
extern pbool opt_overlaptemps;
extern pbool opt_shortenifnots;
@ -1033,7 +1034,9 @@ int QCC_CopyStringLength (char *str, size_t length);
typedef struct qcc_cachedsourcefile_s {
char filename[128];
int size;
size_t size;
size_t zhdrofs;
int zcrc;
char *file;
enum{FT_CODE, FT_DATA} type; //quakec source file or not.
struct qcc_cachedsourcefile_s *next;

View file

@ -108,6 +108,7 @@ pbool flag_guiannotate;
pbool flag_brokenarrays; //return array; returns array[0] instead of &array;
pbool flag_rootconstructor; //if true, class constructors are ordered to call the super constructor first, rather than the child constructor
pbool flag_qccx;
pbool flag_embedsrc;
pbool opt_overlaptemps; //reduce numpr_globals by reuse of temps. When they are not needed they are freed for reuse. The way this is implemented is better than frikqcc's. (This is the single most important optimisation)
pbool opt_assignments; //STORE_F isn't used if an operation wrote to a temp.
@ -5054,6 +5055,7 @@ QCC_sref_t QCC_PR_GenerateFunctionCallRef (QCC_sref_t newself, QCC_sref_t func,
{
fparm.sym = &def_parms[parm+ofs/3];
fparm.cast = type_vector;
QCC_ForceUnFreeDef(fparm.sym);
}
fparm.ofs = ofs - (ofs%3);
if (!fparm.ofs)
@ -5122,6 +5124,7 @@ QCC_sref_t QCC_PR_GenerateFunctionCallRef (QCC_sref_t newself, QCC_sref_t func,
{
if (args[i].ref.sym != d.sym || args[i].ref.ofs != d.ofs)
{
QCC_ForceUnFreeDef(d.sym);
if (args[i].ref.cast->size == 3)
QCC_FreeTemp(QCC_PR_StatementFlags (&pr_opcodes[OP_STORE_V], args[i].ref, d, NULL, 0));
else
@ -5238,6 +5241,7 @@ QCC_sref_t QCC_PR_GenerateFunctionCallRef (QCC_sref_t newself, QCC_sref_t func,
d.sym = &def_parms[parm];
d.ofs = 0;
d.cast = type_vector;
QCC_ForceUnFreeDef(d.sym);
}
d.cast = arglist[i]->cast;
@ -9545,6 +9549,145 @@ void PR_GenerateReturnOuts(void)
local = local->deftail->nextlocal;
}
}
/*
============
QCC_PR_ParseStatement_For
pulled out of QCC_PR_ParseStatement because of stack use.
============
*/
void QCC_PR_ParseStatement (void);
void QCC_PR_ParseStatement_For(void)
{
int continues;
int breaks;
int i;
QCC_sref_t e;
QCC_def_t *d;
QCC_statement_t *patch1, *patch2, *patch3, *patch4;
int old_numstatements;
int numtemp;
QCC_def_t *subscopestop;
QCC_def_t *subscopestart = pr.local_tail;
QCC_statement_t temp[256];
continues = num_continues;
breaks = num_breaks;
QCC_PR_Expect("(");
if (!QCC_PR_CheckToken(";"))
{
do
{
QCC_type_t *type = QCC_PR_ParseType (false, true);
if (type)
{
d = QCC_PR_GetDef (type, QCC_PR_ParseName(), pr_scope, true, 0, 0);
QCC_PR_Expect("=");
QCC_PR_ParseInitializerDef(d);
QCC_FreeDef(d);
QCC_FreeDef(d);
}
else
QCC_PR_DiscardExpression(TOP_PRIORITY, EXPR_DISALLOW_COMMA);
} while(QCC_PR_CheckToken(","));
QCC_PR_Expect(";");
}
subscopestop = pr_subscopedlocals?NULL:pr.local_tail->nextlocal;
QCC_ClobberDef(NULL);
patch2 = &statements[numstatements]; //restart of the loop
if (!QCC_PR_CheckToken(";"))
{
conditional = 1;
e = QCC_PR_Expression(TOP_PRIORITY, 0);
conditional = 0;
QCC_PR_Expect(";");
}
else
e = nullsref;
if (e.cast) //final condition+jump
QCC_FreeTemp(QCC_PR_StatementFlags(&pr_opcodes[OP_IFNOT_I], e, nullsref, &patch1, STFL_DISCARDRESULT));
else
patch1 = NULL;
if (!QCC_PR_CheckToken(")"))
{
old_numstatements = numstatements;
QCC_PR_DiscardExpression(TOP_PRIORITY, 0);
numtemp = numstatements - old_numstatements;
if (numtemp > sizeof(temp)/sizeof(temp[0]))
QCC_PR_ParseError(ERR_TOOCOMPLEX, "Update expression too large");
numstatements = old_numstatements;
for (i = 0 ; i < numtemp ; i++)
{
temp[i] = statements[numstatements + i];
}
QCC_PR_Expect(")");
}
else
numtemp = 0;
//parse the statement block
if (!QCC_PR_CheckToken(";"))
QCC_PR_ParseStatement(); //don't give the hanging ';' warning.
patch3 = &statements[numstatements]; //location for continues
//reinsert the 'increment' statements. lets hope they didn't have any gotos...
for (i = 0 ; i < numtemp ; i++)
{
statements[numstatements] = temp[i];
statements[numstatements].linenum = pr_token_line_last;
numstatements++;
}
patch4 = QCC_Generate_OP_GOTO();
patch4->a.ofs = patch2 - patch4;
if (patch1)
patch1->b.ofs = &statements[numstatements] - patch1; //condition failure jumps here
//fix up breaks+continues
if (breaks != num_breaks)
{
for(i = breaks; i < num_breaks; i++)
{
patch1 = &statements[pr_breaks[i]];
statements[pr_breaks[i]].a.ofs = &statements[numstatements] - patch1;
}
num_breaks = breaks;
}
if (continues != num_continues)
{
for(i = continues; i < num_continues; i++)
{
patch1 = &statements[pr_continues[i]];
statements[pr_continues[i]].a.ofs = patch3 - patch1;
}
num_continues = continues;
}
//remove any new locals from the hashtable.
//typically this is just the stuff inside the for(here;;)
for (d = subscopestart->nextlocal; d != subscopestop; d = d->nextlocal)
{
if (!d->subscoped_away)
{
pHash_RemoveData(&localstable, d->name, d);
d->subscoped_away = true;
}
}
return;
}
/*
============
PR_ParseStatement
@ -9559,7 +9702,7 @@ void QCC_PR_ParseStatement (void)
int i;
QCC_sref_t e, e2;
QCC_def_t *d;
QCC_statement_t *patch1, *patch2, *patch3, *patch4;
QCC_statement_t *patch1, *patch2, *patch3;
int statementstart = pr_source_line;
pbool wasuntil;
@ -9733,122 +9876,7 @@ void QCC_PR_ParseStatement (void)
}
if (QCC_PR_CheckKeyword(keyword_for, "for"))
{
int old_numstatements;
int numtemp, i;
QCC_def_t *subscopestop;
QCC_def_t *subscopestart = pr.local_tail;
QCC_statement_t temp[256];
continues = num_continues;
breaks = num_breaks;
QCC_PR_Expect("(");
if (!QCC_PR_CheckToken(";"))
{
do
{
QCC_type_t *type = QCC_PR_ParseType (false, true);
if (type)
{
d = QCC_PR_GetDef (type, QCC_PR_ParseName(), pr_scope, true, 0, 0);
QCC_PR_Expect("=");
QCC_PR_ParseInitializerDef(d);
QCC_FreeDef(d);
QCC_FreeDef(d);
}
else
QCC_PR_DiscardExpression(TOP_PRIORITY, EXPR_DISALLOW_COMMA);
} while(QCC_PR_CheckToken(","));
QCC_PR_Expect(";");
}
subscopestop = pr_subscopedlocals?NULL:pr.local_tail->nextlocal;
QCC_ClobberDef(NULL);
patch2 = &statements[numstatements]; //restart of the loop
if (!QCC_PR_CheckToken(";"))
{
conditional = 1;
e = QCC_PR_Expression(TOP_PRIORITY, 0);
conditional = 0;
QCC_PR_Expect(";");
}
else
e = nullsref;
if (e.cast) //final condition+jump
QCC_FreeTemp(QCC_PR_StatementFlags(&pr_opcodes[OP_IFNOT_I], e, nullsref, &patch1, STFL_DISCARDRESULT));
else
patch1 = NULL;
if (!QCC_PR_CheckToken(")"))
{
old_numstatements = numstatements;
QCC_PR_DiscardExpression(TOP_PRIORITY, 0);
numtemp = numstatements - old_numstatements;
if (numtemp > sizeof(temp)/sizeof(temp[0]))
QCC_PR_ParseError(ERR_TOOCOMPLEX, "Update expression too large");
numstatements = old_numstatements;
for (i = 0 ; i < numtemp ; i++)
{
temp[i] = statements[numstatements + i];
}
QCC_PR_Expect(")");
}
else
numtemp = 0;
//parse the statement block
if (!QCC_PR_CheckToken(";"))
QCC_PR_ParseStatement(); //don't give the hanging ';' warning.
patch3 = &statements[numstatements]; //location for continues
//reinsert the 'increment' statements. lets hope they didn't have any gotos...
for (i = 0 ; i < numtemp ; i++)
{
statements[numstatements] = temp[i];
statements[numstatements].linenum = pr_token_line_last;
numstatements++;
}
patch4 = QCC_Generate_OP_GOTO();
patch4->a.ofs = patch2 - patch4;
if (patch1)
patch1->b.ofs = &statements[numstatements] - patch1; //condition failure jumps here
//fix up breaks+continues
if (breaks != num_breaks)
{
for(i = breaks; i < num_breaks; i++)
{
patch1 = &statements[pr_breaks[i]];
statements[pr_breaks[i]].a.ofs = &statements[numstatements] - patch1;
}
num_breaks = breaks;
}
if (continues != num_continues)
{
for(i = continues; i < num_continues; i++)
{
patch1 = &statements[pr_continues[i]];
statements[pr_continues[i]].a.ofs = patch3 - patch1;
}
num_continues = continues;
}
//remove any new locals from the hashtable.
//typically this is just the stuff inside the for(here;;)
for (d = subscopestart->nextlocal; d != subscopestop; d = d->nextlocal)
{
if (!d->subscoped_away)
{
pHash_RemoveData(&localstable, d->name, d);
d->subscoped_away = true;
}
}
QCC_PR_ParseStatement_For();
return;
}
if (QCC_PR_CheckKeyword(keyword_do, "do"))
@ -14178,6 +14206,19 @@ pbool QCC_PR_CompileFile (char *string, char *filename)
{
QCC_def_t *d;
unsigned int i;
for (i = 0; i < MAX_PARMS; i++)
{
d = &def_parms[i];
if (d->refcount)
{
QCC_sref_t sr;
sr.sym = d;
sr.cast = d->type;
sr.ofs = 0;
QCC_PR_ParseWarning(WARN_DEBUGGING, "INTERNAL: %i references still held on %s (%s)", d->refcount, d->name, QCC_VarAtOffset(sr, 1));
d->refcount = 0;
}
}
for (d = pr.def_head.next; d; d = d->next)
{
if (d->refcount)

View file

@ -3319,24 +3319,14 @@ void QCC_PR_Lex (void)
// if the first character is a valid identifier, parse until a non-id
// character is reached
if ((c == '%') && (pr_file_p[1] == '-' || (pr_file_p[1] >= '0' && pr_file_p[1] <= '9')))
if ((c == '%') && flag_qccx && (pr_file_p[1] == '-' || (pr_file_p[1] >= '0' && pr_file_p[1] <= '9')))
{
if (flag_qccx)
{ //with qccx, %5 is a denormalized float.
pr_file_p++;
pr_token_type = tt_immediate;
pr_immediate_type = type_float;
QCC_PR_ParseWarning(WARN_DENORMAL, "denormalized immediate");
pr_immediate._int = QCC_PR_LexInteger ();
}
else
{
QCC_PR_ParseWarning(0, "%% prefixes to denote integers are deprecated. Please use a postfix of 'i'");
pr_file_p++;
pr_token_type = tt_immediate;
pr_immediate_type = type_integer;
pr_immediate._int = QCC_PR_LexInteger ();
}
//with qccx, %5 is a denormalized float.
pr_file_p++;
pr_token_type = tt_immediate;
pr_immediate_type = type_float;
QCC_PR_ParseWarning(WARN_DENORMAL, "denormalized immediate");
pr_immediate._int = QCC_PR_LexInteger ();
return;
}
if ( c == '0' && pr_file_p[1] == 'x')

View file

@ -349,6 +349,7 @@ compiler_flag_t compiler_flag[] = {
{&flag_typeexplicit, FLAG_MIDCOMPILE,"typeexplicit", "Explicit types", "All type conversions must be explicit or directly supported by instruction set."},
{&flag_noboundchecks, FLAG_MIDCOMPILE,"noboundchecks","Disable Bound Checks", "Disable array index checks, speeding up array access but can result in your code misbehaving."},
{&flag_qccx, FLAG_MIDCOMPILE,"qccx", "QCCX syntax", "WARNING: This syntax makes mods inherantly engine specific.\nDo NOT use unless you know what you're doing.This is provided for compatibility only\nAny entity hacks will be unsupported in FTEQW, DP, and others, resulting in engine crashes if the code in question is executed."},
{&flag_embedsrc, FLAG_MIDCOMPILE,"embedsrc", "Embed Sources", "Write the sourcecode into the output file."},
// {&flag_noreflection, FLAG_MIDCOMPILE,"omitinternals","Omit Reflection Info", "Keeps internal symbols private (equivelent to unix's hidden visibility). This has the effect of reducing filesize, thwarting debuggers, and breaking saved games. This allows you to use arrays without massively bloating the size of your progs.\nWARNING: The bit about breaking saved games was NOT a joke, but does not apply to menuqc or csqc. It also interferes with FTE_MULTIPROGS."},
{NULL}
};
@ -657,7 +658,7 @@ void QCC_PrintFiles (void)
continue; //*-prefixed models are not real, and shouldn't be included in file lists.
if (!header)
{
printf("pak%i:\n", b);
printf("pak%i:\n", b-1);
header=true;
}
printf("%s\n", precaches[g].list[i].name);
@ -670,66 +671,169 @@ void QCC_PrintFiles (void)
}
int encode(int len, int method, char *in, int handle);
int WriteSourceFiles(int h, dprograms_t *progs, pbool sourceaswell)
int WriteSourceFiles(int h, pbool sourceaswell, pbool legacyembed)
{
//helpers to deal with misaligned data. writes little-endian.
#define misbyte(ptr,ofs,data) ((unsigned char*)(ptr))[ofs] = (data)&0xff;
#define misshort(ptr,ofs,data) misbyte((ptr),(ofs),(data));misbyte((ptr),(ofs)+1,(data)>>8);
#define misint(ptr,ofs,data) misshort((ptr),(ofs),(data));misshort((ptr),(ofs)+2,(data)>>16);
includeddatafile_t *idf;
qcc_cachedsourcefile_t *f;
int num=0;
int ofs;
/*
for (f = qcc_sourcefile; f ; f=f->next)
{
if (f->type == FT_CODE && !sourceaswell)
continue;
SafeWrite(h, f->filename, strlen(f->filename)+1);
i = PRLittleLong(f->size);
SafeWrite(h, &i, sizeof(int));
i = PRLittleLong(encrpytmode);
SafeWrite(h, &i, sizeof(int));
if (encrpytmode)
for (i = 0; i < f->size; i++)
f->file[i] ^= 0xA5;
SafeWrite(h, f->file, f->size);
}*/
pbool zipembed = true;
int startofs;
sourceaswell |= flag_embedsrc;
for (f = qcc_sourcefile,num=0; f ; f=f->next)
{
if (f->type == FT_CODE && !sourceaswell)
continue;
num++;
}
if (!num)
{
if (zipembed)
{ //zips are found by scanning. so make sure something can be found so noone will erroneously find something
char centralheader[22];
int centraldirofs = SafeSeek(h, 0, SEEK_CUR);
misint (centralheader, 0, 0x06054b50);
misshort(centralheader, 4, 0); //this disk number
misshort(centralheader, 6, 0); //centraldir first disk
misshort(centralheader, 8, 0); //centraldir entries
misshort(centralheader, 10, 0); //total centraldir entries
misint (centralheader, 12, 0); //centraldir size
misint (centralheader, 16, centraldirofs); //centraldir offset
misshort(centralheader, 20, 0); //comment length
SafeWrite(h, centralheader, 22);
}
return 0;
}
startofs = SafeSeek(h, 0, SEEK_CUR);
idf = qccHunkAlloc(sizeof(includeddatafile_t)*num);
for (f = qcc_sourcefile,num=0; f ; f=f->next)
{
if (f->type == FT_CODE && !sourceaswell)
continue;
strcpy(idf[num].filename, f->filename);
idf[num].size = f->size;
#ifdef AVAIL_ZLIB
idf[num].compmethod = 2;
#else
idf[num].compmethod = 1;
#endif
idf[num].ofs = SafeSeek(h, 0, SEEK_CUR);
idf[num].compsize = QC_encode(progfuncs, f->size, idf[num].compmethod, f->file, h);
if (zipembed)
{
size_t end;
char header[32+sizeof(f->filename)];
size_t fnamelen = strlen(f->filename);
f->zcrc = QC_encodecrc(f->size, f->file);
misint (header, 0, 0x04034b50);
misshort(header, 4, 0);//minver
misshort(header, 6, 0);//general purpose flags
misshort(header, 8, 0);//compression method, 0=store, 8=deflate
misshort(header, 10, 0);//lastmodfiletime
misshort(header, 12, 0);//lastmodfiledate
misint (header, 14, f->zcrc);//crc32
misint (header, 18, f->size);//compressed size
misint (header, 22, f->size);//uncompressed size
misshort(header, 26, fnamelen);//filename length
misshort(header, 28, 0);//extradata length
strcpy(header+30, f->filename);
f->zhdrofs = SafeSeek(h, 0, SEEK_CUR);
SafeWrite(h, header, 30+fnamelen);
strcpy(idf[num].filename, f->filename);
idf[num].size = f->size;
idf[num].compmethod = 8; //must be 0(raw) or 8(raw deflate) for zips to work
idf[num].ofs = SafeSeek(h, 0, SEEK_CUR);
if (idf[num].compmethod==0)
SafeWrite(h, f->file, f->size);
else
{
idf[num].compsize = QC_encode(progfuncs, f->size, idf[num].compmethod, f->file, h);
misshort(header, 8, idf[num].compmethod);//compression method, 0=store, 8=deflate
misint (header, 18, idf[num].compsize);
end = SafeSeek(h, 0, SEEK_CUR);
SafeSeek(h, f->zhdrofs, SEEK_SET);
SafeWrite(h, header, 30+strlen(f->filename));
SafeSeek(h, end, SEEK_SET);
}
}
else
{
if (f->type == FT_CODE && !sourceaswell)
continue;
strcpy(idf[num].filename, f->filename);
idf[num].size = f->size;
#ifdef AVAIL_ZLIB
idf[num].compmethod = 2;
#else
idf[num].compmethod = 1;
#endif
idf[num].ofs = SafeSeek(h, 0, SEEK_CUR);
idf[num].compsize = QC_encode(progfuncs, f->size, idf[num].compmethod, f->file, h);
}
num++;
}
ofs = SafeSeek(h, 0, SEEK_CUR);
SafeWrite(h, &num, sizeof(int));
SafeWrite(h, idf, sizeof(includeddatafile_t)*num);
if (zipembed)
{
char centralheader[46+sizeof(f->filename)];
int centraldirsize;
ofs = SafeSeek(h, 0, SEEK_CUR);
for (f = qcc_sourcefile,num=0; f ; f=f->next)
{
size_t fnamelen;
if (f->type == FT_CODE && !sourceaswell)
continue;
fnamelen = strlen(f->filename);
misint (centralheader, 0, 0x02014b50);
misshort(centralheader, 4, 0);//ourver
misshort(centralheader, 6, 0);//minver
misshort(centralheader, 8, 0);//general purpose flags
misshort(centralheader, 10, idf[num].compmethod);//compression method, 0=store, 8=deflate
misshort(centralheader, 12, 0);//lastmodfiletime
misshort(centralheader, 14, 0);//lastmodfiledate
misint (centralheader, 16, f->zcrc);//crc32
misint (centralheader, 20, idf[num].compsize);//compressed size
misint (centralheader, 24, f->size);//uncompressed size
misshort(centralheader, 28, fnamelen);//filename length
misshort(centralheader, 30, 0);//extradata length
misshort(centralheader, 32, 0);//comment length
misshort(centralheader, 34, 0);//first disk number
misshort(centralheader, 36, 0);//internal file attribs
misint (centralheader, 38, 0);//external file attribs
misint (centralheader, 42, f->zhdrofs);//local header offset
strcpy(centralheader+46, f->filename);
SafeWrite(h, centralheader, 46 + fnamelen);
num++;
}
centraldirsize = SafeSeek(h, 0, SEEK_CUR)-ofs;
misint (centralheader, 0, 0x06054b50);
misshort(centralheader, 4, 0); //this disk number
misshort(centralheader, 6, 0); //centraldir first disk
misshort(centralheader, 8, num); //centraldir entries
misshort(centralheader, 10, num); //total centraldir entries
misint (centralheader, 12, centraldirsize); //centraldir size
misint (centralheader, 16, ofs); //centraldir offset
misshort(centralheader, 20, 0); //comment length
SafeWrite(h, centralheader, 22);
ofs = 0;
}
else if (legacyembed)
{
ofs = SafeSeek(h, 0, SEEK_CUR);
SafeWrite(h, &num, sizeof(int));
SafeWrite(h, idf, sizeof(includeddatafile_t)*num);
}
else
ofs = 0;
qcc_sourcefile = NULL;
printf("Embedded files take %u bytes\n", SafeSeek(h, 0, SEEK_CUR) - startofs);
return ofs;
}
@ -760,6 +864,7 @@ void QCC_InitData (void)
def_ret.symbolheader = &def_ret;
for (i=0 ; i<MAX_PARMS ; i++)
{
def_parms[i].symbolheader = &def_parms[i];
def_parms[i].temp = NULL;
def_parms[i].type = NULL;
def_parms[i].ofs = OFS_PARM0 + 3*i;
@ -1044,6 +1149,8 @@ pbool QCC_WriteData (int crc)
extern char *basictypenames[];
memset(&progs, 0, sizeof(progs));
if (numstatements==1 && numfunctions==1 && numglobaldefs==1 && numfielddefs==1)
{
printf("nothing to write\n");
@ -1955,13 +2062,17 @@ strofs = (strofs+3)&~3;
{
case QCF_QTEST:
progs.version = PROG_QTESTVERSION;
progs.ofsfiles = WriteSourceFiles(h, debugtarget, false);
break;
case QCF_KK7:
progs.version = PROG_KKQWSVVERSION;
progs.ofsfiles = WriteSourceFiles(h, debugtarget, false);
break;
default:
case QCF_STANDARD:
case QCF_HEXEN2: //urgh
progs.version = PROG_VERSION;
progs.ofsfiles = WriteSourceFiles(h, debugtarget, false);
break;
case QCF_DARKPLACES:
case QCF_FTE:
@ -2017,7 +2128,7 @@ strofs = (strofs+3)&~3;
progs.numtypes = 0;
}
progs.ofsfiles = WriteSourceFiles(h, &progs, debugtarget);
progs.ofsfiles = WriteSourceFiles(h, debugtarget, true);
break;
}

View file

@ -1,6 +1,7 @@
pbool QC_decodeMethodSupported(int method);
char *QC_decode(progfuncs_t *progfuncs, int complen, int len, int method, char *info, char *buffer);
int QC_encode(progfuncs_t *progfuncs, int len, int method, char *in, int handle);
int QC_encodecrc(int len, char *in);
char *PDECL filefromprogs(pubprogfuncs_t *progfuncs, progsnum_t prnum, char *fname, size_t *size, char *buffer);
char *filefromnewprogs(pubprogfuncs_t *progfuncs, char *prname, char *fname, size_t *size, char *buffer);//fixme - remove parm 1

View file

@ -1,7 +1,9 @@
#include "progsint.h"
//#include "qcc.h"
//#define AVAIL_ZLIB
#ifndef NO_ZLIB
#define AVAIL_ZLIB
#endif
#ifdef AVAIL_ZLIB
#ifdef _WIN32
@ -86,6 +88,14 @@ char *QC_decode(progfuncs_t *progfuncs, int complen, int len, int method, char *
}
#if !defined(MINIMAL) && !defined(OMIT_QCC)
int QC_encodecrc(int len, char *in)
{
#ifdef AVAIL_ZLIB
return crc32(0, in, len);
#else
return 0;
#endif
}
void SafeWrite(int hand, void *buf, long count);
int SafeSeek(int hand, int ofs, int mode);
//we are allowed to trash our input here.
@ -104,7 +114,7 @@ int QC_encode(progfuncs_t *progfuncs, int len, int method, char *in, int handle)
SafeWrite(handle, in, len);
return len;
}
else if (method == 2) //compression (ZLIB)
else if (method == 2 || method == 8) //compression (ZLIB)
{
#ifdef AVAIL_ZLIB
char out[8192];
@ -131,7 +141,10 @@ int QC_encode(progfuncs_t *progfuncs, int len, int method, char *in, int handle)
};
i=0;
deflateInit(&strm, Z_BEST_COMPRESSION);
if (method == 8)
deflateInit2(&strm, 9, Z_DEFLATED, -MAX_WBITS, 9, Z_DEFAULT_STRATEGY); //zip deflate compression
else
deflateInit(&strm, Z_BEST_COMPRESSION); //zlib compression
while(deflate(&strm, Z_FINISH) == Z_OK)
{
SafeWrite(handle, out, sizeof(out) - strm.avail_out); //compress in chunks of 8192. Saves having to allocate a huge-mega-big buffer
@ -170,7 +183,7 @@ char *PDECL filefromprogs(pubprogfuncs_t *ppf, progsnum_t prnum, char *fname, si
if (!pr_progstate[prnum].progs->secondaryversion != PROG_SECONDARYVERSION16 &&
!pr_progstate[prnum].progs->secondaryversion != PROG_SECONDARYVERSION32)
return NULL;
num = *(int*)((char *)pr_progstate[prnum].progs + pr_progstate[prnum].progs->ofsfiles);
s = (includeddatafile_t *)((char *)pr_progstate[prnum].progs + pr_progstate[prnum].progs->ofsfiles+4);
while(num>0)

View file

@ -4944,6 +4944,22 @@ static void QCBUILTIN PF_WriteString (pubprogfuncs_t *prinst, struct globalvars_
PF_WriteString_Internal(G_FLOAT(OFS_PARM0), str);
}
static void QCBUILTIN PF_WritePicture (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
//name size data
//this is basically a stub, so we write a size of 0. the client will have to just deal with it.
int target = G_FLOAT(OFS_PARM0);
string_t o = G_INT(OFS_PARM1);
float sizelimit = G_INT(OFS_PARM2);
(void)sizelimit; //we don't use this, because we don't bother trying to re-compress the thing here.
PF_WriteString_Internal(target, PR_GetString(prinst, o));
G_FLOAT(OFS_PARM1) = 0;
PF_WriteShort(prinst, pr_globals);
G_INT(OFS_PARM1) = o;
}
void QCBUILTIN PF_WriteEntity (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
@ -9783,7 +9799,7 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
{"mvdstrcpy", PF_MVDSV_strcpy, 0, 0, 0, 97, D("void(string dst, string src)",NULL), true},
{"strstr", PF_strstr, 0, 0, 0, 98, D("string(string str, string sub)",NULL), true},
{"mvdstrncpy", PF_MVDSV_strncpy, 0, 0, 0, 99, D("void(string dst, string src, float count)",NULL), true},
{"log", PF_logtext, 0, 0, 0, 100, D("void(string name, float console, string text)",NULL), true},
{"logtext", PF_logtext, 0, 0, 0, 100, D("void(string name, float console, string text)",NULL), true},
// {"redirectcmd", PF_redirectcmd, 0, 0, 0, 101, D("void(entity to, string str)",NULL), true},
{"mvdcalltimeofday",PF_calltimeofday, 0, 0, 0, 102, D("void()",NULL), true},
{"forcedemoframe", PF_forcedemoframe, 0, 0, 0, 103, D("void(float now)",NULL), true},
@ -10404,7 +10420,7 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
{"precache_vwep_model",PF_precache_vwep_model,0,0, 0, 532, "float(string mname)"},
//end mvdsv extras
//restart dp extras
// {"log", PF_Logarithm, 0, 0, 0, 532, "float(float v, float base)", true},
{"log", PF_Logarithm, 0, 0, 0, 532, D("float(float v, optional float base)", "Determines the logarithm of the input value according to the specified base. This can be used to calculate how much something was shifted by.")},
{"soundupdate", PF_Fixme, 0, 0, 0, 0, D("float(entity e, float channel, string newsample, float volume, float attenuation, float pitchpct, float flags, float timeoffset)", "Changes the properties of the current sound being played on the given entity channel. newsample may be empty, and will be ignored in this case. timeoffset is relative to the current position (subtract the result of getsoundtime for absolute positions). Negative volume can be used to stop the sound. Return value is a fractional value based upon the number of audio devices that could be updated - test against TRUE rather than non-zero.")},
{"getsoundtime", PF_Ignore, 0, 0, 0, 533, D("float(entity e, float channel)", "Returns the current playback time of the sample on the given entity's channel. Beware CHAN_AUTO (in csqc, channels are not limited by network protocol).")},
{"soundlength", PF_Ignore, 0, 0, 0, 534, D("float(string sample)", "Provides a way to query the duration of a sound sample, allowing you to set up a timer to chain samples.")},
@ -10718,7 +10734,7 @@ void PR_ResetBuiltins(progstype_t type) //fix all nulls to PF_FIXME and add any
PR_EnableEBFSBuiltin("mvdstrcpy", 97) != 97 ||
PR_EnableEBFSBuiltin("strstr", 98) != 98 ||
PR_EnableEBFSBuiltin("mvdstrncpy", 99) != 99 ||
PR_EnableEBFSBuiltin("log", 100)!= 100 ||
PR_EnableEBFSBuiltin("logtext", 100)!= 100 ||
// PR_EnableEBFSBuiltin("redirectcmd", 101)!= 101 ||
PR_EnableEBFSBuiltin("mvdcalltimeofday",102)!= 102 ||
PR_EnableEBFSBuiltin("forcedemoframe", 103)!= 103)
@ -11407,6 +11423,7 @@ void PR_DumpPlatform_f(void)
{"INFOKEY_P_ISLAGGED", "const string", QW|NQ, "1 if the player has the fakelag penalty and has an extra 200ms of lag.", 0, "\"*ismuted\""},
{"INFOKEY_P_PING", "const string", CS|QW|NQ, "The player's ping time, in milliseconds.", 0, "\"ping\""},
{"INFOKEY_P_NAME", "const string", CS|QW|NQ, "The player's name.", 0, "\"name\""},
{"INFOKEY_P_SPECTATOR", "const string", CS|QW|NQ, "Whether the player is a spectator or not.", 0, "\"*spectator\""},
{"INFOKEY_P_TOPCOLOR", "const string", CS|QW|NQ, "The player's upper/shirt colour (palette index).", 0, "\"topcolor\""},
{"INFOKEY_P_BOTTOMCOLOR","const string", CS|QW|NQ, "The player's lower/pants/trouser colour (palette index).", 0, "\"bottomcolor\""},
{"INFOKEY_P_TOPCOLOR_RGB","const string", CS, "The player's upper/shirt colour as an rgb value in a format usable with stov.", 0, "\"topcolor_rgb\""},

View file

@ -3872,7 +3872,7 @@ void SV_WriteEntitiesToClient (client_t *client, sizebuf_t *msg, qboolean ignore
}
host_client = client;
if (client->fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS)
if ((client->fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS) || !frame->entities.entities)
{
pack = &svs.entstatebuffer;
if (pack->max_entities < client->max_net_ents)

View file

@ -1688,6 +1688,7 @@ void SV_AcceptMessage(client_t *newcl)
{
MSG_WriteByte(&sb, 1/*MOD_PROQUAKE*/);
MSG_WriteByte(&sb, 10 * 3.50/*MOD_PROQUAKE_VERSION*/);
MSG_WriteByte(&sb, 0/*flags*/);
}
*(int*)sb.data = BigLong(NETFLAG_CTL|sb.cursize);
NET_SendPacket(NS_SERVER, sb.cursize, sb.data, &net_from);
@ -1796,7 +1797,7 @@ void SV_ClientProtocolExtensionsChanged(client_t *client)
client->max_net_clients = NQMAX_CLIENTS;
client->max_net_ents = bound(512, pr_maxedicts.ival, 32768); //fitzquake supports 65535, but our writeentity builtin works differently, which causes problems.
client->maxmodels = MAX_PRECACHE_MODELS;
maxpacketentities = 65535;
maxpacketentities = client->max_net_ents;
client->datagram.maxsize = sizeof(host_client->datagram_buf);
}
@ -1873,6 +1874,16 @@ void SV_ClientProtocolExtensionsChanged(client_t *client)
//make sure the reset is sent.
client->pendingdeltabits[0] = UF_REMOVE;
}
else if (ISNQCLIENT(client))
{
client->frameunion.frames = Z_Malloc((sizeof(client_frame_t))*UPDATE_BACKUP);
for (i = 0; i < UPDATE_BACKUP; i++)
{
client->frameunion.frames[i].entities.max_entities = 0;
client->frameunion.frames[i].entities.entities = NULL;
client->frameunion.frames[i].senttime = realtime;
}
}
else
{
client->frameunion.frames = Z_Malloc((sizeof(client_frame_t)+sizeof(entity_state_t)*maxpacketentities)*UPDATE_BACKUP);

View file

@ -7391,7 +7391,7 @@ void SV_ExecuteClientMessage (client_t *cl)
}
else
#endif
if (!sv.paused)
if (!sv.paused && sv.world.worldmodel && sv.world.worldmodel->loadstate == MLS_LOADED)
{
if (sv_nqplayerphysics.ival || split->state < cs_spawned)
{