2008-05-25 22:23:43 +00:00
/*
Copyright ( C ) 1996 - 1997 Id Software , Inc .
This program is free software ; you can redistribute it and / or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation ; either version 2
of the License , or ( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE .
See the GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 59 Temple Place - Suite 330 , Boston , MA 02111 - 1307 , USA .
*/
2014-03-30 08:55:06 +00:00
/*64bit cpu notes:
string_t is a 32 bit quantity .
this datatype needs to have enough bits to express any address that contains a string .
in a 32 bit build , this is fine . with a qvm , the offset between the vm base and the string is always less than 32 bits so this is fine too .
HOWEVER . . .
native code uses a base address of 0. this needs a 48 bit datatype for any userland address . 32 bits just ain ' t enough .
even worse : ktx defines string_t as a ' char * ' . okay , its 64 bit at last . . . but it means that the entire entity field structure is now the wrong size with the wrong offsets .
this means CRASH !
how to fix ? good luck with that . seriously .
the only sane way to fix it is to either define a better base address ( say the dll base ,
and require that all string_t values are bss or data and not from malloc , which is problematic when loading dynamic stuff from a map )
alternatively , you could create some string_t - > pointer lookup . messy .
either way , string_t cannot be a pointer .
probably the best solution is to stop using string_t stuff completely . move all those string values somewhere else .
netnames will still mess things up .
so just use qvms .
oh , wait , ktx no longer supports those properly .
*/
2008-05-25 22:23:43 +00:00
# include "quakedef.h"
# ifdef VM_Q1
2009-11-04 21:16:50 +00:00
# include "pr_common.h"
2017-10-12 12:02:25 +00:00
/*version changes:
13 : 2009 / june gamecode no longer aware of edict_t data ( just ' qc ' fields ) .
14 : 2017 / march gamedata_t . maxentities added
15 : 2017 / june for - 64 bit string indirection changes . added GAME_CLEAR_EDICT .
2021-12-20 10:07:55 +00:00
16 : wasted_edict_t_size is finally 0 , mod is responsible for querying all strings .
2017-10-12 12:02:25 +00:00
*/
2021-12-20 10:07:55 +00:00
# define GAME_API_VERSION 16
2017-10-12 12:02:25 +00:00
# define GAME_API_VERSION_MIN 8
2021-12-20 10:07:55 +00:00
# define MAX_Q1QVM_EDICTS 768 //according to ktx at api version 12 (fte's protocols go to 2048). removed in v14.
2011-07-30 14:14:56 +00:00
# define MAPNAME_LEN 64
2008-05-25 22:23:43 +00:00
2013-03-12 23:24:15 +00:00
void PR_SV_FillWorldGlobals ( world_t * w ) ;
2017-10-12 12:02:25 +00:00
static int qvm_api_version ;
static size_t wasted_edict_t_size ;
2008-05-25 22:23:43 +00:00
//===============================================================
//
// system traps provided by the main engine
//
typedef enum
{
//============== general Quake services ==================
G_GETAPIVERSION , // ( void); //0
G_DPRINT , // ( const char *string ); //1
// print message on the local console
G_ERROR , // ( const char *string ); //2
// abort the game
G_GetEntityToken , //3
G_SPAWN_ENT , //4
G_REMOVE_ENT , //5
G_PRECACHE_SOUND ,
G_PRECACHE_MODEL ,
G_LIGHTSTYLE ,
G_SETORIGIN ,
G_SETSIZE , //10
G_SETMODEL ,
G_BPRINT ,
G_SPRINT ,
G_CENTERPRINT ,
G_AMBIENTSOUND , //15
G_SOUND ,
G_TRACELINE ,
G_CHECKCLIENT ,
G_STUFFCMD ,
G_LOCALCMD , //20
G_CVAR ,
G_CVAR_SET ,
G_FINDRADIUS ,
G_WALKMOVE ,
G_DROPTOFLOOR , //25
G_CHECKBOTTOM ,
G_POINTCONTENTS ,
G_NEXTENT ,
G_AIM ,
G_MAKESTATIC , //30
G_SETSPAWNPARAMS ,
G_CHANGELEVEL ,
G_LOGFRAG ,
G_GETINFOKEY ,
G_MULTICAST , //35
G_DISABLEUPDATES ,
2019-07-16 02:59:12 +00:00
G_WRITEBYTE ,
G_WRITECHAR ,
G_WRITESHORT ,
2008-05-25 22:23:43 +00:00
G_WRITELONG , //40
2019-07-16 02:59:12 +00:00
G_WRITEANGLE ,
G_WRITECOORD ,
G_WRITESTRING ,
2008-05-25 22:23:43 +00:00
G_WRITEENTITY ,
G_FLUSHSIGNON , //45
g_memset ,
2019-07-16 02:59:12 +00:00
g_memcpy ,
g_strncpy ,
g_sin ,
2008-05-25 22:23:43 +00:00
g_cos , //50
2019-07-16 02:59:12 +00:00
g_atan2 ,
g_sqrt ,
g_floor ,
g_ceil ,
2008-05-25 22:23:43 +00:00
g_acos , //55
G_CMD_ARGC ,
G_CMD_ARGV ,
2019-07-16 02:59:12 +00:00
G_TraceBox , //was G_TraceCapsule, which is a misnomer.
2008-05-25 22:23:43 +00:00
G_FS_OpenFile ,
G_FS_CloseFile , //60
G_FS_ReadFile ,
G_FS_WriteFile ,
G_FS_SeekFile ,
G_FS_TellFile ,
G_FS_GetFileList , //65
G_CVAR_SET_FLOAT ,
G_CVAR_STRING ,
G_Map_Extension ,
G_strcmp ,
G_strncmp , //70
G_stricmp ,
G_strnicmp ,
G_Find ,
G_executecmd ,
G_conprint , //75
G_readcmd ,
G_redirectcmd ,
G_Add_Bot ,
G_Remove_Bot ,
G_SetBotUserInfo , //80
G_SetBotCMD ,
G_strftime ,
G_CMD_ARGS ,
G_CMD_TOKENIZE ,
G_strlcpy , //85
G_strlcat ,
G_MAKEVECTORS ,
G_NEXTCLIENT ,
2009-07-06 01:20:20 +00:00
G_PRECACHE_VWEP_MODEL ,
2008-05-25 22:23:43 +00:00
G_SETPAUSE ,
2009-07-11 18:22:02 +00:00
G_SETUSERINFO ,
2008-06-27 20:26:33 +00:00
G_MOVETOGOAL ,
2022-01-08 09:59:59 +00:00
G_VISIBLETO ,
2008-05-25 22:23:43 +00:00
G_MAX
} gameImport_t ;
//
// functions exported by the game subsystem
//
typedef enum
{
GAME_INIT , // ( int levelTime, int randomSeed, int restart );
// init and shutdown will be called every single level
// The game should call G_GET_ENTITY_TOKEN to parse through all the
// entity configuration text and spawn gentities.
GAME_LOADENTS ,
GAME_SHUTDOWN , // (void);
GAME_CLIENT_CONNECT , // ( int clientNum ,int isSpectator);
GAME_PUT_CLIENT_IN_SERVER ,
GAME_CLIENT_USERINFO_CHANGED , // ( int clientNum,int isSpectator );
GAME_CLIENT_DISCONNECT , // ( int clientNum,int isSpectator );
GAME_CLIENT_COMMAND , // ( int clientNum,int isSpectator );
GAME_CLIENT_PRETHINK ,
GAME_CLIENT_THINK , // ( int clientNum,int isSpectator );
GAME_CLIENT_POSTTHINK ,
GAME_START_FRAME , // ( int levelTime );
GAME_SETCHANGEPARMS , //self
GAME_SETNEWPARMS ,
GAME_CONSOLE_COMMAND , // ( void );
GAME_EDICT_TOUCH , //(self,other)
GAME_EDICT_THINK , //(self,other=world,time)
GAME_EDICT_BLOCKED , //(self,other)
GAME_CLIENT_SAY , //(int isteam)
2009-07-14 23:42:54 +00:00
GAME_PAUSED_TIC , //(int milliseconds)
2017-10-12 12:02:25 +00:00
GAME_CLEAR_EDICT , //v15 (sets self.fields to safe values after they're cleared)
2021-11-19 19:40:25 +00:00
GAME_EDICT_CSQCSEND = 200 , //fte entrypoint, called when using SendEntity.
2013-03-12 22:44:00 +00:00
} q1qvmgameExport_t ;
2008-05-25 22:23:43 +00:00
typedef enum
{
2019-07-16 02:59:12 +00:00
F_INT ,
2008-05-25 22:23:43 +00:00
F_FLOAT ,
F_LSTRING , // string on disk, pointer in memory, TAG_LEVEL
// F_GSTRING, // string on disk, pointer in memory, TAG_GAME
F_VECTOR ,
F_ANGLEHACK ,
// F_ENTITY, // index on disk, pointer in memory
// F_ITEM, // index on disk, pointer in memory
// F_CLIENT, // index on disk, pointer in memory
F_IGNORE
} fieldtype_t ;
typedef struct
{
2015-11-18 07:37:39 +00:00
quintptr_t name ;
2008-05-25 22:23:43 +00:00
int ofs ;
fieldtype_t type ;
// int flags;
2015-11-18 07:37:39 +00:00
} fieldN_t ;
typedef struct
{
unsigned int name ;
int ofs ;
fieldtype_t type ;
// int flags;
} field32_t ;
2008-05-25 22:23:43 +00:00
typedef struct {
int pad [ 28 ] ;
int self ;
int other ;
int world ;
float time ;
float frametime ;
int newmis ;
float force_retouch ;
string_t mapname ;
float serverflags ;
float total_secrets ;
float total_monsters ;
float found_secrets ;
float killed_monsters ;
float parm1 ;
float parm2 ;
float parm3 ;
float parm4 ;
float parm5 ;
float parm6 ;
float parm7 ;
float parm8 ;
float parm9 ;
float parm10 ;
float parm11 ;
float parm12 ;
float parm13 ;
float parm14 ;
float parm15 ;
float parm16 ;
vec3_t v_forward ;
vec3_t v_up ;
vec3_t v_right ;
float trace_allsolid ;
float trace_startsolid ;
float trace_fraction ;
vec3_t trace_endpos ;
vec3_t trace_plane_normal ;
float trace_plane_dist ;
int trace_ent ;
float trace_inopen ;
float trace_inwater ;
int msg_entity ;
func_t main ;
func_t StartFrame ;
func_t PlayerPreThink ;
func_t PlayerPostThink ;
func_t ClientKill ;
func_t ClientConnect ;
func_t PutClientInServer ;
func_t ClientDisconnect ;
func_t SetNewParms ;
func_t SetChangeParms ;
} q1qvmglobalvars_t ;
2009-07-14 23:42:54 +00:00
//this is not directly usable in 64bit to refer to a 32bit qvm (hence why we have two versions).
2008-05-25 22:23:43 +00:00
typedef struct
{
2015-11-18 07:37:39 +00:00
unsigned int APIversion ;
unsigned int sizeofent ;
unsigned int maxedicts ;
quintptr_t global ;
quintptr_t fields ;
quintptr_t ents ;
} gameDataPrivate_t ;
2008-05-25 22:23:43 +00:00
typedef struct
{
unsigned int ents ;
2015-11-18 07:37:39 +00:00
int sizeofent ;
2008-05-25 22:23:43 +00:00
unsigned int global ;
unsigned int fields ;
2015-11-18 07:37:39 +00:00
int APIversion ;
2017-10-12 12:02:25 +00:00
# if GAME_API_VERSION >= 14
unsigned int maxentities ;
# endif
2008-05-25 22:23:43 +00:00
} gameData32_t ;
2015-11-18 07:37:39 +00:00
typedef struct
{
quintptr_t ents ;
int sizeofent ;
quintptr_t global ;
quintptr_t fields ;
int APIversion ;
2017-10-12 12:02:25 +00:00
# if GAME_API_VERSION >= 14
unsigned int maxentities ;
# endif
2015-11-18 07:37:39 +00:00
} gameDataN_t ;
2008-05-25 22:23:43 +00:00
typedef enum {
FS_READ_BIN ,
FS_READ_TXT ,
FS_WRITE_BIN ,
FS_WRITE_TXT ,
FS_APPEND_BIN ,
FS_APPEND_TXT
2011-06-29 18:39:11 +00:00
} q1qvmfsMode_t ;
2008-05-25 22:23:43 +00:00
typedef enum {
FS_SEEK_CUR ,
FS_SEEK_END ,
FS_SEEK_SET
} fsOrigin_t ;
2015-07-01 23:15:25 +00:00
# define emufields \
2017-10-12 12:02:25 +00:00
emufield ( gravity , F_FLOAT ) \
emufield ( maxspeed , F_FLOAT ) \
emufield ( movement , F_VECTOR ) \
emufield ( vw_index , F_FLOAT ) \
2019-02-16 19:09:07 +00:00
emufield ( isBot , F_INT ) \
emufield ( items2 , F_FLOAT ) \
2019-03-23 07:06:37 +00:00
emufield ( trackent , F_INT ) /*network another player instead, but not entity because of an mvdsv bug. used during bloodfest.*/ \
emufield ( hideentity , F_INT ) /*backward nodrawtoclient, used by race mode spectators*/ \
emufield ( hideplayers , F_INT ) /*force other clients as invisible, for race mode*/
2019-02-16 19:09:07 +00:00
// emufield(visclients, F_INT) /*bitfield of clients that can see this entity (borked with playerslots>32). used for 'cmd tpmsg foo', and bots.*/
// emufield(teleported, F_INT) /*teleport angle twisting*/
// emufield(brokenankle, F_FLOAT) /*not actually in mvdsv after all*/
2019-03-23 07:06:37 +00:00
// emufield(mod_admin, F_INT) /*enable 'cmd ban' etc when &2*/
2008-05-25 22:23:43 +00:00
2019-02-16 19:09:07 +00:00
static struct
2015-07-01 23:15:25 +00:00
{
# define emufield(n,t) int n;
emufields
# undef emufield
} fofs ;
2008-05-25 22:23:43 +00:00
2014-08-15 02:20:41 +00:00
static const char * q1qvmentstring ;
2008-05-25 22:23:43 +00:00
static vm_t * q1qvm ;
------------------------------------------------------------------------
r4169 | acceptthis | 2013-01-17 08:55:12 +0000 (Thu, 17 Jan 2013) | 31 lines
removed MAX_VISEDICTS limit.
PEXT2_REPLACEMENTDELTAS tweaked, now has 4 million entity limit. still not enabled by default.
TE_BEAM now maps to a separate TEQW_BEAM to avoid conflicts with QW.
added android multitouch emulation for windows/rawinput (in_simulatemultitouch).
split topcolor/bottomcolor from scoreboard, for dp's colormap|1024 feature.
now using utf-8 for windows consoles.
qcc warnings/errors now give clickable console links for quick+easy editing.
disabled menutint when the currently active item changes contrast or gamma (for OneManClan).
Added support for drawfont/drawfontscale.
tweaked the qcvm a little to reduce the number of pointers.
.doll file loading. still experimental and will likely crash. requires csqc active, even if its a dummy progs. this will be fixed in time. Still other things that need cleaning up.
windows: gl_font "?" shows the standard windows font-selection dialog, and can be used to select windows fonts. not all work. and you probably don't want to use windings.
fixed splitscreen support when playing mvds. added mini-scoreboards to splitscreen.
editor/debugger now shows asm if there's no linenumber info. also, pressing f1 for help shows the shortcuts.
Added support for .framegroups files for psk(psa) and iqm formats.
True support for ezquake's colour codes. Mutually exclusive with background colours.
path command output slightly more readable.
added support for digest_hex (MD4, SHA1, CRC16).
skingroups now colourmap correctly.
Fix terrain colour hints, and litdata from the wrong bsp.
fix ftp dual-homed issue. support epsv command, and enable ipv6 (eprt still not supported).
remove d3d11 compilation from the makefile. the required headers are not provided by mingw, and are not available to the build bot, so don't bother.
fix v *= v.x and similar opcodes.
fteqcc: fixed support for áéÃóú type chars in names. utf-8 files now properly supported (even with the utf-8 bom/identifier). utf-16 also supported.
fteqcc: fixed '#if 1 == 3 && 4' parsing.
fteqcc: -Werror acts on the warning, rather than as a separate error. Line numbers are thus more readable.
fteqcc: copyright message now includes compile date instead.
fteqccgui: the treeview control is now coloured depending on whether there were warnings/errors in the last compile.
fteqccgui: the output window is now focused and scrolls down as compilation progresses.
pr_dumpplatform command dumps out some pragmas to convert more serious warnings to errors. This is to avoid the infamous 'fteqcc sucks cos my code sucks' issue.
rewrote prespawn/modelist/soundlist code. server tracks progress now.
------------------------------------------------------------------------
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4167 fc73d0e0-1445-4013-8a0c-d673dee63da5
2013-03-12 22:29:40 +00:00
static pubprogfuncs_t q1qvmprogfuncs ;
2008-05-25 22:23:43 +00:00
2017-10-12 12:02:25 +00:00
static q1qvmglobalvars_t * gvars ;
2008-05-25 22:23:43 +00:00
static void * evars ; //pointer to the gamecodes idea of an edict_t
2015-11-18 07:37:39 +00:00
static quintptr_t vevars ; //offset into the vm base of evars
2008-05-25 22:23:43 +00:00
/*
------------------------------------------------------------------------
r4169 | acceptthis | 2013-01-17 08:55:12 +0000 (Thu, 17 Jan 2013) | 31 lines
removed MAX_VISEDICTS limit.
PEXT2_REPLACEMENTDELTAS tweaked, now has 4 million entity limit. still not enabled by default.
TE_BEAM now maps to a separate TEQW_BEAM to avoid conflicts with QW.
added android multitouch emulation for windows/rawinput (in_simulatemultitouch).
split topcolor/bottomcolor from scoreboard, for dp's colormap|1024 feature.
now using utf-8 for windows consoles.
qcc warnings/errors now give clickable console links for quick+easy editing.
disabled menutint when the currently active item changes contrast or gamma (for OneManClan).
Added support for drawfont/drawfontscale.
tweaked the qcvm a little to reduce the number of pointers.
.doll file loading. still experimental and will likely crash. requires csqc active, even if its a dummy progs. this will be fixed in time. Still other things that need cleaning up.
windows: gl_font "?" shows the standard windows font-selection dialog, and can be used to select windows fonts. not all work. and you probably don't want to use windings.
fixed splitscreen support when playing mvds. added mini-scoreboards to splitscreen.
editor/debugger now shows asm if there's no linenumber info. also, pressing f1 for help shows the shortcuts.
Added support for .framegroups files for psk(psa) and iqm formats.
True support for ezquake's colour codes. Mutually exclusive with background colours.
path command output slightly more readable.
added support for digest_hex (MD4, SHA1, CRC16).
skingroups now colourmap correctly.
Fix terrain colour hints, and litdata from the wrong bsp.
fix ftp dual-homed issue. support epsv command, and enable ipv6 (eprt still not supported).
remove d3d11 compilation from the makefile. the required headers are not provided by mingw, and are not available to the build bot, so don't bother.
fix v *= v.x and similar opcodes.
fteqcc: fixed support for áéÃóú type chars in names. utf-8 files now properly supported (even with the utf-8 bom/identifier). utf-16 also supported.
fteqcc: fixed '#if 1 == 3 && 4' parsing.
fteqcc: -Werror acts on the warning, rather than as a separate error. Line numbers are thus more readable.
fteqcc: copyright message now includes compile date instead.
fteqccgui: the treeview control is now coloured depending on whether there were warnings/errors in the last compile.
fteqccgui: the output window is now focused and scrolls down as compilation progresses.
pr_dumpplatform command dumps out some pragmas to convert more serious warnings to errors. This is to avoid the infamous 'fteqcc sucks cos my code sucks' issue.
rewrote prespawn/modelist/soundlist code. server tracks progress now.
------------------------------------------------------------------------
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4167 fc73d0e0-1445-4013-8a0c-d673dee63da5
2013-03-12 22:29:40 +00:00
static char * Q1QVMPF_AddString ( pubprogfuncs_t * pf , char * base , int minlength )
2008-05-25 22:23:43 +00:00
{
char * n ;
int l = strlen ( base ) ;
Con_Printf ( " warning: string %s will not be readable from the qvm \n " , base ) ;
l = l < minlength ? minlength : l ;
n = Z_TagMalloc ( l + 1 , VMFSID_Q1QVM ) ;
strcpy ( n , base ) ;
return n ;
}
*/
------------------------------------------------------------------------
r4169 | acceptthis | 2013-01-17 08:55:12 +0000 (Thu, 17 Jan 2013) | 31 lines
removed MAX_VISEDICTS limit.
PEXT2_REPLACEMENTDELTAS tweaked, now has 4 million entity limit. still not enabled by default.
TE_BEAM now maps to a separate TEQW_BEAM to avoid conflicts with QW.
added android multitouch emulation for windows/rawinput (in_simulatemultitouch).
split topcolor/bottomcolor from scoreboard, for dp's colormap|1024 feature.
now using utf-8 for windows consoles.
qcc warnings/errors now give clickable console links for quick+easy editing.
disabled menutint when the currently active item changes contrast or gamma (for OneManClan).
Added support for drawfont/drawfontscale.
tweaked the qcvm a little to reduce the number of pointers.
.doll file loading. still experimental and will likely crash. requires csqc active, even if its a dummy progs. this will be fixed in time. Still other things that need cleaning up.
windows: gl_font "?" shows the standard windows font-selection dialog, and can be used to select windows fonts. not all work. and you probably don't want to use windings.
fixed splitscreen support when playing mvds. added mini-scoreboards to splitscreen.
editor/debugger now shows asm if there's no linenumber info. also, pressing f1 for help shows the shortcuts.
Added support for .framegroups files for psk(psa) and iqm formats.
True support for ezquake's colour codes. Mutually exclusive with background colours.
path command output slightly more readable.
added support for digest_hex (MD4, SHA1, CRC16).
skingroups now colourmap correctly.
Fix terrain colour hints, and litdata from the wrong bsp.
fix ftp dual-homed issue. support epsv command, and enable ipv6 (eprt still not supported).
remove d3d11 compilation from the makefile. the required headers are not provided by mingw, and are not available to the build bot, so don't bother.
fix v *= v.x and similar opcodes.
fteqcc: fixed support for áéÃóú type chars in names. utf-8 files now properly supported (even with the utf-8 bom/identifier). utf-16 also supported.
fteqcc: fixed '#if 1 == 3 && 4' parsing.
fteqcc: -Werror acts on the warning, rather than as a separate error. Line numbers are thus more readable.
fteqcc: copyright message now includes compile date instead.
fteqccgui: the treeview control is now coloured depending on whether there were warnings/errors in the last compile.
fteqccgui: the output window is now focused and scrolls down as compilation progresses.
pr_dumpplatform command dumps out some pragmas to convert more serious warnings to errors. This is to avoid the infamous 'fteqcc sucks cos my code sucks' issue.
rewrote prespawn/modelist/soundlist code. server tracks progress now.
------------------------------------------------------------------------
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4167 fc73d0e0-1445-4013-8a0c-d673dee63da5
2013-03-12 22:29:40 +00:00
static edict_t * QDECL Q1QVMPF_EdictNum ( pubprogfuncs_t * pf , unsigned int num )
2008-05-25 22:23:43 +00:00
{
edict_t * e ;
2009-11-04 21:16:50 +00:00
if ( /*num < 0 ||*/ num > = sv . world . max_edicts )
2008-05-25 22:23:43 +00:00
return NULL ;
2015-09-10 10:16:26 +00:00
e = q1qvmprogfuncs . edicttable [ num ] ;
2008-05-25 22:23:43 +00:00
if ( ! e )
{
2015-09-10 10:16:26 +00:00
e = q1qvmprogfuncs . edicttable [ num ] = Z_TagMalloc ( sizeof ( edict_t ) + sizeof ( extentvars_t ) , VMFSID_Q1QVM ) ;
2017-10-12 12:02:25 +00:00
e - > v = ( stdentvars_t * ) ( ( char * ) evars + ( num * sv . world . edict_size ) + wasted_edict_t_size ) ;
2008-05-25 22:23:43 +00:00
e - > xv = ( extentvars_t * ) ( e + 1 ) ;
e - > entnum = num ;
}
return e ;
}
------------------------------------------------------------------------
r4169 | acceptthis | 2013-01-17 08:55:12 +0000 (Thu, 17 Jan 2013) | 31 lines
removed MAX_VISEDICTS limit.
PEXT2_REPLACEMENTDELTAS tweaked, now has 4 million entity limit. still not enabled by default.
TE_BEAM now maps to a separate TEQW_BEAM to avoid conflicts with QW.
added android multitouch emulation for windows/rawinput (in_simulatemultitouch).
split topcolor/bottomcolor from scoreboard, for dp's colormap|1024 feature.
now using utf-8 for windows consoles.
qcc warnings/errors now give clickable console links for quick+easy editing.
disabled menutint when the currently active item changes contrast or gamma (for OneManClan).
Added support for drawfont/drawfontscale.
tweaked the qcvm a little to reduce the number of pointers.
.doll file loading. still experimental and will likely crash. requires csqc active, even if its a dummy progs. this will be fixed in time. Still other things that need cleaning up.
windows: gl_font "?" shows the standard windows font-selection dialog, and can be used to select windows fonts. not all work. and you probably don't want to use windings.
fixed splitscreen support when playing mvds. added mini-scoreboards to splitscreen.
editor/debugger now shows asm if there's no linenumber info. also, pressing f1 for help shows the shortcuts.
Added support for .framegroups files for psk(psa) and iqm formats.
True support for ezquake's colour codes. Mutually exclusive with background colours.
path command output slightly more readable.
added support for digest_hex (MD4, SHA1, CRC16).
skingroups now colourmap correctly.
Fix terrain colour hints, and litdata from the wrong bsp.
fix ftp dual-homed issue. support epsv command, and enable ipv6 (eprt still not supported).
remove d3d11 compilation from the makefile. the required headers are not provided by mingw, and are not available to the build bot, so don't bother.
fix v *= v.x and similar opcodes.
fteqcc: fixed support for áéÃóú type chars in names. utf-8 files now properly supported (even with the utf-8 bom/identifier). utf-16 also supported.
fteqcc: fixed '#if 1 == 3 && 4' parsing.
fteqcc: -Werror acts on the warning, rather than as a separate error. Line numbers are thus more readable.
fteqcc: copyright message now includes compile date instead.
fteqccgui: the treeview control is now coloured depending on whether there were warnings/errors in the last compile.
fteqccgui: the output window is now focused and scrolls down as compilation progresses.
pr_dumpplatform command dumps out some pragmas to convert more serious warnings to errors. This is to avoid the infamous 'fteqcc sucks cos my code sucks' issue.
rewrote prespawn/modelist/soundlist code. server tracks progress now.
------------------------------------------------------------------------
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4167 fc73d0e0-1445-4013-8a0c-d673dee63da5
2013-03-12 22:29:40 +00:00
static unsigned int QDECL Q1QVMPF_NumForEdict ( pubprogfuncs_t * pf , edict_t * e )
2008-05-25 22:23:43 +00:00
{
return e - > entnum ;
}
------------------------------------------------------------------------
r4169 | acceptthis | 2013-01-17 08:55:12 +0000 (Thu, 17 Jan 2013) | 31 lines
removed MAX_VISEDICTS limit.
PEXT2_REPLACEMENTDELTAS tweaked, now has 4 million entity limit. still not enabled by default.
TE_BEAM now maps to a separate TEQW_BEAM to avoid conflicts with QW.
added android multitouch emulation for windows/rawinput (in_simulatemultitouch).
split topcolor/bottomcolor from scoreboard, for dp's colormap|1024 feature.
now using utf-8 for windows consoles.
qcc warnings/errors now give clickable console links for quick+easy editing.
disabled menutint when the currently active item changes contrast or gamma (for OneManClan).
Added support for drawfont/drawfontscale.
tweaked the qcvm a little to reduce the number of pointers.
.doll file loading. still experimental and will likely crash. requires csqc active, even if its a dummy progs. this will be fixed in time. Still other things that need cleaning up.
windows: gl_font "?" shows the standard windows font-selection dialog, and can be used to select windows fonts. not all work. and you probably don't want to use windings.
fixed splitscreen support when playing mvds. added mini-scoreboards to splitscreen.
editor/debugger now shows asm if there's no linenumber info. also, pressing f1 for help shows the shortcuts.
Added support for .framegroups files for psk(psa) and iqm formats.
True support for ezquake's colour codes. Mutually exclusive with background colours.
path command output slightly more readable.
added support for digest_hex (MD4, SHA1, CRC16).
skingroups now colourmap correctly.
Fix terrain colour hints, and litdata from the wrong bsp.
fix ftp dual-homed issue. support epsv command, and enable ipv6 (eprt still not supported).
remove d3d11 compilation from the makefile. the required headers are not provided by mingw, and are not available to the build bot, so don't bother.
fix v *= v.x and similar opcodes.
fteqcc: fixed support for áéÃóú type chars in names. utf-8 files now properly supported (even with the utf-8 bom/identifier). utf-16 also supported.
fteqcc: fixed '#if 1 == 3 && 4' parsing.
fteqcc: -Werror acts on the warning, rather than as a separate error. Line numbers are thus more readable.
fteqcc: copyright message now includes compile date instead.
fteqccgui: the treeview control is now coloured depending on whether there were warnings/errors in the last compile.
fteqccgui: the output window is now focused and scrolls down as compilation progresses.
pr_dumpplatform command dumps out some pragmas to convert more serious warnings to errors. This is to avoid the infamous 'fteqcc sucks cos my code sucks' issue.
rewrote prespawn/modelist/soundlist code. server tracks progress now.
------------------------------------------------------------------------
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4167 fc73d0e0-1445-4013-8a0c-d673dee63da5
2013-03-12 22:29:40 +00:00
static int QDECL Q1QVMPF_EdictToProgs ( pubprogfuncs_t * pf , edict_t * e )
2021-05-27 11:34:01 +00:00
{ //sadly ktx still uses byte-offset-from-world :(
2009-11-04 21:16:50 +00:00
return e - > entnum * sv . world . edict_size ;
2008-05-25 22:23:43 +00:00
}
------------------------------------------------------------------------
r4169 | acceptthis | 2013-01-17 08:55:12 +0000 (Thu, 17 Jan 2013) | 31 lines
removed MAX_VISEDICTS limit.
PEXT2_REPLACEMENTDELTAS tweaked, now has 4 million entity limit. still not enabled by default.
TE_BEAM now maps to a separate TEQW_BEAM to avoid conflicts with QW.
added android multitouch emulation for windows/rawinput (in_simulatemultitouch).
split topcolor/bottomcolor from scoreboard, for dp's colormap|1024 feature.
now using utf-8 for windows consoles.
qcc warnings/errors now give clickable console links for quick+easy editing.
disabled menutint when the currently active item changes contrast or gamma (for OneManClan).
Added support for drawfont/drawfontscale.
tweaked the qcvm a little to reduce the number of pointers.
.doll file loading. still experimental and will likely crash. requires csqc active, even if its a dummy progs. this will be fixed in time. Still other things that need cleaning up.
windows: gl_font "?" shows the standard windows font-selection dialog, and can be used to select windows fonts. not all work. and you probably don't want to use windings.
fixed splitscreen support when playing mvds. added mini-scoreboards to splitscreen.
editor/debugger now shows asm if there's no linenumber info. also, pressing f1 for help shows the shortcuts.
Added support for .framegroups files for psk(psa) and iqm formats.
True support for ezquake's colour codes. Mutually exclusive with background colours.
path command output slightly more readable.
added support for digest_hex (MD4, SHA1, CRC16).
skingroups now colourmap correctly.
Fix terrain colour hints, and litdata from the wrong bsp.
fix ftp dual-homed issue. support epsv command, and enable ipv6 (eprt still not supported).
remove d3d11 compilation from the makefile. the required headers are not provided by mingw, and are not available to the build bot, so don't bother.
fix v *= v.x and similar opcodes.
fteqcc: fixed support for áéÃóú type chars in names. utf-8 files now properly supported (even with the utf-8 bom/identifier). utf-16 also supported.
fteqcc: fixed '#if 1 == 3 && 4' parsing.
fteqcc: -Werror acts on the warning, rather than as a separate error. Line numbers are thus more readable.
fteqcc: copyright message now includes compile date instead.
fteqccgui: the treeview control is now coloured depending on whether there were warnings/errors in the last compile.
fteqccgui: the output window is now focused and scrolls down as compilation progresses.
pr_dumpplatform command dumps out some pragmas to convert more serious warnings to errors. This is to avoid the infamous 'fteqcc sucks cos my code sucks' issue.
rewrote prespawn/modelist/soundlist code. server tracks progress now.
------------------------------------------------------------------------
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4167 fc73d0e0-1445-4013-8a0c-d673dee63da5
2013-03-12 22:29:40 +00:00
static edict_t * QDECL Q1QVMPF_ProgsToEdict ( pubprogfuncs_t * pf , int num )
2008-05-25 22:23:43 +00:00
{
2021-05-27 11:34:01 +00:00
//sadly ktx still uses byte-offset-from-world :(
2009-11-04 21:16:50 +00:00
if ( num % sv . world . edict_size )
2008-05-25 22:23:43 +00:00
Con_Printf ( " Edict To Progs with remainder \n " ) ;
2009-11-04 21:16:50 +00:00
num / = sv . world . edict_size ;
2008-05-25 22:23:43 +00:00
return Q1QVMPF_EdictNum ( pf , num ) ;
}
2015-06-20 14:22:06 +00:00
static void Q1QVMED_ClearEdict ( edict_t * e , qboolean wipe )
2008-05-25 22:23:43 +00:00
{
int num = e - > entnum ;
if ( wipe )
2021-12-20 10:07:55 +00:00
{
2017-10-12 12:02:25 +00:00
memset ( e - > v , 0 , sv . world . edict_size - wasted_edict_t_size ) ;
2021-12-20 10:07:55 +00:00
memset ( e - > xv , 0 , sizeof ( * e - > xv ) ) ;
}
2017-10-12 12:02:25 +00:00
if ( qvm_api_version > = 15 )
{
int oself = pr_global_struct - > self ;
pr_global_struct - > self = Q1QVMPF_EdictToProgs ( svprogfuncs , e ) ;
VM_Call ( q1qvm , GAME_CLEAR_EDICT , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ) ;
pr_global_struct - > self = oself ;
}
2016-07-12 00:40:13 +00:00
e - > ereftype = ER_ENTITY ;
2008-05-25 22:23:43 +00:00
e - > entnum = num ;
}
2015-06-21 12:10:25 +00:00
static void QDECL Q1QVMPF_ClearEdict ( pubprogfuncs_t * pf , edict_t * e )
2015-06-20 14:22:06 +00:00
{
Q1QVMED_ClearEdict ( e , true ) ;
}
2008-05-25 22:23:43 +00:00
2021-08-04 21:17:31 +00:00
static void QDECL Q1QVMPF_EntRemove ( pubprogfuncs_t * pf , edict_t * e , pbool instant )
2008-05-25 22:23:43 +00:00
{
if ( ! ED_CanFree ( e ) )
return ;
2016-07-12 00:40:13 +00:00
e - > ereftype = ER_FREE ;
2020-02-11 18:06:10 +00:00
e - > freetime = instant ? 0 : sv . time ;
2008-05-25 22:23:43 +00:00
}
2015-09-14 15:20:09 +00:00
static edict_t * QDECL Q1QVMPF_EntAlloc ( pubprogfuncs_t * pf , pbool object , size_t extrasize )
2008-05-25 22:23:43 +00:00
{
int i ;
edict_t * e ;
2009-11-04 21:16:50 +00:00
for ( i = 0 ; i < sv . world . num_edicts ; i + + )
2008-05-25 22:23:43 +00:00
{
2018-04-06 17:21:15 +00:00
e = ( edict_t * ) EDICT_NUM_PB ( pf , i ) ;
2008-05-25 22:23:43 +00:00
// the first couple seconds of server time can involve a lot of
// freeing and allocating, so relax the replacement policy
2016-07-21 19:27:59 +00:00
if ( ! e | | ( ED_ISFREE ( e ) & & ( e - > freetime < 2 | | sv . time - e - > freetime > 0.5 ) ) )
2008-05-25 22:23:43 +00:00
{
Q1QVMED_ClearEdict ( e , true ) ;
2008-06-01 22:06:22 +00:00
ED_Spawned ( ( struct edict_s * ) e , false ) ;
2008-05-25 22:23:43 +00:00
return ( struct edict_s * ) e ;
}
}
2009-11-04 21:16:50 +00:00
if ( i > = sv . world . max_edicts - 1 ) //try again, but use timed out ents.
2008-05-25 22:23:43 +00:00
{
2009-11-04 21:16:50 +00:00
for ( i = 0 ; i < sv . world . num_edicts ; i + + )
2008-05-25 22:23:43 +00:00
{
2018-04-06 17:21:15 +00:00
e = ( edict_t * ) EDICT_NUM_PB ( pf , i ) ;
2008-05-25 22:23:43 +00:00
// the first couple seconds of server time can involve a lot of
// freeing and allocating, so relax the replacement policy
2016-07-21 19:27:59 +00:00
if ( ! e | | ED_ISFREE ( e ) )
2008-05-25 22:23:43 +00:00
{
Q1QVMED_ClearEdict ( e , true ) ;
2008-06-01 22:06:22 +00:00
ED_Spawned ( ( struct edict_s * ) e , false ) ;
2008-05-25 22:23:43 +00:00
return ( struct edict_s * ) e ;
}
}
2009-11-04 21:16:50 +00:00
if ( i > = sv . world . max_edicts - 1 )
2008-05-25 22:23:43 +00:00
{
Sys_Error ( " ED_Alloc: no free edicts " ) ;
}
}
2009-11-04 21:16:50 +00:00
sv . world . num_edicts + + ;
2015-09-10 10:16:26 +00:00
e = ( edict_t * ) Q1QVMPF_EdictNum ( pf , i ) ;
2008-05-25 22:23:43 +00:00
2021-12-20 10:07:55 +00:00
// new ents come ready wiped (unless 15 in which case we need to give the gamecode a chance to set safe defaults)
if ( qvm_api_version > = 15 )
Q1QVMED_ClearEdict ( e , false ) ;
2008-05-25 22:23:43 +00:00
2008-06-01 22:06:22 +00:00
ED_Spawned ( ( struct edict_s * ) e , false ) ;
2008-05-25 22:23:43 +00:00
return ( struct edict_s * ) e ;
}
2018-08-23 06:03:31 +00:00
static int QDECL Q1QVMPF_LoadEnts ( pubprogfuncs_t * pf , const char * mapstring , void * ctx ,
2021-09-01 07:30:48 +00:00
void ( PDECL * memoryreset ) ( pubprogfuncs_t * progfuncs , void * ctx ) ,
2018-08-23 06:03:31 +00:00
void ( PDECL * ent_callback ) ( pubprogfuncs_t * progfuncs , struct edict_s * ed , void * ctx , const char * entstart , const char * entend ) ,
pbool ( PDECL * ext_callback ) ( pubprogfuncs_t * pf , void * ctx , const char * * str ) )
2008-05-25 22:23:43 +00:00
{
2016-10-22 07:06:51 +00:00
//the qvm calls the spawn functions itself.
//no saved-games.
2008-05-25 22:23:43 +00:00
q1qvmentstring = mapstring ;
2015-06-14 01:28:01 +00:00
VM_Call ( q1qvm , GAME_LOADENTS , 0 , 0 , 0 ) ;
2008-05-25 22:23:43 +00:00
q1qvmentstring = NULL ;
2009-11-04 21:16:50 +00:00
return sv . world . edict_size ;
2008-05-25 22:23:43 +00:00
}
2018-10-11 10:31:23 +00:00
static int QDECL Q1QVMPF_QueryField ( pubprogfuncs_t * prinst , unsigned int fieldoffset , etype_t * type , char const * * name , evalc_t * fieldcache )
2015-11-18 07:37:39 +00:00
{
* type = ev_void ;
* name = " ? " ;
fieldcache - > varname = NULL ;
fieldcache - > spare [ 0 ] = fieldoffset ;
return true ;
}
2018-10-11 10:31:23 +00:00
static eval_t * QDECL Q1QVMPF_GetEdictFieldValue ( pubprogfuncs_t * pf , edict_t * e , const char * fieldname , etype_t type , evalc_t * cache )
2008-05-25 22:23:43 +00:00
{
2015-11-18 07:37:39 +00:00
if ( cache & & ! cache - > varname )
{
2017-10-12 12:02:25 +00:00
return ( eval_t * ) ( ( char * ) e - > v + cache - > spare [ 0 ] - wasted_edict_t_size ) ;
2015-11-18 07:37:39 +00:00
}
2008-05-25 22:23:43 +00:00
if ( ! strcmp ( fieldname , " message " ) )
{
2011-12-05 15:23:40 +00:00
return ( eval_t * ) & e - > v - > message ;
2008-05-25 22:23:43 +00:00
}
return NULL ;
}
2013-11-21 23:02:28 +00:00
static eval_t * QDECL Q1QVMPF_FindGlobal ( pubprogfuncs_t * prinst , const char * name , progsnum_t num , etype_t * type )
2008-05-25 22:23:43 +00:00
{
return NULL ;
}
2020-06-27 19:32:49 +00:00
static globalvars_t * QDECL Q1QVMPF_Globals ( pubprogfuncs_t * prinst , progsnum_t prnum )
2008-05-25 22:23:43 +00:00
{
return NULL ;
}
2014-03-30 08:55:06 +00:00
static string_t QDECL Q1QVMPF_StringToProgs ( pubprogfuncs_t * prinst , const char * str )
2008-05-25 22:23:43 +00:00
{
2015-11-18 07:37:39 +00:00
quintptr_t ret = ( str - ( char * ) VM_MemoryBase ( q1qvm ) ) ;
2014-03-30 08:55:06 +00:00
if ( ret > = VM_MemoryMask ( q1qvm ) )
return 0 ;
2015-11-18 07:37:39 +00:00
if ( ret > = 0xffffffff )
return 0 ; //invalid string! blame 64bit.
return ret ;
}
static void * ASMCALL QDECL Q1QVMPF_PointerToNative ( pubprogfuncs_t * prinst , quintptr_t str )
{
void * ret ;
if ( ! str | | ( quintptr_t ) str > = VM_MemoryMask ( q1qvm ) )
return NULL ; //null or invalid pointers.
ret = ( char * ) VM_MemoryBase ( q1qvm ) + str ;
2014-03-30 08:55:06 +00:00
return ret ;
2008-05-25 22:23:43 +00:00
}
2014-08-15 02:20:41 +00:00
static const char * ASMCALL QDECL Q1QVMPF_StringToNative ( pubprogfuncs_t * prinst , string_t str )
2008-05-25 22:23:43 +00:00
{
2017-10-12 12:02:25 +00:00
quintptr_t ref ;
2015-11-18 07:37:39 +00:00
if ( str = = ~ 0 )
return " " ; //models are weird. yes, this is a hack.
2017-10-12 12:02:25 +00:00
if ( qvm_api_version > = 15 )
{
qboolean stringishacky = sizeof ( quintptr_t ) ! = sizeof ( string_t ) & & qvm_api_version > = 15 & & ! VM_NonNative ( q1qvm ) ; //silly bullshit. Really, native gamecode should have its own implementation of this builtin or something, especially as its pretty much only ever used for classnames.
if ( ! str )
return " " ; //invalid...
else if ( stringishacky )
{
if ( str > = 0 & & str < sv . world . edict_size * sv . world . max_edicts - sizeof ( quintptr_t ) )
ref = * ( quintptr_t * ) ( ( char * ) evars + ( int ) str ) ; //extra indirection added in api 15.
else
return " " ; //error
}
else
{
if ( str > = 0 & & str < sv . world . edict_size * sv . world . max_edicts - sizeof ( quintptr_t ) )
ref = * ( string_t * ) ( ( char * ) evars + ( int ) str ) ; //extra indirection added in api 15.
else
return " " ; //error
}
}
else
ref = str ;
if ( ! ref | | ( quintptr_t ) ref > = VM_MemoryMask ( q1qvm ) )
2015-11-18 07:37:39 +00:00
return " " ; //null or invalid pointers.
2017-10-12 12:02:25 +00:00
return ( char * ) VM_MemoryBase ( q1qvm ) + ref ;
}
static void QDECL Q1QVMPF_SetStringField ( pubprogfuncs_t * progfuncs , struct edict_s * ed , string_t * fld , const char * str , pbool str_is_static )
{
if ( ! str_is_static )
return ;
if ( qvm_api_version > = 15 )
{
qboolean stringishacky = sizeof ( quintptr_t ) ! = sizeof ( string_t ) & & qvm_api_version > = 15 & & ! VM_NonNative ( q1qvm ) ; //silly bullshit. Really, native gamecode should have its own implementation of this builtin or something, especially as its pretty much only ever used for classnames.
quintptr_t nval = ( str - ( char * ) VM_MemoryBase ( q1qvm ) ) ;
if ( nval > = VM_MemoryMask ( q1qvm ) )
return ;
if ( ! * fld )
Con_DPrintf ( " Ignoring string set. mod pointer not set. \n " ) ;
else if ( stringishacky )
{
if ( * fld > = 0 & & * fld < sv . world . edict_size * sv . world . max_edicts - sizeof ( quintptr_t ) )
* ( quintptr_t * ) ( ( char * ) evars + * fld ) = nval ;
else
Con_DPrintf ( " Ignoring string set outside of progs VM \n " ) ;
}
else
{
if ( nval > = 0xffffffff )
return ; //invalid string! blame 64bit.
if ( * fld > = 0 & & * fld < sv . world . edict_size * sv . world . max_edicts - sizeof ( string_t ) )
* ( string_t * ) ( ( char * ) evars + * fld ) = ( string_t ) nval ;
else
Con_DPrintf ( " Ignoring string set outside of progs VM \n " ) ;
}
}
else
{
string_t newval = progfuncs - > StringToProgs ( progfuncs , str ) ;
if ( newval | | ! str )
* fld = newval ;
else if ( ! str )
* fld = 0 ;
else
{
* fld = ~ 0 ;
//Con_DPrintf("Ignoring string set outside of progs VM\n");
}
}
}
static void Q1QVMPF_SetStringGlobal ( pubprogfuncs_t * progfuncs , string_t * fld , const char * str , size_t copysize )
{
if ( qvm_api_version > = 15 )
{
qboolean stringishacky = sizeof ( quintptr_t ) ! = sizeof ( string_t ) & & qvm_api_version > = 15 & & ! VM_NonNative ( q1qvm ) ; //silly bullshit. Really, native gamecode should have its own implementation of this builtin or something, especially as its pretty much only ever used for classnames.
if ( ! * fld )
Con_Printf ( " Q1QVM: string reference not set. Fix the mod. \n " ) ;
else if ( stringishacky )
{ //quintptr_t
// if (*fld >= 0 && *fld < sv.world.edict_size*sv.world.max_edicts - sizeof(intptr_t))
{
if ( ! * ( quintptr_t * ) ( ( char * ) gvars + * fld ) )
{
Con_DPrintf ( " String buffer not set. Hacking the data in instead. \n " ) ;
* ( quintptr_t * ) ( ( char * ) gvars + * fld ) = ( str - ( char * ) VM_MemoryBase ( q1qvm ) ) ;
}
else
{
char * ptr = ( char * ) * ( quintptr_t * ) ( ( char * ) gvars + * fld ) ;
Q_strncpyz ( ptr , str , copysize ) ;
}
}
}
else
{ //string_t
// if (*fld >= 0 && *fld < sv.world.edict_size*sv.world.max_edicts - sizeof(string_t))
{
if ( ! * ( quintptr_t * ) ( ( char * ) gvars + * fld ) )
{
quintptr_t nval = ( str - ( char * ) VM_MemoryBase ( q1qvm ) ) ; ;
if ( nval > VM_MemoryMask ( q1qvm ) )
{
Con_Printf ( " Q1QVM: String buffer not set. Data out of QVM memory space. Fix the mod. \n " ) ;
}
else
{
Con_DPrintf ( " String buffer not set. Hacking the data in instead. \n " ) ;
* ( quintptr_t * ) ( ( char * ) gvars + * fld ) = ( str - ( char * ) VM_MemoryBase ( q1qvm ) ) ; ;
}
}
else
{
char * ptr = ( char * ) * ( quintptr_t * ) ( ( char * ) gvars + * fld ) ;
Q_strncpyz ( ptr , str , copysize ) ;
}
}
}
}
else
{
if ( ! * fld )
{
quintptr_t nval = ( str - ( char * ) VM_MemoryBase ( q1qvm ) ) ;
if ( nval > VM_MemoryMask ( q1qvm ) )
{
Con_Printf ( " Q1QVM: String buffer not set. Data out of QVM memory space. Fix the mod. \n " ) ;
}
else
{
Con_DPrintf ( " String buffer not set. Hacking the data in instead. \n " ) ;
* fld = ( str - ( char * ) VM_MemoryBase ( q1qvm ) ) ;
}
}
else
{
char * ptr = ( char * ) VM_MemoryBase ( q1qvm ) + * fld ;
Q_strncpyz ( ptr , str , copysize ) ;
}
}
2008-05-25 22:23:43 +00:00
}
2009-07-17 15:34:16 +00:00
static int WrapQCBuiltin ( builtin_t func , void * offset , quintptr_t mask , const qintptr_t * arg , char * argtypes )
2008-05-25 22:23:43 +00:00
{
globalvars_t gv ;
int argnum = 0 ;
while ( * argtypes )
{
switch ( * argtypes + + )
{
case ' f ' :
gv . param [ argnum + + ] . f = VM_FLOAT ( * arg + + ) ;
break ;
case ' i ' :
2015-04-21 04:12:00 +00:00
gv . param [ argnum + + ] . f = VM_LONG ( * arg + + ) ; //vanilla qc does not support ints, but qvms do. this means ints need to be converted to floats for the builtin to understand them properly.
2008-05-25 22:23:43 +00:00
break ;
case ' n ' : //ent num
gv . param [ argnum + + ] . i = EDICT_TO_PROG ( svprogfuncs , Q1QVMPF_EdictNum ( svprogfuncs , VM_LONG ( * arg + + ) ) ) ;
break ;
case ' v ' : //three seperate args -> 1 vector
gv . param [ argnum ] . vec [ 0 ] = VM_FLOAT ( * arg + + ) ;
gv . param [ argnum ] . vec [ 1 ] = VM_FLOAT ( * arg + + ) ;
gv . param [ argnum ] . vec [ 2 ] = VM_FLOAT ( * arg + + ) ;
argnum + + ;
break ;
2009-07-14 23:42:54 +00:00
case ' s ' :
2008-05-25 22:23:43 +00:00
gv . param [ argnum ] . i = VM_LONG ( * arg + + ) ;
argnum + + ;
break ;
}
}
------------------------------------------------------------------------
r4169 | acceptthis | 2013-01-17 08:55:12 +0000 (Thu, 17 Jan 2013) | 31 lines
removed MAX_VISEDICTS limit.
PEXT2_REPLACEMENTDELTAS tweaked, now has 4 million entity limit. still not enabled by default.
TE_BEAM now maps to a separate TEQW_BEAM to avoid conflicts with QW.
added android multitouch emulation for windows/rawinput (in_simulatemultitouch).
split topcolor/bottomcolor from scoreboard, for dp's colormap|1024 feature.
now using utf-8 for windows consoles.
qcc warnings/errors now give clickable console links for quick+easy editing.
disabled menutint when the currently active item changes contrast or gamma (for OneManClan).
Added support for drawfont/drawfontscale.
tweaked the qcvm a little to reduce the number of pointers.
.doll file loading. still experimental and will likely crash. requires csqc active, even if its a dummy progs. this will be fixed in time. Still other things that need cleaning up.
windows: gl_font "?" shows the standard windows font-selection dialog, and can be used to select windows fonts. not all work. and you probably don't want to use windings.
fixed splitscreen support when playing mvds. added mini-scoreboards to splitscreen.
editor/debugger now shows asm if there's no linenumber info. also, pressing f1 for help shows the shortcuts.
Added support for .framegroups files for psk(psa) and iqm formats.
True support for ezquake's colour codes. Mutually exclusive with background colours.
path command output slightly more readable.
added support for digest_hex (MD4, SHA1, CRC16).
skingroups now colourmap correctly.
Fix terrain colour hints, and litdata from the wrong bsp.
fix ftp dual-homed issue. support epsv command, and enable ipv6 (eprt still not supported).
remove d3d11 compilation from the makefile. the required headers are not provided by mingw, and are not available to the build bot, so don't bother.
fix v *= v.x and similar opcodes.
fteqcc: fixed support for áéÃóú type chars in names. utf-8 files now properly supported (even with the utf-8 bom/identifier). utf-16 also supported.
fteqcc: fixed '#if 1 == 3 && 4' parsing.
fteqcc: -Werror acts on the warning, rather than as a separate error. Line numbers are thus more readable.
fteqcc: copyright message now includes compile date instead.
fteqccgui: the treeview control is now coloured depending on whether there were warnings/errors in the last compile.
fteqccgui: the output window is now focused and scrolls down as compilation progresses.
pr_dumpplatform command dumps out some pragmas to convert more serious warnings to errors. This is to avoid the infamous 'fteqcc sucks cos my code sucks' issue.
rewrote prespawn/modelist/soundlist code. server tracks progress now.
------------------------------------------------------------------------
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4167 fc73d0e0-1445-4013-8a0c-d673dee63da5
2013-03-12 22:29:40 +00:00
svprogfuncs - > callargc = argnum ;
2008-05-25 22:23:43 +00:00
gv . ret . i = 0 ;
func ( svprogfuncs , & gv ) ;
return gv . ret . i ;
}
2015-07-01 23:15:25 +00:00
# define VALIDATEPOINTER(o,l) if ((qintptr_t)o + l >= mask || VM_POINTER(o) < offset) SV_Error("Call to game trap passes invalid pointer\n"); //out of bounds.
static qintptr_t QVM_GetAPIVersion ( void * offset , quintptr_t mask , const qintptr_t * arg )
2008-05-25 22:23:43 +00:00
{
2017-10-12 12:02:25 +00:00
return qvm_api_version ;
2015-07-01 23:15:25 +00:00
}
2008-05-25 22:23:43 +00:00
2015-07-01 23:15:25 +00:00
static qintptr_t QVM_DPrint ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
Con_DPrintf ( " %s " , ( char * ) VM_POINTER ( arg [ 0 ] ) ) ;
return 0 ;
}
2008-05-25 22:23:43 +00:00
2015-07-01 23:15:25 +00:00
static qintptr_t QVM_Error ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
SV_Error ( " Q1QVM: %s " , ( char * ) VM_POINTER ( arg [ 0 ] ) ) ;
return 0 ;
}
2008-05-25 22:23:43 +00:00
2015-07-01 23:15:25 +00:00
static qintptr_t QVM_GetEntityToken ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
if ( VM_OOB ( arg [ 0 ] , arg [ 1 ] ) | | ! arg [ 1 ] )
return false ;
if ( q1qvmentstring )
{
char * ret = VM_POINTER ( arg [ 0 ] ) ;
q1qvmentstring = COM_Parse ( q1qvmentstring ) ;
Q_strncpyz ( ret , com_token , VM_LONG ( arg [ 1 ] ) ) ;
return * com_token ! = 0 ;
}
else
{
char * ret = VM_POINTER ( arg [ 0 ] ) ;
* ret = ' \0 ' ;
return false ;
}
}
2008-05-25 22:23:43 +00:00
2015-07-01 23:15:25 +00:00
static qintptr_t QVM_Spawn_Ent ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
2015-09-14 15:20:09 +00:00
return Q1QVMPF_EntAlloc ( svprogfuncs , false , 0 ) - > entnum ;
2015-07-01 23:15:25 +00:00
}
2008-05-25 22:23:43 +00:00
2015-07-01 23:15:25 +00:00
static qintptr_t QVM_Remove_Ent ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
if ( arg [ 0 ] > = sv . world . max_edicts )
return false ;
2020-02-11 18:06:10 +00:00
Q1QVMPF_EntRemove ( svprogfuncs , q1qvmprogfuncs . edicttable [ arg [ 0 ] ] , false ) ;
2015-07-01 23:15:25 +00:00
return true ;
}
2008-05-25 22:23:43 +00:00
2015-07-01 23:15:25 +00:00
static qintptr_t QVM_Precache_Sound ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
2019-07-16 02:59:12 +00:00
return PF_precache_sound_Internal ( svprogfuncs , VM_POINTER ( arg [ 0 ] ) , false ) ;
2015-07-01 23:15:25 +00:00
}
static qintptr_t QVM_Precache_Model ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
return PF_precache_model_Internal ( svprogfuncs , VM_POINTER ( arg [ 0 ] ) , false ) ;
}
static qintptr_t QVM_LightStyle ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
vec3_t rgb = { 1 , 1 , 1 } ;
PF_applylightstyle ( VM_LONG ( arg [ 0 ] ) , VM_POINTER ( arg [ 1 ] ) , rgb ) ;
return 0 ;
}
static qintptr_t QVM_SetOrigin ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
edict_t * e = Q1QVMPF_EdictNum ( svprogfuncs , VM_LONG ( arg [ 0 ] ) ) ;
2016-07-21 19:27:59 +00:00
if ( ! e | | ED_ISFREE ( e ) )
2015-07-01 23:15:25 +00:00
return false ;
2008-05-25 22:23:43 +00:00
2015-07-01 23:15:25 +00:00
e - > v - > origin [ 0 ] = VM_FLOAT ( arg [ 1 ] ) ;
e - > v - > origin [ 1 ] = VM_FLOAT ( arg [ 2 ] ) ;
e - > v - > origin [ 2 ] = VM_FLOAT ( arg [ 3 ] ) ;
World_LinkEdict ( & sv . world , ( wedict_t * ) e , false ) ;
return true ;
}
static qintptr_t QVM_SetSize ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
edict_t * e = Q1QVMPF_EdictNum ( svprogfuncs , arg [ 0 ] ) ;
2016-07-21 19:27:59 +00:00
if ( ! e | | ED_ISFREE ( e ) )
2015-07-01 23:15:25 +00:00
return false ;
2008-05-25 22:23:43 +00:00
2015-07-01 23:15:25 +00:00
e - > v - > mins [ 0 ] = VM_FLOAT ( arg [ 1 ] ) ;
e - > v - > mins [ 1 ] = VM_FLOAT ( arg [ 2 ] ) ;
e - > v - > mins [ 2 ] = VM_FLOAT ( arg [ 3 ] ) ;
2008-05-25 22:23:43 +00:00
2015-07-01 23:15:25 +00:00
e - > v - > maxs [ 0 ] = VM_FLOAT ( arg [ 4 ] ) ;
e - > v - > maxs [ 1 ] = VM_FLOAT ( arg [ 5 ] ) ;
e - > v - > maxs [ 2 ] = VM_FLOAT ( arg [ 6 ] ) ;
2008-05-25 22:23:43 +00:00
2015-07-01 23:15:25 +00:00
VectorSubtract ( e - > v - > maxs , e - > v - > mins , e - > v - > size ) ;
World_LinkEdict ( & sv . world , ( wedict_t * ) e , false ) ;
return true ;
}
static qintptr_t QVM_SetModel ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
edict_t * e = Q1QVMPF_EdictNum ( svprogfuncs , arg [ 0 ] ) ;
PF_setmodel_Internal ( svprogfuncs , e , VM_POINTER ( arg [ 1 ] ) ) ;
return 0 ;
}
static qintptr_t QVM_BPrint ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
2022-05-28 17:59:17 +00:00
unsigned int flags = VM_LONG ( arg [ 2 ] ) ;
if ( qvm_api_version < 13 )
flags = 0 ; //added mid-v12, resulting in undefined values with early-12 mods.
SV_BroadcastPrint ( flags , arg [ 0 ] , ( char * ) VM_POINTER ( arg [ 1 ] ) ) ;
2015-07-01 23:15:25 +00:00
return 0 ;
}
static qintptr_t QVM_SPrint ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
2022-05-28 17:59:17 +00:00
unsigned int clnum = VM_LONG ( arg [ 0 ] ) - 1 ;
int level = VM_LONG ( arg [ 1 ] ) ;
const char * text = VM_POINTER ( arg [ 2 ] ) ;
unsigned int flags = VM_LONG ( arg [ 3 ] ) ;
# define SPRINT_IGNOREINDEMO ( 1<<0) // do not put such message in mvd demo
client_t * cl = & svs . clients [ clnum ] ;
if ( clnum > = sv . allocated_client_slots )
2015-07-01 23:15:25 +00:00
return 0 ;
2022-05-28 17:59:17 +00:00
if ( qvm_api_version < 13 )
flags = 0 ; //added mid-v12, resulting in undefined values with early-12 mods.
if ( flags & SPRINT_IGNOREINDEMO )
{
if ( level > = cl - > messagelevel )
SV_PrintToClient ( cl , level , text ) ;
}
else
SV_ClientPrintf ( cl , level , " %s " , text ) ;
2015-07-01 23:15:25 +00:00
return 0 ;
}
static qintptr_t QVM_CenterPrint ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
PF_centerprint_Internal ( VM_LONG ( arg [ 0 ] ) , false , VM_POINTER ( arg [ 1 ] ) ) ;
return 0 ;
}
static qintptr_t QVM_AmbientSound ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
vec3_t pos ;
pos [ 0 ] = VM_FLOAT ( arg [ 0 ] ) ;
pos [ 1 ] = VM_FLOAT ( arg [ 1 ] ) ;
pos [ 2 ] = VM_FLOAT ( arg [ 2 ] ) ;
PF_ambientsound_Internal ( pos , VM_POINTER ( arg [ 3 ] ) , VM_FLOAT ( arg [ 4 ] ) , VM_FLOAT ( arg [ 5 ] ) ) ;
return 0 ;
}
static qintptr_t QVM_Sound ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
// ( int edn, int channel, char *samp, float vol, float att )
2015-07-27 08:21:34 +00:00
int channel = VM_LONG ( arg [ 1 ] ) ;
int flags = 0 ;
if ( channel & 8 )
{ //based on quakeworld, remember
channel = ( channel & 7 ) | ( ( channel & ~ 15 ) > > 1 ) ;
2018-10-17 00:43:04 +00:00
flags | = CF_SV_RELIABLE ;
2015-07-27 08:21:34 +00:00
}
SVQ1_StartSound ( NULL , ( wedict_t * ) Q1QVMPF_EdictNum ( svprogfuncs , VM_LONG ( arg [ 0 ] ) ) , channel , VM_POINTER ( arg [ 2 ] ) , VM_FLOAT ( arg [ 3 ] ) * 255 , VM_FLOAT ( arg [ 4 ] ) , 0 , 0 , flags ) ;
2015-07-01 23:15:25 +00:00
return 0 ;
}
static qintptr_t QVM_TraceLine ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
WrapQCBuiltin ( PF_svtraceline , offset , mask , arg , " vvin " ) ;
return 0 ;
}
static qintptr_t QVM_CheckClient ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
return PF_checkclient_Internal ( svprogfuncs ) ;
}
static qintptr_t QVM_StuffCmd ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
PF_stuffcmd_Internal ( VM_LONG ( arg [ 0 ] ) , VM_POINTER ( arg [ 1 ] ) , VM_LONG ( arg [ 2 ] ) ) ;
return 0 ;
}
static qintptr_t QVM_LocalCmd ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
Cbuf_AddText ( VM_POINTER ( arg [ 0 ] ) , RESTRICT_INSECURE ) ;
return 0 ;
}
static qintptr_t QVM_CVar ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
cvar_t * c ;
char * vname = VM_POINTER ( arg [ 0 ] ) ;
2008-05-25 22:23:43 +00:00
2015-07-01 23:15:25 +00:00
//paused state is not a cvar in fte.
if ( ! strcmp ( vname , " sv_paused " ) )
return VM_LONG ( sv . paused ) ;
2008-05-25 22:23:43 +00:00
2015-07-01 23:15:25 +00:00
c = Cvar_Get ( vname , " " , 0 , " Gamecode " ) ;
return VM_LONG ( c - > value ) ;
}
static qintptr_t QVM_CVar_Set ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
cvar_t * var ;
var = Cvar_Get ( VM_POINTER ( arg [ 0 ] ) , VM_POINTER ( arg [ 1 ] ) , 0 , " Gamecode variables " ) ;
if ( ! var )
return - 1 ;
Cvar_Set ( var , VM_POINTER ( arg [ 1 ] ) ) ;
return 0 ;
}
2008-05-25 22:23:43 +00:00
2015-07-01 23:15:25 +00:00
static qintptr_t QVM_FindRadius ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
int start = ( ( char * ) VM_POINTER ( arg [ 0 ] ) - ( char * ) evars ) / sv . world . edict_size ;
edict_t * ed ;
vec3_t diff ;
float * org = VM_POINTER ( arg [ 1 ] ) ;
float rad = VM_FLOAT ( arg [ 2 ] ) ;
rad * = rad ;
for ( start + + ; start < sv . world . num_edicts ; start + + )
{
2018-04-06 17:21:15 +00:00
ed = EDICT_NUM_PB ( svprogfuncs , start ) ;
2016-07-21 19:27:59 +00:00
if ( ED_ISFREE ( ed ) )
2015-07-01 23:15:25 +00:00
continue ;
VectorSubtract ( ed - > v - > origin , org , diff ) ;
if ( rad > DotProduct ( diff , diff ) )
return ( qintptr_t ) ( vevars + start * sv . world . edict_size ) ;
}
return 0 ;
}
static qintptr_t QVM_WalkMove ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
2018-04-06 17:21:15 +00:00
wedict_t * ed = WEDICT_NUM_UB ( svprogfuncs , arg [ 0 ] ) ;
2015-07-01 23:15:25 +00:00
float yaw = VM_FLOAT ( arg [ 1 ] ) ;
float dist = VM_FLOAT ( arg [ 2 ] ) ;
vec3_t move ;
vec3_t axis [ 3 ] ;
2008-05-25 22:23:43 +00:00
2015-07-01 23:15:25 +00:00
World_GetEntGravityAxis ( ed , axis ) ;
2008-05-25 22:23:43 +00:00
2015-07-01 23:15:25 +00:00
yaw = yaw * M_PI * 2 / 360 ;
move [ 0 ] = cos ( yaw ) * dist ;
move [ 1 ] = sin ( yaw ) * dist ;
move [ 2 ] = 0 ;
2008-05-25 22:23:43 +00:00
2018-09-23 19:35:24 +00:00
return World_movestep ( & sv . world , ( wedict_t * ) ed , move , axis , true , false , NULL ) ;
2015-07-01 23:15:25 +00:00
}
static qintptr_t QVM_DropToFloor ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
edict_t * ent ;
2020-06-27 19:32:49 +00:00
pvec3_t end ;
pvec3_t start ;
2015-07-01 23:15:25 +00:00
trace_t trace ;
extern cvar_t pr_droptofloorunits ;
2008-05-25 22:23:43 +00:00
2018-04-06 17:21:15 +00:00
ent = EDICT_NUM_UB ( svprogfuncs , arg [ 0 ] ) ;
2009-07-14 23:42:54 +00:00
2015-07-01 23:15:25 +00:00
VectorCopy ( ent - > v - > origin , end ) ;
if ( pr_droptofloorunits . value > 0 )
end [ 2 ] - = pr_droptofloorunits . value ;
else
end [ 2 ] - = 256 ;
2009-07-14 23:42:54 +00:00
2015-07-01 23:15:25 +00:00
VectorCopy ( ent - > v - > origin , start ) ;
trace = World_Move ( & sv . world , start , ent - > v - > mins , ent - > v - > maxs , end , MOVE_NORMAL , ( wedict_t * ) ent ) ;
2008-05-25 22:23:43 +00:00
2015-07-01 23:15:25 +00:00
if ( trace . fraction = = 1 | | trace . allsolid )
return false ;
else
{
VectorCopy ( trace . endpos , ent - > v - > origin ) ;
World_LinkEdict ( & sv . world , ( wedict_t * ) ent , false ) ;
ent - > v - > flags = ( int ) ent - > v - > flags | FL_ONGROUND ;
ent - > v - > groundentity = EDICT_TO_PROG ( svprogfuncs , trace . ent ) ;
return true ;
}
}
static qintptr_t QVM_CheckBottom ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
vec3_t up = { 0 , 0 , 1 } ;
2018-04-06 17:21:15 +00:00
return World_CheckBottom ( & sv . world , ( wedict_t * ) EDICT_NUM_UB ( svprogfuncs , VM_LONG ( arg [ 0 ] ) ) , up ) ;
2015-07-01 23:15:25 +00:00
}
static qintptr_t QVM_PointContents ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
vec3_t v ;
v [ 0 ] = VM_FLOAT ( arg [ 0 ] ) ;
v [ 1 ] = VM_FLOAT ( arg [ 1 ] ) ;
v [ 2 ] = VM_FLOAT ( arg [ 2 ] ) ;
return sv . world . worldmodel - > funcs . PointContents ( sv . world . worldmodel , NULL , v ) ;
}
static qintptr_t QVM_NextEnt ( void * offset , quintptr_t mask , const qintptr_t * arg )
{ //input output are entity numbers
unsigned int i ;
edict_t * ent ;
2008-05-25 22:23:43 +00:00
2015-07-01 23:15:25 +00:00
i = VM_LONG ( arg [ 0 ] ) ;
while ( 1 )
{
i + + ;
if ( i > = sv . world . num_edicts )
2008-05-25 22:23:43 +00:00
{
return 0 ;
}
2018-04-06 17:21:15 +00:00
ent = EDICT_NUM_PB ( svprogfuncs , i ) ;
2016-07-21 19:27:59 +00:00
if ( ! ED_ISFREE ( ent ) )
2014-06-21 17:58:17 +00:00
{
2015-07-01 23:15:25 +00:00
return i ;
2008-05-25 22:23:43 +00:00
}
2015-07-01 23:15:25 +00:00
}
}
static qintptr_t QVM_Aim ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
Con_DPrintf ( " QVM_Aim: not implemented \n " ) ;
return 0 ; //not in mvdsv anyway
}
static qintptr_t QVM_MakeStatic ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
WrapQCBuiltin ( PF_makestatic , offset , mask , arg , " n " ) ;
return 0 ;
}
static qintptr_t QVM_SetSpawnParams ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
WrapQCBuiltin ( PF_setspawnparms , offset , mask , arg , " n " ) ;
return 0 ;
}
static qintptr_t QVM_ChangeLevel ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
2021-05-27 11:34:01 +00:00
const char * arg_mapname = VM_POINTER ( arg [ 0 ] ) ;
2023-02-20 05:50:50 +00:00
const char * arg_entfilename = ( qvm_api_version > 13 ) ? ( VM_POINTER ( arg [ 1 ] ) ) : " " ;
2021-05-27 11:34:01 +00:00
2015-11-18 07:37:39 +00:00
char newmap [ MAX_QPATH ] ;
if ( sv . mapchangelocked )
return 0 ;
2023-02-20 05:50:50 +00:00
if ( arg_entfilename & & * arg_entfilename )
{
int nl = strlen ( arg_mapname ) ;
if ( ! strncmp ( arg_mapname , arg_entfilename , nl ) & & arg_mapname [ nl ] = = ' # ' )
arg_mapname = arg_entfilename ;
else
Con_Printf ( CON_ERROR " %s: named ent file does not match map \n " , " QVM_ChangeLevel " ) ;
}
2015-11-18 07:37:39 +00:00
sv . mapchangelocked = true ;
2021-05-27 11:34:01 +00:00
COM_QuotedString ( arg_mapname , newmap , sizeof ( newmap ) , false ) ;
2015-11-18 07:37:39 +00:00
Cbuf_AddText ( va ( " \n changelevel %s \n " , newmap ) , RESTRICT_LOCAL ) ;
return 1 ;
2015-07-01 23:15:25 +00:00
}
2021-05-27 11:34:01 +00:00
static qintptr_t QVM_ChangeLevelHub ( void * offset , quintptr_t mask , const qintptr_t * arg )
2015-07-01 23:15:25 +00:00
{
2021-05-27 11:34:01 +00:00
const char * arg_mapname = VM_POINTER ( arg [ 0 ] ) ;
2023-02-20 05:50:50 +00:00
const char * arg_entfilename = VM_POINTER ( arg [ 1 ] ) ;
2021-05-27 11:34:01 +00:00
const char * arg_startspot = VM_POINTER ( arg [ 2 ] ) ;
2015-11-18 07:37:39 +00:00
char newmap [ MAX_QPATH ] ;
char startspot [ MAX_QPATH ] ;
if ( sv . mapchangelocked )
return 0 ;
2023-02-20 05:50:50 +00:00
if ( arg_entfilename & & * arg_entfilename )
{
int nl = strlen ( arg_mapname ) ;
if ( ! strncmp ( arg_mapname , arg_entfilename , nl ) & & arg_mapname [ nl ] = = ' # ' )
arg_mapname = arg_entfilename ;
else
Con_Printf ( CON_ERROR " %s: named ent file does not match map \n " , " QVM_ChangeLevelHub " ) ;
}
2015-11-18 07:37:39 +00:00
sv . mapchangelocked = true ;
2021-05-27 11:34:01 +00:00
COM_QuotedString ( arg_mapname , newmap , sizeof ( newmap ) , false ) ;
COM_QuotedString ( arg_startspot , startspot , sizeof ( startspot ) , false ) ;
2015-11-18 07:37:39 +00:00
Cbuf_AddText ( va ( " \n changelevel %s %s \n " , newmap , startspot ) , RESTRICT_LOCAL ) ;
return 1 ;
2015-07-01 23:15:25 +00:00
}
static qintptr_t QVM_LogFrag ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
WrapQCBuiltin ( PF_logfrag , offset , mask , arg , " nn " ) ;
return 0 ;
}
static qintptr_t QVM_Precache_VWep_Model ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
2015-11-18 07:37:39 +00:00
const char * s = VM_POINTER ( arg [ 0 ] ) ;
int i ;
if ( ! * s | | strchr ( s , ' \" ' ) | | strchr ( s , ' ; ' ) | | strchr ( s , ' \t ' ) | | strchr ( s , ' \n ' ) )
Con_Printf ( " QVM_Precache_VWep_Model: bad string \n " ) ;
else
{
for ( i = 0 ; i < sizeof ( sv . strings . vw_model_precache ) / sizeof ( sv . strings . vw_model_precache [ 0 ] ) ; i + + )
{
if ( ! sv . strings . vw_model_precache [ i ] )
{
if ( sv . state ! = ss_loading )
{
Con_Printf ( " QVM_Precache_VWep_Model: not spawning \n " ) ;
return 0 ;
}
sv . strings . vw_model_precache [ i ] = s ;
return i ;
}
if ( ! strcmp ( sv . strings . vw_model_precache [ i ] , s ) )
return i ;
}
Con_Printf ( " QVM_Precache_VWep_Model: overflow \n " ) ;
}
return 0 ;
2015-07-01 23:15:25 +00:00
}
static qintptr_t QVM_GetInfoKey ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
char * v ;
if ( VM_OOB ( arg [ 2 ] , arg [ 3 ] ) )
return - 1 ;
v = PF_infokey_Internal ( VM_LONG ( arg [ 0 ] ) , VM_POINTER ( arg [ 1 ] ) ) ;
Q_strncpyz ( VM_POINTER ( arg [ 2 ] ) , v , VM_LONG ( arg [ 3 ] ) ) ;
return 0 ;
}
static qintptr_t QVM_Multicast ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
WrapQCBuiltin ( PF_multicast , offset , mask , arg , " vi " ) ;
return 0 ;
}
static qintptr_t QVM_DisableUpdates ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
//FIXME: remember to ask mvdsv people why this is useful
Con_Printf ( " G_DISABLEUPDATES: not supported \n " ) ;
return 0 ;
}
static qintptr_t QVM_WriteByte ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
WrapQCBuiltin ( PF_WriteByte , offset , mask , arg , " ii " ) ;
return 0 ;
}
static qintptr_t QVM_WriteChar ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
WrapQCBuiltin ( PF_WriteChar , offset , mask , arg , " ii " ) ;
return 0 ;
}
static qintptr_t QVM_WriteShort ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
WrapQCBuiltin ( PF_WriteShort , offset , mask , arg , " ii " ) ;
return 0 ;
}
static qintptr_t QVM_WriteLong ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
WrapQCBuiltin ( PF_WriteLong , offset , mask , arg , " ii " ) ;
return 0 ;
}
static qintptr_t QVM_WriteAngle ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
WrapQCBuiltin ( PF_WriteAngle , offset , mask , arg , " if " ) ;
return 0 ;
}
static qintptr_t QVM_WriteCoord ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
WrapQCBuiltin ( PF_WriteCoord , offset , mask , arg , " if " ) ;
return 0 ;
}
static qintptr_t QVM_WriteString ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
PF_WriteString_Internal ( VM_LONG ( arg [ 0 ] ) , VM_POINTER ( arg [ 1 ] ) ) ;
return 0 ;
}
static qintptr_t QVM_WriteEntity ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
WrapQCBuiltin ( PF_WriteEntity , offset , mask , arg , " in " ) ;
return 0 ;
}
static qintptr_t QVM_FlushSignon ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
2019-09-17 19:49:39 +00:00
SV_FlushSignon ( false ) ;
2015-07-01 23:15:25 +00:00
return 0 ;
}
static qintptr_t QVM_memset ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
void * dst = VM_POINTER ( arg [ 0 ] ) ;
VALIDATEPOINTER ( arg [ 0 ] , arg [ 2 ] ) ;
memset ( dst , arg [ 1 ] , arg [ 2 ] ) ;
return arg [ 0 ] ;
}
static qintptr_t QVM_memcpy ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
void * dst = VM_POINTER ( arg [ 0 ] ) ;
void * src = VM_POINTER ( arg [ 1 ] ) ;
VALIDATEPOINTER ( arg [ 0 ] , arg [ 2 ] ) ;
memmove ( dst , src , arg [ 2 ] ) ;
return arg [ 0 ] ;
}
static qintptr_t QVM_strncpy ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
VALIDATEPOINTER ( arg [ 0 ] , arg [ 2 ] ) ;
Q_strncpyS ( VM_POINTER ( arg [ 0 ] ) , VM_POINTER ( arg [ 1 ] ) , arg [ 2 ] ) ;
return arg [ 0 ] ;
}
static qintptr_t QVM_sin ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
2015-07-27 08:21:34 +00:00
union
{
qintptr_t r ;
float f ;
} u = { 0 } ;
u . f = sin ( VM_FLOAT ( arg [ 0 ] ) ) ;
return u . r ;
2015-07-01 23:15:25 +00:00
}
static qintptr_t QVM_cos ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
2015-07-27 08:21:34 +00:00
union
{
qintptr_t r ;
float f ;
} u = { 0 } ;
u . f = cos ( VM_FLOAT ( arg [ 0 ] ) ) ;
return u . r ;
2015-07-01 23:15:25 +00:00
}
static qintptr_t QVM_atan2 ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
2015-07-27 08:21:34 +00:00
union
{
qintptr_t r ;
float f ;
} u = { 0 } ;
u . f = atan2 ( VM_FLOAT ( arg [ 0 ] ) , VM_FLOAT ( arg [ 1 ] ) ) ;
return u . r ;
2015-07-01 23:15:25 +00:00
}
static qintptr_t QVM_sqrt ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
2015-07-27 08:21:34 +00:00
union
{
qintptr_t r ;
float f ;
} u = { 0 } ;
u . f = sqrt ( VM_FLOAT ( arg [ 0 ] ) ) ;
return u . r ;
2015-07-01 23:15:25 +00:00
}
static qintptr_t QVM_floor ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
2015-07-27 08:21:34 +00:00
union
{
qintptr_t r ;
float f ;
} u = { 0 } ;
u . f = floor ( VM_FLOAT ( arg [ 0 ] ) ) ;
return u . r ;
2015-07-01 23:15:25 +00:00
}
static qintptr_t QVM_ceil ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
2015-07-27 08:21:34 +00:00
union
{
qintptr_t r ;
float f ;
} u = { 0 } ;
u . f = ceil ( VM_FLOAT ( arg [ 0 ] ) ) ;
return u . r ;
2015-07-01 23:15:25 +00:00
}
static qintptr_t QVM_acos ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
2015-07-27 08:21:34 +00:00
union
{
qintptr_t r ;
float f ;
} u = { 0 } ;
u . f = acos ( VM_FLOAT ( arg [ 0 ] ) ) ;
return u . r ;
2015-07-01 23:15:25 +00:00
}
static qintptr_t QVM_Cmd_ArgC ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
return Cmd_Argc ( ) ;
}
static qintptr_t QVM_Cmd_ArgV ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
char * c ;
c = Cmd_Argv ( VM_LONG ( arg [ 0 ] ) ) ;
if ( VM_OOB ( arg [ 1 ] , arg [ 2 ] ) )
return - 1 ;
Q_strncpyz ( VM_POINTER ( arg [ 1 ] ) , c , VM_LONG ( arg [ 2 ] ) ) ;
return 0 ;
}
static qintptr_t QVM_TraceBox ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
WrapQCBuiltin ( PF_svtraceline , offset , mask , arg , " vvinvv " ) ;
return 0 ;
}
2022-03-08 05:31:34 +00:00
typedef struct {
vfsfile_t * file ;
} vm_fopen_files_t ;
static vm_fopen_files_t vm_fopen_files [ 64 ] ;
2015-07-01 23:15:25 +00:00
static qintptr_t QVM_FS_OpenFile ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
2022-03-08 05:31:34 +00:00
const char * name = VM_POINTER ( arg [ 0 ] ) ;
int * handle = VM_POINTER ( arg [ 1 ] ) ;
int fmode = VM_LONG ( arg [ 2 ] ) ;
int fnum ;
static struct {
const char * mode ;
enum fs_relative root ;
} mode [ ] = {
/*FS_READ_BIN*/ { " rb " , FS_GAME } ,
/*FS_READ_TXT*/ { " rt " , FS_GAME } ,
/*FS_WRITE_BIN*/ { " wb " , FS_GAMEONLY } ,
/*FS_WRITE_TXT*/ { " wt " , FS_GAMEONLY } ,
/*FS_APPEND_BIN*/ { " ab " , FS_GAMEONLY } ,
/*FS_APPEND_TXT*/ { " at " , FS_GAMEONLY } ,
} ;
if ( fmode < 0 | | fmode > = countof ( mode ) )
return - 1 ;
for ( fnum = 0 ; fnum < countof ( vm_fopen_files ) ; fnum + + )
if ( ! vm_fopen_files [ fnum ] . file )
break ;
if ( fnum = = countof ( vm_fopen_files ) ) //too many already open
return - 1 ;
2015-07-01 23:15:25 +00:00
2022-03-08 05:31:34 +00:00
vm_fopen_files [ fnum ] . file = FS_OpenVFS ( name , mode [ fmode ] . mode , mode [ fmode ] . root ) ;
if ( ! vm_fopen_files [ fnum ] . file )
2015-07-01 23:15:25 +00:00
return - 1 ;
2022-03-08 05:31:34 +00:00
* handle = fnum + 1 ;
return VFS_GETLEN ( vm_fopen_files [ fnum ] . file ) ;
2015-07-01 23:15:25 +00:00
}
static qintptr_t QVM_FS_CloseFile ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
2022-03-08 05:31:34 +00:00
int fnum = VM_LONG ( arg [ 0 ] ) - 1 ;
if ( fnum > = 0 & & fnum < countof ( vm_fopen_files ) & & vm_fopen_files [ fnum ] . file )
{
VFS_CLOSE ( vm_fopen_files [ fnum ] . file ) ;
vm_fopen_files [ fnum ] . file = NULL ;
return 0 ;
}
return - 1 ;
}
static void QVM_FS_CloseFileAll ( void )
{
size_t fnum ;
for ( fnum = 0 ; fnum < countof ( vm_fopen_files ) ; fnum + + )
if ( vm_fopen_files [ fnum ] . file )
{
VFS_CLOSE ( vm_fopen_files [ fnum ] . file ) ;
vm_fopen_files [ fnum ] . file = NULL ;
}
2015-07-01 23:15:25 +00:00
}
static qintptr_t QVM_FS_ReadFile ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
2022-03-08 05:31:34 +00:00
void * dest = VM_POINTER ( arg [ 0 ] ) ;
int size = VM_LONG ( arg [ 1 ] ) ;
int fnum = VM_LONG ( arg [ 2 ] ) - 1 ;
if ( VM_OOB ( arg [ 0 ] , size ) )
2015-07-01 23:15:25 +00:00
return 0 ;
2022-03-08 05:31:34 +00:00
if ( fnum > = 0 & & fnum < countof ( vm_fopen_files ) & & vm_fopen_files [ fnum ] . file & & vm_fopen_files [ fnum ] . file - > ReadBytes )
return VFS_READ ( vm_fopen_files [ fnum ] . file , dest , size ) ;
return 0 ;
2015-07-01 23:15:25 +00:00
}
static qintptr_t QVM_FS_WriteFile ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
2022-03-08 05:31:34 +00:00
void * dest = VM_POINTER ( arg [ 0 ] ) ;
int size = VM_LONG ( arg [ 1 ] ) ;
int fnum = VM_LONG ( arg [ 2 ] ) - 1 ;
if ( VM_OOB ( arg [ 0 ] , size ) )
2015-07-01 23:15:25 +00:00
return 0 ;
2022-03-08 05:31:34 +00:00
if ( fnum > = 0 & & fnum < countof ( vm_fopen_files ) & & vm_fopen_files [ fnum ] . file & & vm_fopen_files [ fnum ] . file - > ReadBytes )
return VFS_WRITE ( vm_fopen_files [ fnum ] . file , dest , size ) ;
return 0 ;
2015-07-01 23:15:25 +00:00
}
static qintptr_t QVM_FS_SeekFile ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
2022-03-08 05:31:34 +00:00
int fnum = VM_LONG ( arg [ 0 ] ) - 1 ;
quintptr_t foffset = arg [ 1 ] ;
int seektype = VM_LONG ( arg [ 2 ] ) ;
if ( fnum > = 0 & & fnum < countof ( vm_fopen_files ) & & vm_fopen_files [ fnum ] . file & & vm_fopen_files [ fnum ] . file - > seekstyle ! = SS_UNSEEKABLE )
{
if ( seektype = = 0 ) //cur
foffset + = VFS_TELL ( vm_fopen_files [ fnum ] . file ) ;
else if ( seektype = = 2 ) //end
foffset = VFS_GETLEN ( vm_fopen_files [ fnum ] . file ) + ( qintptr_t ) foffset ;
return VFS_SEEK ( vm_fopen_files [ fnum ] . file , foffset ) ;
}
2015-07-01 23:15:25 +00:00
return 0 ;
}
static qintptr_t QVM_FS_TellFile ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
2022-03-08 05:31:34 +00:00
int fnum = VM_LONG ( arg [ 0 ] ) - 1 ;
if ( fnum > = 0 & & fnum < countof ( vm_fopen_files ) & & vm_fopen_files [ fnum ] . file )
{
return VFS_TELL ( vm_fopen_files [ fnum ] . file ) ;
}
return - 1 ;
}
//filesystem searches result in a tightly-packed blob of null-terminated filenames (along with a count for how many entries)
typedef struct {
char * initialbuffer ;
char * buffer ;
int found ;
int bufferleft ;
int skip ;
} vmsearch_t ;
static int QDECL VMEnum ( const char * match , qofs_t size , time_t mtime , void * args , searchpathfuncs_t * spath )
{
char * check ;
int newlen ;
match + = ( ( vmsearch_t * ) args ) - > skip ;
newlen = strlen ( match ) + 1 ;
if ( newlen > ( ( vmsearch_t * ) args ) - > bufferleft )
return false ; //too many files for the buffer
check = ( ( vmsearch_t * ) args ) - > initialbuffer ;
while ( check < ( ( vmsearch_t * ) args ) - > buffer )
{
if ( ! Q_strcasecmp ( check , match ) )
return true ; //we found this one already
check + = strlen ( check ) + 1 ;
}
memcpy ( ( ( vmsearch_t * ) args ) - > buffer , match , newlen ) ;
( ( vmsearch_t * ) args ) - > buffer + = newlen ;
( ( vmsearch_t * ) args ) - > bufferleft - = newlen ;
( ( vmsearch_t * ) args ) - > found + + ;
return true ;
2015-07-01 23:15:25 +00:00
}
static qintptr_t QVM_FS_GetFileList ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
2022-03-08 05:31:34 +00:00
vmsearch_t vms ;
const char * path = VM_POINTER ( arg [ 0 ] ) ;
const char * ext = VM_POINTER ( arg [ 1 ] ) ;
char * output = VM_POINTER ( arg [ 2 ] ) ;
size_t buffersize = VM_LONG ( arg [ 3 ] ) ;
if ( VM_OOB ( arg [ 2 ] , buffersize ) )
2015-07-01 23:15:25 +00:00
return 0 ;
2022-03-08 05:31:34 +00:00
vms . initialbuffer = vms . buffer = output ;
vms . skip = strlen ( path ) + 1 ;
vms . bufferleft = buffersize ;
vms . found = 0 ;
if ( * ( const char * ) ext = = ' . ' | | * ( const char * ) ext = = ' / ' )
COM_EnumerateFiles ( va ( " %s/*%s " , path , ext ) , VMEnum , & vms ) ;
else
COM_EnumerateFiles ( va ( " %s/*.%s " , path , ext ) , VMEnum , & vms ) ;
return vms . found ;
2015-07-01 23:15:25 +00:00
}
static qintptr_t QVM_CVar_Set_Float ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
cvar_t * var ;
var = Cvar_Get ( VM_POINTER ( arg [ 0 ] ) , va ( " %f " , VM_FLOAT ( arg [ 1 ] ) ) , 0 , " Gamecode variables " ) ;
if ( ! var )
return - 1 ;
Cvar_SetValue ( var , VM_FLOAT ( arg [ 1 ] ) ) ;
return 0 ;
}
static qintptr_t QVM_CVar_String ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
char * n = VM_POINTER ( arg [ 0 ] ) ;
cvar_t * cv ;
if ( VM_OOB ( arg [ 1 ] , arg [ 2 ] ) )
return - 1 ;
if ( ! strcmp ( n , " version " ) )
{
n = version_string ( ) ;
Q_strncpyz ( VM_POINTER ( arg [ 1 ] ) , n , VM_LONG ( arg [ 2 ] ) ) ;
}
else
{
cv = Cvar_Get ( n , " " , 0 , " QC variables " ) ;
if ( cv )
Q_strncpyz ( VM_POINTER ( arg [ 1 ] ) , cv - > string , VM_LONG ( arg [ 2 ] ) ) ;
else
Q_strncpyz ( VM_POINTER ( arg [ 1 ] ) , " " , VM_LONG ( arg [ 2 ] ) ) ;
}
return 0 ;
}
static qintptr_t QVM_strcmp ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
char * a = VM_POINTER ( arg [ 0 ] ) ;
char * b = VM_POINTER ( arg [ 1 ] ) ;
return strcmp ( a , b ) ;
}
static qintptr_t QVM_strncmp ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
char * a = VM_POINTER ( arg [ 0 ] ) ;
char * b = VM_POINTER ( arg [ 1 ] ) ;
return strncmp ( a , b , VM_LONG ( arg [ 2 ] ) ) ;
}
static qintptr_t QVM_stricmp ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
char * a = VM_POINTER ( arg [ 0 ] ) ;
char * b = VM_POINTER ( arg [ 1 ] ) ;
return stricmp ( a , b ) ;
}
static qintptr_t QVM_strnicmp ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
char * a = VM_POINTER ( arg [ 0 ] ) ;
char * b = VM_POINTER ( arg [ 1 ] ) ;
return strnicmp ( a , b , VM_LONG ( arg [ 2 ] ) ) ;
}
static qintptr_t QVM_Find ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
edict_t * e = VM_POINTER ( arg [ 0 ] ) ;
2017-10-12 12:02:25 +00:00
int ofs = ( VM_LONG ( arg [ 1 ] ) - wasted_edict_t_size ) ;
2015-07-01 23:15:25 +00:00
char * match = VM_POINTER ( arg [ 2 ] ) ;
char * field ;
int first = e ? ( ( char * ) e - ( char * ) evars ) / sv . world . edict_size : 0 ;
int i ;
2017-10-12 12:02:25 +00:00
qboolean stringishacky = sizeof ( quintptr_t ) ! = sizeof ( string_t ) & & qvm_api_version > = 15 & & ! VM_NonNative ( q1qvm ) ; //silly bullshit. Really, native gamecode should have its own implementation of this builtin or something, especially as its pretty much only ever used for classnames.
2015-07-01 23:15:25 +00:00
if ( ! match )
match = " " ;
for ( i = first + 1 ; i < sv . world . num_edicts ; i + + )
{
2015-09-10 10:16:26 +00:00
e = q1qvmprogfuncs . edicttable [ i ] ;
2017-10-12 12:02:25 +00:00
if ( stringishacky )
field = VM_POINTER ( * ( quintptr_t * ) ( ( char * ) e - > v + ofs ) ) ;
else
field = VM_POINTER ( * ( string_t * ) ( ( char * ) e - > v + ofs ) ) ;
2015-07-01 23:15:25 +00:00
if ( field = = NULL )
2008-05-25 22:23:43 +00:00
{
2015-07-01 23:15:25 +00:00
if ( * match = = ' \0 ' )
2017-10-12 12:02:25 +00:00
return ( ( char * ) e - > v - ( char * ) offset ) - wasted_edict_t_size ;
2008-05-25 22:23:43 +00:00
}
2015-07-01 23:15:25 +00:00
else
2011-06-29 18:39:11 +00:00
{
2015-07-01 23:15:25 +00:00
if ( ! strcmp ( field , match ) )
2017-10-12 12:02:25 +00:00
return ( ( char * ) e - > v - ( char * ) offset ) - wasted_edict_t_size ;
2011-06-29 18:39:11 +00:00
}
2015-07-01 23:15:25 +00:00
}
return 0 ;
}
static qintptr_t QVM_ExecuteCmd ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
WrapQCBuiltin ( PF_ExecuteCommand , offset , mask , arg , " " ) ;
return 0 ;
}
static qintptr_t QVM_ConPrint ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
Con_Printf ( " %s " , ( char * ) VM_POINTER ( arg [ 0 ] ) ) ;
return 0 ;
}
static qintptr_t QVM_ReadCmd ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
2016-07-12 00:40:13 +00:00
extern char sv_redirected_buf [ ] ;
2015-07-01 23:15:25 +00:00
extern redirect_t sv_redirected ;
extern int sv_redirectedlang ;
redirect_t old ;
int oldl ;
2021-07-17 15:10:35 +00:00
int spawncount = svs . spawncount ;
2008-05-25 22:23:43 +00:00
2015-07-01 23:15:25 +00:00
char * s = VM_POINTER ( arg [ 0 ] ) ;
char * output = VM_POINTER ( arg [ 1 ] ) ;
int outputlen = VM_LONG ( arg [ 2 ] ) ;
2008-05-25 22:23:43 +00:00
2015-07-01 23:15:25 +00:00
if ( VM_OOB ( arg [ 1 ] , arg [ 2 ] ) )
return - 1 ;
2015-04-21 04:12:00 +00:00
2015-07-01 23:15:25 +00:00
Cbuf_Execute ( ) ; //FIXME: this code is flawed
2021-07-17 15:10:35 +00:00
if ( svs . spawncount ! = spawncount | | sv . state < ss_loading )
Host_EndGame ( " QVM_ReadCmd: Map changed before reading " ) ;
2015-07-01 23:15:25 +00:00
Cbuf_AddText ( s , RESTRICT_LOCAL ) ;
2008-05-25 22:23:43 +00:00
2015-07-01 23:15:25 +00:00
old = sv_redirected ;
oldl = sv_redirectedlang ;
if ( old ! = RD_NONE )
SV_EndRedirect ( ) ;
2008-05-25 22:23:43 +00:00
2015-07-01 23:15:25 +00:00
SV_BeginRedirect ( RD_OBLIVION , TL_FindLanguage ( " " ) ) ;
Cbuf_Execute ( ) ;
2021-07-17 15:10:35 +00:00
if ( svs . spawncount ! = spawncount | | sv . state < ss_loading )
Added sys_openfile console command(and menu option) to web and flatpak(via cmake+dbus) builds, to 'install' packages on sandboxed systems a bit more easily.
Cmake: Add FTE_WERROR option, defaults to true in debug builds and off in release builds (in case future compilers have issues).
Cmake: Pull in libXscreensaver so we don't get interrupted by screensavers when playing demos.
Make: Added `make webcl-rel` for a web build without server bloat (eg for sites focused on demo playback. Yes, this means you XantoM).
fteqcc: Include the decompiler in fteqcc (non-gui) builds ('-d' arg).
fteqcc: Decompiler can now mostly handle hexen2 mods without any unknown opcodes.
Allow ezHud and OpenSSL to be compiled as in-engine plugins, potentially for web and windows ports respectively.
Web: Fix support for ogg vorbis. Add support for voip.
Web: Added basic support for WebXR.
QTV: Don't try seeking on unseekable qtv streams. Don't spam when developer 1 is set.
QTV: add support for some eztv extensions.
MVD: added hack to use ktx's vweps in mvd where mvdsv doesn't bother to record the info.
qwfwd: hack around a hack in qwfwd, allowing it to work again.
recording: favour qwd in single player, instead of mvd.
Protocol: reduce client memory used for precache names. Bump maximum precache counts - some people are just abusive, yes you Orl.
hexen2: add enough clientside protocol compat to play the demo included with h2mp. lacks effects.
in_xflip: restored this setting.
fs_hidesyspaths: new cvar, defaults to enabled so you won't find your username or whatever turning up in screenshots or the like. change it to 0 before debuging stuff eg via 'path'.
gl_overbright_models: Added cvar to match QS.
netchan: Added MTU determination, we'll no longer fail to connect when routers stupidly drop icmp packets.
Win: try a few other versions of xinput too.
CSQC: Added a CSQC_GenerateMaterial function, to give the csqc a chance to generate custom materials.
MenuQC: Added support for the skeletal objects API.
2024-04-09 17:13:59 +00:00
{
SV_EndRedirect ( ) ;
2021-07-17 15:10:35 +00:00
Host_EndGame ( " QVM_ReadCmd: Map changed after reading " ) ;
Added sys_openfile console command(and menu option) to web and flatpak(via cmake+dbus) builds, to 'install' packages on sandboxed systems a bit more easily.
Cmake: Add FTE_WERROR option, defaults to true in debug builds and off in release builds (in case future compilers have issues).
Cmake: Pull in libXscreensaver so we don't get interrupted by screensavers when playing demos.
Make: Added `make webcl-rel` for a web build without server bloat (eg for sites focused on demo playback. Yes, this means you XantoM).
fteqcc: Include the decompiler in fteqcc (non-gui) builds ('-d' arg).
fteqcc: Decompiler can now mostly handle hexen2 mods without any unknown opcodes.
Allow ezHud and OpenSSL to be compiled as in-engine plugins, potentially for web and windows ports respectively.
Web: Fix support for ogg vorbis. Add support for voip.
Web: Added basic support for WebXR.
QTV: Don't try seeking on unseekable qtv streams. Don't spam when developer 1 is set.
QTV: add support for some eztv extensions.
MVD: added hack to use ktx's vweps in mvd where mvdsv doesn't bother to record the info.
qwfwd: hack around a hack in qwfwd, allowing it to work again.
recording: favour qwd in single player, instead of mvd.
Protocol: reduce client memory used for precache names. Bump maximum precache counts - some people are just abusive, yes you Orl.
hexen2: add enough clientside protocol compat to play the demo included with h2mp. lacks effects.
in_xflip: restored this setting.
fs_hidesyspaths: new cvar, defaults to enabled so you won't find your username or whatever turning up in screenshots or the like. change it to 0 before debuging stuff eg via 'path'.
gl_overbright_models: Added cvar to match QS.
netchan: Added MTU determination, we'll no longer fail to connect when routers stupidly drop icmp packets.
Win: try a few other versions of xinput too.
CSQC: Added a CSQC_GenerateMaterial function, to give the csqc a chance to generate custom materials.
MenuQC: Added support for the skeletal objects API.
2024-04-09 17:13:59 +00:00
}
Q_strncpyz ( output , sv_redirected_buf , outputlen ) ;
SV_EndRedirect ( ) ;
2021-07-17 15:10:35 +00:00
2015-07-01 23:15:25 +00:00
if ( old ! = RD_NONE )
SV_BeginRedirect ( old , oldl ) ;
2008-05-25 22:23:43 +00:00
2015-07-01 23:15:25 +00:00
Con_DPrintf ( " PF_readcmd: %s \n %s " , s , output ) ;
2008-05-25 22:23:43 +00:00
2015-07-01 23:15:25 +00:00
return 0 ;
}
2017-05-23 07:03:07 +00:00
static void QVM_RedirectCmdCallback ( struct frameendtasks_s * task )
Added sys_openfile console command(and menu option) to web and flatpak(via cmake+dbus) builds, to 'install' packages on sandboxed systems a bit more easily.
Cmake: Add FTE_WERROR option, defaults to true in debug builds and off in release builds (in case future compilers have issues).
Cmake: Pull in libXscreensaver so we don't get interrupted by screensavers when playing demos.
Make: Added `make webcl-rel` for a web build without server bloat (eg for sites focused on demo playback. Yes, this means you XantoM).
fteqcc: Include the decompiler in fteqcc (non-gui) builds ('-d' arg).
fteqcc: Decompiler can now mostly handle hexen2 mods without any unknown opcodes.
Allow ezHud and OpenSSL to be compiled as in-engine plugins, potentially for web and windows ports respectively.
Web: Fix support for ogg vorbis. Add support for voip.
Web: Added basic support for WebXR.
QTV: Don't try seeking on unseekable qtv streams. Don't spam when developer 1 is set.
QTV: add support for some eztv extensions.
MVD: added hack to use ktx's vweps in mvd where mvdsv doesn't bother to record the info.
qwfwd: hack around a hack in qwfwd, allowing it to work again.
recording: favour qwd in single player, instead of mvd.
Protocol: reduce client memory used for precache names. Bump maximum precache counts - some people are just abusive, yes you Orl.
hexen2: add enough clientside protocol compat to play the demo included with h2mp. lacks effects.
in_xflip: restored this setting.
fs_hidesyspaths: new cvar, defaults to enabled so you won't find your username or whatever turning up in screenshots or the like. change it to 0 before debuging stuff eg via 'path'.
gl_overbright_models: Added cvar to match QS.
netchan: Added MTU determination, we'll no longer fail to connect when routers stupidly drop icmp packets.
Win: try a few other versions of xinput too.
CSQC: Added a CSQC_GenerateMaterial function, to give the csqc a chance to generate custom materials.
MenuQC: Added support for the skeletal objects API.
2024-04-09 17:13:59 +00:00
{ //called at the end of the frame when there's no gamecode running
2017-05-23 07:03:07 +00:00
host_client = svs . clients + task - > ctxint ;
if ( host_client - > state > = cs_connected )
{
SV_BeginRedirect ( RD_CLIENT , host_client - > language ) ;
Cmd_ExecuteString ( task - > data , RESTRICT_INSECURE ) ;
SV_EndRedirect ( ) ;
}
}
2015-07-01 23:15:25 +00:00
static qintptr_t QVM_RedirectCmd ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
2017-05-23 07:03:07 +00:00
struct frameendtasks_s * task , * * link ;
unsigned int entnum = ( ( char * ) VM_POINTER ( arg [ 0 ] ) - ( char * ) evars ) / sv . world . edict_size ;
const char * s = VM_POINTER ( arg [ 1 ] ) ;
if ( entnum < 1 | | entnum > sv . allocated_client_slots )
SV_Error ( " QVM_RedirectCmd: Parm 0 not a client " ) ;
task = Z_Malloc ( sizeof ( * task ) + strlen ( s ) ) ;
task - > callback = QVM_RedirectCmdCallback ;
strcpy ( task - > data , s ) ;
task - > ctxint = entnum - 1 ;
for ( link = & svs . frameendtasks ; * link ; link = & ( * link ) - > next )
; //add them on the end, so they're execed in order
* link = task ;
2015-07-01 23:15:25 +00:00
return 0 ;
}
static qintptr_t QVM_Add_Bot ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
2017-10-12 12:02:25 +00:00
char * name = VM_POINTER ( arg [ 0 ] ) ;
int bottom = VM_LONG ( arg [ 1 ] ) ;
int top = VM_LONG ( arg [ 2 ] ) ;
char * skin = VM_POINTER ( arg [ 3 ] ) ;
# if 1
extern int nextuserid ;
int i ;
for ( i = 0 ; i < sv . allocated_client_slots ; i + + )
{
client_t * cl = & svs . clients [ i ] ;
if ( ! * cl - > name & & ! cl - > protocol & & cl - > state = = cs_free )
{
cl - > userid = + + nextuserid ;
cl - > protocol = SCP_BAD ; //marker for bots
cl - > state = cs_spawned ;
2023-01-26 07:07:53 +00:00
cl - > connection_started = realtime ;
2017-10-12 12:02:25 +00:00
cl - > spawned = true ;
sv . spawned_client_slots + + ;
cl - > netchan . message . allowoverflow = true ;
cl - > netchan . message . maxsize = 0 ;
cl - > datagram . allowoverflow = true ;
cl - > datagram . maxsize = 0 ;
2018-04-06 17:21:15 +00:00
cl - > edict = EDICT_NUM_PB ( sv . world . progs , i + 1 ) ;
2017-10-12 12:02:25 +00:00
2018-07-05 16:21:44 +00:00
InfoBuf_SetKey ( & cl - > userinfo , " name " , name ) ;
InfoBuf_SetKey ( & cl - > userinfo , " topcolor " , va ( " %i " , top ) ) ;
InfoBuf_SetKey ( & cl - > userinfo , " bottomcolor " , va ( " %i " , bottom ) ) ;
InfoBuf_SetKey ( & cl - > userinfo , " skin " , skin ) ;
InfoBuf_SetStarKey ( & cl - > userinfo , " *bot " , " 1 " ) ;
2017-10-12 12:02:25 +00:00
SV_ExtractFromUserinfo ( cl , true ) ;
SV_SetUpClientEdict ( cl , cl - > edict ) ;
SV_FullClientUpdate ( cl , NULL ) ;
Q1QVM_ClientConnect ( cl ) ;
return cl - > edict - > entnum ;
}
}
# else
2015-07-01 23:15:25 +00:00
//FIXME: not implemented, always returns failure.
//the other bot functions only ever work on bots anyway, so don't need to be implemented until this one is
2008-05-25 22:23:43 +00:00
2015-07-01 23:15:25 +00:00
//return WrapQCBuiltin(PF_spawnclient, offset, mask, arg, "");
Con_DPrintf ( " QVM_Add_Bot: not implemented \n " ) ;
2017-10-12 12:02:25 +00:00
# endif
2015-07-01 23:15:25 +00:00
return 0 ;
}
static qintptr_t QVM_Remove_Bot ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
2017-10-12 12:02:25 +00:00
//kicks NOW. which generally makes it unsafe for players (calling from StartFrame should be okay).
int entnum = VM_LONG ( arg [ 0 ] ) ;
if ( entnum > = 1 & & entnum < = svs . allocated_client_slots )
{
client_t * cl = & svs . clients [ entnum - 1 ] ;
SV_DropClient ( cl ) ;
}
2008-05-25 22:23:43 +00:00
2015-07-01 23:15:25 +00:00
return 0 ;
}
static qintptr_t QVM_SetBotCMD ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
2017-10-12 12:02:25 +00:00
//this just queues the command for later, even in mvdsv. ignore the msecs value because its basically pointless
int edn = VM_LONG ( arg [ 0 ] ) ;
int msec = VM_LONG ( arg [ 1 ] ) ;
float angles_x = VM_FLOAT ( arg [ 2 ] ) ;
float angles_y = VM_FLOAT ( arg [ 3 ] ) ;
float angles_z = VM_FLOAT ( arg [ 4 ] ) ;
int forwardmove = VM_LONG ( arg [ 5 ] ) ;
int sidemove = VM_LONG ( arg [ 6 ] ) ;
int upmove = VM_LONG ( arg [ 7 ] ) ;
int buttons = VM_LONG ( arg [ 8 ] ) ;
int impulse = VM_LONG ( arg [ 9 ] ) ;
if ( edn > = 1 & & edn < = svs . allocated_client_slots )
{
client_t * cl = & svs . clients [ edn - 1 ] ;
cl - > lastcmd . msec = msec ;
cl - > lastcmd . angles [ 0 ] = ANGLE2SHORT ( angles_x ) ;
cl - > lastcmd . angles [ 1 ] = ANGLE2SHORT ( angles_y ) ;
cl - > lastcmd . angles [ 2 ] = ANGLE2SHORT ( angles_z ) ;
cl - > lastcmd . forwardmove = forwardmove ;
cl - > lastcmd . sidemove = sidemove ;
cl - > lastcmd . upmove = upmove ;
cl - > lastcmd . buttons = buttons ;
cl - > lastcmd . impulse = impulse ;
}
2015-07-01 23:15:25 +00:00
return 0 ;
}
static qintptr_t QVM_SetUserInfo ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
2018-07-05 16:21:44 +00:00
int ent = VM_LONG ( arg [ 0 ] ) ;
const char * key = VM_POINTER ( arg [ 1 ] ) ;
const char * val = VM_POINTER ( arg [ 2 ] ) ;
2015-07-01 23:15:25 +00:00
if ( * key = = ' * ' & & ( VM_LONG ( arg [ 3 ] ) & 1 ) )
return - 1 ; //denied!
2018-07-05 16:21:44 +00:00
return PF_ForceInfoKey_Internal ( ent , key , val , strlen ( val ) ) ;
2015-07-01 23:15:25 +00:00
}
static qintptr_t QVM_SetBotUserInfo ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
2018-07-05 16:21:44 +00:00
int ent = VM_LONG ( arg [ 0 ] ) ;
const char * key = VM_POINTER ( arg [ 1 ] ) ;
const char * val = VM_POINTER ( arg [ 2 ] ) ;
return PF_ForceInfoKey_Internal ( ent , key , val , strlen ( val ) ) ;
2015-07-01 23:15:25 +00:00
}
static qintptr_t QVM_MoveToGoal ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
return World_MoveToGoal ( & sv . world , ( wedict_t * ) Q1QVMPF_ProgsToEdict ( svprogfuncs , pr_global_struct - > self ) , VM_FLOAT ( arg [ 0 ] ) ) ;
}
static qintptr_t QVM_strftime ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
char * out = VM_POINTER ( arg [ 0 ] ) ;
char * fmt = VM_POINTER ( arg [ 2 ] ) ;
time_t curtime ;
struct tm * local ;
if ( VM_OOB ( arg [ 0 ] , arg [ 1 ] ) | | ! out )
return - 1 ; //please don't corrupt me
time ( & curtime ) ;
curtime + = VM_LONG ( arg [ 3 ] ) ;
local = localtime ( & curtime ) ;
2022-01-08 09:59:38 +00:00
return strftime ( out , VM_LONG ( arg [ 1 ] ) , fmt , local ) ;
2015-07-01 23:15:25 +00:00
}
static qintptr_t QVM_Cmd_ArgS ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
char * c ;
c = Cmd_Args ( ) ;
if ( VM_OOB ( arg [ 0 ] , arg [ 1 ] ) )
return - 1 ;
Q_strncpyz ( VM_POINTER ( arg [ 0 ] ) , c , VM_LONG ( arg [ 1 ] ) ) ;
return arg [ 0 ] ;
}
static qintptr_t QVM_Cmd_Tokenize ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
char * str = VM_POINTER ( arg [ 0 ] ) ;
Cmd_TokenizeString ( str , false , false ) ;
return Cmd_Argc ( ) ;
}
static qintptr_t QVM_strlcpy ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
char * dst = VM_POINTER ( arg [ 0 ] ) ;
char * src = VM_POINTER ( arg [ 1 ] ) ;
if ( VM_OOB ( arg [ 0 ] , arg [ 2 ] ) | | VM_LONG ( arg [ 2 ] ) < 1 )
return - 1 ;
else if ( ! src )
{
* dst = 0 ;
return 0 ;
}
else
{
Q_strncpyz ( dst , src , VM_LONG ( arg [ 2 ] ) ) ;
return strlen ( src ) ;
}
}
static qintptr_t QVM_strlcat ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
char * dst = VM_POINTER ( arg [ 0 ] ) ;
char * src = VM_POINTER ( arg [ 1 ] ) ;
if ( VM_OOB ( arg [ 0 ] , arg [ 2 ] ) )
return - 1 ;
Q_strncatz ( dst , src , VM_LONG ( arg [ 2 ] ) ) ;
//WARNING: no return value
return 0 ;
}
static qintptr_t QVM_MakeVectors ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
AngleVectors ( VM_POINTER ( arg [ 0 ] ) , P_VEC ( v_forward ) , P_VEC ( v_right ) , P_VEC ( v_up ) ) ;
return 0 ;
}
static qintptr_t QVM_NextClient ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
unsigned int start = ( ( char * ) VM_POINTER ( arg [ 0 ] ) - ( char * ) evars ) / sv . world . edict_size ;
while ( start < sv . allocated_client_slots )
{
if ( svs . clients [ start ] . state = = cs_spawned )
return ( qintptr_t ) ( vevars + ( start + 1 ) * sv . world . edict_size ) ;
start + + ;
}
return 0 ;
}
static qintptr_t QVM_SetPause ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
int pause = VM_LONG ( arg [ 0 ] ) ;
2016-08-25 00:12:14 +00:00
if ( ( sv . paused & PAUSE_EXPLICIT ) = = ( pause & PAUSE_EXPLICIT ) )
return ! ! ( sv . paused & PAUSE_EXPLICIT ) ; //nothing changed, ignore it.
2015-07-01 23:15:25 +00:00
sv . paused = pause ;
sv . pausedstart = Sys_DoubleTime ( ) ;
2016-08-25 00:12:14 +00:00
return ! ! ( sv . paused & PAUSE_EXPLICIT ) ;
2015-07-01 23:15:25 +00:00
}
2022-01-08 09:59:59 +00:00
static qintptr_t QVM_VisibleTo ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
unsigned int viewernum = VM_LONG ( arg [ 0 ] ) ;
unsigned int first = VM_LONG ( arg [ 1 ] ) ;
unsigned int count = VM_LONG ( arg [ 2 ] ) ;
qbyte * results = VM_POINTER ( arg [ 3 ] ) ;
unsigned int i , e , last = first + count ;
unsigned int ret = 0 ;
if ( viewernum < sv . world . num_edicts & & ! VM_OOB ( arg [ 3 ] , count ) & & first < last & & last < = sv . world . num_edicts )
{
pvscache_t * viewer = & q1qvmprogfuncs . edicttable [ viewernum ] - > pvsinfo ;
pvscache_t * viewee ;
edict_t * ed ;
int areas [ ] = { 2 , viewer - > areanum , viewer - > areanum2 } ;
memset ( results , 0 , count ) ; //assume the worst...
for ( e = first ; e < last ; e + + )
{
ed = q1qvmprogfuncs . edicttable [ e ] ;
if ( ED_ISFREE ( ed ) )
continue ; //free ents can't be visible (should not be linked, but oh well)
if ( e > = 1 & & e < = sv . allocated_client_slots & & svs . clients [ e - 1 ] . state ! = cs_spawned )
continue ; //player ents are weird, skip them for mods that do weird stuff.
viewee = & ed - > pvsinfo ;
for ( i = 0 ; i < viewer - > num_leafs ; i + + )
{
qbyte * pvs = sv . world . worldmodel - > funcs . ClusterPVS ( sv . world . worldmodel , viewer - > leafnums [ i ] , NULL , PVM_FAST ) ;
if ( sv . world . worldmodel - > funcs . EdictInFatPVS ( sv . world . worldmodel , viewee , pvs , areas ) )
{ //one of the viewer's clusters can see the viewee.
results [ e - first ] = true ;
ret + = 1 ;
break ;
}
}
}
}
return ret ;
}
2015-07-01 23:15:25 +00:00
static qintptr_t QVM_NotYetImplemented ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
SV_Error ( " Q1QVM: Trap not implemented \n " ) ;
return 0 ;
}
2008-05-25 22:23:43 +00:00
2015-07-01 23:15:25 +00:00
static int QVM_FindExtField ( char * fname )
{
extentvars_t * xv = NULL ;
# define comfieldfloat(name,desc) if (!strcmp(fname, #name)) return ((int*)&xv->name - (int*)xv);
2016-07-12 00:40:13 +00:00
# define comfieldint(name,desc) if (!strcmp(fname, #name)) return ((int*)&xv->name - (int*)xv);
2015-07-01 23:15:25 +00:00
# define comfieldvector(name,desc) if (!strcmp(fname, #name)) return ((int*)&xv->name - (int*)xv);
# define comfieldentity(name,desc) if (!strcmp(fname, #name)) return ((int*)&xv->name - (int*)xv);
# define comfieldstring(name,desc) if (!strcmp(fname, #name)) return ((int*)&xv->name - (int*)xv);
# define comfieldfunction(name, typestr,desc) if (!strcmp(fname, #name)) return ((int*)&xv->name - (int*)xv);
comextqcfields
svextqcfields
# undef comfieldfloat
2016-07-12 00:40:13 +00:00
# undef comfieldint
2015-07-01 23:15:25 +00:00
# undef comfieldvector
# undef comfieldentity
# undef comfieldstring
# undef comfieldfunction
return - 1 ; //unsupported
}
static qintptr_t QVM_SetExtField ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
2022-01-16 18:41:53 +00:00
unsigned int entnum = ( ( char * ) VM_POINTER ( arg [ 0 ] ) - ( char * ) evars ) / sv . world . edict_size ;
2015-07-01 23:15:25 +00:00
int i = QVM_FindExtField ( VM_POINTER ( arg [ 1 ] ) ) ;
int value = VM_LONG ( arg [ 2 ] ) ;
2008-05-25 22:23:43 +00:00
2022-01-16 18:41:53 +00:00
if ( i > = 0 & & entnum < q1qvmprogfuncs . edicttable_length & & q1qvmprogfuncs . edicttable [ entnum ] )
{
( ( int * ) q1qvmprogfuncs . edicttable [ entnum ] - > xv ) [ i ] = value ;
return value ;
}
return 0 ;
2015-07-01 23:15:25 +00:00
}
static qintptr_t QVM_GetExtField ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
2022-01-16 18:41:53 +00:00
unsigned int entnum = ( ( char * ) VM_POINTER ( arg [ 0 ] ) - ( char * ) evars ) / sv . world . edict_size ;
2015-07-01 23:15:25 +00:00
int i = QVM_FindExtField ( VM_POINTER ( arg [ 1 ] ) ) ;
2008-05-25 22:23:43 +00:00
2022-01-16 18:41:53 +00:00
if ( i > = 0 & & entnum < q1qvmprogfuncs . edicttable_length & & q1qvmprogfuncs . edicttable [ entnum ] )
{
return ( ( int * ) q1qvmprogfuncs . edicttable [ entnum ] - > xv ) [ i ] ;
}
return 0 ;
2015-07-01 23:15:25 +00:00
}
2008-05-25 22:23:43 +00:00
2015-07-01 23:15:25 +00:00
# ifdef WEBCLIENT
static void QVM_uri_query_callback ( struct dl_download * dl )
{
void * cb_context = dl - > user_ctx ;
int cb_entry = dl - > user_float ;
int selfnum = dl - > user_num ;
2008-05-25 22:23:43 +00:00
2015-07-01 23:15:25 +00:00
if ( svs . gametype ! = GT_Q1QVM | | svs . spawncount ! = dl - > user_sequence )
return ; //the world moved on.
//fixme: pointers might not still be valid if the map changed.
2008-05-25 22:23:43 +00:00
2015-07-01 23:15:25 +00:00
* sv . world . g . self = selfnum ;
if ( dl - > file )
{
size_t len = VFS_GETLEN ( dl - > file ) ;
char * buffer = malloc ( len + 1 ) ;
buffer [ len ] = 0 ;
VFS_READ ( dl - > file , buffer , len ) ;
playdemo accepts https urls now. will start playing before the file has finished downloading, to avoid unnecessary delays.
reworked network addresses to separate address family and connection type. this should make banning people more reliable, as well as simplifying a whole load of logic (no need to check for ipv4 AND ipv6).
tcpconnect will keep trying to connect even if the connection wasn't instant, instead of giving up instantly.
rewrote tcp connections quite a bit. sv_port_tcp now handles qtv+qizmo+http+ws+rtcbroker+tls equivalents.
qtv_streamport is now a legacy cvar and now acts equivalently to sv_port_tcp (but still separate).
rewrote screenshot and video capture code to use strides. this solves image-is-upside down issues with vulkan.
ignore alt key in browser port. oh no! no more red text! oh no! no more alt-being-wrongly-down-and-being-unable-to-type-anything-without-forcing-alt-released!
reworked audio decoder interface. now has clearly defined success/unavailable/end-of-file results. this should solve a whole load of issues with audio streaming.
fixed various openal audio streaming issues too. openal also got some workarounds for emscripten's poor emulation.
fixed ogg decoder to retain sync properly if seeked.
updated menu_media a bit. now reads vorbis comments/id3v1 tags to get proper track names. also saves the playlist so you don't have to manually repopulate the list so it might actually be usable now (after how many years?)
r_stains now defaults to 0, and is no longer enabled by presets. use decals if you want that sort of thing.
added fs_noreexec cvar, so configs will not be reexeced on gamedir change. this also means defaults won't be reapplied, etc.
added 'nvvk' renderer on windows, using nvidia's vulkan-inside-opengl gl extension. mostly just to see how much slower it is.
fixed up the ftp server quite a lot. more complete, more compliant, and should do ipv6 properly to-boot. file transfers also threaded.
fixed potential crash inside runclientphys.
experimental sv_antilag=3 setting. totally untested. the aim is to avoid missing due to lagged knockbacks. may be expensive for the server.
browser port's websockets support fixed. experimental support for webrtc ('works for me', requires a broker server).
updated avplug(renamed to ffmpeg so people know what it is) to use ffmpeg 3.2.4 properly, with its new encoder api. should be much more robust... also added experimental audio decoder for game music etc (currently doesn't resample, so playback rates are screwed, disabled by cvar).
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5097 fc73d0e0-1445-4013-8a0c-d673dee63da5
2017-05-10 02:08:58 +00:00
Cmd_Args_Set ( buffer , strlen ( buffer ) ) ;
2015-07-01 23:15:25 +00:00
free ( buffer ) ;
}
else
playdemo accepts https urls now. will start playing before the file has finished downloading, to avoid unnecessary delays.
reworked network addresses to separate address family and connection type. this should make banning people more reliable, as well as simplifying a whole load of logic (no need to check for ipv4 AND ipv6).
tcpconnect will keep trying to connect even if the connection wasn't instant, instead of giving up instantly.
rewrote tcp connections quite a bit. sv_port_tcp now handles qtv+qizmo+http+ws+rtcbroker+tls equivalents.
qtv_streamport is now a legacy cvar and now acts equivalently to sv_port_tcp (but still separate).
rewrote screenshot and video capture code to use strides. this solves image-is-upside down issues with vulkan.
ignore alt key in browser port. oh no! no more red text! oh no! no more alt-being-wrongly-down-and-being-unable-to-type-anything-without-forcing-alt-released!
reworked audio decoder interface. now has clearly defined success/unavailable/end-of-file results. this should solve a whole load of issues with audio streaming.
fixed various openal audio streaming issues too. openal also got some workarounds for emscripten's poor emulation.
fixed ogg decoder to retain sync properly if seeked.
updated menu_media a bit. now reads vorbis comments/id3v1 tags to get proper track names. also saves the playlist so you don't have to manually repopulate the list so it might actually be usable now (after how many years?)
r_stains now defaults to 0, and is no longer enabled by presets. use decals if you want that sort of thing.
added fs_noreexec cvar, so configs will not be reexeced on gamedir change. this also means defaults won't be reapplied, etc.
added 'nvvk' renderer on windows, using nvidia's vulkan-inside-opengl gl extension. mostly just to see how much slower it is.
fixed up the ftp server quite a lot. more complete, more compliant, and should do ipv6 properly to-boot. file transfers also threaded.
fixed potential crash inside runclientphys.
experimental sv_antilag=3 setting. totally untested. the aim is to avoid missing due to lagged knockbacks. may be expensive for the server.
browser port's websockets support fixed. experimental support for webrtc ('works for me', requires a broker server).
updated avplug(renamed to ffmpeg so people know what it is) to use ffmpeg 3.2.4 properly, with its new encoder api. should be much more robust... also added experimental audio decoder for game music etc (currently doesn't resample, so playback rates are screwed, disabled by cvar).
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5097 fc73d0e0-1445-4013-8a0c-d673dee63da5
2017-05-10 02:08:58 +00:00
Cmd_Args_Set ( NULL , 0 ) ;
2015-07-01 23:15:25 +00:00
VM_Call ( q1qvm , cb_entry , cb_context , dl - > replycode , 0 , 0 , 0 ) ;
}
2008-05-25 22:23:43 +00:00
2015-07-01 23:15:25 +00:00
//bool uri_get(char *uri, int cb_entry, void *cb_ctx, char *mime, void *data, unsigned datasize)
static qintptr_t QVM_uri_query ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
struct dl_download * dl ;
const unsigned char * url = VM_POINTER ( arg [ 0 ] ) ;
int cb_entry = VM_LONG ( arg [ 1 ] ) ;
void * cb_context = VM_POINTER ( arg [ 2 ] ) ;
const char * mimetype = VM_POINTER ( arg [ 3 ] ) ;
const char * data = VM_POINTER ( arg [ 4 ] ) ;
size_t datasize = VM_LONG ( arg [ 5 ] ) ;
extern cvar_t pr_enable_uriget ;
2019-07-16 02:59:12 +00:00
2015-07-01 23:15:25 +00:00
if ( ! pr_enable_uriget . ival )
{
2017-10-12 12:02:25 +00:00
Con_Printf ( " QVM_uri_query( \" %s \" ): %s disabled \n " , url , pr_enable_uriget . name ) ;
2008-05-25 22:23:43 +00:00
return 0 ;
2015-07-01 23:15:25 +00:00
}
2008-05-25 22:23:43 +00:00
2015-07-01 23:15:25 +00:00
if ( mimetype & & * mimetype )
{
VALIDATEPOINTER ( arg [ 4 ] , datasize ) ;
2017-10-12 12:02:25 +00:00
Con_DPrintf ( " QVM_uri_query(%s) \n " , url ) ;
2015-07-01 23:15:25 +00:00
dl = HTTP_CL_Put ( url , mimetype , data , datasize , QVM_uri_query_callback ) ;
}
else
{
2017-10-12 12:02:25 +00:00
Con_DPrintf ( " QVM_uri_query(%s) \n " , url ) ;
2015-07-01 23:15:25 +00:00
dl = HTTP_CL_Get ( url , NULL , QVM_uri_query_callback ) ;
}
if ( dl )
{
dl - > user_ctx = cb_context ;
dl - > user_float = cb_entry ;
dl - > user_num = * sv . world . g . self ;
dl - > user_sequence = svs . spawncount ;
dl - > isquery = true ;
return 1 ;
}
else
2008-05-25 22:23:43 +00:00
return 0 ;
2015-07-01 23:15:25 +00:00
}
# endif
2014-03-30 08:55:06 +00:00
2015-07-01 23:15:25 +00:00
void QCBUILTIN PF_sv_trailparticles ( pubprogfuncs_t * prinst , struct globalvars_s * pr_globals ) ;
void QCBUILTIN PF_sv_pointparticles ( pubprogfuncs_t * prinst , struct globalvars_s * pr_globals ) ;
void QCBUILTIN PF_sv_particleeffectnum ( pubprogfuncs_t * prinst , struct globalvars_s * pr_globals ) ;
static qintptr_t QVM_particleeffectnum ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
int i = WrapQCBuiltin ( PF_sv_particleeffectnum , offset , mask , arg , " s " ) ;
return VM_FLOAT ( i ) ;
}
static qintptr_t QVM_trailparticles ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
return WrapQCBuiltin ( PF_sv_trailparticles , offset , mask , arg , " invv " ) ;
}
static qintptr_t QVM_pointparticles ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
return WrapQCBuiltin ( PF_sv_pointparticles , offset , mask , arg , " ivvi " ) ;
}
2008-06-27 20:26:33 +00:00
2015-11-18 07:37:39 +00:00
static qintptr_t QVM_clientstat ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
int num = VM_LONG ( arg [ 0 ] ) ;
int type = VM_LONG ( arg [ 1 ] ) ;
int fieldofs = VM_LONG ( arg [ 2 ] ) ;
// SV_QCStatEval(type, "", &cache, NULL, num);
SV_QCStatFieldIdx ( type , fieldofs , num ) ;
return 0 ;
}
static qintptr_t QVM_pointerstat ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
int num = VM_LONG ( arg [ 0 ] ) ;
int type = VM_LONG ( arg [ 1 ] ) ;
void * ptr = VM_POINTER ( arg [ 2 ] ) ;
SV_QCStatPtr ( type , ptr , num ) ;
return 0 ;
}
2021-11-19 19:40:25 +00:00
//void(entity e, vector flags, entity target) setsendneeded
static qintptr_t QVM_SetSendNeeded ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
unsigned int subject = VM_LONG ( arg [ 0 ] ) ;
quint64_t fl = arg [ 1 ] ;
unsigned int to = VM_LONG ( arg [ 2 ] ) ;
if ( ! to )
{ //broadcast
for ( to = 0 ; to < sv . allocated_client_slots ; to + + )
if ( svs . clients [ to ] . pendingcsqcbits & & subject < svs . clients [ to ] . max_net_ents )
svs . clients [ to ] . pendingcsqcbits [ subject ] | = fl ;
}
else
{
to - - ;
if ( to > = sv . allocated_client_slots | | ! svs . clients [ to ] . pendingcsqcbits | | subject > = svs . clients [ to ] . max_net_ents )
; //some kind of error.
else
svs . clients [ to ] . pendingcsqcbits [ subject ] | = fl ;
}
return 0 ;
}
2022-01-08 09:59:59 +00:00
static qintptr_t QVM_VisibleTo_FTE ( void * offset , quintptr_t mask , const qintptr_t * arg )
2019-07-16 02:59:12 +00:00
{
unsigned int a0 = VM_LONG ( arg [ 0 ] ) ;
unsigned int a1 = VM_LONG ( arg [ 1 ] ) ;
2021-12-20 10:07:55 +00:00
if ( a0 < sv . world . num_edicts & & a1 < sv . world . num_edicts )
2019-07-16 02:59:12 +00:00
{
pvscache_t * viewer = & q1qvmprogfuncs . edicttable [ a0 ] - > pvsinfo ;
pvscache_t * viewee = & q1qvmprogfuncs . edicttable [ a1 ] - > pvsinfo ;
if ( viewer - > num_leafs & & viewee - > num_leafs )
{
unsigned int i ;
2021-12-20 10:07:55 +00:00
int areas [ ] = { 2 , viewer - > areanum , viewer - > areanum2 } ;
2019-07-16 02:59:12 +00:00
for ( i = 0 ; i < viewer - > num_leafs ; i + + )
{
qbyte * pvs = sv . world . worldmodel - > funcs . ClusterPVS ( sv . world . worldmodel , viewer - > leafnums [ i ] , NULL , PVM_FAST ) ;
if ( sv . world . worldmodel - > funcs . EdictInFatPVS ( sv . world . worldmodel , viewee , pvs , areas ) )
return true ; //viewer can see viewee
}
}
}
return 0 ;
}
2015-07-01 23:15:25 +00:00
static qintptr_t QVM_Map_Extension ( void * offset , quintptr_t mask , const qintptr_t * arg ) ;
2008-05-25 22:23:43 +00:00
2015-07-01 23:15:25 +00:00
typedef qintptr_t ( * traps_t ) ( void * offset , quintptr_t mask , const qintptr_t * arg ) ;
traps_t bitraps [ G_MAX ] =
{
QVM_GetAPIVersion ,
QVM_DPrint ,
QVM_Error ,
QVM_GetEntityToken ,
QVM_Spawn_Ent ,
QVM_Remove_Ent ,
QVM_Precache_Sound ,
QVM_Precache_Model ,
QVM_LightStyle ,
QVM_SetOrigin ,
QVM_SetSize , //10
QVM_SetModel ,
QVM_BPrint ,
QVM_SPrint ,
QVM_CenterPrint ,
QVM_AmbientSound , //15
QVM_Sound ,
QVM_TraceLine ,
QVM_CheckClient ,
QVM_StuffCmd ,
QVM_LocalCmd , //20
QVM_CVar ,
QVM_CVar_Set ,
QVM_FindRadius ,
QVM_WalkMove ,
QVM_DropToFloor , //25
QVM_CheckBottom ,
QVM_PointContents ,
QVM_NextEnt ,
QVM_Aim ,
QVM_MakeStatic , //30
QVM_SetSpawnParams ,
QVM_ChangeLevel ,
QVM_LogFrag ,
QVM_GetInfoKey ,
QVM_Multicast , //35
QVM_DisableUpdates ,
2019-07-16 02:59:12 +00:00
QVM_WriteByte ,
QVM_WriteChar ,
QVM_WriteShort ,
2015-07-01 23:15:25 +00:00
QVM_WriteLong , //40
2019-07-16 02:59:12 +00:00
QVM_WriteAngle ,
QVM_WriteCoord ,
QVM_WriteString ,
2015-07-01 23:15:25 +00:00
QVM_WriteEntity ,
QVM_FlushSignon , //45
QVM_memset ,
2019-07-16 02:59:12 +00:00
QVM_memcpy ,
QVM_strncpy ,
QVM_sin ,
2015-07-01 23:15:25 +00:00
QVM_cos , //50
2019-07-16 02:59:12 +00:00
QVM_atan2 ,
QVM_sqrt ,
QVM_floor ,
QVM_ceil ,
2015-07-01 23:15:25 +00:00
QVM_acos , //55
QVM_Cmd_ArgC ,
QVM_Cmd_ArgV ,
QVM_TraceBox , //was G_TraceCapsule
QVM_FS_OpenFile ,
QVM_FS_CloseFile , //60
QVM_FS_ReadFile ,
QVM_FS_WriteFile ,
QVM_FS_SeekFile ,
QVM_FS_TellFile ,
QVM_FS_GetFileList , //65
QVM_CVar_Set_Float ,
QVM_CVar_String ,
QVM_Map_Extension ,
QVM_strcmp ,
QVM_strncmp , //70
QVM_stricmp ,
QVM_strnicmp ,
QVM_Find ,
QVM_ExecuteCmd ,
QVM_ConPrint , //75
QVM_ReadCmd ,
QVM_RedirectCmd ,
QVM_Add_Bot ,
QVM_Remove_Bot ,
QVM_SetBotUserInfo , //80
QVM_SetBotCMD ,
QVM_strftime ,
QVM_Cmd_ArgS ,
QVM_Cmd_Tokenize ,
QVM_strlcpy , //85
QVM_strlcat ,
QVM_MakeVectors ,
QVM_NextClient ,
QVM_Precache_VWep_Model ,
QVM_SetPause ,
QVM_SetUserInfo ,
2022-01-08 09:59:59 +00:00
QVM_MoveToGoal ,
QVM_VisibleTo ,
2015-07-01 23:15:25 +00:00
} ;
struct
{
char * extname ;
traps_t trap ;
} qvmextensions [ ] =
{
{ " SetExtField " , QVM_SetExtField } ,
{ " GetExtField " , QVM_GetExtField } ,
2021-05-27 11:34:01 +00:00
{ " ChangeLevelHub " , QVM_ChangeLevelHub } , //with start spot
2017-03-26 23:03:02 +00:00
# ifdef WEBCLIENT
{ " URI_Query " , QVM_uri_query } ,
# endif
2015-07-01 23:15:25 +00:00
{ " particleeffectnum " , QVM_particleeffectnum } ,
{ " trailparticles " , QVM_trailparticles } ,
{ " pointparticles " , QVM_pointparticles } ,
2015-11-18 07:37:39 +00:00
{ " clientstat " , QVM_clientstat } , //csqc extension
{ " pointerstat " , QVM_pointerstat } , //csqc extension
2021-11-19 19:40:25 +00:00
{ " setsendneeded " , QVM_SetSendNeeded } , //csqc extension
2022-01-08 09:59:59 +00:00
{ " VisibleTo " , QVM_VisibleTo_FTE } , //alternative to mvdsv's visclients hack. redundant now. FIXME: Remove.
2015-07-01 23:15:25 +00:00
//sql?
//model querying?
2017-10-12 12:02:25 +00:00
//skeletal objects/tags?
2015-07-01 23:15:25 +00:00
//heightmap / brush editing?
//csqc ents
{ NULL , NULL }
} ;
traps_t traps [ 512 ] ;
static qintptr_t QVM_Map_Extension ( void * offset , quintptr_t mask , const qintptr_t * arg )
{
char * extname = VM_POINTER ( arg [ 0 ] ) ;
unsigned int slot = VM_LONG ( arg [ 1 ] ) ;
int i ;
2008-05-25 22:23:43 +00:00
2015-07-01 23:15:25 +00:00
if ( slot > = countof ( traps ) )
return - 2 ; //invalid slot.
2008-05-25 22:23:43 +00:00
2015-07-01 23:15:25 +00:00
if ( ! extname )
{ //special handling for vauge compat with mvdsv, for testing how many 'known' builtins are implemented.
if ( slot < G_MAX )
return - 2 ;
return - 1 ;
}
2008-05-25 22:23:43 +00:00
2015-07-01 23:15:25 +00:00
//find the extension and map it to the slot if found.
for ( i = 0 ; qvmextensions [ i ] . extname ; i + + )
{
if ( ! Q_strcasecmp ( extname , qvmextensions [ i ] . extname ) )
2009-07-14 23:42:54 +00:00
{
2015-07-01 23:15:25 +00:00
traps [ slot ] = qvmextensions [ i ] . trap ;
return slot ;
2009-07-14 23:42:54 +00:00
}
2008-05-25 22:23:43 +00:00
}
2015-07-01 23:15:25 +00:00
return - 1 ; //extension not known
2008-05-25 22:23:43 +00:00
}
2015-07-01 23:15:25 +00:00
//============== general Quake services ==================
2009-07-17 15:34:16 +00:00
static int syscallqvm ( void * offset , quintptr_t mask , int fn , const int * arg )
2009-07-14 23:42:54 +00:00
{
2016-02-10 23:23:43 +00:00
if ( sizeof ( int ) = = sizeof ( qintptr_t ) )
{ //should allow the slow copy below to be optimised out
if ( fn > = countof ( traps ) )
return QVM_NotYetImplemented ( offset , mask , ( qintptr_t * ) arg ) ;
return traps [ fn ] ( offset , mask , ( qintptr_t * ) arg ) ;
}
else
{
qintptr_t args [ 13 ] ;
int i ;
2022-01-08 10:00:40 +00:00
for ( i = 0 ; i < countof ( args ) ; i + + )
2016-02-10 23:23:43 +00:00
args [ i ] = arg [ i ] ;
if ( fn > = countof ( traps ) )
return QVM_NotYetImplemented ( offset , mask , args ) ;
return traps [ fn ] ( offset , mask , args ) ;
}
2009-07-14 23:42:54 +00:00
}
static qintptr_t EXPORT_FN syscallnative ( qintptr_t arg , . . . )
2008-05-25 22:23:43 +00:00
{
2009-07-14 23:42:54 +00:00
qintptr_t args [ 13 ] ;
2008-05-25 22:23:43 +00:00
va_list argptr ;
va_start ( argptr , arg ) ;
2009-07-14 23:42:54 +00:00
args [ 0 ] = va_arg ( argptr , qintptr_t ) ;
args [ 1 ] = va_arg ( argptr , qintptr_t ) ;
args [ 2 ] = va_arg ( argptr , qintptr_t ) ;
args [ 3 ] = va_arg ( argptr , qintptr_t ) ;
args [ 4 ] = va_arg ( argptr , qintptr_t ) ;
args [ 5 ] = va_arg ( argptr , qintptr_t ) ;
args [ 6 ] = va_arg ( argptr , qintptr_t ) ;
args [ 7 ] = va_arg ( argptr , qintptr_t ) ;
args [ 8 ] = va_arg ( argptr , qintptr_t ) ;
args [ 9 ] = va_arg ( argptr , qintptr_t ) ;
args [ 10 ] = va_arg ( argptr , qintptr_t ) ;
args [ 11 ] = va_arg ( argptr , qintptr_t ) ;
args [ 12 ] = va_arg ( argptr , qintptr_t ) ;
2008-05-25 22:23:43 +00:00
va_end ( argptr ) ;
2015-07-01 23:15:25 +00:00
if ( arg > = countof ( traps ) )
return QVM_NotYetImplemented ( NULL , ~ ( quintptr_t ) 0 , args ) ;
return traps [ arg ] ( NULL , ~ ( quintptr_t ) 0 , args ) ;
2008-05-25 22:23:43 +00:00
}
2017-10-12 12:02:25 +00:00
void Q1QVM_Shutdown ( qboolean notifygame )
2008-05-25 22:23:43 +00:00
{
int i ;
if ( q1qvm )
{
2011-04-25 03:25:22 +00:00
for ( i = 0 ; i < sv . allocated_client_slots ; i + + )
2008-05-25 22:23:43 +00:00
{
if ( svs . clients [ i ] . name )
Q_strncpyz ( svs . clients [ i ] . namebuf , svs . clients [ i ] . name , sizeof ( svs . clients [ i ] . namebuf ) ) ;
svs . clients [ i ] . name = svs . clients [ i ] . namebuf ;
}
2019-07-16 02:59:12 +00:00
if ( notifygame & & gvars )
2017-10-12 12:02:25 +00:00
VM_Call ( q1qvm , GAME_SHUTDOWN , 0 , 0 , 0 ) ;
2008-05-25 22:23:43 +00:00
VM_Destroy ( q1qvm ) ;
2014-03-30 08:55:06 +00:00
q1qvm = NULL ;
2022-03-08 05:31:34 +00:00
QVM_FS_CloseFileAll ( ) ;
2014-03-30 08:55:06 +00:00
if ( svprogfuncs = = & q1qvmprogfuncs )
sv . world . progs = svprogfuncs = NULL ;
Z_FreeTags ( VMFSID_Q1QVM ) ;
2015-09-10 10:16:26 +00:00
if ( q1qvmprogfuncs . edicttable )
2015-04-21 04:12:00 +00:00
{
2015-09-10 10:16:26 +00:00
Z_Free ( q1qvmprogfuncs . edicttable ) ;
q1qvmprogfuncs . edicttable = NULL ;
2015-04-21 04:12:00 +00:00
}
2015-11-18 07:37:39 +00:00
vevars = 0 ;
2008-05-25 22:23:43 +00:00
}
}
2017-10-12 12:02:25 +00:00
static void QDECL Q1QVM_Get_FrameState ( world_t * w , wedict_t * ent , framestate_t * fstate )
{
memset ( fstate , 0 , sizeof ( * fstate ) ) ;
fstate - > g [ FS_REG ] . frame [ 0 ] = ent - > v - > frame ;
fstate - > g [ FS_REG ] . frametime [ 0 ] = ent - > xv - > frame1time ;
fstate - > g [ FS_REG ] . lerpweight [ 0 ] = 1 ;
fstate - > g [ FS_REG ] . endbone = 0x7fffffff ;
fstate - > g [ FST_BASE ] . frame [ 0 ] = ent - > xv - > baseframe ;
fstate - > g [ FST_BASE ] . frametime [ 0 ] = ent - > xv - > /*base*/ frame1time ;
fstate - > g [ FST_BASE ] . lerpweight [ 0 ] = 1 ;
fstate - > g [ FST_BASE ] . endbone = ent - > xv - > basebone ;
# if defined(SKELETALOBJECTS) || defined(RAGDOLL)
if ( ent - > xv - > skeletonindex )
skel_lookup ( w , ent - > xv - > skeletonindex , fstate ) ;
# endif
}
2018-09-23 19:35:24 +00:00
static void QDECL Q1QVM_Event_Touch ( world_t * w , wedict_t * s , wedict_t * o , trace_t * trace )
2011-09-03 03:49:43 +00:00
{
int oself = pr_global_struct - > self ;
int oother = pr_global_struct - > other ;
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 ;
2015-06-14 01:28:01 +00:00
VM_Call ( q1qvm , GAME_EDICT_TOUCH , 0 , 0 , 0 ) ;
2011-09-03 03:49:43 +00:00
pr_global_struct - > self = oself ;
pr_global_struct - > other = oother ;
}
2016-07-12 00:40:13 +00:00
static void QDECL Q1QVM_Event_Think ( world_t * w , wedict_t * s )
2011-09-03 03:49:43 +00:00
{
pr_global_struct - > self = EDICT_TO_PROG ( w - > progs , s ) ;
pr_global_struct - > other = EDICT_TO_PROG ( w - > progs , w - > edicts ) ;
2015-06-14 01:28:01 +00:00
VM_Call ( q1qvm , GAME_EDICT_THINK , 0 , 0 , 0 ) ;
2011-09-03 03:49:43 +00:00
}
2016-07-12 00:40:13 +00:00
static qboolean QDECL Q1QVM_Event_ContentsTransition ( world_t * w , wedict_t * ent , int oldwatertype , int newwatertype )
2012-07-05 19:42:36 +00:00
{
return false ; //always do legacy behaviour
}
2008-05-25 22:23:43 +00:00
qboolean PR_LoadQ1QVM ( void )
{
2020-06-27 19:32:49 +00:00
static pint_t writable_int ;
static pvec_t writable ;
static pvec_t dimensionsend = 255 ;
static pvec_t dimensiondefault = 255 ;
static pvec_t physics_mode = 2 ;
static pvec3_t defaultgravity = { 0 , 0 , - 1 } ;
2008-05-25 22:23:43 +00:00
int i ;
2015-11-18 07:37:39 +00:00
gameDataPrivate_t gd ;
gameDataN_t * gdn ;
2008-05-25 22:23:43 +00:00
gameData32_t * gd32 ;
2009-07-14 23:42:54 +00:00
qintptr_t ret ;
2015-04-21 04:12:00 +00:00
qintptr_t limit ;
extern cvar_t pr_maxedicts ;
2008-05-25 22:23:43 +00:00
2019-07-16 02:59:12 +00:00
const char * fname = pr_ssqc_progs . string ;
if ( ! * fname )
fname = " qwprogs " ;
2017-10-12 12:02:25 +00:00
Q1QVM_Shutdown ( true ) ;
2008-05-25 22:23:43 +00:00
2022-03-08 05:31:34 +00:00
q1qvm = VM_Create ( fname , com_gamedirnativecode . ival ? syscallnative : NULL , fname , syscallqvm ) ;
2015-07-01 23:15:25 +00:00
if ( ! q1qvm )
2019-07-16 02:59:12 +00:00
q1qvm = VM_Create ( fname , syscallnative , fname , NULL ) ;
2008-05-25 22:23:43 +00:00
if ( ! q1qvm )
2009-11-17 00:15:44 +00:00
{
2022-03-08 05:31:34 +00:00
if ( ! com_gamedirnativecode . ival & & COM_FCheckExists ( va ( " %s " ARCH_DL_POSTFIX , fname ) ) )
2022-05-28 17:59:17 +00:00
Con_Printf ( CON_WARNING " %s " ARCH_DL_POSTFIX " exists, but is blocked from loading due to known bugs in other engines. If this is from a safe source then either ^aset com_gamedirnativecode 1^a or rename to eg %s%s_%s " ARCH_DL_POSTFIX " \n " , fname , ( ( host_parms . binarydir & & * host_parms . binarydir ) ? host_parms . binarydir : host_parms . basedir ) , fname , FS_GetGamedir ( false ) ) ;
2009-11-17 00:15:44 +00:00
if ( svprogfuncs = = & q1qvmprogfuncs )
sv . world . progs = svprogfuncs = NULL ;
2008-05-25 22:23:43 +00:00
return false ;
2009-11-17 00:15:44 +00:00
}
2008-05-25 22:23:43 +00:00
2015-07-01 23:15:25 +00:00
for ( i = 0 ; i < G_MAX ; i + + )
traps [ i ] = bitraps [ i ] ;
for ( ; i < countof ( traps ) ; i + + )
traps [ i ] = QVM_NotYetImplemented ;
memset ( & fofs , 0 , sizeof ( fofs ) ) ;
2008-05-25 22:23:43 +00:00
progstype = PROG_QW ;
svprogfuncs = & q1qvmprogfuncs ;
// q1qvmprogfuncs.AddString = Q1QVMPF_AddString; //using this breaks 64bit support, and is a 'bad plan' elsewhere too,
2018-04-06 17:21:15 +00:00
q1qvmprogfuncs . EdictNum = Q1QVMPF_EdictNum ;
q1qvmprogfuncs . NumForEdict = Q1QVMPF_NumForEdict ;
2008-05-25 22:23:43 +00:00
q1qvmprogfuncs . EdictToProgs = Q1QVMPF_EdictToProgs ;
q1qvmprogfuncs . ProgsToEdict = Q1QVMPF_ProgsToEdict ;
q1qvmprogfuncs . EntAlloc = Q1QVMPF_EntAlloc ;
q1qvmprogfuncs . EntFree = Q1QVMPF_EntRemove ;
q1qvmprogfuncs . FindGlobal = Q1QVMPF_FindGlobal ;
q1qvmprogfuncs . load_ents = Q1QVMPF_LoadEnts ;
q1qvmprogfuncs . globals = Q1QVMPF_Globals ;
q1qvmprogfuncs . GetEdictFieldValue = Q1QVMPF_GetEdictFieldValue ;
2015-11-18 07:37:39 +00:00
q1qvmprogfuncs . QueryField = Q1QVMPF_QueryField ;
2008-05-25 22:23:43 +00:00
q1qvmprogfuncs . StringToProgs = Q1QVMPF_StringToProgs ;
q1qvmprogfuncs . StringToNative = Q1QVMPF_StringToNative ;
2014-03-30 08:55:06 +00:00
q1qvmprogfuncs . SetStringField = Q1QVMPF_SetStringField ;
2015-06-20 14:22:06 +00:00
q1qvmprogfuncs . EntClear = Q1QVMPF_ClearEdict ;
2008-05-25 22:23:43 +00:00
2011-09-03 03:49:43 +00:00
sv . world . Event_Touch = Q1QVM_Event_Touch ;
sv . world . Event_Think = Q1QVM_Event_Think ;
2012-07-05 19:42:36 +00:00
sv . world . Event_Sound = SVQ1_StartSound ;
sv . world . Event_ContentsTransition = Q1QVM_Event_ContentsTransition ;
2011-10-27 16:16:29 +00:00
sv . world . Get_CModel = SVPR_GetCModel ;
2017-10-12 12:02:25 +00:00
sv . world . Get_FrameState = Q1QVM_Get_FrameState ;
2009-11-07 13:29:15 +00:00
2009-11-04 21:16:50 +00:00
sv . world . num_edicts = 0 ; //we're not ready for most of the builtins yet
sv . world . max_edicts = 0 ; //so clear these out, just in case
sv . world . edict_size = 0 ; //if we get a division by zero, then at least its a safe crash
2008-05-25 22:23:43 +00:00
2015-09-10 10:16:26 +00:00
q1qvmprogfuncs . edicttable = NULL ;
2008-05-25 22:23:43 +00:00
q1qvmprogfuncs . stringtable = VM_MemoryBase ( q1qvm ) ;
2017-10-12 12:02:25 +00:00
qvm_api_version = GAME_API_VERSION ;
2015-06-14 01:28:01 +00:00
ret = VM_Call ( q1qvm , GAME_INIT , ( qintptr_t ) ( sv . time * 1000 ) , rand ( ) , 0 , 0 , 0 ) ;
2008-05-25 22:23:43 +00:00
if ( ! ret )
{
2017-10-12 12:02:25 +00:00
Q1QVM_Shutdown ( false ) ;
2008-05-25 22:23:43 +00:00
return false ;
}
2009-07-14 23:42:54 +00:00
if ( VM_NonNative ( q1qvm ) )
2015-11-18 07:37:39 +00:00
{ //when non native, this can only be a 32bit qvm in a 64bit server.
2009-07-14 23:42:54 +00:00
gd32 = ( gameData32_t * ) ( ( char * ) VM_MemoryBase ( q1qvm ) + ret ) ; //qvm is 32bit
2015-11-18 07:37:39 +00:00
gd . APIversion = gd32 - > APIversion ;
gd . sizeofent = gd32 - > sizeofent ;
gd . ents = gd32 - > ents ;
gd . global = gd32 - > global ;
gd . fields = gd32 - > fields ;
2017-10-12 12:02:25 +00:00
if ( qvm_api_version > = 14 )
gd . maxedicts = gd32 - > maxentities ;
else
gd . maxedicts = MAX_Q1QVM_EDICTS ;
2009-07-14 23:42:54 +00:00
}
else
{
2015-11-18 07:37:39 +00:00
gdn = ( gameDataN_t * ) ( ( char * ) VM_MemoryBase ( q1qvm ) + ret ) ;
gd . APIversion = gdn - > APIversion ;
gd . sizeofent = gdn - > sizeofent ;
2019-07-16 02:59:12 +00:00
2015-11-18 07:37:39 +00:00
gd . ents = gdn - > ents ;
gd . global = gdn - > global ;
gd . fields = gdn - > fields ;
2017-10-12 12:02:25 +00:00
if ( qvm_api_version > = 14 )
gd . maxedicts = gdn - > maxentities ;
else
gd . maxedicts = MAX_Q1QVM_EDICTS ;
}
gd . maxedicts = bound ( 1 , pr_maxedicts . ival , gd . maxedicts ) ;
2020-03-25 21:29:30 +00:00
gd . maxedicts = bound ( 1 , gd . maxedicts , MAX_EDICTS ) ;
2017-10-12 12:02:25 +00:00
qvm_api_version = gd . APIversion ;
if ( ! ( GAME_API_VERSION_MIN < = qvm_api_version & & qvm_api_version < = GAME_API_VERSION ) )
{
Con_Printf ( " QVM-API version %i not supported \n " , qvm_api_version ) ;
Q1QVM_Shutdown ( false ) ;
return false ;
}
2021-12-20 10:07:55 +00:00
if ( qvm_api_version > = 16 )
{ //version 16 finally removed the last remnant of the server's state from the qvm.
wasted_edict_t_size = 0 ;
}
else if ( qvm_api_version > = 13 )
{
//in version 13, the actual edict_t struct is gone, and there's a pointer to it in its place (which is unusable, and changes depending on modes).
2017-10-12 12:02:25 +00:00
wasted_edict_t_size = ( VM_NonNative ( q1qvm ) ? sizeof ( int ) : sizeof ( void * ) ) ;
2021-12-20 10:07:55 +00:00
}
2017-10-12 12:02:25 +00:00
else
{
//fte/qclib has split edict_t and entvars_t.
//older versions of the qvm api has them in one lump
//so we need to bias the mod's entvars_t offsets a little.
wasted_edict_t_size = 114 ;
2009-07-14 23:42:54 +00:00
}
2008-05-25 22:23:43 +00:00
2015-04-21 04:12:00 +00:00
sv . world . num_edicts = 1 ;
2015-11-18 07:37:39 +00:00
sv . world . max_edicts = bound ( 64 , gd . maxedicts , MAX_EDICTS ) ;
2015-09-10 10:16:26 +00:00
q1qvmprogfuncs . edicttable = Z_Malloc ( sizeof ( * q1qvmprogfuncs . edicttable ) * sv . world . max_edicts ) ;
2018-04-06 17:21:15 +00:00
q1qvmprogfuncs . edicttable_length = sv . world . max_edicts ;
2015-04-21 04:12:00 +00:00
limit = VM_MemoryMask ( q1qvm ) ;
2018-06-18 16:44:29 +00:00
if ( gd . sizeofent > 0xffffffff / gd . maxedicts )
2015-11-18 07:37:39 +00:00
gd . sizeofent = 0xffffffff / gd . maxedicts ;
if ( ( quintptr_t ) gd . ents + ( gd . sizeofent * gd . maxedicts ) < ( quintptr_t ) gd . ents | | ( quintptr_t ) gd . ents > ( quintptr_t ) limit )
gd . ents = 0 ;
if ( ( quintptr_t ) ( gd . global + 1 ) < ( quintptr_t ) gd . global | | ( quintptr_t ) gd . global > ( quintptr_t ) limit )
gd . global = 0 ;
if ( /*(quintptr_t)gd.fields < (quintptr_t)gd.fields ||*/ ( quintptr_t ) gd . fields > limit )
gd . fields = 0 ;
sv . world . edict_size = gd . sizeofent ;
vevars = gd . ents ;
evars = Q1QVMPF_PointerToNative ( & q1qvmprogfuncs , vevars ) ;
2017-10-12 12:02:25 +00:00
gvars = Q1QVMPF_PointerToNative ( & q1qvmprogfuncs , gd . global ) ;
2015-11-18 07:37:39 +00:00
2017-10-12 12:02:25 +00:00
if ( ! evars | | ! gvars )
2015-11-18 07:37:39 +00:00
{
2017-10-12 12:02:25 +00:00
Q1QVM_Shutdown ( false ) ;
2015-11-18 07:37:39 +00:00
return false ;
}
2008-05-25 22:23:43 +00:00
//WARNING: global is not remapped yet...
//This code is written evilly, but works well enough
2022-01-08 10:00:40 +00:00
# define globalint(required, name) pr_global_ptrs->name = Q1QVMPF_PointerToNative(&q1qvmprogfuncs, (qintptr_t)&gvars->name - (qintptr_t)q1qvmprogfuncs.stringtable) //the logic of this is somewhat crazy
# define globalfloat(required, name) pr_global_ptrs->name = Q1QVMPF_PointerToNative(&q1qvmprogfuncs, (qintptr_t)&gvars->name - (qintptr_t)q1qvmprogfuncs.stringtable)
# define globalstring(required, name) pr_global_ptrs->name = Q1QVMPF_PointerToNative(&q1qvmprogfuncs, (qintptr_t)&gvars->name - (qintptr_t)q1qvmprogfuncs.stringtable)
# define globalvec(required, name) pr_global_ptrs->name = Q1QVMPF_PointerToNative(&q1qvmprogfuncs, (qintptr_t)&gvars->name - (qintptr_t)q1qvmprogfuncs.stringtable)
# define globalfunc(required, name) pr_global_ptrs->name = Q1QVMPF_PointerToNative(&q1qvmprogfuncs, (qintptr_t)&gvars->name - (qintptr_t)q1qvmprogfuncs.stringtable)
2016-07-12 00:40:13 +00:00
# define globalnull(required, name) pr_global_ptrs->name = NULL
2008-05-25 22:23:43 +00:00
globalint ( true , self ) ; //we need the qw ones, but any in standard quake and not quakeworld, we don't really care about.
globalint ( true , other ) ;
globalint ( true , world ) ;
globalfloat ( true , time ) ;
globalfloat ( true , frametime ) ;
globalint ( false , newmis ) ; //not always in nq.
globalfloat ( false , force_retouch ) ;
globalstring ( true , mapname ) ;
2016-07-12 00:40:13 +00:00
globalnull ( false , deathmatch ) ;
globalnull ( false , coop ) ;
globalnull ( false , teamplay ) ;
2008-05-25 22:23:43 +00:00
globalfloat ( true , serverflags ) ;
globalfloat ( true , total_secrets ) ;
globalfloat ( true , total_monsters ) ;
globalfloat ( true , found_secrets ) ;
globalfloat ( true , killed_monsters ) ;
globalvec ( true , v_forward ) ;
globalvec ( true , v_up ) ;
globalvec ( true , v_right ) ;
globalfloat ( true , trace_allsolid ) ;
globalfloat ( true , trace_startsolid ) ;
globalfloat ( true , trace_fraction ) ;
globalvec ( true , trace_endpos ) ;
globalvec ( true , trace_plane_normal ) ;
globalfloat ( true , trace_plane_dist ) ;
globalint ( true , trace_ent ) ;
globalfloat ( true , trace_inopen ) ;
globalfloat ( true , trace_inwater ) ;
2016-07-21 19:27:59 +00:00
globalnull ( false , trace_endcontentsf ) ;
2016-07-12 00:40:13 +00:00
globalnull ( false , trace_endcontentsi ) ;
2016-07-21 19:27:59 +00:00
globalnull ( false , trace_surfaceflagsf ) ;
2016-07-12 00:40:13 +00:00
globalnull ( false , trace_surfaceflagsi ) ;
globalnull ( false , cycle_wrapped ) ;
2008-05-25 22:23:43 +00:00
globalint ( false , msg_entity ) ;
globalfunc ( false , main ) ;
globalfunc ( true , StartFrame ) ;
globalfunc ( true , PlayerPreThink ) ;
globalfunc ( true , PlayerPostThink ) ;
globalfunc ( true , ClientKill ) ;
globalfunc ( true , ClientConnect ) ;
globalfunc ( true , PutClientInServer ) ;
globalfunc ( true , ClientDisconnect ) ;
globalfunc ( false , SetNewParms ) ;
globalfunc ( false , SetChangeParms ) ;
2016-07-21 19:27:59 +00:00
pr_global_ptrs - > trace_surfaceflagsf = & writable ;
2016-07-12 00:40:13 +00:00
pr_global_ptrs - > trace_surfaceflagsi = & writable_int ;
2016-07-21 19:27:59 +00:00
pr_global_ptrs - > trace_endcontentsf = & writable ;
2016-07-12 00:40:13 +00:00
pr_global_ptrs - > trace_endcontentsi = & writable_int ;
2015-06-11 23:33:13 +00:00
pr_global_ptrs - > dimension_default = & dimensiondefault ;
2011-10-27 16:16:29 +00:00
pr_global_ptrs - > dimension_send = & dimensionsend ;
2013-03-12 23:24:15 +00:00
pr_global_ptrs - > physics_mode = & physics_mode ;
2015-10-27 15:20:15 +00:00
pr_global_ptrs - > trace_brush_id = & writable_int ;
pr_global_ptrs - > trace_brush_faceid = & writable_int ;
2017-10-12 12:02:25 +00:00
pr_global_ptrs - > trace_surface_id = & writable_int ;
pr_global_ptrs - > trace_bone_id = & writable_int ;
pr_global_ptrs - > trace_triangle_id = & writable_int ;
2015-10-27 15:20:15 +00:00
pr_global_ptrs - > global_gravitydir = & defaultgravity ;
// ensureglobal(input_timelength, input_timelength_default);
// ensureglobal(input_impulse, input_impulse_default);
// ensureglobal(input_angles, input_angles_default);
// ensureglobal(input_movevalues, input_movevalues_default);
// ensureglobal(input_buttons, input_buttons_default);
2008-05-25 22:23:43 +00:00
2015-06-14 01:28:01 +00:00
dimensionsend = dimensiondefault = 255 ;
2008-05-25 22:23:43 +00:00
for ( i = 0 ; i < 16 ; i + + )
2022-01-08 10:00:40 +00:00
pr_global_ptrs - > spawnparamglobals [ i ] = ( float * ) ( & gvars - > parm1 + i ) ;
2008-05-25 22:23:43 +00:00
for ( ; i < NUM_SPAWN_PARMS ; i + + )
2011-10-27 16:16:29 +00:00
pr_global_ptrs - > spawnparamglobals [ i ] = NULL ;
2017-05-28 15:42:32 +00:00
pr_global_ptrs - > parm_string = NULL ;
2008-05-25 22:23:43 +00:00
2017-10-12 12:02:25 +00:00
# define emufield(n,t) if (field[i].type == t && !strcmp(#n, fname)) {fofs.n = (field[i].ofs - wasted_edict_t_size) / sizeof(float); continue;}
2015-11-18 07:37:39 +00:00
if ( VM_NonNative ( q1qvm ) )
2015-07-01 23:15:25 +00:00
{
2015-11-18 07:37:39 +00:00
field32_t * field = Q1QVMPF_PointerToNative ( & q1qvmprogfuncs , gd . fields ) ;
if ( field )
for ( i = 0 ; field [ i ] . name ; i + + )
{
const char * fname = Q1QVMPF_PointerToNative ( & q1qvmprogfuncs , field [ i ] . name ) ;
emufields
2019-07-16 02:59:12 +00:00
Con_DPrintf ( " Extension field %s is not supported \n " , fname ) ;
2015-11-18 07:37:39 +00:00
}
2015-07-01 23:15:25 +00:00
}
2015-11-18 07:37:39 +00:00
else
{
fieldN_t * field = Q1QVMPF_PointerToNative ( & q1qvmprogfuncs , gd . fields ) ;
if ( field )
for ( i = 0 ; field [ i ] . name ; i + + )
{
const char * fname = Q1QVMPF_PointerToNative ( & q1qvmprogfuncs , field [ i ] . name ) ;
emufields
2019-07-16 02:59:12 +00:00
Con_DPrintf ( " Extension field %s is not supported \n " , fname ) ;
2015-11-18 07:37:39 +00:00
}
}
# undef emufield
2015-07-01 23:15:25 +00:00
2008-05-25 22:23:43 +00:00
2009-11-15 03:16:49 +00:00
sv . world . progs = & q1qvmprogfuncs ;
2015-09-10 10:16:26 +00:00
sv . world . edicts = ( wedict_t * ) Q1QVMPF_EdictNum ( svprogfuncs , 0 ) ;
Fixes, workarounds, and breakages. Hexen2 should work much better (-hexen2 says no mission pack, -portals says h2mp). Started working on splitting bigcoords per client, far too much work still to go on that. Removed gl_ztrick entirely. Enabled csprogs download by default. Added client support for fitzquake's 666 protocol, needs testing, some cleanup for dp protocols too, no server support, couldn't selectively enable it anyway. Now attempting to cache shadow meshes for explosions and stuff. Played with lightmaps a little, should potentially run a little faster on certain (intel?) cards. Tweeked npfte a little to try to avoid deadlocks and crashes. Fixed sky worldspawn parsing. Added h2mp's model format. Fixed baseline issue in q2 client, made servers generate q2 baselines. MOVETYPE_PUSH will not rotate extra if rotation is forced. Made status command show allowed client types. Changed lighting on weapons - should now be shaded.
git-svn-id: https://svn.code.sf.net/p/fteqw/code/branches/wip@3572 fc73d0e0-1445-4013-8a0c-d673dee63da5
2010-08-11 03:36:31 +00:00
sv . world . usesolidcorpse = true ;
2011-07-30 14:14:56 +00:00
2017-10-12 12:02:25 +00:00
if ( qvm_api_version > = 15 )
{
int e ;
for ( e = 0 ; e < = 32 ; e + + )
{
pr_global_struct - > self = Q1QVMPF_EdictToProgs ( svprogfuncs , Q1QVMPF_EdictNum ( svprogfuncs , e ) ) ;
VM_Call ( q1qvm , GAME_CLEAR_EDICT , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ) ;
}
pr_global_struct - > self = 0 ;
2021-12-20 10:07:55 +00:00
if ( qvm_api_version = = 15 )
Q1QVMPF_SetStringGlobal ( sv . world . progs , & gvars - > mapname , svs . name , MAPNAME_LEN ) ;
2017-10-12 12:02:25 +00:00
}
2015-07-01 23:15:25 +00:00
else
2017-10-12 12:02:25 +00:00
{
if ( ( quintptr_t ) gvars - > mapname & & ( quintptr_t ) gvars - > mapname + MAPNAME_LEN < VM_MemoryMask ( q1qvm ) )
Q_strncpyz ( ( char * ) VM_MemoryBase ( q1qvm ) + gvars - > mapname , svs . name , MAPNAME_LEN ) ;
else
gvars - > mapname = Q1QVMPF_StringToProgs ( sv . world . progs , svs . name ) ;
}
2013-03-12 23:24:15 +00:00
PR_SV_FillWorldGlobals ( & sv . world ) ;
2008-05-25 22:23:43 +00:00
return true ;
}
void Q1QVM_ClientConnect ( client_t * cl )
{
2021-12-20 10:07:55 +00:00
if ( qvm_api_version > = 16 )
{
Q_strncpyz ( cl - > namebuf , cl - > name , sizeof ( cl - > namebuf ) ) ;
cl - > name = cl - > namebuf ;
}
else if ( qvm_api_version > = 15 & & ! VM_NonNative ( q1qvm ) )
2017-10-12 12:02:25 +00:00
{
Q_strncpyz ( cl - > namebuf , cl - > name , sizeof ( cl - > namebuf ) ) ;
Q1QVMPF_SetStringField ( sv . world . progs , cl - > edict , & cl - > edict - > v - > netname , cl - > namebuf , true ) ;
}
else if ( cl - > edict - > v - > netname )
2008-05-25 22:23:43 +00:00
{
2017-10-12 12:02:25 +00:00
char * name ;
char * base = VM_MemoryBase ( q1qvm ) ;
quintptr_t mask = VM_MemoryMask ( q1qvm ) ;
name = ( char * ) Q1QVMPF_StringToNative ( svprogfuncs , cl - > edict - > v - > netname ) ;
if ( cl - > name > base & & cl - > name < base + mask )
{
Q_strncpyz ( cl - > namebuf , name , sizeof ( cl - > namebuf ) ) ;
strcpy ( name , cl - > namebuf ) ;
cl - > name = name ; //so the gamecode can do changes if it wants.
}
else
Con_Printf ( " WARNING: Mod provided no netname buffer. Player names will not be set properly. \n " ) ;
2008-05-25 22:23:43 +00:00
}
2014-03-30 08:55:06 +00:00
else if ( ! VM_NonNative ( q1qvm ) )
{
Q_strncpyz ( cl - > namebuf , cl - > name , sizeof ( cl - > namebuf ) ) ;
cl - > name = cl - > namebuf ;
cl - > edict - > v - > netname = Q1QVMPF_StringToProgs ( svprogfuncs , cl - > namebuf ) ;
2015-11-18 07:37:39 +00:00
// Con_DPrintf("WARNING: Mod provided no netname buffer and will not function correctly when compiled as a qvm.\n");
2014-03-30 08:55:06 +00:00
}
else
Con_Printf ( " WARNING: Mod provided no netname buffer. Player names will not be set properly. \n " ) ;
2015-07-01 23:15:25 +00:00
if ( fofs . gravity )
2017-10-12 12:02:25 +00:00
( ( float * ) cl - > edict - > v ) [ fofs . gravity ] = cl - > edict - > xv - > gravity ;
2015-07-01 23:15:25 +00:00
if ( fofs . maxspeed )
2017-10-12 12:02:25 +00:00
( ( float * ) cl - > edict - > v ) [ fofs . maxspeed ] = cl - > edict - > xv - > maxspeed ;
if ( fofs . isBot )
( ( float * ) cl - > edict - > v ) [ fofs . isBot ] = ! cl - > protocol ;
2015-07-01 23:15:25 +00:00
2008-05-25 22:23:43 +00:00
// call the spawn function
2009-11-04 21:16:50 +00:00
pr_global_struct - > time = sv . world . physicstime ;
2008-05-25 22:23:43 +00:00
pr_global_struct - > self = EDICT_TO_PROG ( svprogfuncs , cl - > edict ) ;
2015-06-14 01:28:01 +00:00
VM_Call ( q1qvm , GAME_CLIENT_CONNECT , cl - > spectator , 0 , 0 , 0 ) ;
2008-05-25 22:23:43 +00:00
// actually spawn the player
2009-11-04 21:16:50 +00:00
pr_global_struct - > time = sv . world . physicstime ;
2008-05-25 22:23:43 +00:00
pr_global_struct - > self = EDICT_TO_PROG ( svprogfuncs , cl - > edict ) ;
2015-06-14 01:28:01 +00:00
VM_Call ( q1qvm , GAME_PUT_CLIENT_IN_SERVER , cl - > spectator , 0 , 0 , 0 ) ;
2008-05-25 22:23:43 +00:00
}
qboolean Q1QVM_GameConsoleCommand ( void )
{
int oldself , oldother ;
if ( ! q1qvm )
return false ;
//FIXME: if an rcon command from someone on the server, mvdsv sets self to match the ip of that player
//this is not required (broken by proxies anyway) but is a nice handy feature
2019-07-16 02:59:12 +00:00
2009-11-04 21:16:50 +00:00
pr_global_struct - > time = sv . world . physicstime ;
2008-05-25 22:23:43 +00:00
oldself = pr_global_struct - > self ; //these are usually useless
oldother = pr_global_struct - > other ; //but its possible that someone makes a mod that depends on the 'mod' command working via redirectcmd+co
//this at least matches mvdsv
pr_global_struct - > self = 0 ;
pr_global_struct - > other = 0 ;
2015-06-14 01:28:01 +00:00
VM_Call ( q1qvm , GAME_CONSOLE_COMMAND , 0 , 0 , 0 ) ; //mod uses Cmd_Argv+co to get args
2008-05-25 22:23:43 +00:00
pr_global_struct - > self = oldself ;
pr_global_struct - > other = oldother ;
return true ;
}
qboolean Q1QVM_ClientSay ( edict_t * player , qboolean team )
{
qboolean washandled ;
if ( ! q1qvm )
return false ;
2009-11-04 21:16:50 +00:00
pr_global_struct - > time = sv . world . physicstime ;
2008-05-25 22:23:43 +00:00
pr_global_struct - > self = Q1QVMPF_EdictToProgs ( svprogfuncs , player ) ;
2015-06-14 01:28:01 +00:00
washandled = VM_Call ( q1qvm , GAME_CLIENT_SAY , team , 0 , 0 , 0 ) ;
2008-05-25 22:23:43 +00:00
return washandled ;
}
2021-12-20 10:07:55 +00:00
qboolean Q1QVM_UserInfoChanged ( edict_t * player , qboolean after )
2018-07-05 16:21:44 +00:00
{ //mod will use G_CMD_ARGV to get argv1+argv2 to read the info that is changing.
2008-05-25 22:23:43 +00:00
if ( ! q1qvm )
return false ;
2009-11-04 21:16:50 +00:00
pr_global_struct - > time = sv . world . physicstime ;
2008-05-25 22:23:43 +00:00
pr_global_struct - > self = Q1QVMPF_EdictToProgs ( svprogfuncs , player ) ;
2021-12-20 10:07:55 +00:00
return VM_Call ( q1qvm , GAME_CLIENT_USERINFO_CHANGED , after , 0 , 0 ) ;
2008-05-25 22:23:43 +00:00
}
void Q1QVM_PlayerPreThink ( void )
{
2015-07-01 23:15:25 +00:00
if ( fofs . movement )
{
sv_player - > xv - > movement [ 0 ] = ( ( float * ) sv_player - > v ) [ fofs . movement + 0 ] ;
sv_player - > xv - > movement [ 1 ] = ( ( float * ) sv_player - > v ) [ fofs . movement + 1 ] ;
sv_player - > xv - > movement [ 2 ] = ( ( float * ) sv_player - > v ) [ fofs . movement + 2 ] ;
}
if ( fofs . gravity )
sv_player - > xv - > gravity = ( ( float * ) sv_player - > v ) [ fofs . gravity ] ;
if ( fofs . maxspeed )
sv_player - > xv - > maxspeed = ( ( float * ) sv_player - > v ) [ fofs . maxspeed ] ;
2015-06-14 01:28:01 +00:00
VM_Call ( q1qvm , GAME_CLIENT_PRETHINK , host_client - > spectator , 0 , 0 , 0 ) ;
2008-05-25 22:23:43 +00:00
}
void Q1QVM_RunPlayerThink ( void )
{
2015-06-14 01:28:01 +00:00
VM_Call ( q1qvm , GAME_EDICT_THINK , 0 , 0 , 0 ) ;
VM_Call ( q1qvm , GAME_CLIENT_THINK , host_client - > spectator , 0 , 0 , 0 ) ;
2008-05-25 22:23:43 +00:00
}
void Q1QVM_PostThink ( void )
{
2015-06-14 01:28:01 +00:00
VM_Call ( q1qvm , GAME_CLIENT_POSTTHINK , host_client - > spectator , 0 , 0 , 0 ) ;
2015-07-01 23:15:25 +00:00
if ( fofs . vw_index )
sv_player - > xv - > vw_index = ( ( float * ) sv_player - > v ) [ fofs . vw_index ] ;
2019-02-16 19:09:07 +00:00
if ( fofs . items2 )
sv_player - > xv - > items2 = ( ( float * ) sv_player - > v ) [ fofs . items2 ] ;
if ( fofs . trackent )
host_client - > viewent = ( ( int * ) sv_player - > v ) [ fofs . trackent ] ;
2019-03-23 07:06:37 +00:00
if ( fofs . hideplayers )
host_client - > hideplayers = ( ( int * ) sv_player - > v ) [ fofs . hideplayers ] ;
if ( fofs . hideentity )
host_client - > hideentity = ( ( int * ) sv_player - > v ) [ fofs . hideentity ] ;
2008-05-25 22:23:43 +00:00
}
2017-10-12 12:02:25 +00:00
void Q1QVM_StartFrame ( qboolean botsarespecialsnowflakes )
2008-05-25 22:23:43 +00:00
{
2017-10-12 12:02:25 +00:00
if ( botsarespecialsnowflakes & & qvm_api_version < 15 )
return ; //this stupidity brought to you with api 15!
VM_Call ( q1qvm , GAME_START_FRAME , ( qintptr_t ) ( sv . time * 1000 ) , botsarespecialsnowflakes , 0 , 0 ) ;
2008-05-25 22:23:43 +00:00
}
2021-11-19 19:40:25 +00:00
void Q1QVM_SendEntity ( quint64_t sendflags )
{
VM_Call ( q1qvm , GAME_EDICT_CSQCSEND , sendflags , 0 , 0 , 0 ) ;
}
2008-05-25 22:23:43 +00:00
void Q1QVM_Blocked ( void )
{
2015-06-14 01:28:01 +00:00
VM_Call ( q1qvm , GAME_EDICT_BLOCKED , 0 , 0 , 0 ) ;
2008-05-25 22:23:43 +00:00
}
void Q1QVM_SetNewParms ( void )
{
2015-06-14 01:28:01 +00:00
VM_Call ( q1qvm , GAME_SETNEWPARMS , 0 , 0 , 0 ) ;
2008-05-25 22:23:43 +00:00
}
void Q1QVM_SetChangeParms ( void )
{
2015-06-14 01:28:01 +00:00
VM_Call ( q1qvm , GAME_SETCHANGEPARMS , 0 , 0 , 0 ) ;
2008-05-25 22:23:43 +00:00
}
2015-06-20 14:22:06 +00:00
qboolean Q1QVM_ClientCommand ( void )
2008-05-25 22:23:43 +00:00
{
2015-06-20 14:22:06 +00:00
return VM_Call ( q1qvm , GAME_CLIENT_COMMAND , 0 , 0 , 0 ) ;
2008-05-25 22:23:43 +00:00
}
2009-07-14 23:42:54 +00:00
void Q1QVM_GameCodePausedTic ( float pausedduration )
{
2015-06-14 01:28:01 +00:00
VM_Call ( q1qvm , GAME_PAUSED_TIC , ( qintptr_t ) ( pausedduration * 1000 ) , 0 , 0 , 0 ) ;
2009-07-14 23:42:54 +00:00
}
2008-05-25 22:23:43 +00:00
void Q1QVM_DropClient ( client_t * cl )
{
2009-11-17 00:15:44 +00:00
if ( cl - > name )
Q_strncpyz ( cl - > namebuf , cl - > name , sizeof ( cl - > namebuf ) ) ;
2008-05-25 22:23:43 +00:00
pr_global_struct - > self = EDICT_TO_PROG ( svprogfuncs , cl - > edict ) ;
2015-06-14 01:28:01 +00:00
VM_Call ( q1qvm , GAME_CLIENT_DISCONNECT , 0 , 0 , 0 ) ;
2009-11-17 00:15:44 +00:00
cl - > name = cl - > namebuf ;
2008-05-25 22:23:43 +00:00
}
void Q1QVM_ChainMoved ( void )
{
}
void Q1QVM_EndFrame ( void )
{
}
# endif