diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index a5c72a51..bd148975 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -44,25 +44,25 @@ cvar_t rcon_address = SCVARF("rcon_address", "", CVAR_NOUNSAFEEXPAND); cvar_t cl_timeout = SCVAR("cl_timeout", "60"); -cvar_t cl_shownet = SCVAR("cl_shownet","0"); // can be 0, 1, or 2 +cvar_t cl_shownet = CVAR("cl_shownet","0", "Debugging var. 0 shows nothing. 1 shows incoming packet sizes. 2 shows individual messages. 3 shows entities too."); // can be 0, 1, or 2 cvar_t cl_pure = CVARD("cl_pure", "0", "If enabled, the filesystem will be restricted to allow only the content of the current server."); cvar_t cl_sbar = CVARFC("cl_sbar", "0", CVAR_ARCHIVE, CL_Sbar_Callback); cvar_t cl_hudswap = CVARF("cl_hudswap", "0", CVAR_ARCHIVE); cvar_t cl_maxfps = CVARF("cl_maxfps", "500", CVAR_ARCHIVE); -cvar_t cl_idlefps = CVARF("cl_idlefps", "0", CVAR_ARCHIVE); -cvar_t cl_yieldcpu = CVARF("cl_yieldcpu", "0", CVAR_ARCHIVE); +cvar_t cl_idlefps = CVARF("cl_idlefps", "0", CVAR_ARCHIVE, "This is the maximum framerate to attain while idle/paused."); +cvar_t cl_yieldcpu = CVARFD("cl_yieldcpu", "0", CVAR_ARCHIVE, "Attempt to yield between frames. This can resolve issues with certain drivers and background software, but can mean less consistant frame times. Will reduce power consumption/heat generation so should be set on laptops or similar (over-hot/battery powered) devices."); cvar_t cl_nopext = CVARF("cl_nopext", "0", CVAR_ARCHIVE); cvar_t cl_pext_mask = CVAR("cl_pext_mask", "0xffffffff"); cvar_t cl_nolerp = CVARD("cl_nolerp", "0", "Disables interpolation. If set, missiles/monsters will be smoother, but they may be more laggy. Does not affect players. A value of 2 means 'interpolate only in single-player/coop'."); cvar_t cl_nolerp_netquake = CVARD("cl_nolerp_netquake", "0", "Disables interpolation when connected to an NQ server. Does affect players, even the local player. You probably don't want to set this."); cvar_t hud_tracking_show = CVAR("hud_tracking_show", "1"); -cvar_t cl_defaultport = CVARAF("cl_defaultport", STRINGIFY(PORT_QWSERVER), "port", 0); +cvar_t cl_defaultport = CVARAFD("cl_defaultport", STRINGIFY(PORT_QWSERVER), "port", 0, "The default port to connect to servers.\nQW: "STRINGIFY(PORT_QWSERVER)", NQ: "STRINGIFY(PORT_NQSERVER)", Q2: "STRINGIFY(PORT_Q2SERVER)"."); cvar_t cfg_save_name = CVARF("cfg_save_name", "fte", CVAR_ARCHIVE); -cvar_t cl_splitscreen = CVAR("cl_splitscreen", "0"); +cvar_t cl_splitscreen = CVARD("cl_splitscreen", "0", "Enables splitscreen support. See also: allow_splitscreen, in_rawinput*, the \"p\" command."); cvar_t lookspring = CVARF("lookspring","0", CVAR_ARCHIVE); cvar_t lookstrafe = CVARF("lookstrafe","0", CVAR_ARCHIVE); @@ -116,7 +116,7 @@ cvar_t noaim = CVARF("noaim", "", CVAR_ARCHIVE | CVAR_USERINFO); cvar_t msg = CVARF("msg", "1", CVAR_ARCHIVE | CVAR_USERINFO); cvar_t b_switch = CVARF("b_switch", "", CVAR_ARCHIVE | CVAR_USERINFO); cvar_t w_switch = CVARF("w_switch", "", CVAR_ARCHIVE | CVAR_USERINFO); -cvar_t cl_nofake = CVAR("cl_nofake", "2"); +cvar_t cl_nofake = CVARD("cl_nofake", "2", "value 0: permits \\r chars in chat messages\nvalue 1: blocks all \\r chars\nvalue 2: allows \\r chars, but only from teammates"); cvar_t cl_chatsound = CVAR("cl_chatsound","1"); cvar_t cl_enemychatsound = CVAR("cl_enemychatsound", "misc/talk.wav"); cvar_t cl_teamchatsound = CVAR("cl_teamchatsound", "misc/talk.wav"); @@ -152,7 +152,7 @@ cvar_t cl_countpendingpl = SCVAR("cl_countpendingpl", "0"); cvar_t cl_standardchat = SCVARF("cl_standardchat", "0", CVAR_ARCHIVE); cvar_t msg_filter = SCVAR("msg_filter", "0"); //0 for neither, 1 for mm1, 2 for mm2, 3 for both cvar_t cl_standardmsg = SCVARF("cl_standardmsg", "0", CVAR_ARCHIVE); -cvar_t cl_parsewhitetext = SCVAR("cl_parsewhitetext", "1"); +cvar_t cl_parsewhitetext = CVARD("cl_parsewhitetext", "1", "When parsing chat messages, enable support for messages like: red{white}red"); cvar_t cl_dlemptyterminate = SCVAR("cl_dlemptyterminate", "1"); @@ -3770,6 +3770,8 @@ void Host_Init (quakeparms_t *parms) int i; int qrc, hrc, def; #endif + extern cvar_t com_parseutf8; + com_parseutf8.ival = 1; COM_InitArgv (parms->argc, parms->argv); diff --git a/engine/client/console.c b/engine/client/console.c index 883455e3..c64eca00 100644 --- a/engine/client/console.c +++ b/engine/client/console.c @@ -562,7 +562,6 @@ void Con_PrintCon (console_t *con, char *txt) conchar_t expanded[4096]; conchar_t *c; conline_t *oc; - static int cr; COM_ParseFunString(CON_WHITEMASK, txt, expanded, sizeof(expanded), false); @@ -574,10 +573,10 @@ void Con_PrintCon (console_t *con, char *txt) switch (*c & (CON_CHARMASK)) { case '\r': - cr = true; + con->cr = true; break; case '\n': - cr = false; + con->cr = false; while (con->linecount >= con_maxlines.ival) { if (con->oldest == con->current) @@ -616,10 +615,10 @@ void Con_PrintCon (console_t *con, char *txt) con->display = con->current; break; default: - if (cr) + if (con->cr) { con->current->length = 0; - cr = false; + con->cr = false; } if (selstartline == con->current) @@ -798,9 +797,11 @@ DRAWING Con_DrawInput The input line scrolls horizontally if typing goes beyond the right edge +y is the bottom of the input +return value is the top of the region ================ */ -void Con_DrawInput (int left, int right, int y) +int Con_DrawInput (int left, int right, int y) { #ifdef _WIN32 extern qboolean ActiveApp; @@ -808,9 +809,9 @@ void Con_DrawInput (int left, int right, int y) int i; int lhs, rhs; int p; - unsigned char *text, *fname; + unsigned char *text, *fname = NULL; extern int con_commandmatch; - conchar_t maskedtext[MAXCMDLINE]; + conchar_t maskedtext[2048]; conchar_t *endmtext; conchar_t *cursor; conchar_t *cchar; @@ -818,11 +819,13 @@ void Con_DrawInput (int left, int right, int y) int x; + y -= Font_CharHeight(); + if (key_dest != key_console && con_current->vislines != vid.height) - return; // don't draw anything (always draw if not active) + return y; // don't draw anything (always draw if not active) if (!con_current->linebuffered) - return; //fixme: draw any unfinished lines of the current console instead. + return y; //fixme: draw any unfinished lines of the current console instead. text = key_lines[edit_line]; @@ -833,9 +836,9 @@ void Con_DrawInput (int left, int right, int y) i = text[key_linepos]; text[key_linepos] = 0; - cursor = COM_ParseFunString(CON_WHITEMASK, text, maskedtext, sizeof(maskedtext)-1*sizeof(conchar_t), true); + cursor = COM_ParseFunString(CON_WHITEMASK, text, maskedtext, sizeof(maskedtext) - sizeof(maskedtext[0]), true); text[key_linepos] = i; - endmtext = COM_ParseFunString(CON_WHITEMASK, text, maskedtext, sizeof(maskedtext)-1*sizeof(conchar_t), true); + endmtext = COM_ParseFunString(CON_WHITEMASK, text, maskedtext, sizeof(maskedtext) - sizeof(maskedtext[0]), true); endmtext[1] = 0; @@ -859,9 +862,11 @@ void Con_DrawInput (int left, int right, int y) fname = Cmd_CompleteCommand(text+cmdstart, true, true, con_commandmatch); if (fname) //we can compleate it to: { - for (p = key_linepos-cmdstart; fname[p]>' '; p++) + for (p = min(strlen(fname), key_linepos-cmdstart); fname[p]>' '; p++) maskedtext[p+cmdstart] = (unsigned int)fname[p] | (COLOR_GREEN<description) + desc = var->description; + } + if (!desc) + { + desc = Cmd_Describe(fname); + } + + if (desc) + { + int lines; + conchar_t *starts[8]; + conchar_t *ends[8]; + conchar_t *end; + end = maskedtext; + + end = COM_ParseFunString((COLOR_YELLOW<0) + { + rhs = left; + y -= Font_CharHeight(); + for (cchar = starts[lines]; cchar < ends[lines]; cchar++) + { + rhs = Font_DrawChar(rhs, y, *cchar); + } + } + } + } + + /*just above that, we have the tab completion list*/ + if (con_commandmatch && con_displaypossibilities.value) + { + int lines; + conchar_t *starts[32]; + conchar_t *ends[32]; + conchar_t *end; + char *cmd; + int cmdstart; + cmdstart = text[1] == '/'?2:1; + end = maskedtext; + + for (i = 1; ; i++) + { + cmd = Cmd_CompleteCommand (text+cmdstart, true, true, i); + if (!cmd) + break; + + end = COM_ParseFunString((COLOR_GREEN<0) + { + rhs = left; + y -= Font_CharHeight(); + for (cchar = starts[lines]; cchar < ends[lines]; cchar++) + { + rhs = Font_DrawChar(rhs, y, *cchar); + } + } + } + + return y; } /* @@ -1304,8 +1384,7 @@ void Con_DrawConsole (int lines, qboolean noback) y -= Font_CharHeight(); haveprogress = Con_DrawProgress(x, ex - x, y) != y; - y -= Font_CharHeight(); - Con_DrawInput (x, ex - x, y); + y = Con_DrawInput (x, ex - x, y); if (selactive) { diff --git a/engine/client/in_win.c b/engine/client/in_win.c index cb42abd2..d7aab219 100644 --- a/engine/client/in_win.c +++ b/engine/client/in_win.c @@ -266,9 +266,9 @@ int rawkbdcount; RAWINPUT *raw; int ribuffersize; -cvar_t in_rawinput = SCVAR("in_rawinput", "0"); -cvar_t in_rawinput_keyboard = SCVAR("in_rawinput_keyboard", "0"); -cvar_t in_rawinput_rdp = SCVAR("in_rawinput_rdp", "0"); +cvar_t in_rawinput = CVARD("in_rawinput", "0", "Enables rawinput support for mice in XP onwards. Rawinput permits independant device identification (ie: splitscreen clients can each have their own mouse)"); +cvar_t in_rawinput_keyboard = SCVAR("in_rawinput_keyboard", "0", "Enables rawinput support for keyboards in XP onwards as well as just mice. Requires in_rawinput to be set."); +cvar_t in_rawinput_rdp = CVARD("in_rawinput_rdp", "0", "Activate Remote Desktop Protocol devices too."); void IN_RawInput_MouseDeRegister(void); int IN_RawInput_MouseRegister(void); diff --git a/engine/client/keys.c b/engine/client/keys.c index 086818d9..cfb7b342 100644 --- a/engine/client/keys.c +++ b/engine/client/keys.c @@ -251,7 +251,7 @@ qboolean Cmd_IsCommand (char *line) int PaddedPrint (char *s, int x) { - Con_Printf ("%s\t", s); + Con_Printf ("^4%s\t", s); x+=strlen(s); return x; @@ -268,22 +268,6 @@ void CompleteCommand (qboolean force) if (*s == '\\' || *s == '/') s++; - if (!force && con_displaypossibilities.value) - { - int x=0; - for (i = 1; ; i++) - { - cmd = Cmd_CompleteCommand (s, true, true, i); - if (!cmd) - break; - if (i == 1) - Con_Printf("---------\n"); - x = PaddedPrint(cmd, x); - } - if (i != 1) - Con_Printf("\n"); - } - cmd = Cmd_CompleteCommand (s, true, true, 2); if (!cmd || force) { @@ -311,6 +295,8 @@ void CompleteCommand (qboolean force) } } key_lines[edit_line][key_linepos] = 0; + if (!con_commandmatch) + con_commandmatch = 1; return; } } @@ -330,6 +316,8 @@ void CompleteCommand (qboolean force) key_lines[edit_line][key_linepos] = 0; + if (!con_commandmatch) + con_commandmatch = 1; return; //don't alter con_commandmatch if we compleated a tiny bit more } } @@ -533,7 +521,7 @@ void Key_Console (unsigned int unicode, int key) CompleteCommand (false); return; } - if (key != K_SHIFT) + if (key != K_SHIFT && con_commandmatch) con_commandmatch=1; if (key == K_LEFTARROW) diff --git a/engine/client/p_script.c b/engine/client/p_script.c index 0812db71..5aa14ed1 100644 --- a/engine/client/p_script.c +++ b/engine/client/p_script.c @@ -1843,6 +1843,11 @@ static void P_ImportEffectInfo_f(void) ptype->looks.type = PT_BEAM; ptype->looks.blendmode = BM_ADD; } +// else if (!strcmp(arg[1], "snow")) +// { +// ptype->looks.type = PT_NORMAL; +// ptype->looks.blendmode = BM_BLEND; +// } else { Con_Printf("effectinfo type %s not supported\n", arg[1]); @@ -1963,6 +1968,8 @@ static void P_ImportEffectInfo_f(void) ; else if (!strcmp(arg[0], "rotate") && args == 2) ; + else if (!strcmp(arg[0], "rotate") && args == 4) + ; #endif else Con_Printf("Particle effect token not recognised, or invalid args: %s %s %s %s %s %s\n", arg[0], args<2?"":arg[1], args<3?"":arg[2], args<4?"":arg[3], args<5?"":arg[4], args<6?"":arg[5]); diff --git a/engine/client/pr_csqc.c b/engine/client/pr_csqc.c index d4b9c271..3212837a 100644 --- a/engine/client/pr_csqc.c +++ b/engine/client/pr_csqc.c @@ -4334,6 +4334,12 @@ static struct { {"skel_ragupdate", PF_skel_ragedit, 281},// (FTE_QC_RAGDOLL) {"skel_mmap", PF_skel_mmap, 282},// (FTE_QC_RAGDOLL) {"skel_set_bone_world", PF_skel_set_bone_world, 283}, + + {"memalloc", PF_memalloc, 384}, + {"memfree", PF_memfree, 385}, + {"memcpy", PF_memcpy, 386}, + {"memset", PF_memset, 387}, + //300 {"clearscene", PF_R_ClearScene, 300}, // #300 void() clearscene (EXT_CSQC) {"addentities", PF_R_AddEntityMask, 301}, // #301 void(float mask) addentities (EXT_CSQC) diff --git a/engine/client/r_surf.c b/engine/client/r_surf.c index ba0fd3ce..1a3f66f6 100644 --- a/engine/client/r_surf.c +++ b/engine/client/r_surf.c @@ -1756,6 +1756,8 @@ void Surf_SetupFrame(void) leaf = RMod_PointInLeaf (cl.worldmodel, r_origin); r_viewcluster = r_viewcluster2 = leaf->cluster; + r_viewcontents = 0;//leaf->contents; + // check above and below so crossing solid water doesn't draw wrong if (!leaf->contents) { // look down a bit @@ -1779,8 +1781,6 @@ void Surf_SetupFrame(void) (leaf->cluster != r_viewcluster2) ) r_viewcluster2 = leaf->cluster; } - - r_viewcontents = leaf->contents; } #endif else if (cl.worldmodel && cl.worldmodel->fromgame == fg_doom3) diff --git a/engine/client/renderer.c b/engine/client/renderer.c index d82aa284..2d5394f4 100644 --- a/engine/client/renderer.c +++ b/engine/client/renderer.c @@ -239,8 +239,11 @@ cvar_t gl_contrast = CVAR ("gl_contrast", "1"); cvar_t gl_detail = CVARF ("gl_detail", "0", CVAR_ARCHIVE); cvar_t gl_detailscale = CVAR ("gl_detailscale", "5"); -cvar_t gl_font = CVARF ("gl_font", "", - CVAR_RENDERERCALLBACK); +cvar_t gl_font = CVARFD ("gl_font", "", + CVAR_RENDERERCALLBACK, ("Specifies the font file to use. a value such as FONT:ALTFONT specifies an alternative font to be used when ^^a is used." + "When using TTF fonts, you will likely need to scale text to at least 150% - vid_conautoscale 1.5 will do this." + "TTF fonts may be loaded from your windows directory. \'gl_font cour\' loads eg: c:\\windows\\fonts\\cour.ttf." + )); cvar_t gl_lateswap = CVAR ("gl_lateswap", "0"); cvar_t gl_lerpimages = CVARF ("gl_lerpimages", "1", CVAR_ARCHIVE); //cvar_t gl_lightmapmode = SCVARF("gl_lightmapmode", "", diff --git a/engine/client/screen.h b/engine/client/screen.h index 373e69a7..5fb15da0 100644 --- a/engine/client/screen.h +++ b/engine/client/screen.h @@ -106,7 +106,7 @@ void Font_BeginScaledString(struct font_s *font, float vx, float vy, float *px, void Font_Transform(int vx, int vy, int *px, int *py); int Font_CharHeight(void); int Font_CharWidth(unsigned int charcode); -int Font_CharEndCoord(int x, unsigned int charcode); +int Font_CharEndCoord(struct font_s *font, int x, unsigned int charcode); int Font_DrawChar(int px, int py, unsigned int charcode); float Font_DrawScaleChar(float px, float py, float cw, float ch, unsigned int charcode); /*avoid using*/ void Font_EndString(struct font_s *font); diff --git a/engine/client/snd_dma.c b/engine/client/snd_dma.c index 980a3b33..132f6938 100644 --- a/engine/client/snd_dma.c +++ b/engine/client/snd_dma.c @@ -80,20 +80,20 @@ cvar_t snd_noextraupdate = CVARAF( "s_noextraupdate", "0", "snd_noextraupdate", 0); cvar_t snd_show = CVARAF( "s_show", "0", "snd_show", 0); -cvar_t snd_khz = CVARAF( "s_khz", "44", - "snd_khz", CVAR_ARCHIVE); +cvar_t snd_khz = CVARAFD( "s_khz", "44", + "snd_khz", CVAR_ARCHIVE, "Sound speed, in kilohertz. Common values are 11, 22, 44, 48."); cvar_t snd_inactive = CVARAFD( "s_inactive", "0", "snd_inactive", 0, - "Play sound while application is inactive (ex. tabbed out)." + "Play sound while application is inactive (ex. tabbed out). Needs a snd_restart if changed." ); //set if you want sound even when tabbed out. -cvar_t _snd_mixahead = CVARAF( "s_mixahead", "0.08", - "_snd_mixahead", CVAR_ARCHIVE); +cvar_t _snd_mixahead = CVARAFD( "s_mixahead", "0.08", + "_snd_mixahead", CVAR_ARCHIVE, "Specifies how many seconds to prebuffer audio. Lower values give less latency, but might result in crackling. Different hardware/drivers have different tolerances."); cvar_t snd_leftisright = CVARAF( "s_swapstereo", "0", "snd_leftisright", CVAR_ARCHIVE); cvar_t snd_eax = CVARAF( "s_eax", "0", "snd_eax", 0); -cvar_t snd_speakers = CVARAF( "s_numspeakers", "2", - "snd_numspeakers", 0); +cvar_t snd_speakers = CVARAFD( "s_numspeakers", "2", + "snd_numspeakers", 0, "Number of hardware audio channels to use. "DISTRIBUTION" supports up to 6."); cvar_t snd_buffersize = CVARAF( "s_buffersize", "0", "snd_buffersize", 0); cvar_t snd_samplebits = CVARAF( "s_bits", "16", @@ -109,8 +109,8 @@ cvar_t snd_linearresample = CVARAF( "s_linearresample", "1", cvar_t snd_linearresample_stream = CVARAF( "s_linearresample_stream", "0", "snd_linearresample_stream", 0); -cvar_t snd_usemultipledevices = CVARAF( "s_multipledevices", "0", - "snd_multipledevices", 0); +cvar_t snd_usemultipledevices = CVARAFD( "s_multipledevices", "0", + "snd_multipledevices", 0, "If enabled, all output sound devices in your computer will be initialised for playback, not just the default device."); cvar_t snd_driver = CVARAF( "s_driver", "", "snd_driver", 0); diff --git a/engine/common/cmd.c b/engine/common/cmd.c index b2006e14..90eb2d90 100644 --- a/engine/common/cmd.c +++ b/engine/common/cmd.c @@ -988,6 +988,7 @@ typedef struct cmd_function_s { struct cmd_function_s *next; char *name; + char *description; xcommand_t function; qbyte restriction; //restriction of admin level @@ -1679,6 +1680,23 @@ qboolean Cmd_Exists (char *cmd_name) return false; } +/* +============ +Cmd_Exists +============ +*/ +char *Cmd_Describe (char *cmd_name) +{ + cmd_function_t *cmd; + + for (cmd=cmd_functions ; cmd ; cmd=cmd->next) + { + if (!Q_strcmp (cmd_name,cmd->name)) + return cmd->description; + } + + return NULL; +} /* @@ -1734,8 +1752,13 @@ char *Cmd_CompleteCommand (char *partial, qboolean fullonly, qboolean caseinsens cvar_group_t *grp; cvar_t *cvar; + char *sp; - len = Q_strlen(partial); + sp = strchr(partial, ' '); + if (sp) + len = sp - partial; + else + len = Q_strlen(partial); if (!len) return NULL; @@ -1756,17 +1779,17 @@ char *Cmd_CompleteCommand (char *partial, qboolean fullonly, qboolean caseinsens if (caseinsens) { for (cmd=cmd_functions ; cmd ; cmd=cmd->next) - if (!Q_strncasecmp (partial,cmd->name, len)) + if (!Q_strncasecmp (partial,cmd->name, len) && (matchnum == -1 || !partial[len] || strlen(cmd->name) == len)) Cmd_CompleteCheck(cmd->name, &match); for (a=cmd_alias ; a ; a=a->next) - if (!Q_strncasecmp (partial, a->name, len)) + if (!Q_strncasecmp (partial, a->name, len) && (matchnum == -1 || !partial[len] || strlen(a->name) == len)) Cmd_CompleteCheck(a->name, &match); for (grp=cvar_groups ; grp ; grp=grp->next) for (cvar=grp->cvars ; cvar ; cvar=cvar->next) { - if (!Q_strncasecmp (partial,cvar->name, len)) + if (!Q_strncasecmp (partial,cvar->name, len) && (matchnum == -1 || !partial[len] || strlen(cvar->name) == len)) Cmd_CompleteCheck(cvar->name, &match); - if (cvar->name2 && !Q_strncasecmp (partial,cvar->name2, len)) + if (cvar->name2 && !Q_strncasecmp (partial,cvar->name2, len) && (matchnum == -1 || !partial[len] || strlen(cvar->name2) == len)) Cmd_CompleteCheck(cvar->name2, &match); } @@ -1774,17 +1797,17 @@ char *Cmd_CompleteCommand (char *partial, qboolean fullonly, qboolean caseinsens else { for (cmd=cmd_functions ; cmd ; cmd=cmd->next) - if (!Q_strncmp (partial,cmd->name, len)) + if (!Q_strncmp (partial,cmd->name, len) && (matchnum == -1 || !partial[len] || strlen(cmd->name) == len)) Cmd_CompleteCheck(cmd->name, &match); for (a=cmd_alias ; a ; a=a->next) - if (!Q_strncmp (partial, a->name, len)) + if (!Q_strncmp (partial, a->name, len) && (matchnum == -1 || !partial[len] || strlen(a->name) == len)) Cmd_CompleteCheck(a->name, &match); for (grp=cvar_groups ; grp ; grp=grp->next) for (cvar=grp->cvars ; cvar ; cvar=cvar->next) { - if (!Q_strncmp (partial,cvar->name, len)) + if (!Q_strncmp (partial,cvar->name, len) && (matchnum == -1 || !partial[len] || strlen(cvar->name) == len)) Cmd_CompleteCheck(cvar->name, &match); - if (cvar->name2 && !Q_strncmp (partial,cvar->name2, len)) + if (cvar->name2 && !Q_strncmp (partial,cvar->name2, len) && (matchnum == -1 || !partial[len] || strlen(cvar->name2) == len)) Cmd_CompleteCheck(cvar->name2, &match); } } diff --git a/engine/common/cmd.h b/engine/common/cmd.h index 237953b4..59fad05e 100644 --- a/engine/common/cmd.h +++ b/engine/common/cmd.h @@ -84,6 +84,8 @@ qboolean Cmd_AddCommand (char *cmd_name, xcommand_t function); qboolean Cmd_Exists (char *cmd_name); // used by the cvar code to check for cvar / command name overlap +char *Cmd_Describe (char *cmd_name); + char *Cmd_CompleteCommand (char *partial, qboolean fullonly, qboolean caseinsens, int matchnum); qboolean Cmd_IsCommand (char *line); // attempts to match a partial command for automatic command line completion diff --git a/engine/common/console.h b/engine/common/console.h index 203b3f89..dcf74b34 100644 --- a/engine/common/console.h +++ b/engine/common/console.h @@ -112,6 +112,7 @@ typedef struct console_s conline_t *oldest; conline_t *current; // line where next message will be printed int x; // offset in current line for next print + int cr; conline_t *display; // bottom of console displays this line int subline; int vislines; // pixel lines diff --git a/engine/common/cvar.h b/engine/common/cvar.h index 7ebc569a..b7d82316 100644 --- a/engine/common/cvar.h +++ b/engine/common/cvar.h @@ -84,7 +84,11 @@ typedef struct cvar_s bucket_t hbn1, hbn2; } cvar_t; +#ifdef MINIMAL +#define CVARAFDC(ConsoleName,Value,ConsoleName2,Flags,Description,Callback) {ConsoleName, Value, NULL, Flags, 0, 0, 0, ConsoleName2, Callback, NULL} +#else #define CVARAFDC(ConsoleName,Value,ConsoleName2,Flags,Description,Callback) {ConsoleName, Value, NULL, Flags, 0, 0, 0, ConsoleName2, Callback, Description} +#endif #define CVARAFD(ConsoleName,Value,ConsoleName2,Flags,Description)CVARAFDC(ConsoleName, Value, ConsoleName2, Flags, Description, NULL) #define CVARAFC(ConsoleName,Value,ConsoleName2,Flags,Callback) CVARAFC(ConsoleName, Value, ConsoleName2, Flags, NULL, Callback) #define CVARAF(ConsoleName,Value,ConsoleName2,Flags) CVARAFDC(ConsoleName, Value, ConsoleName2, Flags, NULL, NULL) diff --git a/engine/common/net_wins.c b/engine/common/net_wins.c index 87802764..68b703a2 100644 --- a/engine/common/net_wins.c +++ b/engine/common/net_wins.c @@ -186,12 +186,12 @@ void SockadrToNetadr (struct sockaddr_qstorage *s, netadr_t *a) a->port = ((struct sockaddr_ipx *)s)->sa_socket; break; #endif + default: + Con_Printf("SockadrToNetadr: bad socket family - %i", ((struct sockaddr*)s)->sa_family); case AF_UNSPEC: memset(a, 0, sizeof(*a)); a->type = NA_INVALID; break; - default: - Sys_Error("SockadrToNetadr: bad socket family"); } } @@ -293,7 +293,9 @@ qboolean NET_CompareBaseAdr (netadr_t a, netadr_t b) qboolean NET_AddressSmellsFunny(netadr_t a) { +#ifdef IPPROTO_IPV6 int i; +#endif //rejects certain blacklisted addresses switch(a.type) @@ -342,9 +344,11 @@ qboolean NET_AddressSmellsFunny(netadr_t a) char *NET_AdrToString (char *s, int len, netadr_t a) { char *rs = s; - qboolean doneblank; char *p; int i; +#ifdef IPPROTO_IPV6 + qboolean doneblank; +#endif switch(a.type) { @@ -1577,6 +1581,12 @@ int FTENET_Generic_GetLocalAddress(ftenet_generic_connection_t *con, netadr_t *o continue; } + if (itr->ai_addr->sa_family == AF_INET + || itr->ai_addr->sa_family == AF_INET6 +#ifdef USEIPX + || itr->ai_addr->sa_family == AF_IPX +#endif + ) if (idx++ == count) { SockadrToNetadr((struct sockaddr_qstorage*)itr->ai_addr, out); @@ -1831,7 +1841,7 @@ ftenet_generic_connection_t *FTENET_Generic_EstablishConnection(int adrfamily, i temp = NetadrToSockadr(&adr, &qs); family = ((struct sockaddr*)&qs)->sa_family; -#ifdef IPV6_V6ONLY +#if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY) if (isserver && family == AF_INET && net_hybriddualstack.ival && !((struct sockaddr_in*)&qs)->sin_addr.s_addr) { unsigned long _false = false; @@ -1875,7 +1885,7 @@ ftenet_generic_connection_t *FTENET_Generic_EstablishConnection(int adrfamily, i return NULL; } -#ifdef IPV6_V6ONLY +#if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY) if (family == AF_INET6) setsockopt(newsocket, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&_true, sizeof(_true)); #endif diff --git a/engine/common/pr_bgcmd.c b/engine/common/pr_bgcmd.c index d9da67d9..0697d4f9 100644 --- a/engine/common/pr_bgcmd.c +++ b/engine/common/pr_bgcmd.c @@ -715,6 +715,47 @@ void QCBUILTIN PF_registercvar (progfuncs_t *prinst, struct globalvars_s *pr_glo //Cvars //////////////////////////////////////////////////// +//memory stuff +void QCBUILTIN PF_memalloc (progfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + void *ptr = prinst->AddressableAlloc(prinst, G_INT(OFS_PARM0)); + G_INT(OFS_RETURN) = (char*)ptr - prinst->stringtable; +} +void QCBUILTIN PF_memfree (progfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + prinst->AddressableFree(prinst, prinst->stringtable + G_INT(OFS_PARM0)); +} +void QCBUILTIN PF_memcpy (progfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + int dst = G_INT(OFS_PARM0); + int src = G_INT(OFS_PARM1); + int size = G_INT(OFS_PARM2); + if (dst < 0 || dst+size >= prinst->stringtablesize) + { + PR_BIError(prinst, "PF_memcpy: invalid dest\n"); + return; + } + if (src < 0 || src+size >= prinst->stringtablesize) + { + PR_BIError(prinst, "PF_memcpy: invalid source\n"); + return; + } + memcpy(prinst->stringtable + dst, prinst->stringtable + src, size); +} +void QCBUILTIN PF_memset (progfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + int dst = G_INT(OFS_PARM0); + int val = G_INT(OFS_PARM1); + int size = G_INT(OFS_PARM2); + if (dst < 0 || dst+size >= prinst->stringtablesize) + { + PR_BIError(prinst, "PF_memcpy: invalid dest\n"); + return; + } + memset(prinst->stringtable + dst, val, size); +} +//memory stuff +//////////////////////////////////////////////////// //File access #define MAX_QC_FILES 256 @@ -1817,8 +1858,12 @@ void QCBUILTIN PF_vtos (progfuncs_t *prinst, struct globalvars_s *pr_globals) RETURN_TSTRING(pr_string_temp); } + void QCBUILTIN PF_forgetstring(progfuncs_t *prinst, struct globalvars_s *pr_globals) { +#if 1 + prinst->AddressableFree(prinst, prinst->stringtable + G_INT(OFS_PARM0)); +#else char *s=PR_RemoveProgsString(prinst, G_INT(OFS_PARM0)); if (!s) { @@ -1838,7 +1883,7 @@ void QCBUILTIN PF_forgetstring(progfuncs_t *prinst, struct globalvars_s *pr_glob } ((int *)s)[0] = 0xabcd1234; Z_TagFree(s); - +#endif } void QCBUILTIN PF_dupstring(progfuncs_t *prinst, struct globalvars_s *pr_globals) //frik_file @@ -1856,11 +1901,21 @@ void QCBUILTIN PF_dupstring(progfuncs_t *prinst, struct globalvars_s *pr_globals } len++; /*for the null*/ +#if 1 + buf = prinst->AddressableAlloc(prinst, len); + if (!buf) + { + G_INT(OFS_RETURN) = 0; + return; + } + G_INT(OFS_RETURN) = (char*)buf - prinst->stringtable; +#else buf = Z_TagMalloc(len+8, Z_QC_TAG); RETURN_SSTRING(buf+8); ((int *)buf)[0] = PRSTR; ((int *)buf)[1] = len; buf += 8; +#endif len = 0; for (i = 0; i < *prinst->callargc; i++) @@ -3663,6 +3718,7 @@ lh_extension_t QSG_Extensions[] = { {"FTE_FORCEINFOKEY", 1, NULL, {"forceinfokey"}}, {"FTE_GFX_QUAKE3SHADERS"}, {"FTE_ISBACKBUFFERED", 1, NULL, {"isbackbuffered"}}, + {"FTE_MEMALLOC", 4, NULL, {"memalloc", "memfree", "memcpy", "memset"}}, #ifndef NOMEDIA {"FTE_MEDIA_AVI"}, //playfilm supports avi files. {"FTE_MEDIA_CIN"}, //playfilm command supports q2 cin files. diff --git a/engine/common/pr_common.h b/engine/common/pr_common.h index 90b9f6df..270d6172 100644 --- a/engine/common/pr_common.h +++ b/engine/common/pr_common.h @@ -298,6 +298,11 @@ void QCBUILTIN PF_bufstr_add (progfuncs_t *prinst, struct globalvars_s *pr_glob void QCBUILTIN PF_bufstr_free (progfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_buf_cvarlist (progfuncs_t *prinst, struct globalvars_s *pr_globals); +void QCBUILTIN PF_memalloc (progfuncs_t *prinst, struct globalvars_s *pr_globals); +void QCBUILTIN PF_memfree (progfuncs_t *prinst, struct globalvars_s *pr_globals); +void QCBUILTIN PF_memcpy (progfuncs_t *prinst, struct globalvars_s *pr_globals); +void QCBUILTIN PF_memset (progfuncs_t *prinst, struct globalvars_s *pr_globals); + void QCBUILTIN PF_calltimeofday (progfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_whichpack (progfuncs_t *prinst, struct globalvars_s *pr_globals); diff --git a/engine/droid/src/com/fteqw/FTEDroidActivity.java b/engine/droid/src/com/fteqw/FTEDroidActivity.java index 2ee20ec6..e42ca462 100644 --- a/engine/droid/src/com/fteqw/FTEDroidActivity.java +++ b/engine/droid/src/com/fteqw/FTEDroidActivity.java @@ -114,7 +114,10 @@ public class FTEDroidActivity extends Activity int sspeed = 11025; int speakers = 1; - int sz = 4*AudioTrack.getMinBufferSize(sspeed, ((speakers==2)?AudioFormat.CHANNEL_CONFIGURATION_STEREO:AudioFormat.CHANNEL_CONFIGURATION_MONO), AudioFormat.ENCODING_PCM_16BIT); + int sz = 2*AudioTrack.getMinBufferSize(sspeed, ((speakers==2)?AudioFormat.CHANNEL_CONFIGURATION_STEREO:AudioFormat.CHANNEL_CONFIGURATION_MONO), AudioFormat.ENCODING_PCM_16BIT); + +// if (sz < sspeed * 0.05) +// sz = sspeed * 0.05; AudioTrack at = new AudioTrack(AudioManager.STREAM_MUSIC, sspeed, ((speakers==2)?AudioFormat.CHANNEL_CONFIGURATION_STEREO:AudioFormat.CHANNEL_CONFIGURATION_MONO), AudioFormat.ENCODING_PCM_16BIT, sz, AudioTrack.MODE_STREAM); diff --git a/engine/gl/gl_font.c b/engine/gl/gl_font.c index 466680ff..748ac86b 100644 --- a/engine/gl/gl_font.c +++ b/engine/gl/gl_font.c @@ -16,7 +16,7 @@ void Font_BeginScaledString(struct font_s *font, float vx, float vy, float *px, void Font_Transform(int vx, int vy, int *px, int *py); int Font_CharHeight(void); int Font_CharWidth(unsigned int charcode); -int Font_CharEndCoord(int x, unsigned int charcode); +int Font_CharEndCoord(struct font_s *font, int x, unsigned int charcode); int Font_DrawChar(int px, int py, unsigned int charcode); float Font_DrawScaleChar(float px, float py, float cw, float ch, unsigned int charcode); /*avoid using*/ void Font_EndString(struct font_s *font); @@ -189,6 +189,7 @@ typedef struct font_s FT_Face face; void *membuf; #endif + struct font_s *alt; } font_t; typedef struct { @@ -901,6 +902,7 @@ struct font_s *Font_LoadFont(int height, char *fontfilename) struct font_s *f; int i = 0; int defaultplane; + char *aname; f = Z_Malloc(sizeof(*f)); f->charheight = height; @@ -1026,6 +1028,12 @@ struct font_s *Font_LoadFont(int height, char *fontfilename) return f; } + aname = strstr(fontfilename, ":"); + if (aname) + { + *aname = 0; + f->alt = Font_LoadFont(height, aname+1); + } if (!Font_LoadFreeTypeFont(f, height, fontfilename)) { if (*fontfilename) @@ -1046,6 +1054,8 @@ struct font_s *Font_LoadFont(int height, char *fontfilename) f->chars[i].texplane = BITMAPPLANE; } } + if (aname) + *aname = ':'; defaultplane = BITMAPPLANE;/*assume the bitmap plane - don't use the fallback as people don't think to use com_parseutf8*/ if (!TEXVALID(f->singletexture)) @@ -1146,17 +1156,20 @@ int Font_CharHeight(void) This is where the character ends. Note: this function supports tabs - x must always be based off 0, with Font_LineDraw actually used to draw the line. */ -int Font_CharEndCoord(int x, unsigned int charcode) +int Font_CharEndCoord(struct font_s *font, int x, unsigned int charcode) { struct charcache_s *c; #define TABWIDTH (8*20) if ((charcode&CON_CHARMASK) == '\t') return x + ((TABWIDTH - (x % TABWIDTH)) % TABWIDTH); - c = Font_GetChar(curfont, (CHARIDXTYPE)(charcode&CON_CHARMASK)); + if ((charcode & CON_2NDCHARSETTEXT) && font->alt) + font = font->alt; + + c = Font_GetChar(font, (CHARIDXTYPE)(charcode&CON_CHARMASK)); if (!c) { - c = Font_TryLoadGlyph(curfont, (CHARIDXTYPE)(charcode&CON_CHARMASK)); + c = Font_TryLoadGlyph(font, (CHARIDXTYPE)(charcode&CON_CHARMASK)); if (!c) return x+0; } @@ -1168,6 +1181,9 @@ int Font_CharEndCoord(int x, unsigned int charcode) int Font_CharWidth(unsigned int charcode) { struct charcache_s *c; + struct font_s *font = curfont; + if ((charcode & CON_2NDCHARSETTEXT) && font->alt) + font = font->alt; c = Font_GetChar(curfont, (CHARIDXTYPE)(charcode&CON_CHARMASK)); if (!c) @@ -1190,6 +1206,7 @@ int Font_LineBreaks(conchar_t *start, conchar_t *end, int maxpixelwidth, int max int l, bt; int px; int foundlines = 0; + struct font_s *font = curfont; while (start < end) { @@ -1199,7 +1216,7 @@ int Font_LineBreaks(conchar_t *start, conchar_t *end, int maxpixelwidth, int max l++; if (start+l >= end || (start[l-1]&CON_CHARMASK) == '\n') break; - px = Font_CharEndCoord(px, start[l]); + px = Font_CharEndCoord(font, px, start[l]); } //if we did get to the end if (px > maxpixelwidth) @@ -1234,19 +1251,21 @@ int Font_LineBreaks(conchar_t *start, conchar_t *end, int maxpixelwidth, int max int Font_LineWidth(conchar_t *start, conchar_t *end) { int x = 0; + struct font_s *font = curfont; for (; start < end; start++) { - x = Font_CharEndCoord(x, *start); + x = Font_CharEndCoord(font, x, *start); } return x; } void Font_LineDraw(int x, int y, conchar_t *start, conchar_t *end) { int lx = 0; + struct font_s *font = curfont; for (; start < end; start++) { Font_DrawChar(x+lx, y, *start); - lx = Font_CharEndCoord(lx, *start); + lx = Font_CharEndCoord(font, lx, *start); } } @@ -1283,18 +1302,23 @@ int Font_DrawChar(int px, int py, unsigned int charcode) float sx, sy, sw, sh; int col; int v; + struct font_s *font = curfont; + if ((charcode & CON_2NDCHARSETTEXT) && font->alt) + font = font->alt; //crash if there is no current font. - c = Font_GetChar(curfont, (CHARIDXTYPE)(charcode&CON_CHARMASK)); + c = Font_GetChar(font, (CHARIDXTYPE)(charcode&CON_CHARMASK)); if (!c) { - c = Font_TryLoadGlyph(curfont, (CHARIDXTYPE)(charcode&CON_CHARMASK)); + c = Font_TryLoadGlyph(font, (CHARIDXTYPE)(charcode&CON_CHARMASK)); if (!c) return px; } nextx = px + c->advance; + if ((charcode & CON_CHARMASK) == '\t') + return px + ((TABWIDTH - (px % TABWIDTH)) % TABWIDTH); if ((charcode & CON_CHARMASK) == ' ') return nextx; @@ -1335,23 +1359,23 @@ int Font_DrawChar(int px, int py, unsigned int charcode) case DEFAULTPLANE: sx = ((px+c->left)*(int)vid.width) / (float)vid.rotpixelwidth; sy = ((py+c->top)*(int)vid.height) / (float)vid.rotpixelheight; - sw = ((curfont->charheight)*vid.width) / (float)vid.rotpixelwidth; - sh = ((curfont->charheight)*vid.height) / (float)vid.rotpixelheight; + sw = ((font->charheight)*vid.width) / (float)vid.rotpixelwidth; + sh = ((font->charheight)*vid.height) / (float)vid.rotpixelheight; v = Font_BeginChar(fontplanes.defaultfont); break; case BITMAPPLANE: sx = ((px+c->left)*(int)vid.width) / (float)vid.rotpixelwidth; sy = ((py+c->top)*(int)vid.height) / (float)vid.rotpixelheight; - sw = ((curfont->charheight)*vid.width) / (float)vid.rotpixelwidth; - sh = ((curfont->charheight)*vid.height) / (float)vid.rotpixelheight; - v = Font_BeginChar(curfont->singletexture); + sw = ((font->charheight)*vid.width) / (float)vid.rotpixelwidth; + sh = ((font->charheight)*vid.height) / (float)vid.rotpixelheight; + v = Font_BeginChar(font->singletexture); break; case SINGLEPLANE: sx = ((px+c->left)*(int)vid.width) / (float)vid.rotpixelwidth; sy = ((py+c->top)*(int)vid.height) / (float)vid.rotpixelheight; sw = ((c->bmw)*vid.width) / (float)vid.rotpixelwidth; sh = ((c->bmh)*vid.height) / (float)vid.rotpixelheight; - v = Font_BeginChar(curfont->singletexture); + v = Font_BeginChar(font->singletexture); break; default: sx = ((px+c->left)*(int)vid.width) / (float)vid.rotpixelwidth; @@ -1402,16 +1426,19 @@ float Font_DrawScaleChar(float px, float py, float cw, float ch, unsigned int ch float sx, sy, sw, sh; int col; int v; + struct font_s *font = curfont; + if ((charcode & CON_2NDCHARSETTEXT) && font->alt) + font = font->alt; - cw /= curfont->charheight; - ch /= curfont->charheight; + cw /= font->charheight; + ch /= font->charheight; //crash if there is no current font. - c = Font_GetChar(curfont, (CHARIDXTYPE)(charcode&CON_CHARMASK)); + c = Font_GetChar(font, (CHARIDXTYPE)(charcode&CON_CHARMASK)); if (!c) { - c = Font_TryLoadGlyph(curfont, (CHARIDXTYPE)(charcode&CON_CHARMASK)); + c = Font_TryLoadGlyph(font, (CHARIDXTYPE)(charcode&CON_CHARMASK)); if (!c) return px; } @@ -1457,13 +1484,13 @@ float Font_DrawScaleChar(float px, float py, float cw, float ch, unsigned int ch { sx = ((px+c->left)); sy = ((py+c->top)); - sw = ((curfont->charheight*cw)); - sh = ((curfont->charheight*ch)); + sw = ((font->charheight*cw)); + sh = ((font->charheight*ch)); if (c->texplane == DEFAULTPLANE) v = Font_BeginChar(fontplanes.defaultfont); else - v = Font_BeginChar(curfont->singletexture); + v = Font_BeginChar(font->singletexture); } else { diff --git a/engine/qclib/execloop.h b/engine/qclib/execloop.h index f6aa4eb5..208a79b3 100644 --- a/engine/qclib/execloop.h +++ b/engine/qclib/execloop.h @@ -294,7 +294,7 @@ reeval: //store a value to a pointer case OP_STOREP_IF: - if ((unsigned int)OPB->_int >= addressableused) + if ((unsigned int)OPB->_int >= prinst->addressableused) { pr_xstatement = st-pr_statements; PR_RunError (progfuncs, "bad pointer write in %s", PR_StringToNative(progfuncs, pr_xfunction->s_name)); @@ -303,7 +303,7 @@ reeval: ptr->_float = (float)OPA->_int; break; case OP_STOREP_FI: - if ((unsigned int)OPB->_int >= addressableused) + if ((unsigned int)OPB->_int >= prinst->addressableused) { pr_xstatement = st-pr_statements; PR_RunError (progfuncs, "bad pointer write in %s", PR_StringToNative(progfuncs, pr_xfunction->s_name)); @@ -313,7 +313,7 @@ reeval: break; case OP_STOREP_I: case OP_GSTOREP_I: - if ((unsigned int)OPB->_int >= addressableused) + if ((unsigned int)OPB->_int >= prinst->addressableused) { pr_xstatement = st-pr_statements; PR_RunError (progfuncs, "bad pointer write in %s", PR_StringToNative(progfuncs, pr_xfunction->s_name)); @@ -331,17 +331,17 @@ reeval: case OP_GSTOREP_S: case OP_STOREP_FNC: // pointers case OP_GSTOREP_FNC: - if ((unsigned int)OPB->_int >= addressableused) + if ((unsigned int)OPB->_int >= prinst->addressableused) { pr_xstatement = st-pr_statements; - PR_RunError (progfuncs, "bad pointer write in %s (%x >= %x)", PR_StringToNative(progfuncs, pr_xfunction->s_name), OPB->_int, addressableused); + PR_RunError (progfuncs, "bad pointer write in %s (%x >= %x)", PR_StringToNative(progfuncs, pr_xfunction->s_name), OPB->_int, prinst->addressableused); } ptr = QCPOINTER(OPB); ptr->_int = OPA->_int; break; case OP_STOREP_V: case OP_GSTOREP_V: - if ((unsigned int)OPB->_int >= addressableused) + if ((unsigned int)OPB->_int >= prinst->addressableused) { pr_xstatement = st-pr_statements; PR_RunError (progfuncs, "bad pointer write in %s", PR_StringToNative(progfuncs, pr_xfunction->s_name)); @@ -353,7 +353,7 @@ reeval: break; case OP_STOREP_C: //store character in a string - if ((unsigned int)OPB->_int >= addressableused) + if ((unsigned int)OPB->_int >= prinst->addressableused) { pr_xstatement = st-pr_statements; PR_RunError (progfuncs, "bad pointer write in %s", PR_StringToNative(progfuncs, pr_xfunction->s_name)); @@ -371,7 +371,7 @@ reeval: OPB->_vector[2] *= OPA->_float; break; case OP_MULSTOREP_F: // e.f *= f - if ((unsigned int)OPB->_int >= addressableused) + if ((unsigned int)OPB->_int >= prinst->addressableused) { pr_xstatement = st-pr_statements; PR_RunError (progfuncs, "bad pointer write in %s", PR_StringToNative(progfuncs, pr_xfunction->s_name)); @@ -380,7 +380,7 @@ reeval: OPC->_float = (ptr->_float *= OPA->_float); break; case OP_MULSTOREP_VF: // e.v *= f - if ((unsigned int)OPB->_int >= addressableused) + if ((unsigned int)OPB->_int >= prinst->addressableused) { pr_xstatement = st-pr_statements; PR_RunError (progfuncs, "bad pointer write in %s", PR_StringToNative(progfuncs, pr_xfunction->s_name)); @@ -395,7 +395,7 @@ reeval: OPB->_float /= OPA->_float; break; case OP_DIVSTOREP_F: // e.f /= f - if ((unsigned int)OPB->_int >= addressableused) + if ((unsigned int)OPB->_int >= prinst->addressableused) { pr_xstatement = st-pr_statements; PR_RunError (progfuncs, "bad pointer write in %s", PR_StringToNative(progfuncs, pr_xfunction->s_name)); @@ -413,7 +413,7 @@ reeval: OPB->_vector[2] += OPA->_vector[2]; break; case OP_ADDSTOREP_F: // e.f += f - if ((unsigned int)OPB->_int >= addressableused) + if ((unsigned int)OPB->_int >= prinst->addressableused) { pr_xstatement = st-pr_statements; PR_RunError (progfuncs, "bad pointer write in %s", PR_StringToNative(progfuncs, pr_xfunction->s_name)); @@ -422,7 +422,7 @@ reeval: OPC->_float = (ptr->_float += OPA->_float); break; case OP_ADDSTOREP_V: // e.v += v - if ((unsigned int)OPB->_int >= addressableused) + if ((unsigned int)OPB->_int >= prinst->addressableused) { pr_xstatement = st-pr_statements; PR_RunError (progfuncs, "bad pointer write in %s", PR_StringToNative(progfuncs, pr_xfunction->s_name)); @@ -442,7 +442,7 @@ reeval: OPB->_vector[2] -= OPA->_vector[2]; break; case OP_SUBSTOREP_F: // e.f -= f - if ((unsigned int)OPB->_int >= addressableused) + if ((unsigned int)OPB->_int >= prinst->addressableused) { pr_xstatement = st-pr_statements; PR_RunError (progfuncs, "bad pointer write in %s", PR_StringToNative(progfuncs, pr_xfunction->s_name)); @@ -451,7 +451,7 @@ reeval: OPC->_float = (ptr->_float -= OPA->_float); break; case OP_SUBSTOREP_V: // e.v -= v - if ((unsigned int)OPB->_int >= addressableused) + if ((unsigned int)OPB->_int >= prinst->addressableused) { pr_xstatement = st-pr_statements; PR_RunError (progfuncs, "bad pointer write in %s", PR_StringToNative(progfuncs, pr_xfunction->s_name)); @@ -818,7 +818,7 @@ reeval: break; case OP_LOADP_C: //load character from a string i = (unsigned int)OPA->_int + (unsigned int)OPB->_float; - if ((unsigned int)i >= addressableused) + if ((unsigned int)i >= prinst->addressableused) { i = (unsigned int)OPB->_float; ptr = (eval_t*)PR_StringToNative(progfuncs, OPA->_int); @@ -840,7 +840,7 @@ reeval: case OP_LOADP_S: case OP_LOADP_FNC: i = OPA->_int + OPB->_int*4; - if ((unsigned int)i >= addressableused) + if ((unsigned int)i >= prinst->addressableused) { pr_xstatement = st-pr_statements; PR_RunError (progfuncs, "bad pointer read in %s", PR_StringToNative(progfuncs, pr_xfunction->s_name)); @@ -851,7 +851,7 @@ reeval: case OP_LOADP_V: i = OPA->_int + OPB->_int*4; - if ((unsigned int)i >= addressableused) + if ((unsigned int)i >= prinst->addressableused) { pr_xstatement = st-pr_statements; PR_RunError (progfuncs, "bad pointer read in %s", PR_StringToNative(progfuncs, pr_xfunction->s_name)); @@ -914,7 +914,7 @@ reeval: OPB->_float = (float)((int)OPB->_float | (int)OPA->_float); break; case OP_BITSETP: // .b (+) a - if ((unsigned int)OPB->_int >= addressableused) + if ((unsigned int)OPB->_int >= prinst->addressableused) { pr_xstatement = st-pr_statements; PR_RunError (progfuncs, "bad pointer write in %s", PR_StringToNative(progfuncs, pr_xfunction->s_name)); @@ -926,7 +926,7 @@ reeval: OPB->_float = (float)((int)OPB->_float & ~((int)OPA->_float)); break; case OP_BITCLRP: // .b (-) a - if ((unsigned int)OPB->_int >= addressableused) + if ((unsigned int)OPB->_int >= prinst->addressableused) { pr_xstatement = st-pr_statements; PR_RunError (progfuncs, "bad pointer write in %s", PR_StringToNative(progfuncs, pr_xfunction->s_name)); diff --git a/engine/qclib/initlib.c b/engine/qclib/initlib.c index e630395a..22602574 100644 --- a/engine/qclib/initlib.c +++ b/engine/qclib/initlib.c @@ -76,10 +76,10 @@ void PRAddressableRelocate(progfuncs_t *progfuncs, char *oldb, char *newb, int o //for 64bit systems. :) //addressable memory is memory available to the vm itself for writing. //once allocated, it cannot be freed for the lifetime of the VM. -void *PRAddressableAlloc(progfuncs_t *progfuncs, int ammount) +void *PRAddressableExtend(progfuncs_t *progfuncs, int ammount) { ammount = (ammount + 4)&~3; //round up to 4 - if (addressableused + ammount > addressablesize) + if (prinst->addressableused + ammount > prinst->addressablesize) { /*only do this if the caller states that it can cope with addressable-block relocations/resizes*/ if (externs->addressablerelocated) @@ -89,74 +89,277 @@ void *PRAddressableAlloc(progfuncs_t *progfuncs, int ammount) #if 0//def _DEBUG int oldtot = addressablesize; #endif - int newsize = (addressableused + ammount + 4096) & ~(4096-1); - newblock = VirtualAlloc (NULL, addressablesize, MEM_RESERVE, PAGE_NOACCESS); + int newsize = (prinst->addressableused + ammount + 4096) & ~(4096-1); + newblock = VirtualAlloc (NULL, prinst->addressablesize, MEM_RESERVE, PAGE_NOACCESS); if (newblock) { - VirtualAlloc (newblock, addressableused, MEM_COMMIT, PAGE_READWRITE); - memcpy(newblock, addressablehunk, addressableused); + VirtualAlloc (newblock, prinst->addressableused, MEM_COMMIT, PAGE_READWRITE); + memcpy(newblock, prinst->addressablehunk, prinst->addressableused); #if 0//def _DEBUG - VirtualAlloc (addressablehunk, oldtot, MEM_RESERVE, PAGE_NOACCESS); + VirtualAlloc (prinst->addressablehunk, oldtot, MEM_RESERVE, PAGE_NOACCESS); #else - VirtualFree (addressablehunk, 0, MEM_RELEASE); + VirtualFree (prinst->addressablehunk, 0, MEM_RELEASE); #endif - PRAddressableRelocate(progfuncs, addressablehunk, newblock, addressableused); - addressablehunk = newblock; - addressablesize = newsize; + PRAddressableRelocate(progfuncs, prinst->addressablehunk, newblock, prinst->addressableused); + prinst->addressablehunk = newblock; + prinst->addressablesize = newsize; } #else char *newblock; - int newsize = (addressableused + ammount + 1024*1024) & ~(1024*1024-1); - newblock = realloc(newblock, addressablesize); + int newsize = (prinst->addressableused + ammount + 1024*1024) & ~(1024*1024-1); + newblock = realloc(newblock, prinst->addressablesize); if (newblock) { - PRAddressableRelocate(progfuncs, addressablehunk, newblock, addressableused); - addressablehunk = newblock; - addressablesize = newsize; + PRAddressableRelocate(progfuncs, prinst->addressablehunk, newblock, prinst->addressableused); + prinst->addressablehunk = newblock; + prinst->addressablesize = newsize; } #endif } - if (addressableused + ammount > addressablesize) + if (prinst->addressableused + ammount > prinst->addressablesize) Sys_Error("Not enough addressable memory for progs VM"); } - addressableused += ammount; + prinst->addressableused += ammount; #ifdef _WIN32 - if (!VirtualAlloc (addressablehunk, addressableused, MEM_COMMIT, PAGE_READWRITE)) + if (!VirtualAlloc (prinst->addressablehunk, prinst->addressableused, MEM_COMMIT, PAGE_READWRITE)) Sys_Error("VirtualAlloc failed. Blame windows."); #endif - return &addressablehunk[addressableused-ammount]; + return &prinst->addressablehunk[prinst->addressableused-ammount]; +} + + +#define MARKER 0xF1E3E3E7u +typedef struct +{ + unsigned int next; + unsigned int prev; + unsigned int size; +} qcmemfreeblock_t; +typedef struct +{ + unsigned int marker; + unsigned int size; +} qcmemusedblock_t; +static void PF_fmem_unlink(progfuncs_t *pr, qcmemfreeblock_t *p) +{ + qcmemfreeblock_t *np; + if (p->prev) + { + np = (qcmemfreeblock_t*)(pr->stringtable + p->prev); + np->next = p->next; + } + else + pr->inst->mfreelist = p->next; + if (p->next) + { + np = (qcmemfreeblock_t*)(pr->stringtable + p->next); + np->prev = p->prev; + } +} +static void *PR_memalloc (progfuncs_t *progfuncs, unsigned int size) +{ + qcmemfreeblock_t *p, *np; + qcmemusedblock_t *ub = NULL; + unsigned int b,n; + /*round size up*/ + size = (size+sizeof(qcmemusedblock_t) + 63) & ~63; + + b = prinst->mfreelist; + while (b) + { + if (b < 0 || b >= prinst->addressableused) + { + printf("PF_memalloc: memory corruption\n"); + PR_StackTrace(progfuncs); + return NULL; + } + p = (qcmemfreeblock_t*)(progfuncs->stringtable + b); + if (p->size >= size) + { + if (p->next && p->next < b + p->size || + p->next >= prinst->addressableused || + b + p->size >= prinst->addressableused || + p->prev >= b) + { + printf("PF_memalloc: memory corruption\n"); + PR_StackTrace(progfuncs); + return NULL; + } + + ub = (qcmemusedblock_t*)p; + if (p->size > size + 63) + { + /*make a new header just after it, with basically the same properties, and shift the important fields over*/ + n = b + size; + np = (qcmemfreeblock_t*)(progfuncs->stringtable + b + size); + np->prev = p->prev; + np->next = p->next; + np->size = p->size - size; + if (np->prev) + { + p = (qcmemfreeblock_t*)(progfuncs->stringtable + np->prev); + p->next = n; + } + else + prinst->mfreelist = n; + if (p->next) + { + p = (qcmemfreeblock_t*)(progfuncs->stringtable + np->next); + p->prev = n; + } + } + else + { + size = p->size; /*alloc the entire block*/ + /*unlink this entry*/ + PF_fmem_unlink(progfuncs, p); + } + break; + } + } + + /*assign more space*/ + if (!ub) + { + ub = PRAddressableExtend(progfuncs, size); + if (!ub) + { + printf("PF_memalloc: memory exausted\n"); + PR_StackTrace(progfuncs); + return NULL; + } + } + memset(ub, 0, size); + ub->marker = MARKER; + ub->size = size; + return ub+1; +} +static void PR_memfree (progfuncs_t *progfuncs, void *memptr) +{ + qcmemusedblock_t *ub; + qcmemfreeblock_t *p, *np; + unsigned int l, ln; + unsigned int size; + unsigned int ptr = memptr?((char*)memptr - progfuncs->stringtable):0; + + /*freeing NULL is ignored*/ + if (!ptr) + return; + if (ptr < sizeof(qcmemusedblock_t) || ptr >= prinst->addressableused) + { + printf("PF_memfree: pointer invalid - out of range (%u >= %u)\n", ptr, prinst->addressableused); + PR_StackTrace(progfuncs); + return; + } + + ub = (qcmemusedblock_t*)(progfuncs->stringtable + ptr); + ub--; + ptr = (char*)ub - progfuncs->stringtable; + if (ub->marker != MARKER || ub->size <= sizeof(*ub) || ptr + ub->size > (unsigned int)prinst->addressableused) + { + printf("PF_memfree: memory corruption or double free\n"); + PR_StackTrace(progfuncs); + return; + } + ub->marker = 0; + size = ub->size; + + for (ln = prinst->mfreelist, l = 0; ;) + { + if (ln < 0 || ln >= prinst->addressableused) + { + printf("PF_memfree: memory corruption\n"); + PR_StackTrace(progfuncs); + return; + } + if (!ln || ln >= ptr) + { + np = (qcmemfreeblock_t*)(progfuncs->stringtable + l); + if (l && l+np->size>ptr) + { + printf("PF_memfree: double free\n"); + PR_StackTrace(progfuncs); + return; + } + + /*generate the free block, now we know its proper values*/ + p = (qcmemfreeblock_t*)(progfuncs->stringtable + ptr); + p->prev = l; + p->next = ln; + p->size = size; + + /*update the next's previous*/ + if (p->next) + { + np = (qcmemfreeblock_t*)(progfuncs->stringtable + p->next); + np->prev = p->prev; + + /*extend this block and kill the next if they are adjacent*/ + if (p->next == ptr + size) + { + p->size += np->size; + PF_fmem_unlink(progfuncs, np); + } + } + + /*update the link to get here*/ + if (!l) + prinst->mfreelist = ptr; + else + { + np = (qcmemfreeblock_t*)(progfuncs->stringtable + l); + np->next = ptr; + + /*we're adjacent to the previous block, so merge them by killing the newly freed region*/ + if (l + np->size == ptr) + { + np->size += size; + PF_fmem_unlink(progfuncs, p); + } + } + break; + } + + l = ln; + p = (qcmemfreeblock_t*)(progfuncs->stringtable + l); + ln = p->next; + } } void PRAddressableFlush(progfuncs_t *progfuncs, int totalammount) { - addressableused = 0; + prinst->addressableused = 0; if (totalammount < 0) //flush { - totalammount = addressablesize; + totalammount = prinst->addressablesize; // return; } #ifdef _WIN32 - if (addressablehunk && addressablesize != totalammount) + if (prinst->addressablehunk && prinst->addressablesize != totalammount) { - VirtualFree(addressablehunk, 0, MEM_RELEASE); //doesn't this look complicated? :p - addressablehunk = NULL; + VirtualFree(prinst->addressablehunk, 0, MEM_RELEASE); //doesn't this look complicated? :p + prinst->addressablehunk = NULL; } - if (!addressablehunk) - addressablehunk = VirtualAlloc (addressablehunk, totalammount, MEM_RESERVE, PAGE_NOACCESS); + if (!prinst->addressablehunk) + prinst->addressablehunk = VirtualAlloc (prinst->addressablehunk, totalammount, MEM_RESERVE, PAGE_NOACCESS); #else - if (addressablehunk) - free(addressablehunk); - addressablehunk = malloc(totalammount); //linux will allocate-on-use anyway, which is handy. -// memset(addressablehunk, 0xff, totalammount); + if (prinst->addressablehunk && prinst->addressablesize != totalammount) + { + free(prinst->addressablehunk); + prinst->addressablehunk = NULL; + } + if (!prinst->addressablehunk) + prinst->addressablehunk = malloc(totalammount); //linux will allocate-on-use anyway, which is handy. +// memset(prinst->addressablehunk, 0xff, totalammount); #endif - if (!addressablehunk) + if (!prinst->addressablehunk) Sys_Error("Out of memory\n"); - addressablesize = totalammount; + prinst->addressablesize = totalammount; } int PR_InitEnts(progfuncs_t *progfuncs, int max_ents) @@ -170,7 +373,7 @@ int PR_InitEnts(progfuncs_t *progfuncs, int max_ents) prinst->edicttable = PRHunkAlloc(progfuncs, maxedicts*sizeof(struct edicts_s *)); sv_edicts = PRHunkAlloc(progfuncs, externs->edictsize); prinst->edicttable[0] = sv_edicts; - ((edictrun_t*)prinst->edicttable[0])->fields = PRAddressableAlloc(progfuncs, max_fields_size); + ((edictrun_t*)prinst->edicttable[0])->fields = PRAddressableExtend(progfuncs, max_fields_size); QC_ClearEdict(progfuncs, sv_edicts); sv_num_edicts = 1; @@ -505,7 +708,7 @@ string_t PR_StringToProgs (progfuncs_t *progfuncs, char *str) if (!str) return 0; - if (str >= progfuncs->stringtable && str < progfuncs->stringtable + addressableused) + if (str >= progfuncs->stringtable && str < progfuncs->stringtable + prinst->addressableused) return str - progfuncs->stringtable; for (i = prinst->numallocedstrings-1; i >= 0; i--) @@ -615,7 +818,7 @@ char *ASMCALL PR_StringToNative (progfuncs_t *progfuncs, string_t str) } } - if (str >= addressableused) + if ((unsigned int)str >= (unsigned int)prinst->addressableused) { printf("invalid string offset %x\n", str); PR_StackTrace(progfuncs); @@ -803,8 +1006,9 @@ progfuncs_t deffuncs = { PR_QueryField, QC_ClearEdict, QC_FindPrefixedGlobals, - PRAddressableAlloc, - PR_AllocTempStringLen + PR_memalloc, + PR_AllocTempStringLen, + PR_memfree, }; #undef printf @@ -859,6 +1063,7 @@ progexterns_t defexterns = { #undef extensionbuiltin #undef field #undef shares +#undef maxedicts #undef sv_num_edicts @@ -875,10 +1080,10 @@ void CloseProgs(progfuncs_t *inst) f = inst->parms->memfree; - for ( i=1 ; imaxedicts; i++) + for ( i=1 ; iinst->maxedicts; i++) { - e = (edictrun_t *)(inst->prinst->edicttable[i]); - inst->prinst->edicttable[i] = NULL; + e = (edictrun_t *)(inst->inst->edicttable[i]); + inst->inst->edicttable[i] = NULL; if (e) { // e->entnum = i; @@ -889,17 +1094,17 @@ void CloseProgs(progfuncs_t *inst) PRHunkFree(inst, 0); #ifdef _WIN32 - VirtualFree(inst->addressablehunk, 0, MEM_RELEASE); //doesn't this look complicated? :p + VirtualFree(inst->inst->addressablehunk, 0, MEM_RELEASE); //doesn't this look complicated? :p #else - free(inst->addressablehunk); + free(inst->inst->addressablehunk); #endif - if (inst->prinst->allocedstrings) - f(inst->prinst->allocedstrings); - inst->prinst->allocedstrings = NULL; - if (inst->prinst->tempstrings) - f(inst->prinst->tempstrings); - inst->prinst->tempstrings = NULL; + if (inst->inst->allocedstrings) + f(inst->inst->allocedstrings); + inst->inst->allocedstrings = NULL; + if (inst->inst->tempstrings) + f(inst->inst->tempstrings); + inst->inst->tempstrings = NULL; /* @@ -910,11 +1115,11 @@ void CloseProgs(progfuncs_t *inst) inst->prinst->extensionbuiltin = eb; } */ - if (inst->prinst->field) - f(inst->prinst->field); - if (inst->prinst->shares) - f(inst->prinst->shares); //free memory - f(inst->prinst); + if (inst->inst->field) + f(inst->inst->field); + if (inst->inst->shares) + f(inst->inst->shares); //free memory + f(inst->inst); f(inst); } @@ -955,15 +1160,17 @@ progfuncs_t * InitProgs(progexterns_t *ext) } #undef memalloc #undef pr_trace +#undef pr_progstate +#undef pr_argc funcs = ext->memalloc(sizeof(progfuncs_t)); memcpy(funcs, &deffuncs, sizeof(progfuncs_t)); - funcs->prinst = ext->memalloc(sizeof(prinst_t)); - memset(funcs->prinst,0, sizeof(prinst_t)); + funcs->inst = ext->memalloc(sizeof(prinst_t)); + memset(funcs->inst,0, sizeof(prinst_t)); - funcs->pr_trace = &funcs->prinst->pr_trace; - funcs->progstate = &funcs->pr_progstate; - funcs->callargc = &funcs->pr_argc; + funcs->pr_trace = &funcs->inst->pr_trace; + funcs->progstate = &funcs->inst->progstate; + funcs->callargc = &funcs->inst->pr_argc; funcs->parms = ext; diff --git a/engine/qclib/pr_edict.c b/engine/qclib/pr_edict.c index 468aea45..292e764b 100644 --- a/engine/qclib/pr_edict.c +++ b/engine/qclib/pr_edict.c @@ -38,7 +38,7 @@ edictrun_t *ED_AllocIntoTable (progfuncs_t *progfuncs, int num) prinst->edicttable[num] = *(struct edict_s **)&e = (void*)memalloc(externs->edictsize); memset(e, 0, externs->edictsize); - e->fields = PRAddressableAlloc(progfuncs, fields_size); + e->fields = PRAddressableExtend(progfuncs, fields_size); e->entnum = num; QC_ClearEdict(progfuncs, (struct edict_s*)e); @@ -996,7 +996,10 @@ char *ED_NewString (progfuncs_t *progfuncs, char *string, int minlength) l = strlen(string) + 1; - newc = PRAddressableAlloc (progfuncs, lAddressableAlloc (progfuncs, lstringtable; + new_p = newc; for (i=0 ; i< l ; i++) @@ -2586,12 +2589,12 @@ retry: } len=sizeof(char)*pr_progs->numstrings; - s = PRAddressableAlloc(progfuncs, len); + s = PRAddressableExtend(progfuncs, len); memcpy(s, pr_strings, len); pr_strings = (char *)s; len=sizeof(float)*pr_progs->numglobals; - s = PRAddressableAlloc(progfuncs, len); + s = PRAddressableExtend(progfuncs, len); memcpy(s, pr_globals, len); glob = pr_globals = (float *)s; diff --git a/engine/qclib/progsint.h b/engine/qclib/progsint.h index 795dcb5e..060d1e84 100644 --- a/engine/qclib/progsint.h +++ b/engine/qclib/progsint.h @@ -46,7 +46,7 @@ typedef unsigned char qbyte; //extern progfuncs_t *progfuncs; -#define prinst progfuncs->prinst +#define prinst progfuncs->inst #define externs progfuncs->parms #include "pr_comp.h" @@ -87,7 +87,7 @@ extern QCC_opcode_t pr_opcodes[]; // sized by initialization int PRHunkMark(progfuncs_t *progfuncs); void PRHunkFree(progfuncs_t *progfuncs, int mark); void *PRHunkAlloc(progfuncs_t *progfuncs, int size); -void *PRAddressableAlloc(progfuncs_t *progfuncs, int ammount); +void *PRAddressableExtend(progfuncs_t *progfuncs, int ammount); #ifdef printf #undef LIKEPRINTF @@ -432,12 +432,10 @@ var(unsigned int, max_fields_size); //initlib.c +int mfreelist; var(char *, addressablehunk); -#define addressablehunk prinst->addressablehunk var(unsigned int, addressableused); -#define addressableused prinst->addressableused var(unsigned int, addressablesize); -#define addressablesize prinst->addressablesize //var(extensionbuiltin_t *, extensionbuiltin); diff --git a/engine/qclib/progslib.h b/engine/qclib/progslib.h index 1160959b..0bb9f1a9 100644 --- a/engine/qclib/progslib.h +++ b/engine/qclib/progslib.h @@ -109,7 +109,7 @@ struct progfuncs_s { pbool (*Decompile) (progfuncs_t *prinst, char *fname); - struct prinst_s *prinst; //internal variables. Leave alone. + struct prinst_s *inst; //internal variables. Leave alone. int *callargc; //number of args of built-in call void (*RegisterBuiltin) (progfuncs_t *prinst, char *, builtin_t); @@ -139,9 +139,10 @@ struct progfuncs_s { void (*EntClear) (progfuncs_t *progfuncs, struct edict_s *e); void (*FindPrefixGlobals) (progfuncs_t *progfuncs, char *prefix, void (*found) (progfuncs_t *progfuncs, char *name, union eval_s *val, etype_t type) ); - void *(*AddressableAlloc) (progfuncs_t *progfuncs, int ammount); /*returns memory within the qc block, use stringtoprogs to get a usable qc pointer/string*/ + void *(*AddressableAlloc) (progfuncs_t *progfuncs, unsigned int ammount); /*returns memory within the qc block, use stringtoprogs to get a usable qc pointer/string*/ string_t (*AllocTempString) (progfuncs_t *prinst, char **str, unsigned int len); + void (*AddressableFree) (progfuncs_t *progfuncs, void *mem); /*frees a block of addressable memory*/ }; typedef struct progexterns_s { diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c index a5c2e2eb..7a245ccd 100644 --- a/engine/server/pr_cmds.c +++ b/engine/server/pr_cmds.c @@ -8938,6 +8938,12 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"skel_mmap", PF_skel_mmap, 0, 0, 0, 282, "float*(float skel)"},// (FTE_QC_RAGDOLL) {"skel_set_bone_world",PF_skel_set_bone_world,0,0, 0, 283, "void(entity ent, float bonenum, vector org, optional vector angorfwd, optional vector right, optional vector up)"}, + {"memalloc", PF_memalloc, 0, 0, 0, 384, "void*(int size)"}, + {"memfree", PF_memfree, 0, 0, 0, 385, "void(void *ptr)"}, + {"memcpy", PF_memcpy, 0, 0, 0, 386, "void(void *dst, void *src, int size)"}, + {"memset", PF_memset, 0, 0, 0, 387, "void(void *dst, int val, int size)"}, + + // {"cvar_setlatch", PF_cvar_setlatch, 0, 0, 0, 284, "void(string cvarname, optional string value)"}, //72