This repository has been archived on 2022-06-27. You can view files and clone it, but cannot push or open issues or pull requests.
Xash3DArchive/engine/progsvm.h

572 lines
17 KiB
C

/*
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.
*/
/*
This is a try to make the vm more generic, it is mainly based on the progs.h file.
For the license refer to progs.h.
Generic means, less as possible hard-coded links with the other parts of the engine.
This means no edict_engineprivate struct usage, etc.
The code uses void pointers instead.
*/
#ifndef PROGSVM_H
#define PROGSVM_H
#include "sv_edict.h" // server progs
#include "cl_edict.h" // client progs
#include "ui_edict.h" // uimenu progs
typedef struct prvm_stack_s
{
int s;
mfunction_t *f;
} prvm_stack_t;
// virtual typedef
typedef union prvm_eval_s
{
int edict;
int _int;
float _float;
float vector[3];
func_t function;
string_t string;
} prvm_eval_t;
typedef struct edict_state_s
{
bool free;
float freetime;
} vm_edict_t;
struct edict_s
{
// engine-private fields (stored in dynamically resized array)
union
{
vm_edict_t *ed; // vm edict state
void *vp; // generic edict
sv_edict_t *sv; // sv edict state
ui_edict_t *ui; // ui edict state
} priv;
// QuakeC prog fields (stored in dynamically resized array)
union
{
void *vp; // generic entvars
sv_entvars_t *sv; // server entvars
ui_entvars_t *ui; // uimenu entvars
} progs;
};
#define PRVM_GETEDICTFIELDVALUE(ed, fieldoffset) (fieldoffset ? (prvm_eval_t *)((unsigned char *)ed->progs.vp + fieldoffset) : NULL)
#define PRVM_GETGLOBALFIELDVALUE(fieldoffset) (fieldoffset ? (prvm_eval_t *)((unsigned char *)prog->globals.gp + fieldoffset) : NULL)
#define PRVM_FE_CLASSNAME 8
#define PRVM_FE_CHAIN 4
#define PRVM_OP_STATE 1
#define PRVM_MAX_STACK_DEPTH 1024
#define PRVM_LOCALSTACK_SIZE 16384
#define PRVM_MAX_OPENFILES 256
#define PRVM_MAX_OPENSEARCHES 128
typedef void (*prvm_builtin_t) (void);
// [INIT] variables flagged with this token can be initialized by 'you'
// NOTE: external code has to create and free the mempools but everything else is done by prvm !
typedef struct prvm_prog_s
{
dprograms_t *progs;
mfunction_t *functions;
char *strings;
int stringssize;
ddef_t *fielddefs;
ddef_t *globaldefs;
dstatement_t *statements;
int *linenums; // debug versions only
type_t *types;
int edict_size; // in bytes
int edictareasize; // in bytes (for bound checking)
int pev_save; // used by PRVM_PUSH_GLOBALS\PRVM_POP_GLOBALS
int other_save; // used by PRVM_PUSH_GLOBALS\PRVM_POP_GLOBALS
int *statement_linenums;// NULL if not available
double *statement_profile; // only incremented if prvm_statementprofiling is on
union
{
float *gp;
sv_globalvars_t *sv;
ui_globalvars_t *ui;
} globals;
int maxknownstrings;
int numknownstrings;
// this is updated whenever a string is removed or added
// (simple optimization of the free string search)
int firstfreeknownstring;
const char **knownstrings;
byte *knownstrings_freeable;
const char ***stringshash;
// all memory allocations related to this vm_prog (code, edicts, strings)
byte *progs_mempool; // [INIT]
prvm_builtin_t *builtins; // [INIT]
int numbuiltins; // [INIT]
int argc;
int trace;
mfunction_t *xfunction;
int xstatement;
// stacktrace writes into stack[MAX_STACK_DEPTH]
// thus increase the array, so depth wont be overwritten
prvm_stack_t stack[PRVM_MAX_STACK_DEPTH + 1];
int depth;
int localstack[PRVM_LOCALSTACK_SIZE];
int localstack_used;
word filecrc;
int intsize;
//============================================================================
// until this point everything also exists (with the pr_ prefix) in the old vm
vfile_t *openfiles[PRVM_MAX_OPENFILES];
search_t *opensearches[PRVM_MAX_OPENSEARCHES];
// copies of some vars that were former read from sv
int num_edicts;
// number of edicts for which space has been (should be) allocated
int max_edicts; // [INIT]
// used instead of the constant MAX_EDICTS
int limit_edicts; // [INIT]
// number of reserved edicts (allocated from 1)
int reserved_edicts; // [INIT]
edict_t *edicts;
void *edictsfields;
void *edictprivate;
// size of the engine private struct
int edictprivate_size; // [INIT]
// has to be updated every frame - so the vm time is up-to-date
// AK changed so time will point to the time field (if there is one) else it points to _time
// actually should be double, but qc doesnt support it
float *time;
float _time;
// allow writing to world entity fields, this is set by server init and
// cleared before first server frame
bool protect_world;
// name of the prog, e.g. "Server", "Client" or "Menu" (used for text output)
char *name; // [INIT]
// flag - used to store general flags like PRVM_GE_PEV, etc.
int flag;
char *extensionstring; // [INIT]
bool loadintoworld; // [INIT]
// used to indicate whether a prog is loaded
bool loaded;
//============================================================================
ddef_t *pev; // if pev != 0 then there is a global pev
//============================================================================
// function pointers
void (*begin_increase_edicts)(void); // [INIT] used by PRVM_MEM_Increase_Edicts
void (*end_increase_edicts)(void); // [INIT]
void (*init_edict)(edict_t *edict); // [INIT] used by PRVM_ED_ClearEdict
void (*free_edict)(edict_t *ed); // [INIT] used by PRVM_ED_Free
void (*count_edicts)(void); // [INIT] used by PRVM_ED_Count_f
bool (*load_edict)(edict_t *ent); // [INIT] used by PRVM_ED_LoadFromFile
void (*init_cmd)(void); // [INIT] used by PRVM_InitProg
void (*reset_cmd)(void); // [INIT] used by PRVM_ResetProg
void (*error_cmd)(const char *format, ...); // [INIT]
} prvm_prog_t;
extern prvm_prog_t *prog;
enum
{
PRVM_SERVERPROG = 0,
PRVM_CLIENTPROG,
PRVM_MENUPROG,
PRVM_MAXPROGS, // must be last
};
extern prvm_prog_t prvm_prog_list[PRVM_MAXPROGS];
//============================================================================
// prvm_cmds part
extern prvm_builtin_t vm_sv_builtins[];
extern prvm_builtin_t vm_cl_builtins[];
extern prvm_builtin_t vm_m_builtins[];
extern const int vm_sv_numbuiltins;
extern const int vm_cl_numbuiltins;
extern const int vm_m_numbuiltins;
extern char * vm_sv_extensions;
extern char * vm_cl_extensions;
extern char * vm_m_extensions;
void VM_SV_Cmd_Init(void);
void VM_SV_Cmd_Reset(void);
void VM_CL_Cmd_Init(void);
void VM_CL_Cmd_Reset(void);
void VM_M_Cmd_Init(void);
void VM_M_Cmd_Reset(void);
void VM_Cmd_Init(void);
void VM_Cmd_Reset(void);
//============================================================================
void PRVM_Init (void);
void PRVM_ExecuteProgram (func_t fnum, const char *errormessage);
#define PRVM_Alloc(buffersize) _PRVM_Alloc(buffersize, __FILE__, __LINE__)
#define PRVM_Free(buffer) _PRVM_Free(buffer, __FILE__, __LINE__)
#define PRVM_FreeAll() _PRVM_FreeAll(__FILE__, __LINE__)
void *_PRVM_Alloc (size_t buffersize, const char *filename, int fileline);
void _PRVM_Free (void *buffer, const char *filename, int fileline);
void _PRVM_FreeAll (const char *filename, int fileline);
void PRVM_Profile (int maxfunctions, int mininstructions);
void PRVM_Profile_f (void);
void PRVM_PrintFunction_f (void);
void PRVM_PrintState(void);
void PRVM_CrashAll (void);
void PRVM_Crash (void);
int PRVM_ED_FindFieldOffset(const char *field);
int PRVM_ED_FindGlobalOffset(const char *global);
ddef_t *PRVM_ED_FindField (const char *name);
ddef_t *PRVM_ED_FindGlobal (const char *name);
mfunction_t *PRVM_ED_FindFunction (const char *name);
func_t PRVM_ED_FindFunctionOffset(const char *function);
void PRVM_MEM_IncreaseEdicts(void);
edict_t *PRVM_ED_Alloc (void);
void PRVM_ED_Free (edict_t *ed);
void PRVM_ED_ClearEdict (edict_t *e);
void PRVM_PrintFunctionStatements (const char *name);
void PRVM_ED_Print(edict_t *ed);
void PRVM_ED_Write (vfile_t *f, edict_t *ed);
char *PRVM_ED_Info(edict_t *ent);
const char *PRVM_ED_ParseEdict (const char *data, edict_t *ent);
void PRVM_ED_WriteGlobals (vfile_t *f);
void PRVM_ED_ParseGlobals (const char *data);
void PRVM_ED_LoadFromFile (const char *data);
edict_t *PRVM_EDICT_NUM_ERROR(int n, char *filename, int fileline);
#define PRVM_EDICT_NUM(n) (((n) >= 0 && (n) < prog->max_edicts) ? prog->edicts + (n) : PRVM_EDICT_NUM_ERROR(n, __FILE__, __LINE__))
#define PRVM_EDICT_NUM_UNSIGNED(n) (((n) < prog->max_edicts) ? prog->edicts + (n) : PRVM_EDICT_NUM_ERROR(n, __FILE__, __LINE__))
#define PRVM_NUM_FOR_EDICT(e) ((int)((edict_t *)(e) - prog->edicts))
#define PRVM_NEXT_EDICT(e) ((e) + 1)
#define PRVM_EDICT_TO_PROG(e) (PRVM_NUM_FOR_EDICT(e))
#define PRVM_PROG_TO_EDICT(n) (PRVM_EDICT_NUM(n))
#define PRVM_PUSH_GLOBALS prog->pev_save = prog->globals.sv->pev, prog->other_save = prog->globals.sv->other
#define PRVM_POP_GLOBALS prog->globals.sv->pev = prog->pev_save, prog->globals.sv->other = prog->other_save
#define PRVM_ED_POINTER(p) (prvm_eval_t *)((byte *)prog->edictsfields + p->_int)
#define PRVM_EM_POINTER(p) (prvm_eval_t *)((byte *)prog->edictsfields + (p))
#define PRVM_EV_POINTER(p) (prvm_eval_t *)(((byte *)prog->edicts) + p->_int) // this is correct ???
#define PRVM_CHECK_PTR(p, size) if(prvm_boundscheck->value && (p->_int < 0 || p->_int + size > prog->edictareasize))\
{\
prog->xfunction->profile += (st - startst);\
prog->xstatement = st - prog->statements;\
PRVM_ERROR("%s attempted to write to an out of bounds edict (%i)", PRVM_NAME, p->_int);\
return;\
}
#define PRVM_CHECK_INFINITE() if (++jumpcount == 10000000)\
{\
prog->xstatement = st - prog->statements;\
PRVM_Profile(1<<30, 1000000);\
PRVM_ERROR("runaway loop counter hit limit of %d jumps\n", jumpcount, PRVM_NAME);\
}
//============================================================================
// get arguments from progs
#define PRVM_G_FLOAT(o) (prog->globals.gp[o])
#define PRVM_G_INT(o) (*(int *)&prog->globals.gp[o])
#define PRVM_G_EDICT(o) (PRVM_PROG_TO_EDICT(*(int *)&prog->globals.gp[o]))
#define PRVM_G_EDICTNUM(o) PRVM_NUM_FOR_EDICT(PRVM_G_EDICT(o))
#define PRVM_G_VECTOR(o) (&prog->globals.gp[o])
#define PRVM_G_STRING(o) (PRVM_GetString(*(string_t *)&prog->globals.gp[o]))
#define PRVM_G_FUNCTION(o) (*(func_t *)&prog->globals.gp[o])
// FIXME: make these go away?
#define PRVM_E_FLOAT(e,o) (((float*)e->progs.vp)[o])
#define PRVM_E_INT(e,o) (((int*)e->progs.vp)[o])
//#define PRVM_E_VECTOR(e,o) (&((float*)e->progs.vp)[o])
#define PRVM_E_STRING(e,o) (PRVM_GetString(*(string_t *)&((float*)e->progs.vp)[o]))
extern int prvm_type_size[8]; // for consistency : I think a goal of this sub-project is to
// make the new vm mostly independent from the old one, thus if it's necessary, I copy everything
void PRVM_Init_Exec(void);
void PRVM_ED_PrintEdicts_f (void);
void PRVM_ED_PrintNum (int ent);
const char *PRVM_GetString(int num);
int PRVM_SetEngineString(const char *s);
int PRVM_AllocString(size_t bufferlength, char **pointer);
void PRVM_FreeString(int num);
//============================================================================
#define PRVM_Begin
#define PRVM_End prog = 0
#define PRVM_NAME (prog->name ? prog->name : "unnamed.dat")
// helper macro to make function pointer calls easier
#define PRVM_GCALL(func) if(prog->func) prog->func
#define PRVM_ERROR if(prog) prog->error_cmd
// other prog handling functions
bool PRVM_SetProgFromString(const char *str);
void PRVM_SetProg(int prognr);
/*
Initializing a vm:
Call InitProg with the num
Set up the fields marked with [INIT] in the prog struct
Load a program with LoadProgs
*/
void PRVM_InitProg(int prognr);
// LoadProgs expects to be called right after InitProg
void PRVM_LoadProgs (const char *filename, int numrequiredfunc, char **required_func, int numrequiredfields, fields_t *required_field);
void PRVM_ResetProg(void);
bool PRVM_ProgLoaded(int prognr);
int PRVM_GetProgNr(void);
void VM_Warning(const char *fmt, ...);
void VM_Error(const char *fmt, ...);
// TODO: fill in the params
//void PRVM_Create();
//============================================================================
// nice helper macros
#ifndef VM_NOPARMCHECK
#define VM_SAFEPARMCOUNT(p,f) if(prog->argc != p) PRVM_ERROR(#f " wrong parameter count (" #p " expected ) !")
#else
#define VM_SAFEPARMCOUNT(p,f)
#endif
#define VM_RETURN_EDICT(e) (((int *)prog->globals.gp)[OFS_RETURN] = PRVM_EDICT_TO_PROG(e))
#define e10 NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL
#define e100 e10,e10,e10,e10,e10,e10,e10,e10,e10,e10
#define e1000 e100,e100,e100,e100,e100,e100,e100,e100,e100,e100
#define VM_STRINGTEMP_BUFFERS 16
#define VM_STRINGTEMP_LENGTH MAX_INPUTLINE
// builtins and other general functions
char *VM_GetTempString(void);
void VM_CheckEmptyString (const char *s);
void VM_VarString(int first, char *out, int outlength);
void VM_checkextension (void);
void VM_error (void);
void VM_objerror (void);
void VM_print (void);
void VM_bprint (void);
void VM_sprint (void);
void VM_centerprint(void);
void VM_normalize (void);
void VM_veclength (void);
void VM_vectoyaw (void);
void VM_vectoangles (void);
void VM_random_long (void);
void VM_random_float (void);
void VM_localsound(void);
void VM_break (void);
void VM_localcmd (void);
void VM_cvar (void);
void VM_cvar_string(void);
void VM_cvar_set (void);
void VM_wprint (void);
void VM_ftoa (void);
void VM_fabs (void);
void VM_vtoa (void);
void VM_atov (void);
void VM_etos (void);
void VM_atof(void);
void VM_itof(void);
void VM_ftoe(void);
void VM_create (void);
void VM_remove (void);
void VM_find (void);
void VM_findfloat (void);
void VM_findchain (void);
void VM_findchainfloat (void);
void VM_findflags (void);
void VM_findchainflags (void);
void VM_precache_file (void);
void VM_precache_error (void);
void VM_precache_sound (void);
void VM_coredump (void);
void VM_stackdump (void);
void VM_crash(void); // REMOVE IT
void VM_traceon (void);
void VM_traceoff (void);
void VM_eprint (void);
void VM_rint (void);
void VM_floor (void);
void VM_ceil (void);
void VM_nextent (void);
void VM_changelevel (void);
void VM_sin (void);
void VM_cos (void);
void VM_sqrt (void);
void VM_randomvec (void);
void VM_registercvar (void);
void VM_min (void);
void VM_max (void);
void VM_bound (void);
void VM_pow (void);
void VM_copyentity (void);
void VM_Files_Init(void);
void VM_Files_CloseAll(void);
void VM_fopen(void);
void VM_fclose(void);
void VM_fgets(void);
void VM_fputs(void);
vfile_t *VM_GetFileHandle( int index );
void VM_strlen(void);
void VM_strcat(void);
void VM_substring(void);
void VM_stov(void);
void VM_allocstring(void);
void VM_freestring(void);
void VM_servercmd (void);
void VM_clientcmd (void);
void VM_tokenize (void);
void VM_argv (void);
void VM_isserver(void);
void VM_clientcount(void);
void VM_clientstate(void);
void VM_getmousepos(void);
void VM_gettime(void);
void VM_loadfromdata(void);
void VM_parseentitydata(void);
void VM_loadfromfile(void);
void VM_modulo(void);
void VM_search_begin(void);
void VM_search_end(void);
void VM_search_getsize(void);
void VM_search_getfilename(void);
void VM_chr(void);
void VM_iscachedpic(void);
void VM_precache_pic(void);
void VM_drawcharacter(void);
void VM_drawstring(void);
void VM_drawpic(void);
void VM_drawfill(void);
void VM_drawsetcliparea(void);
void VM_drawresetcliparea(void);
void VM_getimagesize(void);
void VM_vectorvectors (void);
void VM_makevectors (void);
void VM_makevectors2 (void);
void VM_keynumtostring (void);
void VM_stringtokeynum (void);
void VM_cin_open( void );
void VM_cin_close( void );
void VM_cin_getstate( void );
void VM_cin_restart( void );
void VM_R_PolygonBegin (void);
void VM_R_PolygonVertex (void);
void VM_R_PolygonEnd (void);
void VM_bitshift (void);
void VM_altstr_count( void );
void VM_altstr_prepare( void );
void VM_altstr_get( void );
void VM_altstr_set( void );
void VM_altstr_ins(void);
void VM_buf_create(void);
void VM_buf_del (void);
void VM_buf_getsize (void);
void VM_buf_copy (void);
void VM_buf_sort (void);
void VM_buf_implode (void);
void VM_bufstr_get (void);
void VM_bufstr_set (void);
void VM_bufstr_add (void);
void VM_bufstr_free (void);
void VM_Cmd_Init(void);
void VM_Cmd_Reset(void);
#endif//PROGSVM_H