diff --git a/engine/client/cl_demo.c b/engine/client/cl_demo.c index c777fb2f..2e34bc45 100644 --- a/engine/client/cl_demo.c +++ b/engine/client/cl_demo.c @@ -1939,7 +1939,10 @@ void CL_QTVPoll (void) { if (len < 0) { - Con_Printf("invalid QTV handshake\n"); + if (!qtvrequestsize) + Con_Printf("Connection to QTV server closed without any reply.\n"); + else + Con_Printf("invalid QTV handshake\n"); SCR_SetLoadingStage(LS_NONE); VFS_CLOSE(qtvrequest); qtvrequest = NULL; diff --git a/engine/client/cl_ignore.c b/engine/client/cl_ignore.c index 5ef0050e..edd2acb5 100644 --- a/engine/client/cl_ignore.c +++ b/engine/client/cl_ignore.c @@ -206,6 +206,15 @@ static qboolean Ignorelist_VAdd(int slot) S_Voip_Ignore(slot, true); return true; } +static qboolean Ignorelist_VDel(int slot) +{ + if (!cl.players[slot].vignored) + return false; + + cl.players[slot].vignored = false; + S_Voip_Ignore(slot, false); + return true; +} static qboolean Ignorelist_Del(int slot) { @@ -244,9 +253,40 @@ static void VIgnore_f(void) else { if (Ignorelist_VAdd(slot)) - Con_Printf("Added user %s to ignore list\n", cl.players[slot].name); + Con_Printf("Added user %s to mute list\n", cl.players[slot].name); else - Con_Printf ("User %s is already ignored\n", cl.players[slot].name); + Con_Printf ("User %s is already mute\n", cl.players[slot].name); + } +} +static void VUnignore_f(void) +{ + int c, slot; + + if ((c = Cmd_Argc()) == 1) + { + Display_Ignorelist(); + return; + } + else if (c != 2) + { + Con_Printf("Usage: %s [userid | name]\n", Cmd_Argv(0)); + return; + } + + if ((slot = Player_StringtoSlot(Cmd_Argv(1))) == PLAYER_ID_NOMATCH) + { + Con_Printf("%s : no player with userid %d\n", Cmd_Argv(0), Q_atoi(Cmd_Argv(1))); + } + else if (slot == PLAYER_NAME_NOMATCH) + { + Con_Printf("%s : no player with name %s\n", Cmd_Argv(0), Cmd_Argv(1)); + } + else + { + if (Ignorelist_VDel(slot)) + Con_Printf("Removed user %s from mute list\n", cl.players[slot].name); + else + Con_Printf ("User %s already wasn't muted\n", cl.players[slot].name); } } @@ -613,6 +653,7 @@ void Ignore_Init(void) Cvar_Register (&ignore_opponents, IGNOREGROUP); Cmd_AddCommand ("cl_voip_mute", VIgnore_f); + Cmd_AddCommand ("cl_voip_unmute", VUnignore_f); Cmd_AddCommand ("ignore", Ignore_f); Cmd_AddCommand ("ignorelist", IgnoreList_f); Cmd_AddCommand ("unignore", Unignore_f); diff --git a/engine/client/cl_input.c b/engine/client/cl_input.c index 2f1a0d28..abbf2e32 100644 --- a/engine/client/cl_input.c +++ b/engine/client/cl_input.c @@ -1749,10 +1749,6 @@ void CL_SendCmd (double frametime, qboolean mainloop) msecs += frametime*1000; // Con_Printf("%f\n", msecs); -#ifdef IRCCONNECT - if (cls.netchan.remote_address.type != NA_IRC) -#endif - wantfps = cl_netfps.value; fullsend = true; diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index 33b57e23..25e84494 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -62,6 +62,7 @@ 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_t *hud_miniscores_show; extern cvar_t net_compress; 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)"."); @@ -761,6 +762,20 @@ void CL_CheckForResend (void) cls.protocol = CP_QUAKE3; #endif #ifdef NQPROT + else if (!strcmp(cl_loopbackprotocol.string, "random")) + { //for debugging. + if (rand() & 1) + { + cls.protocol = CP_NETQUAKE; + cls.protocol_nq = CPNQ_FITZ666; + } + else + { + cls.protocol = CP_QUAKEWORLD; + pext1 = Net_PextMask(1, false); + pext2 = Net_PextMask(2, false); + } + } else if (!strcmp(cl_loopbackprotocol.string, "fitz")) //actually proquake, because we might as well use the extra angles { cls.protocol = CP_NETQUAKE; @@ -794,7 +809,7 @@ void CL_CheckForResend (void) } #endif else - { + { //protocol wasn't recognised, and we didn't take the nq fallback, so that must mean we're going for qw. cls.protocol = CP_QUAKEWORLD; pext1 = Net_PextMask(1, false); pext2 = Net_PextMask(2, false); @@ -804,7 +819,10 @@ void CL_CheckForResend (void) if (dpcompat_nopreparse.ival) #endif { - if (progstype == PROG_QW && cls.protocol != CP_QUAKEWORLD) + //disabling preparsing with hexen2 is unsupported. + if (progstype == PROG_H2) + Con_Printf("dpcompat_nopreparse is unsupported with hexen2\n"); + else if (progstype == PROG_QW && cls.protocol != CP_QUAKEWORLD) { cls.protocol = CP_QUAKEWORLD; pext1 = Net_PextMask(1, false); @@ -3847,6 +3865,7 @@ void CL_Init (void) Cvar_Register (&cl_countpendingpl, cl_controlgroup); Cvar_Register (&cl_threadedphysics, cl_controlgroup); hud_tracking_show = Cvar_Get("hud_tracking_show", "1", 0, "statusbar"); + hud_miniscores_show = Cvar_Get("hud_miniscores_show", "1", 0, "statusbar"); Cvar_Register (&cl_download_mapsrc, cl_controlgroup); Cvar_Register (&cl_dlemptyterminate, cl_controlgroup); diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c index e49e8143..e2b29200 100644 --- a/engine/client/cl_parse.c +++ b/engine/client/cl_parse.c @@ -4600,6 +4600,7 @@ CL_UpdateUserinfo */ void CL_ProcessUserInfo (int slot, player_info_t *player) { + int i; char *col; Q_strncpyz (player->name, Info_ValueForKey (player->userinfo, "name"), sizeof(player->name)); Q_strncpyz (player->team, Info_ValueForKey (player->userinfo, "team"), sizeof(player->team)); @@ -4616,7 +4617,10 @@ void CL_ProcessUserInfo (int slot, player_info_t *player) else player->rbottomcolor = atoi(col); - if (atoi(Info_ValueForKey (player->userinfo, "*spectator"))) + i = atoi(Info_ValueForKey (player->userinfo, "*spectator")); + if (i == 2) + player->spectator = 2; + else if (i) player->spectator = true; else player->spectator = false; @@ -4849,7 +4853,16 @@ static void CL_SetStatNumeric (int pnum, int stat, int ivalue, float fvalue) CL_SetStat_Internal(pnum, stat, ivalue, fvalue); } else + { + unsigned int pl = cl.playerview[pnum].playernum; + if (pl < MAX_CLIENTS) + { + cl.players[pl].stats[stat]=ivalue; + cl.players[pl].statsf[stat]=fvalue; + } + CL_SetStat_Internal(pnum, stat, ivalue, fvalue); + } #ifdef QUAKESTATS if (stat == STAT_VIEWHEIGHT && ((cls.z_ext & Z_EXT_VIEWHEIGHT) || cls.protocol == CP_NETQUAKE)) diff --git a/engine/client/cl_plugin.inc b/engine/client/cl_plugin.inc index 8d6b41cb..62ebb8ac 100644 --- a/engine/client/cl_plugin.inc +++ b/engine/client/cl_plugin.inc @@ -710,6 +710,19 @@ static qintptr_t VARGS Plug_GetNetworkInfo(void *offset, quintptr_t mask, const } #undef has +static qintptr_t VARGS Plug_GetTrackerOwnFrags(void *offset, quintptr_t mask, const qintptr_t *arg) +{ + int ret; + int seat = VM_LONG(arg[0]); + char *outptr = VM_POINTER(arg[1]); + size_t outlen = VM_LONG(arg[2]); + if (VM_OOB(arg[1], outlen) || !outlen) + VM_FLOAT(ret) = 0; + else + VM_FLOAT(ret) = Stats_GetLastOwnFrag(seat, outptr, outlen); + return ret; +} + static qintptr_t VARGS Plug_GetLocationName(void *offset, quintptr_t mask, const qintptr_t *arg) { float *locpoint = VM_POINTER(arg[0]); @@ -1249,6 +1262,7 @@ void Plug_Client_Init(void) Plug_RegisterBuiltin("GetServerInfo", Plug_GetServerInfo, PLUG_BIF_NEEDSRENDERER); Plug_RegisterBuiltin("SetUserInfo", Plug_SetUserInfo, PLUG_BIF_NEEDSRENDERER); Plug_RegisterBuiltin("GetNetworkInfo", Plug_GetNetworkInfo, PLUG_BIF_NEEDSRENDERER); + Plug_RegisterBuiltin("GetTrackerOwnFrags", Plug_GetTrackerOwnFrags, PLUG_BIF_NEEDSRENDERER); Plug_RegisterBuiltin("S_RawAudio", Plug_S_RawAudio, PLUG_BIF_NEEDSRENDERER); diff --git a/engine/client/client.h b/engine/client/client.h index 8351858b..a82c7bc9 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -1566,6 +1566,7 @@ int Stats_GetTouches(int playernum); int Stats_GetCaptures(int playernum); qboolean Stats_HaveFlags(int mode); qboolean Stats_HaveKills(void); +float Stats_GetLastOwnFrag(int seat, char *res, int reslen); void VARGS Stats_Message(char *msg, ...) LIKEPRINTF(1); qboolean Stats_ParsePrintLine(char *line); void Stats_NewMap(void); diff --git a/engine/client/console.c b/engine/client/console.c index 2ce8d25d..7a4fe862 100644 --- a/engine/client/console.c +++ b/engine/client/console.c @@ -1381,7 +1381,7 @@ void Con_DrawNotifyOne (console_t *con) while (lines < con->notif_l) { x = 0; - Font_ForceColour(1, 1, 1, alphas[lines]); + R2D_ImageColours(1, 1, 1, alphas[lines]); if (con->flags & CONF_NOTIFY_RIGHT) { for (c = starts[lines]; c < ends[lines]; ) @@ -1409,7 +1409,7 @@ void Con_DrawNotifyOne (console_t *con) Font_EndString(font_console); - Font_InvalidateColour(); + R2D_ImageColours(1,1,1,1); } void Con_ClearNotify(void) diff --git a/engine/client/fragstats.c b/engine/client/fragstats.c index 264b5ace..2a748205 100644 --- a/engine/client/fragstats.c +++ b/engine/client/fragstats.c @@ -118,6 +118,30 @@ qboolean Stats_HaveKills(void) return fragstats.readkills; } +static char lastownfragplayer[64]; +static float lastownfragtime; +float Stats_GetLastOwnFrag(int seat, char *res, int reslen) +{ + if (seat) + { + if (reslen) + *res = 0; + return 0; + } + + //erk, realtime was reset? + if (lastownfragtime > (float)realtime) + lastownfragtime = 0; + + Q_strncpyz(res, lastownfragplayer, reslen); + return realtime - lastownfragtime; +}; +static void Stats_OwnFrag(char *name) +{ + Q_strncpyz(lastownfragplayer, name, sizeof(lastownfragplayer)); + lastownfragtime = realtime; +} + void VARGS Stats_Message(char *msg, ...); qboolean Stats_TrackerImageLoaded(char *in) @@ -332,7 +356,10 @@ void Stats_Evaluate(fragfilemsgtypes_t mt, int wid, int p1, int p2) Stats_FragMessage(-4, wid, p1, false); if (u1) + { + Stats_OwnFrag("someone"); Stats_Message("You killed someone\n%s kills: %i\n", fragstats.weapontotals[wid].fullname, fragstats.weapontotals[wid].ownkills); + } break; case ff_tkbonus: if (u1) @@ -350,7 +377,9 @@ void Stats_Evaluate(fragfilemsgtypes_t mt, int wid, int p1, int p2) Stats_FragMessage(-1, wid, p1, true); if (u1) + { Stats_Message("You killed your teammate\n%s teamkills: %i\n", fragstats.weapontotals[wid].fullname, fragstats.weapontotals[wid].ownteamkills); + } break; case ff_flagtouch: fragstats.clienttotals[p1].grabs++; @@ -397,6 +426,7 @@ void Stats_Evaluate(fragfilemsgtypes_t mt, int wid, int p1, int p2) fragstats.totalkills++; if (u2) { + Stats_OwnFrag(cl.players[p1].name); fragstats.weapontotals[wid].ownkills++; Stats_Message("You killed %s\n%s kills: %i (%i/%i)\n", cl.players[p1].name, fragstats.weapontotals[wid].fullname, fragstats.clienttotals[p2].kills, fragstats.weapontotals[wid].kills, fragstats.totalkills); } @@ -453,7 +483,10 @@ void Stats_Evaluate(fragfilemsgtypes_t mt, int wid, int p1, int p2) if (u1) Stats_Message("%s killed you\n%s deaths: %i (%i/%i)\n", cl.players[p2].name, fragstats.weapontotals[wid].fullname, fragstats.clienttotals[p2].owndeaths, fragstats.weapontotals[wid].owndeaths, fragstats.totaldeaths); if (u2) + { + Stats_OwnFrag(cl.players[p1].name); Stats_Message("You killed %s\n%s kills: %i (%i/%i)\n", cl.players[p1].name, fragstats.weapontotals[wid].fullname, fragstats.clienttotals[p2].kills, fragstats.weapontotals[wid].kills, fragstats.totalkills); + } break; } } diff --git a/engine/client/in_generic.c b/engine/client/in_generic.c index f53a0840..5e1aac21 100644 --- a/engine/client/in_generic.c +++ b/engine/client/in_generic.c @@ -13,14 +13,62 @@ static cvar_t m_strafeonright = CVARFD("m_strafeonright", "1", CVAR_ARCHIVE, "If static cvar_t m_fatpressthreshold = CVARFD("m_fatpressthreshold", "0.2", CVAR_ARCHIVE, "How fat your thumb has to be to register a fat press (touchscreens)."); static cvar_t m_touchmajoraxis = CVARFD("m_touchmajoraxis", "1", CVAR_ARCHIVE, "When using a touchscreen, use only the major axis for strafing."); static cvar_t m_slidethreshold = CVARFD("m_slidethreshold", "10", CVAR_ARCHIVE, "How far your finger needs to move to be considered a slide event (touchscreens)."); + +void QDECL joyaxiscallback(cvar_t *var, char *oldvalue) +{ + int sign; + char *end; + strtol(var->string, &end, 0); + if (!*end) //okay, its missing or an actual number. + return; + + end = var->string; + if (*end == '-') + { + end++; + sign = -1; + } + else if (*end == '+') + { + end++; + sign = 1; + } + else + sign = 1; + if (!Q_strcasecmp(end, "forward") || !Q_strcasecmp(end, "moveforward")) + var->ival = 1*sign; + else if (!Q_strcasecmp(end, "back") || !Q_strcasecmp(end, "moveback")) + var->ival = 1*sign*-1; + else if (!Q_strcasecmp(end, "lookup") || !Q_strcasecmp(end, "pitchup")) + var->ival = 2*sign; + else if (!Q_strcasecmp(end, "lookdown") || !Q_strcasecmp(end, "pitchdown")) + var->ival = 2*sign*-1; + else if (!Q_strcasecmp(end, "moveright")) + var->ival = 3*sign; + else if (!Q_strcasecmp(end, "moveleft")) + var->ival = 3*sign*-1; + else if (!Q_strcasecmp(end, "right") || !Q_strcasecmp(end, "turnright")) + var->ival = 4*sign; + else if (!Q_strcasecmp(end, "left") || !Q_strcasecmp(end, "turnleft")) + var->ival = 4*sign; + else if (!Q_strcasecmp(end, "up") || !Q_strcasecmp(end, "moveup")) + var->ival = 5*sign; + else if (!Q_strcasecmp(end, "down") || !Q_strcasecmp(end, "movedown")) + var->ival = 5*sign*-1; + else if (!Q_strcasecmp(end, "rollright")) + var->ival = 6*sign; + else if (!Q_strcasecmp(end, "rollleft")) + var->ival = 6*sign*-1; +} + static cvar_t joy_advaxis[6] = { - CVARD("joyadvaxisx", "4", "Provides a way to remap each joystick/controller axis.\n0:dead, 1:fwd, 2:pitch, 3:side, 4:yaw, 5:up, 6:roll"), - CVAR("joyadvaxisy", "2"), - CVAR("joyadvaxisz", "5"), - CVAR("joyadvaxisr", "3"), - CVAR("joyadvaxisu", "1"), - CVAR("joyadvaxisv", "6") + CVARCD("joyadvaxisx", "turnright", joyaxiscallback, "Provides a way to remap each joystick/controller axis.\n0:dead, 1:fwd, 2:pitch, 3:side, 4:yaw, 5:up, 6:roll"), + CVARC("joyadvaxisy", "lookup", joyaxiscallback), + CVARC("joyadvaxisz", "moveup", joyaxiscallback), + CVARC("joyadvaxisr", "moveright", joyaxiscallback), + CVARC("joyadvaxisu", "moveforward", joyaxiscallback), + CVARC("joyadvaxisv", "rollright", joyaxiscallback) }; static cvar_t joy_advaxisscale[6] = { @@ -704,28 +752,31 @@ void IN_MoveJoystick(struct joy_s *joy, float *movements, int pnum, float framet for (i = 0; i < 6; i++) { - switch(joy_advaxis[i].ival) + int ax = joy_advaxis[i].ival; + switch(ax) { default: case 0: //dead axis break; case 1: - jstrafe[0] += joy->axis[i] * joy_advaxisscale[i].value; - break; - case 2: - jlook[0] += joy->axis[i] * joy_advaxisscale[i].value; - break; case 3: - jstrafe[1] += joy->axis[i] * joy_advaxisscale[i].value; - break; - case 4: - jlook[1] += joy->axis[i] * joy_advaxisscale[i].value; - break; case 5: - jstrafe[2] += joy->axis[i] * joy_advaxisscale[i].value; + jstrafe[(ax-1)/2] += joy->axis[i] * joy_advaxisscale[i].value; break; + case -1: + case -3: + case -5: + jstrafe[(-ax-1)/2] -= joy->axis[i] * joy_advaxisscale[i].value; + + case 2: + case 4: case 6: - jlook[2] += joy->axis[i] * joy_advaxisscale[i].value; + jlook[(ax-2)/2] += joy->axis[i] * joy_advaxisscale[i].value; + break; + case -2: + case -4: + case -6: + jlook[(-ax-2)/2] -= joy->axis[i] * joy_advaxisscale[i].value; break; } } @@ -788,9 +839,9 @@ void IN_MoveJoystick(struct joy_s *joy, float *movements, int pnum, float framet V_StopPitchDrift (&cl.playerview[pnum]); //movement - movements[0] -= joy_movesens[0].value * cl_forwardspeed.value * jstrafe[0]; - movements[1] -= joy_movesens[1].value * cl_sidespeed.value * jstrafe[1]; - movements[2] -= joy_movesens[2].value * cl_upspeed.value * jstrafe[2]; + movements[0] += joy_movesens[0].value * cl_forwardspeed.value * jstrafe[0]; + movements[1] += joy_movesens[1].value * cl_sidespeed.value * jstrafe[1]; + movements[2] += joy_movesens[2].value * cl_upspeed.value * jstrafe[2]; } void IN_Move (float *movements, int pnum, float frametime) diff --git a/engine/client/in_sdl.c b/engine/client/in_sdl.c index 6c73beeb..4aa9ddee 100644 --- a/engine/client/in_sdl.c +++ b/engine/client/in_sdl.c @@ -97,7 +97,7 @@ static void J_JoystickAdded(int enumid) return; sdljoy[i].id = SDL_JoystickInstanceID(sdljoy[i].joystick); - cname = SDL_GameControllerName(sdljoy[i].controller); + cname = SDL_JoystickName(sdljoy[i].joystick); if (!cname) cname = "Unknown Joystick"; Con_Printf("Found new joystick (%i): %s\n", i, cname); diff --git a/engine/client/in_win.c b/engine/client/in_win.c index f0b21a6c..1ad32b22 100644 --- a/engine/client/in_win.c +++ b/engine/client/in_win.c @@ -102,7 +102,7 @@ static cvar_t in_simulatemultitouch = CVAR("in_simulatemultitouch", "0"); static cvar_t in_nonstandarddeadkeys = CVARD("in_nonstandarddeadkeys", "1", "Discard input events that result in multiple keys. Only the last key will be used. This results in behaviour that differs from eg notepad. To use a dead key, press it twice instead of the dead key followed by space."); static cvar_t xinput_leftvibrator = CVARFD("xinput_leftvibrator","0", CVAR_ARCHIVE, ""); -static cvar_t xinput_rightvibrator = CVARFD("xinput_rightvibrator","0", CVAR_ARCHIVE, "Enables the use of xinput for controllers.\nNote that if you have a headset plugged in, that headset will be used for audio playback if no specific audio device is configured (may require snd_restart too)."); +static cvar_t xinput_rightvibrator = CVARFD("xinput_rightvibrator","0", CVAR_ARCHIVE, ""); static cvar_t m_accel_noforce = CVAR("m_accel_noforce", "0"); static cvar_t m_threshold_noforce = CVAR("m_threshold_noforce", "0"); @@ -1853,14 +1853,14 @@ qboolean INS_ReadJoystick (struct wjoy_s *joy) XINPUT_VIBRATION vibrator; HRESULT hr = pXInputGetState(joy->id, &xistate); -#if 1 +#if 0//def _DEBUG //I don't have a controller to test this with, so we fake stuff. if (joy->id == 3) { POINT p; GetCursorPos(&p); hr = ERROR_SUCCESS; - xistate.Gamepad.wButtons = 0; + xistate.Gamepad.wButtons = 0;//rand() & 0xfff0; xistate.Gamepad.sThumbRX = 0;//(p.x/1920.0)*0xffff - 0x8000; xistate.Gamepad.sThumbRY = 0;//(p.y/1080.0)*0xffff - 0x8000; xistate.Gamepad.sThumbLX = (p.x/1920.0)*0xffff - 0x8000; diff --git a/engine/client/menu.c b/engine/client/menu.c index 92603b97..773f2e29 100644 --- a/engine/client/menu.c +++ b/engine/client/menu.c @@ -128,7 +128,7 @@ int M_FindKeysForBind (int bindmap, const char *command, int *keylist, int *keym lastmod = KEY_MODIFIER_ALTBINDMAP; } - for (j=0 ; j<256 ; j++) + for (j=0 ; jcallargc > 1)?G_FLOAT(OFS_PARM1):0; int keynums[2]; char keyname[512]; @@ -302,7 +302,7 @@ void QCBUILTIN PF_cl_findkeysforcommand (pubprogfuncs_t *prinst, struct globalva void QCBUILTIN PF_cl_findkeysforcommandex (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { const char *cmdname = PR_GetStringOfs(prinst, OFS_PARM0); - int bindmap = G_FLOAT(OFS_PARM1); + int bindmap = (prinst->callargc > 1)?G_FLOAT(OFS_PARM1):0; int keynums[256]; int keymods[countof(keynums)]; char keyname[512]; diff --git a/engine/client/pr_csqc.c b/engine/client/pr_csqc.c index 9227c73c..14d8c9ba 100644 --- a/engine/client/pr_csqc.c +++ b/engine/client/pr_csqc.c @@ -191,6 +191,7 @@ extern sfx_t *cl_sfx_r_exp3; globalvector(input_cursor_impact, "input_cursor_trace_endpos"); /*float filled by getinputstate*/ \ globalfloat(input_cursor_entitynumber, "input_cursor_entitynumber"); /*float filled by getinputstate*/ \ \ + globalvector(global_gravitydir, "global_gravitydir"); /*vector used when .gravitydir is 0 0 0 */ \ globalfloat(dimension_default, "dimension_default"); /*float default value for dimension_hit+dimension_solid*/ \ globalfloat(autocvar_vid_conwidth, "autocvar_vid_conwidth"); /*float hackfix for dp mods*/ \ globalfloat(autocvar_vid_conheight, "autocvar_vid_conheight"); /*float hackfix for dp mods*/ \ @@ -287,6 +288,7 @@ static void CSQC_FindGlobals(qboolean nofuncs) { static float csphysicsmode = 0; static float dimension_default = 255; + static vec3_t defaultgravity = {0, 0, -1}; #define globalfloat(name,qcname) csqcg.name = (float*)PR_FindGlobal(csqcprogs, qcname, 0, NULL); #define globalint(name,qcname) csqcg.name = (int*)PR_FindGlobal(csqcprogs, qcname, 0, NULL); #define globalvector(name,qcname) csqcg.name = (float*)PR_FindGlobal(csqcprogs, qcname, 0, NULL); @@ -308,6 +310,9 @@ static void CSQC_FindGlobals(qboolean nofuncs) if (csqcg.cltime) *csqcg.cltime = realtime; + if (!csqcg.global_gravitydir) + csqcg.global_gravitydir = defaultgravity; + CSQC_ChangeLocalPlayer(cl_forceseat.ival?(cl_forceseat.ival - 1) % cl.splitclients:0); csqc_world.g.self = csqcg.self; @@ -320,6 +325,7 @@ static void CSQC_FindGlobals(qboolean nofuncs) csqc_world.g.v_forward = csqcg.forward; csqc_world.g.v_right = csqcg.right; csqc_world.g.v_up = csqcg.up; + csqc_world.g.defaultgravitydir = csqcg.global_gravitydir; csqc_world.g.drawfont = (float*)PR_FindGlobal(csqcprogs, "drawfont", 0, NULL); csqc_world.g.drawfontscale = (float*)PR_FindGlobal(csqcprogs, "drawfontscale", 0, NULL); @@ -4235,6 +4241,7 @@ void CSQC_EntStateToCSQC(unsigned int flags, float lerptime, entity_state_t *src ent->xv->entnum = src->number; ent->v->modelindex = src->modelindex; +// ent->xv->vw_index = src->modelindex2; // ent->v->flags = src->flags; ent->v->effects = src->effects; @@ -4307,6 +4314,7 @@ void CSQC_PlayerStateToCSQC(int pnum, player_state_t *srcp, csqcedict_t *ent) ent->xv->entnum = pnum+1; ent->v->modelindex = srcp->modelindex; +// ent->xv->vw_index = srcp->modelindex2; ent->v->skin = srcp->skinnum; CSQC_LerpStateToCSQC(&cl.lerpplayers[pnum], ent, true); @@ -4543,6 +4551,8 @@ static void QCBUILTIN PF_getentity(pubprogfuncs_t *prinst, struct globalvars_s * { int entnum = G_FLOAT(OFS_PARM0); int fldnum = G_FLOAT(OFS_PARM1); + lerpents_t *le; + entity_state_t *es; if (fldnum == GE_MAXENTS) { @@ -4557,6 +4567,8 @@ static void QCBUILTIN PF_getentity(pubprogfuncs_t *prinst, struct globalvars_s * VectorCopy(vec3_origin, G_VECTOR(OFS_RETURN)); return; } + le = &cl.lerpents[entnum]; + es = le->entstate; switch(fldnum) { case GE_ACTIVE: @@ -4564,70 +4576,135 @@ static void QCBUILTIN PF_getentity(pubprogfuncs_t *prinst, struct globalvars_s * break; case GE_ORIGIN: /*lerped position*/ - VectorCopy(cl.lerpents[entnum].origin, G_VECTOR(OFS_RETURN)); + VectorCopy(le->origin, G_VECTOR(OFS_RETURN)); break; case GE_SCALE: - G_FLOAT(OFS_RETURN) = cl.lerpents[entnum].entstate->scale / 16.0f; + G_FLOAT(OFS_RETURN) = es->scale / 16.0f; break; case GE_ALPHA: - G_FLOAT(OFS_RETURN) = cl.lerpents[entnum].entstate->trans / 255.0f; + G_FLOAT(OFS_RETURN) = es->trans / 255.0f; break; case GE_COLORMOD: - G_FLOAT(OFS_RETURN+0) = cl.lerpents[entnum].entstate->colormod[0] / 8.0f; - G_FLOAT(OFS_RETURN+1) = cl.lerpents[entnum].entstate->colormod[1] / 8.0f; - G_FLOAT(OFS_RETURN+2) = cl.lerpents[entnum].entstate->colormod[2] / 8.0f; + G_FLOAT(OFS_RETURN+0) = es->colormod[0] / 8.0f; + G_FLOAT(OFS_RETURN+1) = es->colormod[1] / 8.0f; + G_FLOAT(OFS_RETURN+2) = es->colormod[2] / 8.0f; break; case GE_SKIN: - G_FLOAT(OFS_RETURN) = cl.lerpents[entnum].entstate->skinnum; - break; - case GE_LIGHT: - G_FLOAT(OFS_RETURN) = cl.lerpents[entnum].entstate->abslight; + G_FLOAT(OFS_RETURN) = es->skinnum; break; case GE_MINS: - G_FLOAT(OFS_RETURN+0) = -(cl.lerpents[entnum].entstate->solid & 31); - G_FLOAT(OFS_RETURN+1) = -(cl.lerpents[entnum].entstate->solid & 31); - G_FLOAT(OFS_RETURN+2) = -((cl.lerpents[entnum].entstate->solid>>5) & 31); + G_FLOAT(OFS_RETURN+0) = -(es->solid & 31); + G_FLOAT(OFS_RETURN+1) = -(es->solid & 31); + G_FLOAT(OFS_RETURN+2) = -((es->solid>>5) & 31); break; case GE_MAXS: - G_FLOAT(OFS_RETURN+0) = (cl.lerpents[entnum].entstate->solid & 31); - G_FLOAT(OFS_RETURN+1) = (cl.lerpents[entnum].entstate->solid & 31); - G_FLOAT(OFS_RETURN+1) = ((cl.lerpents[entnum].entstate->solid>>10) & 63) - 32; + G_FLOAT(OFS_RETURN+0) = (es->solid & 31); + G_FLOAT(OFS_RETURN+1) = (es->solid & 31); + G_FLOAT(OFS_RETURN+1) = ((es->solid>>10) & 63) - 32; break; case GE_ABSMIN: - G_FLOAT(OFS_RETURN+0) = cl.lerpents[entnum].origin[0] + -(cl.lerpents[entnum].entstate->solid & 31); - G_FLOAT(OFS_RETURN+1) = cl.lerpents[entnum].origin[1] + -(cl.lerpents[entnum].entstate->solid & 31); - G_FLOAT(OFS_RETURN+2) = cl.lerpents[entnum].origin[2] + -((cl.lerpents[entnum].entstate->solid>>5) & 31); + G_FLOAT(OFS_RETURN+0) = le->origin[0] + -(es->solid & 31); + G_FLOAT(OFS_RETURN+1) = le->origin[1] + -(es->solid & 31); + G_FLOAT(OFS_RETURN+2) = le->origin[2] + -((es->solid>>5) & 31); break; case GE_ABSMAX: - G_FLOAT(OFS_RETURN+0) = cl.lerpents[entnum].origin[0] + (cl.lerpents[entnum].entstate->solid & 31); - G_FLOAT(OFS_RETURN+1) = cl.lerpents[entnum].origin[1] + (cl.lerpents[entnum].entstate->solid & 31); - G_FLOAT(OFS_RETURN+1) = cl.lerpents[entnum].origin[2] + ((cl.lerpents[entnum].entstate->solid>>10) & 63) - 32; + G_FLOAT(OFS_RETURN+0) = le->origin[0] + (es->solid & 31); + G_FLOAT(OFS_RETURN+1) = le->origin[1] + (es->solid & 31); + G_FLOAT(OFS_RETURN+1) = le->origin[2] + ((es->solid>>10) & 63) - 32; break; case GE_ORIGINANDVECTORS: - VectorCopy(cl.lerpents[entnum].origin, G_VECTOR(OFS_RETURN)); - AngleVectors(cl.lerpents[entnum].angles, csqcg.forward, csqcg.right, csqcg.up); + VectorCopy(le->origin, G_VECTOR(OFS_RETURN)); + AngleVectors(le->angles, csqcg.forward, csqcg.right, csqcg.up); break; case GE_FORWARD: - AngleVectors(cl.lerpents[entnum].angles, G_VECTOR(OFS_RETURN), NULL, NULL); + AngleVectors(le->angles, G_VECTOR(OFS_RETURN), NULL, NULL); break; case GE_RIGHT: - AngleVectors(cl.lerpents[entnum].angles, NULL, G_VECTOR(OFS_RETURN), NULL); + AngleVectors(le->angles, NULL, G_VECTOR(OFS_RETURN), NULL); break; case GE_UP: - AngleVectors(cl.lerpents[entnum].angles, NULL, NULL, G_VECTOR(OFS_RETURN)); + AngleVectors(le->angles, NULL, NULL, G_VECTOR(OFS_RETURN)); break; case GE_PANTSCOLOR: - if (cl.lerpents[entnum].entstate->colormap <= cl.allocated_client_slots && !(cl.lerpents[entnum].entstate->dpflags & RENDER_COLORMAPPED)) - G_FLOAT(OFS_RETURN) = cl.players[cl.lerpents[entnum].entstate->colormap].tbottomcolor; + if (es->colormap <= cl.allocated_client_slots && !(es->dpflags & RENDER_COLORMAPPED)) + G_FLOAT(OFS_RETURN) = cl.players[es->colormap].tbottomcolor; else - G_FLOAT(OFS_RETURN) = cl.lerpents[entnum].entstate->colormap & 15; + G_FLOAT(OFS_RETURN) = es->colormap & 15; break; case GE_SHIRTCOLOR: - if (cl.lerpents[entnum].entstate->colormap <= cl.allocated_client_slots && !(cl.lerpents[entnum].entstate->dpflags & RENDER_COLORMAPPED)) - G_FLOAT(OFS_RETURN) = cl.players[cl.lerpents[entnum].entstate->colormap].ttopcolor; + if (es->colormap <= cl.allocated_client_slots && !(es->dpflags & RENDER_COLORMAPPED)) + G_FLOAT(OFS_RETURN) = cl.players[es->colormap].ttopcolor; else - G_FLOAT(OFS_RETURN) = cl.lerpents[entnum].entstate->colormap>>4; + G_FLOAT(OFS_RETURN) = es->colormap>>4; break; + case GE_LIGHT: + G_FLOAT(OFS_RETURN) = 0; + break; + + case GE_MODELINDEX: + G_FLOAT(OFS_RETURN) = es->modelindex; + break; + case GE_MODELINDEX2: + G_FLOAT(OFS_RETURN) = es->modelindex2; + break; + case GE_EFFECTS: + G_FLOAT(OFS_RETURN) = es->effects; + break; + case GE_FRAME: + G_FLOAT(OFS_RETURN) = es->frame; + break; + case GE_ANGLES: + VectorCopy(le->angles, G_VECTOR(OFS_RETURN)); + break; + case GE_FATNESS: + G_FLOAT(OFS_RETURN) = es->fatness; + break; + case GE_DRAWFLAGS: + G_FLOAT(OFS_RETURN) = es->hexen2flags; + break; + case GE_ABSLIGHT: + G_FLOAT(OFS_RETURN) = es->abslight; + break; + case GE_GLOWMOD: + VectorScale(es->glowmod, 1/8.0, G_VECTOR(OFS_RETURN)); + break; + case GE_GLOWSIZE: + G_FLOAT(OFS_RETURN) = es->glowsize; + break; + case GE_GLOWCOLOUR: + G_FLOAT(OFS_RETURN) = es->glowcolour; + break; + case GE_RTSTYLE: + G_FLOAT(OFS_RETURN) = es->lightstyle; + break; + case GE_RTPFLAGS: + G_FLOAT(OFS_RETURN) = es->lightpflags; + break; + case GE_RTCOLOUR: + VectorScale(es->light, 1/1024.0, G_VECTOR(OFS_RETURN)); + break; + case GE_RTRADIUS: + G_FLOAT(OFS_RETURN) = es->light[3]; + break; + case GE_TAGENTITY: + G_FLOAT(OFS_RETURN) = es->tagentity; + break; + case GE_TAGINDEX: + G_FLOAT(OFS_RETURN) = es->tagindex; + break; + case GE_GRAVITYDIR: + { + vec3_t a; + a[0] = ((-192-es->u.q1.gravitydir[0])/256.0f) * 360; + a[1] = (es->u.q1.gravitydir[1]/256.0f) * 360; + a[2] = 0; + AngleVectors(a, G_VECTOR(OFS_RETURN), NULL, NULL); + } + break; + case GE_TRAILEFFECTNUM: + G_FLOAT(OFS_RETURN) = es->u.q1.traileffectnum; + break; + default: Con_Printf("PF_getentity: field %i is not supported\n", fldnum); VectorCopy(vec3_origin, G_VECTOR(OFS_RETURN)); @@ -4635,6 +4712,67 @@ static void QCBUILTIN PF_getentity(pubprogfuncs_t *prinst, struct globalvars_s * } } + +static void QCBUILTIN PF_cs_getplayerstat(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + unsigned int playernum = G_FLOAT(OFS_PARM0); + unsigned int statnum = G_FLOAT(OFS_PARM1); + unsigned int stattype = G_FLOAT(OFS_PARM2); + unsigned int i, j; + if (playernum >= cl.allocated_client_slots || statnum >= MAX_CL_STATS) + stattype = ev_void; + + switch(stattype) + { + default: + case ev_void: + G_FLOAT(OFS_RETURN+0) = 0; + G_FLOAT(OFS_RETURN+1) = 0; + G_FLOAT(OFS_RETURN+2) = 0; + break; + + case ev_integer: + case ev_field: //Hopefully NOT useful, certainly not reliable + case ev_function: //Hopefully NOT useful + case ev_pointer: //NOT useful in a networked capacity. + G_INT(OFS_RETURN) = cl.players[playernum].stats[statnum]; + break; + + case ev_float: + G_FLOAT(OFS_RETURN) = cl.players[playernum].statsf[statnum]; + break; + case ev_vector: + G_FLOAT(OFS_RETURN+0) = (statnum+0 >= MAX_CL_STATS)?0:cl.players[playernum].statsf[statnum+0]; + G_FLOAT(OFS_RETURN+1) = (statnum+1 >= MAX_CL_STATS)?0:cl.players[playernum].statsf[statnum+1]; + G_FLOAT(OFS_RETURN+2) = (statnum+2 >= MAX_CL_STATS)?0:cl.players[playernum].statsf[statnum+2]; + break; + case ev_entity: + j = cl.players[playernum].stats[statnum]; + if (j < maxcsqcentities && csqcent[j]) + G_INT(OFS_RETURN) = EDICT_TO_PROG(csqcprogs, csqcent[j]); + else if (j <= cl.allocated_client_slots && j > 0 && csqcdelta_playerents[j]) + G_INT(OFS_RETURN) = EDICT_TO_PROG(csqcprogs, csqcdelta_playerents[j]); + else + { + G_INT(OFS_RETURN) = 0; + //scan for the delta entity reference. + for (i = 0; i < csqcdelta_pack_new.numents; i++) + { + if (csqcdelta_pack_old.e[i].n == j && csqcdelta_pack_old.e[i].e) + { + G_INT(OFS_RETURN) = EDICT_TO_PROG(csqcprogs, csqcdelta_pack_old.e[i].e); + break; + } + } + } + break; + case ev_string: + G_INT(OFS_RETURN) = 0; //FIXME: no info, these are not currently tracked in mvds apparently. + break; + } +} + + static void QCBUILTIN PF_V_CalcRefdef(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { csqcedict_t *ent = (csqcedict_t*)G_EDICT(prinst, OFS_PARM0); @@ -4954,8 +5092,6 @@ static void QCBUILTIN PF_resourcestatus(pubprogfuncs_t *prinst, struct globalvar void QCBUILTIN PF_CL_DrawTextField (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); -#define PF_FixTen PF_Fixme,PF_Fixme,PF_Fixme,PF_Fixme,PF_Fixme,PF_Fixme,PF_Fixme,PF_Fixme,PF_Fixme,PF_Fixme - //prefixes: //PF_ - common, works on any vm //PF_cs_ - works in csqc only (dependant upon globals or fields) @@ -5268,6 +5404,7 @@ static struct { {"getstati", PF_cs_getstati, 330}, // #330 float(float stnum) getstati (EXT_CSQC) {"getstatf", PF_cs_getstatbits, 331}, // #331 float(float stnum) getstatf (EXT_CSQC) {"getstats", PF_cs_getstats, 332}, // #332 string(float firststnum) getstats (EXT_CSQC) + {"getplayerstat", PF_cs_getplayerstat, 0}, // #0 __variant(float playernum, float statnum, float stattype) getplayerstat {"setmodelindex", PF_cs_SetModelIndex, 333}, // #333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC) {"modelnameforindex", PF_cs_ModelnameForIndex, 334}, // #334 string(float mdlindex) modelnameforindex (EXT_CSQC) diff --git a/engine/client/pr_menu.c b/engine/client/pr_menu.c index 15b8c06b..3eeef611 100644 --- a/engine/client/pr_menu.c +++ b/engine/client/pr_menu.c @@ -440,7 +440,7 @@ void QCBUILTIN PF_CL_drawcolouredstring (pubprogfuncs_t *prinst, struct globalva r2d_be_flags = PF_SelectDPDrawFlag(flag); PR_CL_BeginString(prinst, pos[0], pos[1], size[0], size[1], &px, &py); ipx = px; - Font_ForceColour(r, g, b, alpha); + R2D_ImageColours(r, g, b, alpha); while(*str) { str = Font_Decode(str, &codeflags, &codepoint); @@ -451,7 +451,7 @@ void QCBUILTIN PF_CL_drawcolouredstring (pubprogfuncs_t *prinst, struct globalva else px = Font_DrawScaleChar(px, py, codeflags, codepoint); } - Font_InvalidateColour(); + R2D_ImageColours(1,1,1,1); Font_EndString(NULL); r2d_be_flags = 0; } @@ -700,9 +700,9 @@ void QCBUILTIN PF_CL_drawcharacter (pubprogfuncs_t *prinst, struct globalvars_s r2d_be_flags = PF_SelectDPDrawFlag(flag); PR_CL_BeginString(prinst, pos[0], pos[1], size[0], size[1], &x, &y); - Font_ForceColour(rgb[0], rgb[1], rgb[2], alpha); + R2D_ImageColours(rgb[0], rgb[1], rgb[2], alpha); Font_DrawScaleChar(x, y, CON_WHITEMASK, chara); - Font_InvalidateColour(); + R2D_ImageColours(1,1,1,1); Font_EndString(NULL); r2d_be_flags = 0; @@ -730,7 +730,7 @@ void QCBUILTIN PF_CL_drawrawstring (pubprogfuncs_t *prinst, struct globalvars_s r2d_be_flags = PF_SelectDPDrawFlag(flag); PR_CL_BeginString(prinst, pos[0], pos[1], size[0], size[1], &x, &y); - Font_ForceColour(rgb[0], rgb[1], rgb[2], alpha); + R2D_ImageColours(rgb[0], rgb[1], rgb[2], alpha); while(*text) { @@ -748,7 +748,7 @@ void QCBUILTIN PF_CL_drawrawstring (pubprogfuncs_t *prinst, struct globalvars_s } x = Font_DrawScaleChar(x, y, CON_WHITEMASK, c); } - Font_InvalidateColour(); + R2D_ImageColours(1,1,1,1); Font_EndString(NULL); r2d_be_flags = 0; } diff --git a/engine/client/r_2d.c b/engine/client/r_2d.c index 806fa02d..f93ad0d1 100644 --- a/engine/client/r_2d.c +++ b/engine/client/r_2d.c @@ -545,6 +545,8 @@ void R2D_ImageColours(float r, float g, float b, float a) draw_active_colour[1] = g; draw_active_colour[2] = b; draw_active_colour[3] = a; + + Font_InvalidateColour(draw_active_colour); } void R2D_ImagePaletteColour(unsigned int i, float a) { @@ -552,6 +554,8 @@ void R2D_ImagePaletteColour(unsigned int i, float a) draw_active_colour[1] = host_basepal[i*3+1]/255.0; draw_active_colour[2] = host_basepal[i*3+2]/255.0; draw_active_colour[3] = a; + + Font_InvalidateColour(draw_active_colour); } //awkward and weird to use @@ -1521,11 +1525,11 @@ void R2D_DrawCrosshair(void) Font_BeginScaledString(font_default, sx, sy, size, size, &sx, &sy); sx -= Font_CharScaleWidth(CON_WHITEMASK, '+' | 0xe000)/2; sy -= Font_CharScaleHeight()/2; - Font_ForceColour(ch_color[0], ch_color[1], ch_color[2], crosshairalpha.value); + R2D_ImageColours(ch_color[0], ch_color[1], ch_color[2], crosshairalpha.value); Font_DrawScaleChar(sx, sy, CON_WHITEMASK, '+' | 0xe000); - Font_InvalidateColour(); Font_EndString(font_default); } + R2D_ImageColours(1,1,1,1); return; } diff --git a/engine/client/r_part.c b/engine/client/r_part.c index e1b1723d..46f55116 100644 --- a/engine/client/r_part.c +++ b/engine/client/r_part.c @@ -610,7 +610,7 @@ extern cvar_t r_bloodstains; extern cvar_t gl_part_flame; cvar_t r_part_rain_quantity = CVARF("r_part_rain_quantity", "1", CVAR_ARCHIVE); -cvar_t r_particle_tracelimit = CVARFD("r_particle_tracelimit", "200", CVAR_ARCHIVE, "Number of traces to allow per frame for particle physics."); +cvar_t r_particle_tracelimit = CVARFD("r_particle_tracelimit", "0x7fffffff", CVAR_ARCHIVE, "Number of traces to allow per frame for particle physics."); cvar_t r_part_sparks = CVAR("r_part_sparks", "1"); cvar_t r_part_sparks_trifan = CVAR("r_part_sparks_trifan", "1"); cvar_t r_part_sparks_textured = CVAR("r_part_sparks_textured", "1"); diff --git a/engine/client/r_surf.c b/engine/client/r_surf.c index d953daf4..bdaa09d8 100644 --- a/engine/client/r_surf.c +++ b/engine/client/r_surf.c @@ -1825,7 +1825,7 @@ start: if (node->visframe != r_visframecount) return; - for (c = 0, clipplane = r_refdef.frustum; c < r_refdef.frustum_numplanes; c++, clipplane++) + for (c = 0, clipplane = r_refdef.frustum; c < r_refdef.frustum_numworldplanes; c++, clipplane++) { if (!(clipflags & (1 << c))) continue; // don't need to clip against it @@ -1934,7 +1934,7 @@ static void Surf_OrthoRecursiveWorldNode (mnode_t *node, unsigned int clipflags) if (node->visframe != r_visframecount) return; - for (c = 0, clipplane = r_refdef.frustum; c < r_refdef.frustum_numplanes; c++, clipplane++) + for (c = 0, clipplane = r_refdef.frustum; c < r_refdef.frustum_numworldplanes; c++, clipplane++) { if (!(clipflags & (1 << c))) continue; // don't need to clip against it @@ -2192,7 +2192,7 @@ start: if (node->visframe != r_visframecount) return; - for (c = 0, clipplane = r_refdef.frustum; c < r_refdef.frustum_numplanes; c++, clipplane++) + for (c = 0, clipplane = r_refdef.frustum; c < r_refdef.frustum_numworldplanes; c++, clipplane++) { if (!(clipflags & (1 << c))) continue; // don't need to clip against it @@ -2921,7 +2921,7 @@ void Surf_DrawWorld (void) if (cl.worldmodel->fromgame == fg_quake3) { entvis = surfvis = R_MarkLeaves_Q3 (); - Surf_RecursiveQ3WorldNode (cl.worldmodel->nodes, (1<nodes, (1<type == mod_heightmap -#else - && 0 -#endif - ) + if (r_refdef.globalfog.density) { float culldist; float fog; @@ -2533,9 +2529,9 @@ void R_SetFrustum (float projmat[16], float viewmat[16]) r_refdef.frustum[r_refdef.frustum_numplanes].dist = mvp[15] - mvp[14]; scale = 1/sqrt(DotProduct(r_refdef.frustum[r_refdef.frustum_numplanes].normal, r_refdef.frustum[r_refdef.frustum_numplanes].normal)); - r_refdef.frustum[r_refdef.frustum_numplanes].normal[0] *= scale; - r_refdef.frustum[r_refdef.frustum_numplanes].normal[1] *= scale; - r_refdef.frustum[r_refdef.frustum_numplanes].normal[2] *= scale; + r_refdef.frustum[r_refdef.frustum_numplanes].normal[0] *= -scale; + r_refdef.frustum[r_refdef.frustum_numplanes].normal[1] *= -scale; + r_refdef.frustum[r_refdef.frustum_numplanes].normal[2] *= -scale; // r_refdef.frustum[r_refdef.frustum_numplanes].dist *= scale; r_refdef.frustum[r_refdef.frustum_numplanes].dist = DotProduct(r_origin, r_refdef.frustum[r_refdef.frustum_numplanes].normal)-culldist; diff --git a/engine/client/sbar.c b/engine/client/sbar.c index fed4308a..24cd6a55 100644 --- a/engine/client/sbar.c +++ b/engine/client/sbar.c @@ -27,6 +27,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #ifdef QUAKEHUD extern cvar_t *hud_tracking_show; +extern cvar_t *hud_miniscores_show; cvar_t scr_scoreboard_drawtitle = CVARD("scr_scoreboard_drawtitle", "1", "Wastes screen space when looking at the scoreboard."); cvar_t scr_scoreboard_forcecolors = CVARD("scr_scoreboard_forcecolors", "0", "Makes the scoreboard colours obey enemycolor/teamcolor rules."); //damn americans @@ -1951,6 +1952,8 @@ void Sbar_DrawFrags (playerview_t *pv) Sbar_FillPC (sbar_rect.x+x*8 + 10, sbar_rect.y+y, 28, 4, top); Sbar_FillPC (sbar_rect.x+x*8 + 10, sbar_rect.y+y+4, 28, 3, bottom); + R2D_ImageColours(1, 1, 1, 1); + // draw number f = s->frags; sprintf (num, "%3i",f); @@ -2736,7 +2739,7 @@ void Sbar_Draw (playerview_t *pv) R2D_ImageColours(1, 1, 1, 1); - minidmoverlay = cl.deathmatch; + minidmoverlay = cl.deathmatch && hud_miniscores_show->ival; sbar_rect = r_refdef.grect; sbarwidth = 320; @@ -2780,7 +2783,7 @@ void Sbar_Draw (playerview_t *pv) Sbar_Hexen2DrawMinimal(pv); Sbar_Hexen2DrawInventory(pv); - if (cl.deathmatch) + if (minidmoverlay) Sbar_MiniDeathmatchOverlay (pv); Sbar_Hexen2DrawActiveStuff(pv); @@ -2861,7 +2864,7 @@ void Sbar_Draw (playerview_t *pv) Sbar_DrawInventory (pv); else if (cl_sbar.ival) Sbar_DrawPic (0, -24, 320, 24, sb_scorebar); //make sure we don't get HoM - if ((!headsup || sbar_rect.width<512) && cl.deathmatch) + if ((!headsup || sbar_rect.width<512) && cl.deathmatch && hud_miniscores_show->ival) Sbar_DrawFrags (pv); } @@ -3069,6 +3072,8 @@ void Sbar_TeamOverlay (void) R2D_ImagePaletteColour (0, scr_scoreboard_fillalpha.value); R2D_FillBlock (startx - 3, y, 1, 8); // Electro - Border - Left R2D_FillBlock (startx - 3 + rank_width - 2, y, 1, 8); // Electro - Border - Right + + R2D_ImageColours(1, 1, 1, 1); } // draw pings @@ -3161,7 +3166,7 @@ ping time frags name #define COLUMN_FRAGS COLUMN(frags, 5*8, \ { \ int cx; int cy; \ - if (s->spectator) \ + if (s->spectator && s->spectator != 2) \ { \ Draw_FunStringWidth(x, y, "spectator", 5*8, false, false); \ } \ @@ -3349,6 +3354,8 @@ void Sbar_DeathmatchOverlay (int start) // Electro's scoreboard eyecandy: Draw the title row background R2D_ImagePaletteColour (1, scr_scoreboard_fillalpha.value); R2D_FillBlock(startx - 2, y, rank_width - 3, 9); + + R2D_ImageColours(1, 1, 1, 1); } x = startx; @@ -3650,6 +3657,7 @@ static void Sbar_MiniDeathmatchOverlay (playerview_t *pv) Sbar_FillPC ( x, py+4, 40, 4, bottom); py += 8; } + R2D_ImageColours(1, 1, 1, 1); for (/* */ ; i < scoreboardlines && y < sbar_rect.y + sbar_rect.height - 8 + 1; i++) { k = fragsort[i]; diff --git a/engine/client/screen.h b/engine/client/screen.h index 5c86808e..2a9a28b8 100644 --- a/engine/client/screen.h +++ b/engine/client/screen.h @@ -114,8 +114,7 @@ int Font_CharEndCoord(struct font_s *font, int x, unsigned int charflags, unsign int Font_DrawChar(int px, int py, unsigned int charflags, unsigned int codepoint); float Font_DrawScaleChar(float px, float py, unsigned int charflags, unsigned int codepoint); /*avoid using*/ void Font_EndString(struct font_s *font); -void Font_ForceColour(float r, float g, float b, float a); //This colour will be applied while the char mask remains WHITE. If you print char by char, make sure to include the mask. -void Font_InvalidateColour(void); +void Font_InvalidateColour(vec4_t newcolour); /*these three functions deal with formatted blocks of text (including tabs and new lines)*/ fte_inline conchar_t *Font_Decode(conchar_t *start, unsigned int *codeflags, unsigned int *codepoint) { diff --git a/engine/client/snd_dma.c b/engine/client/snd_dma.c index 1e5f289f..0942200d 100644 --- a/engine/client/snd_dma.c +++ b/engine/client/snd_dma.c @@ -98,7 +98,7 @@ cvar_t snd_leftisright = CVARAF( "s_swapstereo", "0", cvar_t snd_eax = CVARAF( "s_eax", "0", "snd_eax", 0); cvar_t snd_speakers = CVARAFD( "s_numspeakers", "2", - "snd_numspeakers", 0, "Number of hardware audio channels to use. "DISTRIBUTION" supports up to 6."); + "snd_numspeakers", CVAR_ARCHIVE, "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", diff --git a/engine/common/bothdefs.h b/engine/common/bothdefs.h index 21085938..54ee1e5e 100644 --- a/engine/common/bothdefs.h +++ b/engine/common/bothdefs.h @@ -214,7 +214,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define USE_MYSQL //allow mysql in dedicated servers. #endif #if defined(_WIN32) && !defined(FTE_SDL) && !defined(WINRT) - //#define SUBSERVERS //use subserver code. + #define SUBSERVERS //use subserver code. #endif #define SIDEVIEWS 4 //enable secondary/reverse views. diff --git a/engine/common/common.c b/engine/common/common.c index b677308a..b9e7528f 100644 --- a/engine/common/common.c +++ b/engine/common/common.c @@ -3537,6 +3537,11 @@ char *COM_ParseStringSet (const char *data, char *out, size_t outsize) data++; } + if (*data == '\"') + { + return COM_ParseCString(data, out, outsize, NULL); + } + // parse a regular word do { diff --git a/engine/common/pr_bgcmd.c b/engine/common/pr_bgcmd.c index 27c7bcde..724552d8 100644 --- a/engine/common/pr_bgcmd.c +++ b/engine/common/pr_bgcmd.c @@ -2452,7 +2452,7 @@ void QCBUILTIN PF_loadfromfile (pubprogfuncs_t *prinst, struct globalvars_s *pr_ const char *filename = PR_GetStringOfs(prinst, OFS_PARM0); const char *file = COM_LoadTempFile(filename, NULL); - int size; + size_t size; if (!file) { @@ -2475,7 +2475,7 @@ void QCBUILTIN PF_writetofile(pubprogfuncs_t *prinst, struct globalvars_s *pr_gl char buffer[65536]; char *entstr; - int buflen; + size_t buflen; buflen = 0; entstr = prinst->saveent(prinst, buffer, &buflen, sizeof(buffer), ed); //will save just one entities vars @@ -2489,7 +2489,7 @@ void QCBUILTIN PF_loadfromdata (pubprogfuncs_t *prinst, struct globalvars_s *pr_ { const char *file = PR_GetStringOfs(prinst, OFS_PARM0); - int size; + size_t size; if (!*file) { @@ -2510,7 +2510,7 @@ void QCBUILTIN PF_parseentitydata(pubprogfuncs_t *prinst, struct globalvars_s *p void *ed = G_EDICT(prinst, OFS_PARM0); const char *file = PR_GetStringOfs(prinst, OFS_PARM1); - int size; + size_t size; if (!*file) { @@ -4964,7 +4964,7 @@ void QCBUILTIN PF_traceoff (pubprogfuncs_t *prinst, struct globalvars_s *pr_glob } void QCBUILTIN PF_coredump (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { - int size = 1024*1024*8; + size_t size = 1024*1024*8; char *buffer = BZ_Malloc(size); prinst->save_ents(prinst, buffer, &size, size, 3); COM_WriteFile("core.txt", FS_GAMEONLY, buffer, size); @@ -4972,8 +4972,8 @@ void QCBUILTIN PF_coredump (pubprogfuncs_t *prinst, struct globalvars_s *pr_glob } void QCBUILTIN PF_eprint (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { - int max = 1024*1024; - int size = 0; + size_t max = 1024*1024; + size_t size = 0; char *buffer = BZ_Malloc(max); char *buf; buf = prinst->saveent(prinst, buffer, &size, max, (struct edict_s*)G_WEDICT(prinst, OFS_PARM0)); diff --git a/engine/common/pr_common.h b/engine/common/pr_common.h index 9c932e48..b04897d7 100644 --- a/engine/common/pr_common.h +++ b/engine/common/pr_common.h @@ -782,7 +782,33 @@ enum GE_MAXS = 13, GE_ABSMIN = 14, GE_ABSMAX = 15, - GE_LIGHT = 16 + GE_LIGHT = 16, + + GE_MODELINDEX = 200, + GE_MODELINDEX2 = 201, + GE_EFFECTS = 202, + GE_FRAME = 203, + GE_ANGLES = 204, + GE_FATNESS = 205, + GE_DRAWFLAGS = 206, + GE_ABSLIGHT = 207, + GE_GLOWMOD = 208, + GE_GLOWSIZE = 209, + GE_GLOWCOLOUR = 210, + GE_RTSTYLE = 211, + GE_RTPFLAGS = 212, + GE_RTCOLOUR = 213, + GE_RTRADIUS = 214, + GE_TAGENTITY = 215, + GE_TAGINDEX = 216, + GE_GRAVITYDIR = 217, + GE_TRAILEFFECTNUM = 218, + +// GE_MOVETYPE, +// GE_LATENCY, +// GE_VIEWANGLES +// GE_MOVEMENT, +// GE_VELOCITY, }; #ifdef __cplusplus }; diff --git a/engine/common/q1bsp.c b/engine/common/q1bsp.c index 6517aa69..7ea8240d 100644 --- a/engine/common/q1bsp.c +++ b/engine/common/q1bsp.c @@ -616,7 +616,12 @@ static void Q1BSP_RecursiveBrushCheck (struct traceinfo_s *traceinfo, mnode_t *n } // put the crosspoint DIST_EPSILON pixels on the near side - if (t1 < 0) + if (t1 == t2) + { + side = 0; + frac = 0; + } + else if (t1 < 0) { frac = (t1 + DIST_EPSILON)/(t1-t2); side = 1; diff --git a/engine/common/sys_win_threads.c b/engine/common/sys_win_threads.c index d230dd06..d3c7fcad 100644 --- a/engine/common/sys_win_threads.c +++ b/engine/common/sys_win_threads.c @@ -443,47 +443,10 @@ typedef struct slaveserver_s int inbufsize; } winsubserver_t; - -pubsubserver_t *Sys_ForkServer(void) -{ - char exename[256]; - char curdir[256]; - char cmdline[8192]; - PROCESS_INFORMATION childinfo; - STARTUPINFO startinfo; - SECURITY_ATTRIBUTES pipesec = {sizeof(pipesec), NULL, TRUE}; - winsubserver_t *ctx = Z_Malloc(sizeof(*ctx)); - - GetModuleFileName(NULL, exename, sizeof(exename)); - GetCurrentDirectory(sizeof(curdir), curdir); - Q_snprintfz(cmdline, sizeof(cmdline), "foo -noreset -clusterslave %s", FS_GetManifestArgs()); //fixme: include which manifest is in use, so configs get set up the same. - - memset(&startinfo, 0, sizeof(startinfo)); - startinfo.cb = sizeof(startinfo); - startinfo.hStdInput = NULL; - startinfo.hStdError = NULL; - startinfo.hStdOutput = NULL; - startinfo.dwFlags |= STARTF_USESTDHANDLES; - - //create pipes for the stdin/stdout. - CreatePipe(&ctx->inpipe, &startinfo.hStdOutput, &pipesec, 0); - CreatePipe(&startinfo.hStdInput, &ctx->outpipe, &pipesec, 0); - - SetHandleInformation(ctx->inpipe, HANDLE_FLAG_INHERIT, 0); - SetHandleInformation(ctx->outpipe, HANDLE_FLAG_INHERIT, 0); - SetHandleInformation(startinfo.hStdOutput, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT); - SetHandleInformation(startinfo.hStdInput, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT); - - CreateProcess(exename, cmdline, NULL, NULL, TRUE, 0, NULL, curdir, &startinfo, &childinfo); - - //these ends of the pipes were inherited by now, so we can discard them in the caller. - CloseHandle(startinfo.hStdOutput); - CloseHandle(startinfo.hStdInput); - return &ctx->pub; -} - -void Sys_InstructSlave(pubsubserver_t *ps, sizebuf_t *cmd) +static void Sys_InstructSlave(pubsubserver_t *ps, sizebuf_t *cmd) { + //FIXME: this is blocking. this is bad if the target is also blocking while trying to write to us. + //FIXME: merge buffering logic with SSV_InstructMaster, and allow for failure if full winsubserver_t *s = (winsubserver_t*)ps; DWORD written = 0; cmd->data[0] = cmd->cursize & 0xff; @@ -491,16 +454,7 @@ void Sys_InstructSlave(pubsubserver_t *ps, sizebuf_t *cmd) WriteFile(s->outpipe, cmd->data, cmd->cursize, &written, NULL); } -void SSV_InstructMaster(sizebuf_t *cmd) -{ - HANDLE output = GetStdHandle(STD_OUTPUT_HANDLE); - DWORD written = 0; - cmd->data[0] = cmd->cursize & 0xff; - cmd->data[1] = (cmd->cursize>>8) & 0xff; - WriteFile(output, cmd->data, cmd->cursize, &written, NULL); -} - -int Sys_SubServerRead(pubsubserver_t *ps) +static int Sys_SubServerRead(pubsubserver_t *ps) { DWORD avail; winsubserver_t *s = (winsubserver_t*)ps; @@ -536,5 +490,62 @@ int Sys_SubServerRead(pubsubserver_t *ps) } return 0; } + +pubsubserver_t *Sys_ForkServer(void) +{ + wchar_t exename[256]; + wchar_t curdir[256]; + char cmdline[8192]; + wchar_t wtmp[countof(cmdline)]; + PROCESS_INFORMATION childinfo; + STARTUPINFOW startinfo; + SECURITY_ATTRIBUTES pipesec = {sizeof(pipesec), NULL, TRUE}; + winsubserver_t *ctx = Z_Malloc(sizeof(*ctx)); + + GetModuleFileNameW(NULL, exename, countof(exename)); + GetCurrentDirectoryW(countof(curdir), curdir); + Q_snprintfz(cmdline, sizeof(cmdline), "foo -noreset -clusterslave %s", FS_GetManifestArgs()); //fixme: include which manifest is in use, so configs get set up the same. + + memset(&startinfo, 0, sizeof(startinfo)); + startinfo.cb = sizeof(startinfo); + startinfo.hStdInput = NULL; + startinfo.hStdError = NULL; + startinfo.hStdOutput = NULL; + startinfo.dwFlags |= STARTF_USESTDHANDLES; + + //create pipes for the stdin/stdout. + CreatePipe(&ctx->inpipe, &startinfo.hStdOutput, &pipesec, 0); + CreatePipe(&startinfo.hStdInput, &ctx->outpipe, &pipesec, 0); + + SetHandleInformation(ctx->inpipe, HANDLE_FLAG_INHERIT, 0); + SetHandleInformation(ctx->outpipe, HANDLE_FLAG_INHERIT, 0); + SetHandleInformation(startinfo.hStdOutput, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT); + SetHandleInformation(startinfo.hStdInput, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT); + + CreateProcessW(exename, widen(wtmp, sizeof(wtmp), cmdline), NULL, NULL, TRUE, 0, NULL, curdir, &startinfo, &childinfo); + + //child will close when its pipes are closed. we don't need to hold on to the child process handle. + CloseHandle(childinfo.hProcess); + CloseHandle(childinfo.hThread); + + //these ends of the pipes were inherited by now, so we can discard them in the caller. + CloseHandle(startinfo.hStdOutput); + CloseHandle(startinfo.hStdInput); + + ctx->pub.funcs.InstructSlave = Sys_InstructSlave; + ctx->pub.funcs.SubServerRead = Sys_SubServerRead; + return &ctx->pub; +} + +void SSV_InstructMaster(sizebuf_t *cmd) +{ + //FIXME: this is blocking. this is bad if the target is also blocking while trying to write to us. + HANDLE output = GetStdHandle(STD_OUTPUT_HANDLE); + DWORD written = 0; + cmd->data[0] = cmd->cursize & 0xff; + cmd->data[1] = (cmd->cursize>>8) & 0xff; + WriteFile(output, cmd->data, cmd->cursize, &written, NULL); +} + #endif diff --git a/engine/gl/gl_alias.c b/engine/gl/gl_alias.c index cdb9e5f7..4040ea17 100644 --- a/engine/gl/gl_alias.c +++ b/engine/gl/gl_alias.c @@ -78,6 +78,7 @@ void Mod_FlushSkin(skinid_t id) } void Mod_WipeSkin(skinid_t id) { + //FIXME: skin objects should persist for a frame. skinfile_t *sk; int i; id--; @@ -584,7 +585,7 @@ static shader_t *GL_ChooseSkin(galiasinfo_t *inf, model_t *model, int surfnum, e if (sk->q1lower != Q1UNSPECIFIED) bc = e->bottomcolour = sk->q1lower; if (sk->q1upper != Q1UNSPECIFIED) - bc = e->topcolour = sk->q1upper; + tc = e->topcolour = sk->q1upper; plskin = sk->qwskin; } } diff --git a/engine/gl/gl_font.c b/engine/gl/gl_font.c index 657494e6..a73f29e9 100644 --- a/engine/gl/gl_font.c +++ b/engine/gl/gl_font.c @@ -261,7 +261,7 @@ static texid_t font_texture; static int font_colourmask; static byte_vec4_t font_forecolour; static byte_vec4_t font_backcolour; -static vec4_t font_foretint; +static avec4_t font_foretint; static struct font_s *curfont; static float curfont_scale[2]; @@ -1806,9 +1806,9 @@ void Font_LineDraw(int x, int y, conchar_t *start, conchar_t *end) /*Note: *all* strings after the current one will inherit the same colour, until one changes it explicitly correct usage of this function thus requires calling this with 1111 before Font_EndString*/ -void Font_ForceColour(float r, float g, float b, float a) +void Font_InvalidateColour(vec4_t newcolour) { - if (font_foretint[0] == r && font_foretint[1] == b && font_foretint[2] == b && font_foretint[3] == a) + if (font_foretint[0] == newcolour[0] && font_foretint[1] == newcolour[1] && font_foretint[2] == newcolour[2] && font_foretint[3] == newcolour[3]) return; if (font_colourmask & CON_NONCLEARBG) @@ -1818,20 +1818,13 @@ void Font_ForceColour(float r, float g, float b, float a) } font_colourmask = CON_WHITEMASK; - font_foretint[0] = r; - font_foretint[1] = g; - font_foretint[2] = b; - font_foretint[3] = a; + Vector4Copy(newcolour, font_foretint); Vector4Scale(font_foretint, 255, font_forecolour); font_backcolour[3] = 0; /*Any drawchars that are now drawn will get the forced colour*/ } -void Font_InvalidateColour(void) -{ - Font_ForceColour(1,1,1,1); -} //draw a character from the current font at a pixel location. int Font_DrawChar(int px, int py, unsigned int charflags, unsigned int codepoint) diff --git a/engine/gl/gl_model.c b/engine/gl/gl_model.c index f03d72f3..45b728a7 100644 --- a/engine/gl/gl_model.c +++ b/engine/gl/gl_model.c @@ -1245,6 +1245,8 @@ static const struct static const char *Mod_RemapBuggyTexture(const char *name, const qbyte *data, unsigned int datalen) { unsigned int i; + if (!data) + return NULL; for (i = 0; i < sizeof(buggytextures)/sizeof(buggytextures[0]); i++) { if (!strcmp(name, buggytextures[i].oldname)) @@ -1938,6 +1940,30 @@ void Mod_LoadLighting (model_t *loadmodel, qbyte *mod_base, lump_t *l, qboolean } } #endif + + if (!overrides->shifts) + { + int size; + overrides->shifts = Q1BSPX_FindLump("LMSHIFT", &size); + if (size != loadmodel->numsurfaces) + overrides->shifts = NULL; + + //if we have shifts, then we probably also have legacy data in the surfaces that we want to override + if (!overrides->offsets) + { + int size; + overrides->offsets = Q1BSPX_FindLump("LMOFFSET", &size); + if (size != loadmodel->numsurfaces * sizeof(int)) + overrides->offsets = NULL; + } + if (!overrides->styles) + { + int size; + overrides->styles = Q1BSPX_FindLump("LMSTYLE", &size); + if (size != loadmodel->numsurfaces * sizeof(qbyte)*MAXQ1LIGHTMAPS) + overrides->styles = NULL; + } + } if (luxdata && luxtmp) { diff --git a/engine/gl/gl_shader.c b/engine/gl/gl_shader.c index 025c0479..9580cfe1 100644 --- a/engine/gl/gl_shader.c +++ b/engine/gl/gl_shader.c @@ -5870,7 +5870,7 @@ void Shader_DoReload(void) Con_DPrintf("Reloading shaders\n"); } shader_reload_needed = false; - Font_InvalidateColour(); + R2D_ImageColours(1,1,1,1); Shader_ReloadGenerics(); for (i = 0; i < r_numshaders; i++) diff --git a/engine/http/iwebiface.c b/engine/http/iwebiface.c index 0e89b9f8..bd7cea7d 100644 --- a/engine/http/iwebiface.c +++ b/engine/http/iwebiface.c @@ -119,7 +119,7 @@ static time_t Sys_FileTimeToTime(FILETIME ft) void COM_EnumerateFiles (const char *match, int (*func)(const char *, qofs_t, time_t mtime, void *, searchpathfuncs_t *f), void *parm) { HANDLE r; - WIN32_FIND_DATA fd; + WIN32_FIND_DATAA fd; char apath[MAX_OSPATH]; char file[MAX_OSPATH]; char *s; @@ -135,10 +135,10 @@ void COM_EnumerateFiles (const char *match, int (*func)(const char *, qofs_t, ti *s = '\0'; strcpy(file, match); - r = FindFirstFile(file, &fd); + r = FindFirstFileA(file, &fd); if (r==(HANDLE)-1) return; - go = true; + go = true; do { if (*fd.cFileName == '.'); @@ -153,7 +153,7 @@ void COM_EnumerateFiles (const char *match, int (*func)(const char *, qofs_t, ti go = func(file, fd.nFileSizeLow, Sys_FileTimeToTime(fd.ftLastWriteTime), parm, NULL); } } - while(FindNextFile(r, &fd) && go); + while(FindNextFileA(r, &fd) && go); FindClose(r); } diff --git a/engine/qclib/pr_edict.c b/engine/qclib/pr_edict.c index 9ec7c08e..d4e720d5 100644 --- a/engine/qclib/pr_edict.c +++ b/engine/qclib/pr_edict.c @@ -138,7 +138,7 @@ struct edict_s *PDECL ED_Alloc (pubprogfuncs_t *ppf, pbool object, size_t extras } if (i >= prinst.maxedicts-1) { - int size; + size_t size; char *buf; buf = PR_SaveEnts(&progfuncs->funcs, NULL, &size, 0, 0); progfuncs->funcs.parms->WriteFile("edalloc.dump", buf, size); @@ -577,7 +577,7 @@ char *PR_ValueString (progfuncs_t *progfuncs, etype_t type, eval_t *val, pbool v if (verbose && (unsigned)val->edict < (unsigned)sv_num_edicts) { struct edict_s *ed = EDICT_NUM(progfuncs, val->edict); - int size = strlen(line); + size_t size = strlen(line); if (ed) PR_SaveEnt(&progfuncs->funcs, line, &size, sizeof(line), ed); } @@ -1436,9 +1436,9 @@ cont: } #endif -static void PR_Cat(char *out, const char *in, int *len, int max) +static void PR_Cat(char *out, const char *in, size_t *len, size_t max) { - int newl = strlen(in); + size_t newl = strlen(in); max-=1; if (*len + newl > max) newl = max - *len; //truncate @@ -1462,7 +1462,7 @@ to call ED_CallSpawnFunctions () to let the objects initialize themselves. ================ */ -char *ED_WriteGlobals(progfuncs_t *progfuncs, char *buf, int *bufofs, int bufmax) //switch first. +char *ED_WriteGlobals(progfuncs_t *progfuncs, char *buf, size_t *bufofs, size_t bufmax) //switch first. { #define AddS(str) PR_Cat(buf, str, bufofs, bufmax) int *v; @@ -1604,7 +1604,7 @@ add32: #undef AddS } -char *ED_WriteEdict(progfuncs_t *progfuncs, edictrun_t *ed, char *buf, int *bufofs, int bufmax, pbool q1compatible) +char *ED_WriteEdict(progfuncs_t *progfuncs, edictrun_t *ed, char *buf, size_t *bufofs, size_t bufmax, pbool q1compatible) { #define AddS(str) PR_Cat(buf, str, bufofs, bufmax) fdef_t *d; @@ -1659,7 +1659,7 @@ static char *PR_StaticString(progfuncs_t *progfuncs, string_t thestring) return thestring + progfuncs->funcs.stringtable; } -char *PR_SaveCallStack (progfuncs_t *progfuncs, char *buf, int *bufofs, int bufmax) +char *PR_SaveCallStack (progfuncs_t *progfuncs, char *buf, size_t *bufofs, size_t bufmax) { #define AddS(str) PR_Cat(buf, str, bufofs, bufmax) char buffer[8192]; @@ -1740,7 +1740,7 @@ char *PR_SaveCallStack (progfuncs_t *progfuncs, char *buf, int *bufofs, int bufm //there are two ways of saving everything. //0 is to save just the entities. //1 is to save the entites, and all the progs info so that all the variables are saved off, and it can be reloaded to exactly how it was (provided no files or data has been changed outside, like the progs.dat for example) -char *PDECL PR_SaveEnts(pubprogfuncs_t *ppf, char *buf, int *bufofs, int bufmax, int alldata) +char *PDECL PR_SaveEnts(pubprogfuncs_t *ppf, char *buf, size_t *bufofs, size_t bufmax, int alldata) { progfuncs_t *progfuncs = (progfuncs_t*)ppf; #define AddS(str) PR_Cat(buf, str, bufofs, bufmax) @@ -2388,7 +2388,7 @@ int PDECL PR_LoadEnts(pubprogfuncs_t *ppf, const char *file, float killonspawnfl } //FIXME: maxsize is ignored. -char *PDECL PR_SaveEnt (pubprogfuncs_t *ppf, char *buf, int *size, int maxsize, struct edict_s *ed) +char *PDECL PR_SaveEnt (pubprogfuncs_t *ppf, char *buf, size_t *size, size_t maxsize, struct edict_s *ed) { #define AddS(str) PR_Cat(buf, str, size, maxsize) progfuncs_t *progfuncs = (progfuncs_t*)ppf; @@ -2468,7 +2468,7 @@ char *PDECL PR_SaveEnt (pubprogfuncs_t *ppf, char *buf, int *size, int maxsize, return buf; } -struct edict_s *PDECL PR_RestoreEnt (pubprogfuncs_t *ppf, const char *buf, int *size, struct edict_s *ed) +struct edict_s *PDECL PR_RestoreEnt (pubprogfuncs_t *ppf, const char *buf, size_t *size, struct edict_s *ed) { progfuncs_t *progfuncs = (progfuncs_t*)ppf; edictrun_t *ent; diff --git a/engine/qclib/pr_x86.c b/engine/qclib/pr_x86.c index 9f1f1acc..043bc348 100644 --- a/engine/qclib/pr_x86.c +++ b/engine/qclib/pr_x86.c @@ -62,42 +62,42 @@ struct jitstate unsigned int cachereg; }; -static void EmitByte(struct jitstate *jit, unsigned char byte) +static void Jit_EmitByte(struct jitstate *jit, unsigned char byte) { jit->code[jit->codesize++] = byte; } -static void Emit4Byte(struct jitstate *jit, unsigned int value) +static void Jit_Emit4Byte(struct jitstate *jit, unsigned int value) { jit->code[jit->codesize++] = (value>> 0)&0xff; jit->code[jit->codesize++] = (value>> 8)&0xff; jit->code[jit->codesize++] = (value>>16)&0xff; jit->code[jit->codesize++] = (value>>24)&0xff; } -static void EmitAdr(struct jitstate *jit, void *value) +static void Jit_EmitAdr(struct jitstate *jit, void *value) { - Emit4Byte(jit, (unsigned int)value); + Jit_Emit4Byte(jit, (unsigned int)value); } -static void EmitFloat(struct jitstate *jit, float value) +static void Jit_EmitFloat(struct jitstate *jit, float value) { union {float f; unsigned int i;} u; u.f = value; - Emit4Byte(jit, u.i); + Jit_Emit4Byte(jit, u.i); } -static void Emit2Byte(struct jitstate *jit, unsigned short value) +static void Jit_Emit2Byte(struct jitstate *jit, unsigned short value) { jit->code[jit->codesize++] = (value>> 0)&0xff; jit->code[jit->codesize++] = (value>> 8)&0xff; } -static void EmitFOffset(struct jitstate *jit, void *func, int bias) +static void Jit_EmitFOffset(struct jitstate *jit, const void *func, int bias) { - union {void *f; unsigned int i;} u; + union {const void *f; unsigned int i;} u; u.f = func; u.i -= (unsigned int)&jit->code[jit->codesize+bias]; - Emit4Byte(jit, u.i); + Jit_Emit4Byte(jit, u.i); } -static void Emit4ByteJump(struct jitstate *jit, int statementnum, int offset) +static void Jit_Emit4ByteJump(struct jitstate *jit, int statementnum, int offset) { jit->statementjumps[jit->numjumps++] = jit->codesize; jit->statementjumps[jit->numjumps++] = statementnum; @@ -107,12 +107,16 @@ static void Emit4ByteJump(struct jitstate *jit, int statementnum, int offset) jit->codesize += 4; } +#ifdef _WIN32 +#undef REG_NONE +#endif + enum { REG_EAX, REG_ECX, REG_EDX, - REG_EBX, + REG_EBX, //note: edicttable REG_ESP, REG_EBP, REG_ESI, @@ -133,6 +137,17 @@ enum #define ARGREGS(a,b,c) GCache_Load(jit, op[i].a, a, op[i].b, b, op[i].c, c) #define RESULTREG(r) GCache_Store(jit, op[i].c, r) + +#define EmitByte(v) Jit_EmitByte(jit, v) +#define EmitAdr(v) Jit_EmitAdr(jit, v) +#define EmitFOffset(a,b) Jit_EmitFOffset(jit, a, b) +#define Emit4ByteJump(a,b) Jit_Emit4ByteJump(jit, a, b) +#define Emit4Byte(v) Jit_Emit4Byte(jit, v) +#define EmitFloat(v) Jit_EmitFloat(jit, v) + +#define LocalJmp(v) Jit_LocalJmp(jit, v) +#define LocalLoc() Jit_LocalLoc(jit) + //for the purposes of the cache, 'temp' offsets are only read when they have been written only within the preceeding control block. //if they were read at any other time, then we must write them out in full. //this logic applies only to locals of a function. @@ -187,7 +202,7 @@ static void GCache_Load(struct jitstate *jit, int ao, int ar, int bo, int br, in break; case REG_S0: //flds glob[A] - EmitByte(0xd9);EmitByte(0x05);EmitAdr(jit->glob + op[i].a); + EmitByte(0xd9);EmitByte(0x05);EmitAdr(jit->glob + ao); break; default: LOADREG(jit->glob + ao, ar); @@ -200,7 +215,7 @@ static void GCache_Load(struct jitstate *jit, int ao, int ar, int bo, int br, in break; case REG_S0: //flds glob[A] - EmitByte(0xd9);EmitByte(0x05);EmitAdr(jit->glob + op[i].b); + EmitByte(0xd9);EmitByte(0x05);EmitAdr(jit->glob + bo); break; default: LOADREG(jit->glob + bo, br); @@ -213,7 +228,7 @@ static void GCache_Load(struct jitstate *jit, int ao, int ar, int bo, int br, in break; case REG_S0: //flds glob[A] - EmitByte(0xd9);EmitByte(0x05);EmitAdr(jit->glob + op[i].c); + EmitByte(0xd9);EmitByte(0x05);EmitAdr(jit->glob + co); break; default: LOADREG(jit->glob + co, cr); @@ -241,31 +256,31 @@ static void GCache_Store(struct jitstate *jit, int ofs, int reg) #endif } -static void *LocalLoc(struct jitstate *jit) +static void *Jit_LocalLoc(struct jitstate *jit) { return &jit->code[jit->codesize]; } -static void *LocalJmp(struct jitstate *jit, int cond) +static void *Jit_LocalJmp(struct jitstate *jit, int cond) { /*floating point ops don't set the sign flag, thus we use the 'above/below' instructions instead of 'greater/less' instructions*/ if (cond == OP_GOTO) - EmitByte(jit, 0xeb); //jmp + Jit_EmitByte(jit, 0xeb); //jmp else if (cond == OP_LE_F) - EmitByte(jit, 0x76); //jbe + Jit_EmitByte(jit, 0x76); //jbe else if (cond == OP_GE_F) - EmitByte(jit, 0x73); //jae + Jit_EmitByte(jit, 0x73); //jae else if (cond == OP_LT_F) - EmitByte(jit, 0x72); //jb + Jit_EmitByte(jit, 0x72); //jb else if (cond == OP_GT_F) - EmitByte(jit, 0x77); //ja + Jit_EmitByte(jit, 0x77); //ja else if (cond == OP_LE_I) - EmitByte(jit, 0x7e); //jle + Jit_EmitByte(jit, 0x7e); //jle else if (cond == OP_LT_I) - EmitByte(jit, 0x7c); //jl + Jit_EmitByte(jit, 0x7c); //jl else if ((cond >= OP_NE_F && cond <= OP_NE_FNC) || cond == OP_NE_I) - EmitByte(jit, 0x75); //jne + Jit_EmitByte(jit, 0x75); //jne else if ((cond >= OP_EQ_F && cond <= OP_EQ_FNC) || cond == OP_EQ_I) - EmitByte(jit, 0x74); //je + Jit_EmitByte(jit, 0x74); //je #if defined(DEBUG) && defined(_WIN32) else { @@ -274,9 +289,9 @@ static void *LocalJmp(struct jitstate *jit, int cond) } #endif - EmitByte(jit, 0); + Jit_EmitByte(jit, 0); - return LocalLoc(jit); + return Jit_LocalLoc(jit); } static void LocalJmpLoc(void *jmp, void *loc) { @@ -336,19 +351,96 @@ void PR_CloseJit(struct jitstate *jit) #else free(jit->code); #endif - free(jit) + free(jit); } } -#define EmitByte(v) EmitByte(jit, v) -#define EmitAdr(v) EmitAdr(jit, v) -#define EmitFOffset(a,b) EmitFOffset(jit, a, b) -#define Emit4ByteJump(a,b) Emit4ByteJump(jit, a, b) -#define Emit4Byte(v) Emit4Byte(jit, v) -#define EmitFloat(v) EmitFloat(jit, v) -#define LocalJmp(v) LocalJmp(jit, v) -#define LocalLoc() LocalLoc(jit) +#if 0 +//called from jit code +static PDECL PR_CallFuncion(progfuncs_t *progfuncs, int fnum) +{ + int callerprogs; + int newpr; + unsigned int fnum; + fnum = OPA->function; + + glob = NULL; //try to derestrict it. + + callerprogs=prinst.pr_typecurrent; //so we can revert to the right caller. + newpr = (fnum & 0xff000000)>>24; //this is the progs index of the callee + fnum &= ~0xff000000; //the callee's function index. + + //if it's an external call, switch now (before any function pointers are used) + if (callerprogs != newpr || !fnum || fnum > pr_progs->numfunctions) + { + char *msg = fnum?"OP_CALL references invalid function in %s\n":"NULL function from qc (inside %s).\n"; + PR_SwitchProgsParms(progfuncs, callerprogs); + + glob = pr_globals; + if (!progfuncs->funcs.debug_trace) + QCFAULT(&progfuncs->funcs, msg, PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name)); + + //skip the instruction if they just try stepping over it anyway. + PR_StackTrace(&progfuncs->funcs, 0); + printf(msg, PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name)); + + pr_globals[OFS_RETURN] = 0; + pr_globals[OFS_RETURN+1] = 0; + pr_globals[OFS_RETURN+2] = 0; + break; + } + + newf = &pr_cp_functions[fnum & ~0xff000000]; + + if (newf->first_statement <= 0) + { // negative statements are built in functions + /*calling a builtin in another progs may affect that other progs' globals instead, is the theory anyway, so args and stuff need to move over*/ + if (prinst.pr_typecurrent != 0) + { + //builtins quite hackily refer to only a single global. + //for builtins to affect the globals of other progs, we need to first switch to the progs that it will affect, so they'll be correct when we switch back + PR_SwitchProgsParms(progfuncs, 0); + } + i = -newf->first_statement; +// p = pr_typecurrent; + if (i < externs->numglobalbuiltins) + { +#ifndef QCGC + prinst.numtempstringsstack = prinst.numtempstrings; +#endif + (*externs->globalbuiltins[i]) (&progfuncs->funcs, (struct globalvars_s *)current_progstate->globals); + + //in case ed_alloc was called + num_edicts = sv_num_edicts; + + if (prinst.continuestatement!=-1) + { + st=&pr_statements[prinst.continuestatement]; + prinst.continuestatement=-1; + glob = pr_globals; + break; + } + } + else + { +// if (newf->first_statement == -0x7fffffff) +// ((builtin_t)newf->profile) (progfuncs, (struct globalvars_s *)current_progstate->globals); +// else + PR_RunError (&progfuncs->funcs, "Bad builtin call number - %i", -newf->first_statement); + } +// memcpy(&pr_progstate[p].globals[OFS_RETURN], ¤t_progstate->globals[OFS_RETURN], sizeof(vec3_t)); + PR_SwitchProgsParms(progfuncs, (progsnum_t)callerprogs); + + //decide weather non debugger wants to start debugging. + s = st-pr_statements; + return s; + } +// PR_SwitchProgsParms((OPA->function & 0xff000000)>>24); + s = PR_EnterFunction (progfuncs, newf, callerprogs); + st = &pr_statements[s]; +} +#endif struct jitstate *PR_GenerateJit(progfuncs_t *progfuncs) { @@ -360,15 +452,19 @@ struct jitstate *PR_GenerateJit(progfuncs_t *progfuncs) unsigned int i; dstatement16_t *op = (dstatement16_t*)current_progstate->statements; unsigned int numstatements = current_progstate->progs->numstatements; + unsigned int numglobals = current_progstate->progs->numglobals+3; //vectors are annoying. int *glob = (int*)current_progstate->globals; + unsigned int numfunctions = current_progstate->progs->numfunctions; + mfunction_t *func; +// pbyte *isconst; + pbool failed = false; - if (current_progstate->numbuiltins) - return NULL; jit = malloc(sizeof(*jit)); jit->jitstatements = numstatements; - jit->statementjumps = malloc(numstatements*12); - jit->statementoffsets = malloc(numstatements*4); +// isconst = malloc(numglobals*sizeof(*isconst)); + jit->statementjumps = malloc(numstatements*3*sizeof(int)); + jit->statementoffsets = malloc(numstatements*sizeof(*jit->statementoffsets)); #ifndef _WIN32 jit->code = mmap(NULL, numstatements*500, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); #else @@ -380,14 +476,76 @@ struct jitstate *PR_GenerateJit(progfuncs_t *progfuncs) jit->numjumps = 0; jit->codesize = 0; - - + for (i = 0; i < numstatements; i++) + jit->statementoffsets[i] = NULL; +// for (i = 0; i < numglobals; i++) +// isconst[i] = true; + for (i = 0; i < numfunctions; i++) + { + + } for (i = 0; i < numstatements; i++) { + //figure out which statements are jumped to. these are statements that must flush registers prior to execution. + switch(op[i].op) + { + case OP_GOTO: + jit->statementoffsets[i + (short)op[i].a] = (void*)~0; + break; + case OP_IF_I: + case OP_IFNOT_I: + case OP_IF_F: + case OP_IFNOT_F: + case OP_IF_S: + case OP_IFNOT_S: + case OP_CASE: + jit->statementoffsets[i + (short)op[i].b] = (void*)~0; + break; + case OP_CASERANGE: + jit->statementoffsets[i + (short)op[i].c] = (void*)~0; + break; + } + //we probably can't do anything about consts. + //we might be able to do something about locals, but we would need to fix this to generate per-function. + //we CAN do something about consts, most of them anyway. + //visible types +/* + if (OpAssignsToA(op[i].op)) + { + if (op[i].a >= numglobals) + failed = true; + else + isconst[op[i].a] = false; + } + if (OpAssignsToB(op[i].op)) + { + if (op[i].b >= numglobals) + failed = true; + else + isconst[op[i].b] = false; + } + if (OpAssignsToC(op[i].op)) + { + if (op[i].c >= numglobals) + failed = true; + else + isconst[op[i].c] = false; + } +*/ + } + + for (i = 0; i < numstatements && !failed; i++) + { + if (jit->statementoffsets[i]) + { + //FIXME: flush any registers. + } jit->statementoffsets[i] = &jit->code[jit->codesize]; +#ifdef _DEBUG /*DEBUG*/ SETREGI(op[i].op, REG_ESI); +#endif switch(op[i].op) { @@ -453,7 +611,7 @@ struct jitstate *PR_GenerateJit(progfuncs_t *progfuncs) // movl pr_depth,%edx EmitByte(0x8b);EmitByte(0x15);EmitAdr(&pr_depth); // cmp prinst->exitdepth,%edx - EmitByte(0x3b);EmitByte(0x15);EmitAdr(&prinst->exitdepth); + EmitByte(0x3b);EmitByte(0x15);EmitAdr(&prinst.exitdepth); // je returntoc j1 = LocalJmp(OP_EQ_E); // mov statementoffsets[%eax*4],%eax @@ -485,7 +643,7 @@ struct jitstate *PR_GenerateJit(progfuncs_t *progfuncs) //movl $i, pr_xstatement EmitByte( 0xc7);EmitByte(0x05);EmitAdr(&pr_xstatement);Emit4Byte(i); //movl $(op[i].op-OP_CALL0), pr_argc - EmitByte( 0xc7);EmitByte(0x05);EmitAdr(&pr_argc);Emit4Byte(op[i].op-OP_CALL0); + EmitByte( 0xc7);EmitByte(0x05);EmitAdr(&progfuncs->funcs.callargc);Emit4Byte(op[i].op-OP_CALL0); //figure out who we're calling, and what that involves //%eax = glob[A] @@ -498,6 +656,7 @@ struct jitstate *PR_GenerateJit(progfuncs_t *progfuncs) EmitByte(0xc1); EmitByte(0xe9); EmitByte(0x18); //ecx is now the progs num for the new func +/* //cmp %ecx,pr_typecurrent EmitByte(0x39); EmitByte(0x0d); EmitAdr(&pr_typecurrent); //je sameprogs @@ -522,6 +681,7 @@ struct jitstate *PR_GenerateJit(progfuncs_t *progfuncs) //sameprogs: l1 = LocalLoc(); LocalJmpLoc(j1,l1); +*/ //andl $0x00ffffff, %eax EmitByte(0x25);Emit4Byte(0x00ffffff); @@ -531,7 +691,7 @@ struct jitstate *PR_GenerateJit(progfuncs_t *progfuncs) //mul %edx EmitByte(0xf7); EmitByte(0xe2); //add pr_functions,%eax - EmitByte(0x05); EmitAdr(pr_functions); + EmitByte(0x05); EmitAdr(current_progstate->functions); //eax is now the dfunction_t to be called //edx is clobbered. @@ -579,14 +739,14 @@ struct jitstate *PR_GenerateJit(progfuncs_t *progfuncs) //but that builtin might have been Abort() - LOADREG(&prinst->continuestatement, REG_EAX); + LOADREG(&prinst.continuestatement, REG_EAX); //cmp $-1,%eax EmitByte(0x83);EmitByte(0xf8);EmitByte(0xff); //je donebuiltincall j1 = LocalJmp(OP_EQ_I); { //mov $-1,prinst->continuestatement - EmitByte(0xc7);EmitByte(0x05);EmitAdr(&prinst->continuestatement);Emit4Byte((unsigned int)-1); + EmitByte(0xc7);EmitByte(0x05);EmitAdr(&prinst.continuestatement);Emit4Byte((unsigned int)-1); //jmp statementoffsets[%eax*4] EmitByte(0xff);EmitByte(0x24);EmitByte(0x85);EmitAdr(jit->statementoffsets); @@ -695,18 +855,18 @@ struct jitstate *PR_GenerateJit(progfuncs_t *progfuncs) //edx is now the field array for that ent //mov fieldajust(%edx,%ecx,4),%eax - EmitByte(0x8b); EmitByte(0x84); EmitByte(0x8a); Emit4Byte(progfuncs->fieldadjust*4); + EmitByte(0x8b); EmitByte(0x84); EmitByte(0x8a); Emit4Byte(progfuncs->funcs.fieldadjust*4); STOREREG(REG_EAX, glob + op[i].c) if (op[i].op == OP_LOAD_V) { //mov fieldajust+4(%edx,%ecx,4),%eax - EmitByte(0x8b); EmitByte(0x84); EmitByte(0x8a); Emit4Byte(4+progfuncs->fieldadjust*4); + EmitByte(0x8b); EmitByte(0x84); EmitByte(0x8a); Emit4Byte(4+progfuncs->funcs.fieldadjust*4); STOREREG(REG_EAX, glob + op[i].c+1) //mov fieldajust+8(%edx,%ecx,4),%eax - EmitByte(0x8b); EmitByte(0x84); EmitByte(0x8a); Emit4Byte(8+progfuncs->fieldadjust*4); + EmitByte(0x8b); EmitByte(0x84); EmitByte(0x8a); Emit4Byte(8+progfuncs->funcs.fieldadjust*4); STOREREG(REG_EAX, glob + op[i].c+2) } break; @@ -727,8 +887,8 @@ struct jitstate *PR_GenerateJit(progfuncs_t *progfuncs) EmitByte(0x8b);EmitByte(0x50);EmitByte((int)&((edictrun_t*)NULL)->fields); //edx is now the field array for that ent //mov fieldajust(%edx,%ecx,4),%eax //offset = progfuncs->fieldadjust - //EmitByte(0x8d); EmitByte(0x84); EmitByte(0x8a); EmitByte(progfuncs->fieldadjust*4); - EmitByte(0x8d); EmitByte(0x84); EmitByte(0x8a); Emit4Byte(progfuncs->fieldadjust*4); + //EmitByte(0x8d); EmitByte(0x84); EmitByte(0x8a); EmitByte(progfuncs->funcs.fieldadjust*4); + EmitByte(0x8d); EmitByte(0x84); EmitByte(0x8a); Emit4Byte(progfuncs->funcs.fieldadjust*4); STOREREG(REG_EAX, glob + op[i].c); break; @@ -1385,14 +1545,20 @@ LOADREG(glob + op[i].b, REG_EDI); } - free(jit->statementjumps); //[MAX_STATEMENTS] - free(jit->statementoffsets); //[MAX_STATEMENTS] - free(jit->code); - free(jit); - return NULL; + failed = true; + break; } } + if(1)//failed) + { + free(jit->statementjumps); //[MAX_STATEMENTS] + free(jit->statementoffsets); //[MAX_STATEMENTS] + free(jit->code); + free(jit); + return NULL; + } + FixupJumps(jit); /* most likely want executable memory calls somewhere else more common */ @@ -1413,7 +1579,7 @@ LOADREG(glob + op[i].b, REG_EDI); return jit; } -float foo(float arg) +static float foo(float arg) { float f; if (!arg) @@ -1427,10 +1593,10 @@ void PR_EnterJIT(progfuncs_t *progfuncs, struct jitstate *jit, int statement) { #ifdef __GNUC__ //call, it clobbers pretty much everything. - asm("call *%0" :: "r"(jit->statementoffsets[statement+1]),"b"(prinst->edicttable):"cc","memory","eax","ecx","edx"); + asm("call *%0" :: "r"(jit->statementoffsets[statement+1]),"b"(prinst->edicttable):"cc","memory","eax","ecx","edx","esi","edi"); #elif defined(_MSC_VER) void *entry = jit->statementoffsets[statement+1]; - void *edicttable = prinst->edicttable; + void *edicttable = prinst.edicttable; __asm { pushad mov eax,entry diff --git a/engine/qclib/progsint.h b/engine/qclib/progsint.h index 0fc67e80..481a9d1d 100644 --- a/engine/qclib/progsint.h +++ b/engine/qclib/progsint.h @@ -279,10 +279,10 @@ int PDECL Comp_Continue(pubprogfuncs_t *progfuncs); pbool PDECL PR_SetWatchPoint(pubprogfuncs_t *progfuncs, char *key); char *PDECL PR_EvaluateDebugString(pubprogfuncs_t *progfuncs, char *key); -char *PDECL PR_SaveEnts(pubprogfuncs_t *progfuncs, char *mem, int *size, int maxsize, int mode); +char *PDECL PR_SaveEnts(pubprogfuncs_t *progfuncs, char *mem, size_t *size, size_t maxsize, int mode); int PDECL PR_LoadEnts(pubprogfuncs_t *progfuncs, const char *file, float killonspawnflags); -char *PDECL PR_SaveEnt (pubprogfuncs_t *progfuncs, char *buf, int *size, int maxsize, struct edict_s *ed); -struct edict_s *PDECL PR_RestoreEnt (pubprogfuncs_t *progfuncs, const char *buf, int *size, struct edict_s *ed); +char *PDECL PR_SaveEnt (pubprogfuncs_t *progfuncs, char *buf, size_t *size, size_t maxsize, struct edict_s *ed); +struct edict_s *PDECL PR_RestoreEnt (pubprogfuncs_t *progfuncs, const char *buf, size_t *size, struct edict_s *ed); void PDECL PR_StackTrace (pubprogfuncs_t *progfuncs, int showlocals); extern int noextensions; diff --git a/engine/qclib/progslib.h b/engine/qclib/progslib.h index 84e3c323..00f85f9d 100644 --- a/engine/qclib/progslib.h +++ b/engine/qclib/progslib.h @@ -16,8 +16,10 @@ #define VARGS #endif -#if defined(_M_IX86) || defined(__i386__) -//#define QCJIT +#if defined(_M_IX86) || defined(__i386__) //supported arch + #if defined(__GNUC__) || defined(_MSC_VER) //supported compilers (yay for inline asm) + //#define QCJIT + #endif #endif #define QCBUILTIN ASMCALL @@ -108,11 +110,11 @@ struct pubprogfuncs_s char *(PDECL *filefromnewprogs) (pubprogfuncs_t *prinst, char *prname, char *fname, size_t *size, char *buffer); //reveals encoded/added files from a progs on the disk somewhere void (PDECL *ED_Print) (pubprogfuncs_t *prinst, struct edict_s *ed); - char *(PDECL *save_ents) (pubprogfuncs_t *prinst, char *buf, int *size, int maxsize, int mode); //dump the entire progs info into one big self allocated string + char *(PDECL *save_ents) (pubprogfuncs_t *prinst, char *buf, size_t *size, size_t maxsize, int mode); //dump the entire progs info into one big self allocated string int (PDECL *load_ents) (pubprogfuncs_t *prinst, const char *s, float killonspawnflags); //restore the entire progs state (or just add some more ents) (returns edicts ize) - char *(PDECL *saveent) (pubprogfuncs_t *prinst, char *buf, int *size, int maxsize, struct edict_s *ed); //will save just one entities vars - struct edict_s *(PDECL *restoreent) (pubprogfuncs_t *prinst, const char *buf, int *size, struct edict_s *ed); //will restore the entity that had it's values saved (can use NULL for ed) + char *(PDECL *saveent) (pubprogfuncs_t *prinst, char *buf, size_t *size, size_t maxsize, struct edict_s *ed); //will save just one entities vars + struct edict_s *(PDECL *restoreent) (pubprogfuncs_t *prinst, const char *buf, size_t *size, struct edict_s *ed); //will restore the entity that had it's values saved (can use NULL for ed) union eval_s *(PDECL *FindGlobal) (pubprogfuncs_t *prinst, const char *name, progsnum_t num, etype_t *type); //find a pointer to the globals value char *(PDECL *AddString) (pubprogfuncs_t *prinst, const char *val, int minlength, pbool demarkup); //dump a string into the progs memory (for setting globals and whatnot) diff --git a/engine/qclib/qcc_pr_comp.c b/engine/qclib/qcc_pr_comp.c index 806c0e6c..d182f140 100644 --- a/engine/qclib/qcc_pr_comp.c +++ b/engine/qclib/qcc_pr_comp.c @@ -680,8 +680,14 @@ pbool OpAssignsToC(unsigned int op) return false; <- add STOREP_*?*/ if(op == OP_STOREP_C || op == OP_LOADP_C) return false; + if (op >= OP_STORE_F && op <= OP_STOREP_FNC) + return false; //actually they do. if(op >= OP_MULSTORE_F && op <= OP_SUBSTOREP_V) return false; //actually they do. + if (op >= OP_STORE_I && op <= OP_STORE_FI) + return false; + if (op == OP_BOUNDCHECK || op == OP_UNUSED || op == OP_POP) + return false; return true; } pbool OpAssignsToB(unsigned int op) @@ -698,6 +704,83 @@ pbool OpAssignsToB(unsigned int op) return true; return false; } +#define OpAssignsToA(op) false +int OpAssignsCount(unsigned int op) +{ + switch(op) + { + case OP_DONE: + case OP_RETURN: + return 0; //eep + case OP_CALL0: + case OP_CALL1: + case OP_CALL2: + case OP_CALL3: + case OP_CALL4: + case OP_CALL5: + case OP_CALL6: + case OP_CALL7: + case OP_CALL8: + case OP_CALL1H: + case OP_CALL2H: + case OP_CALL3H: + case OP_CALL4H: + case OP_CALL5H: + case OP_CALL6H: + case OP_CALL7H: + case OP_CALL8H: + return 0; //also, eep. + case OP_STATE: + case OP_CSTATE: + case OP_CWSTATE: + case OP_THINKTIME: + return 0; //egads + case OP_RAND0: + case OP_RAND1: + case OP_RAND2: + case OP_RANDV0: + case OP_RANDV1: + case OP_RANDV2: + case OP_UNUSED: + case OP_POP: + return 0; //FIXME + //branches have no side effects, other than the next instruction (or runaway loop) + case OP_SWITCH_F: + case OP_SWITCH_V: + case OP_SWITCH_S: + case OP_SWITCH_E: + case OP_SWITCH_FNC: + case OP_SWITCH_I: + case OP_GOTO: + case OP_IF_I: + case OP_IFNOT_I: + case OP_IF_S: + case OP_IFNOT_S: + case OP_IF_F: + case OP_IFNOT_F: + case OP_CASE: + case OP_CASERANGE: + return 0; + case OP_BOUNDCHECK: + return 0; + default: //the majority will write c + return 1; + } +} +#ifdef _DEBUG +static void OpAssignsTo_Debug(void) +{ + int i; + for (i = 0; i < OP_NUMREALOPS; i++) + { + if (OpAssignsToA(i) + OpAssignsToB(i) + OpAssignsToC(i) != OpAssignsCount(i)) + { + //we don't know what it assigns to. bug. + QCC_PR_ParseError(0, "opcode %s metadata is bugged", pr_opcodes[i].opname); + } + } +} +#endif /*pbool OpAssignedTo(QCC_def_t *v, unsigned int op) { if(OpAssignsToC(op)) @@ -10394,8 +10477,6 @@ void QCC_CommonSubExpressionRemoval(int first, int last) } */ -#define OpAssignsToA(op) false - //follow branches (by recursing). //stop on first read(error, return statement) or write(no error, return -1) //end-of-block returns 0, done/return/goto returns -2 @@ -13345,5 +13426,9 @@ void QCC_Cleanup(void) pr_cases = NULL; pr_casesdef = NULL; pr_casesdef2 = NULL; + +#ifdef _DEBUG + OpAssignsTo_Debug(); +#endif } #endif diff --git a/engine/server/net_preparse.c b/engine/server/net_preparse.c index 25ca4785..6978b569 100644 --- a/engine/server/net_preparse.c +++ b/engine/server/net_preparse.c @@ -1804,7 +1804,7 @@ void NPP_QWFlush(void) org[0] = (*(short*)&buffer[multicastpos])/8.0f; org[1] = (*(short*)&buffer[multicastpos+2])/8.0f; org[2] = (*(short*)&buffer[multicastpos+4])/8.0f; - count = bound(0, buffer[2]*20, 255); + count = bound(0, buffer[2]*20, 254); //255 is taken to mean an explosion, for some reason. if (minortype == TEQW_LIGHTNINGBLOOD) colour = 225; else diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c index 02299ca1..46bbb186 100644 --- a/engine/server/pr_cmds.c +++ b/engine/server/pr_cmds.c @@ -693,7 +693,7 @@ void PR_LoadGlabalStruct(qboolean muted) static float input_impulse_default; static vec3_t input_angles_default; static vec3_t input_movevalues_default; - static vec3_t global_gravitydir_default; + static vec3_t global_gravitydir_default = {0,0,-1}; int i; int *v; globalptrs_t *pr_globals = pr_global_ptrs; @@ -1115,7 +1115,8 @@ void PR_ApplyCompilation_f (void) { edict_t *ent; char *s; - int len, i; + size_t len; + int i; if (sv.state < ss_active) { Con_Printf("Can't apply: Server isn't running or is still loading\n"); @@ -1248,7 +1249,7 @@ void PR_SSCoreDump_f(void) } { - int size = 1024*1024*8; + size_t size = 1024*1024*8; char *buffer = BZ_Malloc(size); svprogfuncs->save_ents(svprogfuncs, buffer, &size, size, 3); COM_WriteFile("ssqccore.txt", FS_GAMEONLY, buffer, size); @@ -3959,12 +3960,7 @@ void QCBUILTIN PF_precache_vwep_model (pubprogfuncs_t *prinst, struct globalvars G_FLOAT(OFS_RETURN) = 0; return; } -#ifdef VM_Q1 - if (svs.gametype == GT_Q1QVM) - sv.strings.vw_model_precache[i] = s; - else -#endif - sv.strings.vw_model_precache[i] = PR_AddString(prinst, s, 0, false); + sv.strings.vw_model_precache[i] = PR_AddString(prinst, s, 0, false); return; } if (!strcmp(sv.strings.vw_model_precache[i], s)) @@ -8532,16 +8528,31 @@ int PF_ForceInfoKey_Internal(unsigned int entnum, const char *key, const char *v MSG_WriteString (&sv.reliable_datagram, key); MSG_WriteString (&sv.reliable_datagram, Info_ValueForKey(svs.clients[entnum-1].userinfo, key)); +#ifdef NQPROT + if (!strcmp(key, "name")) + { + MSG_WriteByte(&sv.nqreliable_datagram, svc_updatename); + MSG_WriteByte(&sv.nqreliable_datagram, entnum-1); + MSG_WriteString (&sv.nqreliable_datagram, Info_ValueForKey(svs.clients[entnum-1].userinfo, key)); + } + else if (!strcmp(key, "topcolor") || !strcmp(key, "bottomcolor")) + { + int c; + //this sucks, but whatever. + c = (atoi(Info_ValueForKey(svs.clients[entnum-1].userinfo, "topcolor" )) & 0xf)<<4; + c|= (atoi(Info_ValueForKey(svs.clients[entnum-1].userinfo, "bottomcolor")) & 0xf); + MSG_WriteByte(&sv.nqreliable_datagram, svc_updatecolors); + MSG_WriteByte(&sv.nqreliable_datagram, entnum-1); + MSG_WriteByte (&sv.nqreliable_datagram, c); + } +#endif + if (!strcmp(key, "*spectator")) svs.clients[entnum-1].spectator = !!atoi(value); +#ifdef _DEBUG if (!strcmp(key, "*transfer")) - { -#ifdef SUBSERVERS - SSV_InitiatePlayerTransfer(&svs.clients[entnum-1], value); -#else - PF_ForceInfoKey_Internal(entnum, key, ""); + Con_Printf("WARNING: *transfer is no longer supported\n"); #endif - } } return 1; @@ -9205,6 +9216,42 @@ static void QCBUILTIN PF_clusterevent(pubprogfuncs_t *prinst, struct globalvars_ SSV_Send(dest, src, cmd, info); #endif } +static void QCBUILTIN PF_clustertransfer(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) +{ +#ifdef SUBSERVERS + int p = G_EDICT(prinst, OFS_PARM0)->entnum - 1; + const char *dest = (prinst->callargc >= 2)?PR_GetStringOfs(prinst, OFS_PARM1):NULL; + + G_INT(OFS_RETURN) = 0; + + if (p < 0 || p >= sv.allocated_client_slots) + { + PR_BIError (prinst, "PF_clustertransfer: not a player\n"); + return; + } + + if (dest) + { + if (!SSV_IsSubServer()) + { + Con_DPrintf("PF_clustertransfer: not running in mapcluster mode\n", svs.clients[p].transfer, dest); + return; + } + if (svs.clients[p].transfer) + { + Con_DPrintf("PF_clustertransfer: Already transferring to %s, ignoring transfer to %s\n", svs.clients[p].transfer, dest); + return; + } + svs.clients[p].transfer = Z_StrDup(svs.clients[p].transfer); + SSV_InitiatePlayerTransfer(&svs.clients[p], svs.clients[p].transfer); + } + + if (svs.clients[p].transfer) + RETURN_TSTRING(svs.clients[p].transfer); +#else + G_INT(OFS_RETURN) = 0; +#endif +} @@ -9749,7 +9796,8 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"checkcommand", PF_checkcommand, 0, 0, 0, 294, D("float(string name)", "Checks to see if the supplied name is a valid command, cvar, or alias. Returns 0 if it does not exist.")}, {"argescape", PF_argescape, 0, 0, 0, 295, D("string(string s)", "Marks up a string so that it can be reliably tokenized as a single argument later.")}, // {"cvar_setlatch", PF_cvar_setlatch, 0, 0, 0, ???, "void(string cvarname, optional string value)"}, - {"clusterevent", PF_clusterevent, 0, 0, 0, 296, D("void(string dest, string from, string cmd, string info)", "Only functions in mapcluster mode. Sends an event to whichever server the named player is on. The destination server can then dispatch the event to the client or handle it itself via the SV_ParseClusterEvent entrypoint. If dest is empty, the event is broadcast to ALL servers. If the named player can't be found, the event will be returned to this server with the cmd prefixed with 'error:'.")}, + {"clusterevent", PF_clusterevent, 0, 0, 0, 0, D("void(string dest, string from, string cmd, string info)", "Only functions in mapcluster mode. Sends an event to whichever server the named player is on. The destination server can then dispatch the event to the client or handle it itself via the SV_ParseClusterEvent entrypoint. If dest is empty, the event is broadcast to ALL servers. If the named player can't be found, the event will be returned to this server with the cmd prefixed with 'error:'.")}, + {"clustertransfer", PF_clustertransfer, 0, 0, 0, 0, D("string(entity player, optional string newnode)", "Only functions in mapcluster mode. Initiate transfer of the player to a different node. Can take some time. If dest is specified, returns null on error. Otherwise returns the current/new target node (or null if not transferring).")}, {"clearscene", PF_Fixme, 0, 0, 0, 300, D("void()", "Forgets all rentities, polygons, and temporary dlights. Resets all view properties to their default values.")},// (EXT_CSQC) @@ -9797,7 +9845,8 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs //330 {"getstati", PF_Fixme, 0, 0, 0, 330, D("float(float stnum)", "Retrieves the numerical value of the given EV_INTEGER or EV_ENTITY stat (converted to a float).")},// (EXT_CSQC) {"getstatf", PF_Fixme, 0, 0, 0, 331, D("#define getstatbits getstatf\nfloat(float stnum, optional float firstbit, optional float bitcount)", "Retrieves the numerical value of the given EV_FLOAT stat. If firstbit and bitcount are specified, retrieves the upper bits of the STAT_ITEMS stat.")},// (EXT_CSQC) - {"getstats", PF_Fixme, 0, 0, 0, 332, D("string(float firststnum)", "Retrieves the value of the given EV_STRING stat, as a tempstring.\nOlder engines may use 4 consecutive integer stats, with a limit of 15 chars (yes, really. 15.), but "FULLENGINENAME" uses a separate namespace for string stats and has a much higher length limit.")}, + {"getstats", PF_Fixme, 0, 0, 0, 332, D("string(float stnum)", "Retrieves the value of the given EV_STRING stat, as a tempstring.\nOlder engines may use 4 consecutive integer stats, with a limit of 15 chars (yes, really. 15.), but "FULLENGINENAME" uses a separate namespace for string stats and has a much higher length limit.")}, + {"getplayerstat", PF_Fixme, 0, 0, 0, 0, D("__variant(float playernum, float statnum, float stattype)", "Retrieves a specific player's stat, matching the type specified on the server. This builtin is primarily intended for mvd playback where ALL players are known. For EV_ENTITY, world will be returned if the entity is not in the pvs, use type-punning with EV_INTEGER to get the entity number if you just want to see if its set. STAT_ITEMS should be queried as an EV_INTEGER on account of runes and items2 being packed into the upper bits.")}, //EXT_CSQC {"setmodelindex", PF_Fixme, 0, 0, 0, 333, D("void(entity e, float mdlindex)", "Sets a model by precache index instead of by name. Otherwise identical to setmodel.")},// @@ -10757,6 +10806,7 @@ void PR_DumpPlatform_f(void) {"trace_brush_id", "int", QW|NQ|CS}, {"trace_brush_faceid", "int", QW|NQ|CS}, + {"global_gravitydir", "vector", QW|NQ|CS, "The direction gravity should act in if not otherwise specified per entity.", 0,"'0 0 -1'"}, {"serverid", "int", QW|NQ|CS, "The unique id of this server within the server cluster."}, #define comfieldfloat(name,desc) {#name, ".float", FL, desc}, @@ -10928,6 +10978,25 @@ void PR_DumpPlatform_f(void) {"GE_ABSMAX", "const float", CS, "Valid for getentity. Guesses the entity's .absmax vector.", GE_ABSMAX}, // {"GE_LIGHT", "const float", CS, NULL, GE_LIGHT}, + {"GE_MODELINDEX", "const float", CS, "Valid for getentity. Guesses the entity's .modelindex float.", GE_MODELINDEX}, + {"GE_MODELINDEX2", "const float", CS, "Valid for getentity. Guesses the entity's .vw_index float.", GE_MODELINDEX2}, + {"GE_EFFECTS", "const float", CS, "Valid for getentity. Guesses the entity's .effects float.", GE_EFFECTS}, + {"GE_FRAME", "const float", CS, "Valid for getentity. Guesses the entity's .frame float.", GE_FRAME}, + {"GE_ANGLES", "const float", CS, "Valid for getentity. Guesses the entity's .angles vector.", GE_ANGLES}, + {"GE_FATNESS", "const float", CS, "Valid for getentity. Guesses the entity's .fatness float.", GE_FATNESS}, + {"GE_DRAWFLAGS", "const float", CS, "Valid for getentity. Guesses the entity's .drawflags float.", GE_DRAWFLAGS}, + {"GE_ABSLIGHT", "const float", CS, "Valid for getentity. Guesses the entity's .abslight float.", GE_ABSLIGHT}, + {"GE_GLOWMOD", "const float", CS, "Valid for getentity. Guesses the entity's .glowmod vector.", GE_GLOWMOD}, + {"GE_GLOWSIZE", "const float", CS, "Valid for getentity. Guesses the entity's .glowsize float.", GE_GLOWSIZE}, + {"GE_GLOWCOLOUR", "const float", CS, "Valid for getentity. Guesses the entity's .glowcolor float.", GE_GLOWCOLOUR}, + {"GE_RTSTYLE", "const float", CS, "Valid for getentity. Guesses the entity's .style float.", GE_RTSTYLE}, + {"GE_RTPFLAGS", "const float", CS, "Valid for getentity. Guesses the entity's .pflags float.", GE_RTPFLAGS}, + {"GE_RTCOLOUR", "const float", CS, "Valid for getentity. Guesses the entity's .color vector.", GE_RTCOLOUR}, + {"GE_RTRADIUS", "const float", CS, "Valid for getentity. Guesses the entity's .light_lev float.", GE_RTRADIUS}, + {"GE_TAGENTITY", "const float", CS, "Valid for getentity. Guesses the entity's .tag_entity float.", GE_TAGENTITY}, + {"GE_TAGINDEX", "const float", CS, "Valid for getentity. Guesses the entity's .tag_index float.", GE_TAGINDEX}, + {"GE_GRAVITYDIR", "const float", CS, "Valid for getentity. Guesses the entity's .gravitydir vector.", GE_GRAVITYDIR}, + {"GE_TRAILEFFECTNUM","const float",CS, "Valid for getentity. Guesses the entity's .traileffectnum float.", GE_TRAILEFFECTNUM}, {"DAMAGE_NO", "const float", QW|NQ, NULL, DAMAGE_NO}, {"DAMAGE_YES", "const float", QW|NQ, NULL, DAMAGE_YES}, diff --git a/engine/server/pr_q1qvm.c b/engine/server/pr_q1qvm.c index 3341222a..f8e8001d 100755 --- a/engine/server/pr_q1qvm.c +++ b/engine/server/pr_q1qvm.c @@ -228,11 +228,19 @@ typedef enum typedef struct { - string_t name; + quintptr_t name; int ofs; fieldtype_t type; // int flags; -} field_t; +} fieldN_t; + +typedef struct +{ + unsigned int name; + int ofs; + fieldtype_t type; +// int flags; +} field32_t; @@ -296,22 +304,33 @@ typedef struct { //this is not directly usable in 64bit to refer to a 32bit qvm (hence why we have two versions). typedef struct { - struct vmedict_s *ents; - int sizeofent; - q1qvmglobalvars_t *global; - field_t *fields; - int APIversion; -} gameDataN_t; + unsigned int APIversion; + unsigned int sizeofent; + unsigned int maxedicts; + + quintptr_t global; + quintptr_t fields; + quintptr_t ents; +} gameDataPrivate_t; typedef struct { unsigned int ents; - int sizeofent; + int sizeofent; unsigned int global; unsigned int fields; - int APIversion; + int APIversion; } gameData32_t; +typedef struct +{ + quintptr_t ents; + int sizeofent; + quintptr_t global; + quintptr_t fields; + int APIversion; +} gameDataN_t; + typedef enum { FS_READ_BIN, FS_READ_TXT, @@ -354,7 +373,7 @@ static pubprogfuncs_t q1qvmprogfuncs; static void *evars; //pointer to the gamecodes idea of an edict_t -static qintptr_t vevars; //offset into the vm base of evars +static quintptr_t vevars; //offset into the vm base of evars /* static char *Q1QVMPF_AddString(pubprogfuncs_t *pf, char *base, int minlength) @@ -485,8 +504,22 @@ static int QDECL Q1QVMPF_LoadEnts(pubprogfuncs_t *pf, const char *mapstring, flo return sv.world.edict_size; } +static int QDECL Q1QVMPF_QueryField(pubprogfuncs_t *prinst, unsigned int fieldoffset, etype_t *type, char **name, evalc_t *fieldcache) +{ + *type = ev_void; + *name = "?"; + + fieldcache->varname = NULL; + fieldcache->spare[0] = fieldoffset; + return true; +} + static eval_t *QDECL Q1QVMPF_GetEdictFieldValue(pubprogfuncs_t *pf, edict_t *e, char *fieldname, evalc_t *cache) { + if (cache && !cache->varname) + { + return (eval_t*)((char*)e->v + cache->spare[0]-WASTED_EDICT_T_SIZE); + } if (!strcmp(fieldname, "message")) { return (eval_t*)&e->v->message; @@ -506,17 +539,31 @@ static globalvars_t *QDECL Q1QVMPF_Globals(pubprogfuncs_t *prinst, int prnum) static string_t QDECL Q1QVMPF_StringToProgs(pubprogfuncs_t *prinst, const char *str) { - string_t ret = (string_t)(str - (char*)VM_MemoryBase(q1qvm)); + quintptr_t ret = (str - (char*)VM_MemoryBase(q1qvm)); if (ret >= VM_MemoryMask(q1qvm)) return 0; + 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; return ret; } static const char *ASMCALL QDECL Q1QVMPF_StringToNative(pubprogfuncs_t *prinst, string_t str) { - char *ret = (char*)VM_MemoryBase(q1qvm) + str; - if (!ret) //qvms can never return a null. make sure native code can't crash things either. - return ""; + char *ret; + if (str == ~0) + return " "; //models are weird. yes, this is a hack. + if (!str || (quintptr_t)str >= VM_MemoryMask(q1qvm)) + return ""; //null or invalid pointers. + ret = (char*)VM_MemoryBase(q1qvm) + str; return ret; } @@ -851,13 +898,25 @@ static qintptr_t QVM_SetSpawnParams (void *offset, quintptr_t mask, const qintpt } static qintptr_t QVM_ChangeLevel (void *offset, quintptr_t mask, const qintptr_t *arg) { - WrapQCBuiltin(PF_changelevel, offset, mask, arg, "s"); - return 0; + char newmap[MAX_QPATH]; + if (sv.mapchangelocked) + return 0; + sv.mapchangelocked = true; + COM_QuotedString(VM_POINTER(arg[0]), newmap, sizeof(newmap), false); + Cbuf_AddText (va("\nchangelevel %s\n", newmap), RESTRICT_LOCAL); + return 1; } static qintptr_t QVM_ChangeLevel2 (void *offset, quintptr_t mask, const qintptr_t *arg) { - WrapQCBuiltin(PF_changelevel, offset, mask, arg, "ss"); - return 0; + char newmap[MAX_QPATH]; + char startspot[MAX_QPATH]; + if (sv.mapchangelocked) + return 0; + sv.mapchangelocked = true; + COM_QuotedString(VM_POINTER(arg[0]), newmap, sizeof(newmap), false); + COM_QuotedString(VM_POINTER(arg[1]), startspot, sizeof(startspot), false); + Cbuf_AddText (va("\nchangelevel %s %s\n", newmap, startspot), RESTRICT_LOCAL); + return 1; } static qintptr_t QVM_LogFrag (void *offset, quintptr_t mask, const qintptr_t *arg) { @@ -866,9 +925,31 @@ static qintptr_t QVM_LogFrag (void *offset, quintptr_t mask, const qintptr_t *ar } static qintptr_t QVM_Precache_VWep_Model (void *offset, quintptr_t mask, const qintptr_t *arg) { - int i = WrapQCBuiltin(PF_precache_vwep_model, offset, mask, arg, "s"); - float f = *(float*)&i; - return f; + 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; } static qintptr_t QVM_GetInfoKey (void *offset, quintptr_t mask, const qintptr_t *arg) { @@ -1492,6 +1573,27 @@ static qintptr_t QVM_pointparticles (void *offset, quintptr_t mask, const qintpt return WrapQCBuiltin(PF_sv_pointparticles, offset, mask, arg, "ivvi"); } +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; +} + static qintptr_t QVM_Map_Extension (void *offset, quintptr_t mask, const qintptr_t *arg); typedef qintptr_t (*traps_t) (void *offset, quintptr_t mask, const qintptr_t *arg); @@ -1607,6 +1709,8 @@ struct {"particleeffectnum", QVM_particleeffectnum}, {"trailparticles", QVM_trailparticles}, {"pointparticles", QVM_pointparticles}, + {"clientstat", QVM_clientstat}, //csqc extension + {"pointerstat", QVM_pointerstat}, //csqc extension //sql? //model querying? @@ -1717,6 +1821,7 @@ void Q1QVM_Shutdown(void) Z_Free(q1qvmprogfuncs.edicttable); q1qvmprogfuncs.edicttable = NULL; } + vevars = 0; } } @@ -1751,8 +1856,13 @@ void QDECL Q1QVMPF_SetStringField(pubprogfuncs_t *progfuncs, struct edict_s *ed, string_t newval = progfuncs->StringToProgs(progfuncs, str); if (newval || !str) *fld = newval; + else if (!str) + *fld = 0; else - Con_DPrintf("Ignoring string set outside of progs VM\n"); + { + *fld = ~0; +// Con_DPrintf("Ignoring string set outside of progs VM\n"); + } } qboolean PR_LoadQ1QVM(void) @@ -1764,8 +1874,10 @@ qboolean PR_LoadQ1QVM(void) static float physics_mode = 2; static vec3_t defaultgravity = {0,0,-1}; int i; - gameDataN_t *gd, gdm; + gameDataPrivate_t gd; + gameDataN_t *gdn; gameData32_t *gd32; + q1qvmglobalvars_t *global; qintptr_t ret; qintptr_t limit; extern cvar_t pr_maxedicts; @@ -1807,6 +1919,7 @@ qboolean PR_LoadQ1QVM(void) q1qvmprogfuncs.load_ents = Q1QVMPF_LoadEnts; q1qvmprogfuncs.globals = Q1QVMPF_Globals; q1qvmprogfuncs.GetEdictFieldValue = Q1QVMPF_GetEdictFieldValue; + q1qvmprogfuncs.QueryField = Q1QVMPF_QueryField; q1qvmprogfuncs.StringToProgs = Q1QVMPF_StringToProgs; q1qvmprogfuncs.StringToNative = Q1QVMPF_StringToNative; q1qvmprogfuncs.SetStringField = Q1QVMPF_SetStringField; @@ -1834,48 +1947,63 @@ qboolean PR_LoadQ1QVM(void) } if (VM_NonNative(q1qvm)) - { + { //when non native, this can only be a 32bit qvm in a 64bit server. gd32 = (gameData32_t*)((char*)VM_MemoryBase(q1qvm) + ret); //qvm is 32bit - //when running native64, we need to convert these to real types, so we can use em below - //double casts to silence warnings - gd = &gdm; - gd->ents = (struct vmedict_s *)(qintptr_t)gd32->ents; - gd->sizeofent = gd32->sizeofent; - gd->global = (q1qvmglobalvars_t *)(qintptr_t)gd32->global; - gd->fields = (field_t *)(qintptr_t)gd32->fields; - gd->APIversion = gd32->APIversion; + gd.APIversion = gd32->APIversion; + gd.sizeofent = gd32->sizeofent; + + gd.ents = gd32->ents; + gd.global = gd32->global; + gd.fields = gd32->fields; + + gd.maxedicts = pr_maxedicts.ival; //FIXME } else { - gd = (gameDataN_t*)((char*)VM_MemoryBase(q1qvm) + ret); //qvm is 32bit + gdn = (gameDataN_t*)((char*)VM_MemoryBase(q1qvm) + ret); + gd.APIversion = gdn->APIversion; + gd.sizeofent = gdn->sizeofent; + + gd.ents = gdn->ents; + gd.global = gdn->global; + gd.fields = gdn->fields; + + gd.maxedicts = pr_maxedicts.ival; //FIXME } sv.world.num_edicts = 1; - sv.world.max_edicts = bound(64, pr_maxedicts.ival, MAX_EDICTS); + sv.world.max_edicts = bound(64, gd.maxedicts, MAX_EDICTS); q1qvmprogfuncs.edicttable = Z_Malloc(sizeof(*q1qvmprogfuncs.edicttable) * sv.world.max_edicts); limit = VM_MemoryMask(q1qvm); - if (gd->sizeofent < 0 || gd->sizeofent > (0xffffffff-(qintptr_t)gd->ents) / sv.world.max_edicts) - gd->sizeofent = 0xffffffff / MAX_EDICTS; - if ((quintptr_t)gd->ents+(gd->sizeofent*MAX_Q1QVM_EDICTS) < (quintptr_t)gd->ents || (quintptr_t)gd->ents > (quintptr_t)limit) - gd->ents = NULL; - if ((quintptr_t)(gd->global+1) < (quintptr_t)gd->global || (quintptr_t)gd->global > (quintptr_t)limit) - gd->global = NULL; - if (/*(quintptr_t)gd->fields < (quintptr_t)gd->fields ||*/ (quintptr_t)gd->fields > limit) - gd->fields = NULL; + if (gd.sizeofent < 0 || gd.sizeofent > 0xffffffff / gd.maxedicts) + 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 = (qintptr_t)gd->ents; - evars = ((char*)VM_MemoryBase(q1qvm) + vevars); + sv.world.edict_size = gd.sizeofent; + vevars = gd.ents; + evars = Q1QVMPF_PointerToNative(&q1qvmprogfuncs, vevars); + global = Q1QVMPF_PointerToNative(&q1qvmprogfuncs, gd.global); + + if (!evars || !global) + { + Q1QVM_Shutdown(); + return false; + } //WARNING: global is not remapped yet... //This code is written evilly, but works well enough -#define globalint(required, name) pr_global_ptrs->name = (int*)((char*)VM_MemoryBase(q1qvm)+(qintptr_t)&gd->global->name) //the logic of this is somewhat crazy -#define globalfloat(required, name) pr_global_ptrs->name = (float*)((char*)VM_MemoryBase(q1qvm)+(qintptr_t)&gd->global->name) -#define globalstring(required, name) pr_global_ptrs->name = (string_t*)((char*)VM_MemoryBase(q1qvm)+(qintptr_t)&gd->global->name) -#define globalvec(required, name) pr_global_ptrs->name = (vec3_t*)((char*)VM_MemoryBase(q1qvm)+(qintptr_t)&gd->global->name) -#define globalfunc(required, name) pr_global_ptrs->name = (int*)((char*)VM_MemoryBase(q1qvm)+(qintptr_t)&gd->global->name) +#define globalint(required, name) pr_global_ptrs->name = Q1QVMPF_PointerToNative(&q1qvmprogfuncs, (qintptr_t)&global->name) //the logic of this is somewhat crazy +#define globalfloat(required, name) pr_global_ptrs->name = Q1QVMPF_PointerToNative(&q1qvmprogfuncs, (qintptr_t)&global->name) +#define globalstring(required, name) pr_global_ptrs->name = Q1QVMPF_PointerToNative(&q1qvmprogfuncs, (qintptr_t)&global->name) +#define globalvec(required, name) pr_global_ptrs->name = Q1QVMPF_PointerToNative(&q1qvmprogfuncs, (qintptr_t)&global->name) +#define globalfunc(required, name) pr_global_ptrs->name = Q1QVMPF_PointerToNative(&q1qvmprogfuncs, (qintptr_t)&global->name) #define globalfloatnull(required, name) pr_global_ptrs->name = NULL 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); @@ -1937,27 +2065,42 @@ qboolean PR_LoadQ1QVM(void) dimensionsend = dimensiondefault = 255; for (i = 0; i < 16; i++) - pr_global_ptrs->spawnparamglobals[i] = (float*)((char*)VM_MemoryBase(q1qvm)+(qintptr_t)(&gd->global->parm1 + i)); + pr_global_ptrs->spawnparamglobals[i] = (float*)((char*)VM_MemoryBase(q1qvm)+(qintptr_t)(&global->parm1 + i)); for (; i < NUM_SPAWN_PARMS; i++) pr_global_ptrs->spawnparamglobals[i] = NULL; - for (i = 0; gd->fields[i].name; i++) +#define emufield(n,t) if (field[i].type == t && !strcmp(#n, fname)) {fofs.n = (field[i].ofs - WASTED_EDICT_T_SIZE)/sizeof(float); continue;} + if (VM_NonNative(q1qvm)) { - const char *fname = Q1QVMPF_StringToNative(&q1qvmprogfuncs, gd->fields[i].name); -#define emufield(n,t) if (gd->fields[i].type == t && !strcmp(#n, fname)) {fofs.n = (gd->fields[i].ofs - WASTED_EDICT_T_SIZE)/sizeof(float); continue;} - emufields -#undef emufield + 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 + } } + 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 + } + } +#undef emufield sv.world.progs = &q1qvmprogfuncs; sv.world.edicts = (wedict_t*)Q1QVMPF_EdictNum(svprogfuncs, 0); sv.world.usesolidcorpse = true; - if ((unsigned)gd->global->mapname && (unsigned)gd->global->mapname+MAPNAME_LEN < VM_MemoryMask(q1qvm)) - Q_strncpyz((char*)VM_MemoryBase(q1qvm) + gd->global->mapname, svs.name, MAPNAME_LEN); + if ((quintptr_t)global->mapname && (quintptr_t)global->mapname+MAPNAME_LEN < VM_MemoryMask(q1qvm)) + Q_strncpyz((char*)VM_MemoryBase(q1qvm) + global->mapname, svs.name, MAPNAME_LEN); else - gd->global->mapname = Q1QVMPF_StringToProgs(sv.world.progs, svs.name); + global->mapname = Q1QVMPF_StringToProgs(sv.world.progs, svs.name); PR_SV_FillWorldGlobals(&sv.world); return true; @@ -1981,7 +2124,7 @@ void Q1QVM_ClientConnect(client_t *cl) cl->name = cl->namebuf; cl->edict->v->netname = Q1QVMPF_StringToProgs(svprogfuncs, cl->namebuf); - Con_DPrintf("WARNING: Mod provided no netname buffer and will not function correctly when compiled as a qvm.\n"); +// Con_DPrintf("WARNING: Mod provided no netname buffer and will not function correctly when compiled as a qvm.\n"); } else Con_Printf("WARNING: Mod provided no netname buffer. Player names will not be set properly.\n"); diff --git a/engine/server/savegame.c b/engine/server/savegame.c index a0c02949..482f3929 100644 --- a/engine/server/savegame.c +++ b/engine/server/savegame.c @@ -350,7 +350,7 @@ void SV_Loadgame_Legacy(char *filename, vfsfile_t *f, int version) void SV_LegacySavegame_f (void) { - int len; + size_t len; char *s = NULL; client_t *cl; int clnum; @@ -550,7 +550,8 @@ qboolean SV_LoadLevelCache(char *savename, char *level, char *startspot, qboolea char mapname[MAX_QPATH]; float time; char str[32768]; - int i,j; + int i; + size_t j; edict_t *ent; int version; @@ -848,7 +849,7 @@ qboolean SV_LoadLevelCache(char *savename, char *level, char *startspot, qboolea void SV_SaveLevelCache(char *savedir, qboolean dontharmgame) { - int len; + size_t len; char *s; client_t *cl; int clnum; diff --git a/engine/server/server.h b/engine/server/server.h index ac4b9fc0..ae25b76d 100644 --- a/engine/server/server.h +++ b/engine/server/server.h @@ -407,6 +407,7 @@ typedef struct client_s int challenge; int userid; // identifying number char userinfo[EXTENDED_INFO_STRING]; // infostring + char *transfer; usercmd_t lastcmd; // for filling in big drops and partial predictions double localtime; // of last message @@ -1057,6 +1058,12 @@ void SV_FixupName(char *in, char *out, unsigned int outlen); //cluster stuff typedef struct pubsubserver_s { + struct + { + void (*InstructSlave)(struct pubsubserver_s *ps, sizebuf_t *cmd); //send to + int (*SubServerRead)(struct pubsubserver_s *ps); //read from. fills up net_message + } funcs; + struct pubsubserver_s *next; unsigned int id; char name[64]; @@ -1073,8 +1080,6 @@ void SSV_ReadFromControlServer(void); void SSV_SavePlayerStats(client_t *cl, int reason); //initial, periodic (in case of node crashes), part void SSV_RequestShutdown(void); //asks the cluster to not send us new players -void Sys_InstructSlave(pubsubserver_t *s, sizebuf_t *cmd); -int Sys_SubServerRead(pubsubserver_t *s); //1: yes. 0: no. -1: error pubsubserver_t *Sys_ForkServer(void); #define SSV_IsSubServer() isClusterSlave diff --git a/engine/server/sv_ccmds.c b/engine/server/sv_ccmds.c index 2529c105..d75445ef 100644 --- a/engine/server/sv_ccmds.c +++ b/engine/server/sv_ccmds.c @@ -736,7 +736,7 @@ void SV_Map_f (void) if (preserveplayers && svprogfuncs && host_client->state == cs_spawned && host_client->spawninfo) { - int j = 0; + size_t j = 0; svprogfuncs->restoreent(svprogfuncs, host_client->spawninfo, &j, host_client->edict); host_client->istobeloaded = true; host_client->state=cs_connected; @@ -871,7 +871,7 @@ void SV_EvaluatePenalties(client_t *cl) { bannedips_t *banip; unsigned int penalties = 0, delta, p; - char *penaltyreason[countof(banflags)]; + char *penaltyreason[countof(banflags)] = {NULL}; const char *activepenalties[countof(banflags)]; char *reasons[countof(banflags)] = {NULL}; int numpenalties = 0; @@ -923,8 +923,8 @@ void SV_EvaluatePenalties(client_t *cl) if ((penalties & (BAN_BAN | BAN_PERMIT)) == BAN_BAN) { //we should only reach here by a player getting banned mid-game. - if (penaltyreason[0]) - SV_BroadcastPrintf(PRINT_HIGH, "%s was banned: %s\n", cl->name, penaltyreason[0]); + if (penaltyreason[BAN_BAN]) + SV_BroadcastPrintf(PRINT_HIGH, "%s was banned: %s\n", cl->name, penaltyreason[BAN_BAN]); else SV_BroadcastPrintf(PRINT_HIGH, "%s was banned\n", cl->name); cl->drop = true; diff --git a/engine/server/sv_cluster.c b/engine/server/sv_cluster.c index 4b0acfe6..1a7e04bc 100644 --- a/engine/server/sv_cluster.c +++ b/engine/server/sv_cluster.c @@ -101,7 +101,7 @@ pubsubserver_t *MSV_StartSubServer(unsigned int id, const char *mapname) MSG_WriteByte(&send, ccmd_acceptserver); MSG_WriteLong(&send, s->id); MSG_WriteString(&send, s->name); - Sys_InstructSlave(s, &send); + s->funcs.InstructSlave(s, &send); } return s; } @@ -185,13 +185,13 @@ void MSV_InstructSlave(unsigned int id, sizebuf_t *cmd) if (!id) { for (s = subservers; s; s = s->next) - Sys_InstructSlave(s, cmd); + s->funcs.InstructSlave(s, cmd); } else { s = MSV_FindSubServer(id); if (s) - Sys_InstructSlave(s, cmd); + s->funcs.InstructSlave(s, cmd); } } @@ -381,7 +381,7 @@ void MSV_ReadFromSubServer(pubsubserver_t *s) MSG_WriteByte(&send, ccmd_transferedplayer); MSG_WriteLong(&send, s->id); MSG_WriteLong(&send, plid); - Sys_InstructSlave(pl->server, &send); + pl->server->funcs.InstructSlave(pl->server, &send); } pl->server = s; break; @@ -431,7 +431,7 @@ void MSV_ReadFromSubServer(pubsubserver_t *s) while(c--) MSG_WriteFloat(&send, MSG_ReadFloat()); - Sys_InstructSlave(toptr, &send); + toptr->funcs.InstructSlave(toptr, &send); } else { @@ -447,7 +447,7 @@ void MSV_ReadFromSubServer(pubsubserver_t *s) MSG_WriteLong(&send, plid); MSG_WriteString(&send, ""); - Sys_InstructSlave(s, &send); + s->funcs.InstructSlave(s, &send); } } break; @@ -534,21 +534,21 @@ void MSV_ReadFromSubServer(pubsubserver_t *s) if (!*dest) //broadcast if no dest { for (s = subservers; s; s = s->next) - Sys_InstructSlave(s, &send); + s->funcs.InstructSlave(s, &send); } else if (*dest == '\\') { //send to a specific server (backslashes should not be valid in infostrings, and thus not in names. //FIXME: broadcasting for now. for (s = subservers; s; s = s->next) - Sys_InstructSlave(s, &send); + s->funcs.InstructSlave(s, &send); } else { //send it to the server that the player is currently on. clusterplayer_t *pl = MSV_FindPlayerName(dest); if (pl) - Sys_InstructSlave(pl->server, &send); + pl->server->funcs.InstructSlave(pl->server, &send); else if (!pl && strncmp(cmd, "error:", 6)) { //player not found. send it back to the sender, but add an error prefix. @@ -559,7 +559,7 @@ void MSV_ReadFromSubServer(pubsubserver_t *s) SZ_Write(&send, "error:", 6); MSG_WriteString(&send, cmd); MSG_WriteString(&send, info); - Sys_InstructSlave(s, &send); + s->funcs.InstructSlave(s, &send); } } } @@ -574,7 +574,7 @@ void MSV_PollSlaves(void) pubsubserver_t **link, *s; for (link = &subservers; (s=*link); ) { - switch(Sys_SubServerRead(s)) + switch(s->funcs.SubServerRead(s)) { case -1: //error - server is dead and needs to be freed. @@ -644,7 +644,8 @@ void SSV_ReadFromControlServer(void) if (!*addr) { Con_Printf("%s: tookplayer: failed\n", sv.modelname); - Info_SetValueForStarKey(cl->userinfo, "*transfer", "", sizeof(cl->userinfo)); + Z_Free(cl->transfer); + cl->transfer = NULL; } else { @@ -662,7 +663,6 @@ void SSV_ReadFromControlServer(void) case ccmd_transferedplayer: { client_t *cl; - char *to; int toserver = MSG_ReadLong(); int playerid = MSG_ReadLong(); int i; @@ -673,8 +673,7 @@ void SSV_ReadFromControlServer(void) { cl = &svs.clients[i]; cl->drop = true; - to = Info_ValueForKey(cl->userinfo, "*transfer"); - Con_Printf("%s transfered to %s\n", cl->name, to); + Con_Printf("%s transfered to %s\n", cl->name, cl->transfer); break; } } @@ -850,7 +849,6 @@ void SSV_UpdateAddresses(void) void SSV_SavePlayerStats(client_t *cl, int reason) { - //called when the *transfer userinfo gets set to the new map sizebuf_t send; qbyte send_buf[MAX_QWMSGLEN]; int i; @@ -878,7 +876,6 @@ void SSV_SavePlayerStats(client_t *cl, int reason) } void SSV_Send(const char *dest, const char *src, const char *cmd, const char *msg) { - //called when the *transfer userinfo gets set to the new map sizebuf_t send; qbyte send_buf[MAX_QWMSGLEN]; if (!SSV_IsSubServer()) @@ -899,7 +896,6 @@ void SSV_Send(const char *dest, const char *src, const char *cmd, const char *ms } void SSV_InitiatePlayerTransfer(client_t *cl, const char *newserver) { - //called when the *transfer userinfo gets set to the new map sizebuf_t send; qbyte send_buf[MAX_QWMSGLEN]; int i; @@ -1005,7 +1001,7 @@ qboolean MSV_ClusterLoginReply(netadr_t *legacyclientredirect, unsigned int serv MSG_WriteByte(&send, statsblobsize/4); SZ_Write(&send, statsblob, statsblobsize&~3); - Sys_InstructSlave(s, &send); + s->funcs.InstructSlave(s, &send); if (serveraddr.type == NA_INVALID) { diff --git a/engine/server/sv_ents.c b/engine/server/sv_ents.c index 2efbb1af..ae0233fc 100644 --- a/engine/server/sv_ents.c +++ b/engine/server/sv_ents.c @@ -1328,7 +1328,37 @@ void SVFTE_EmitPacketEntities(client_t *client, packet_entities_t *to, sizebuf_t if (msg->cursize + 50 > msg->maxsize) break; /*give up if it gets full*/ if (outno >= outmax) + { //expand the frames. may need some copying... + client_frame_t *newframes; + char *ptr; + int maxents = outmax * 2; /*this is the max number of ents updated per frame. we can't track more, so...*/ + if (maxents > client->max_net_ents) + maxents = client->max_net_ents; + ptr = Z_Malloc( sizeof(client_frame_t)*UPDATE_BACKUP+ + sizeof(*client->pendingentbits)*client->max_net_ents+ + sizeof(unsigned int)*maxents*UPDATE_BACKUP+ + sizeof(unsigned int)*maxents*UPDATE_BACKUP); + newframes = (void*)ptr; + memcpy(newframes, client->frameunion.frames, sizeof(client_frame_t)*UPDATE_BACKUP); + ptr += sizeof(client_frame_t)*UPDATE_BACKUP; + memcpy(ptr, client->pendingentbits, sizeof(*client->pendingentbits)*client->max_net_ents); + client->pendingentbits = (void*)ptr; + ptr += sizeof(*client->pendingentbits)*client->max_net_ents; + for (i = 0; i < UPDATE_BACKUP; i++) + { + newframes[i].entities.max_entities = maxents; + newframes[i].resendentnum = (void*)ptr; + memcpy(newframes[i].resendentnum, client->frameunion.frames[i].resendentnum, sizeof(unsigned int)*client->frameunion.frames[i].entities.num_entities); + ptr += sizeof(*newframes[i].resendentnum)*maxents; + newframes[i].resendentbits = (void*)ptr; + memcpy(newframes[i].resendentbits, client->frameunion.frames[i].resendentbits, sizeof(unsigned int)*client->frameunion.frames[i].entities.num_entities); + ptr += sizeof(*newframes[i].resendentbits)*maxents; + newframes[i].senttime = realtime; + } + Z_Free(client->frameunion.frames); + client->frameunion.frames = newframes; break; + } client->pendingentbits[j] = 0; if (bits & UF_REMOVE) diff --git a/engine/server/sv_init.c b/engine/server/sv_init.c index 3d50155d..adba0b80 100644 --- a/engine/server/sv_init.c +++ b/engine/server/sv_init.c @@ -326,7 +326,7 @@ void SV_SaveSpawnparmsClient(client_t *client, float *transferparms) if (PR_FindGlobal(svprogfuncs, "ClientReEnter", 0, NULL)) {//oooh, evil. char buffer[65536*4]; - int bufsize = 0; + size_t bufsize = 0; char *buf; for (j=0 ; jspawn_parms[j] = 0; @@ -1081,6 +1081,7 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us #ifdef VM_Q1 if (PR_LoadQ1QVM()) newgametype = GT_Q1QVM; + else #endif { diff --git a/engine/server/sv_main.c b/engine/server/sv_main.c index 91d099b5..3196cd11 100644 --- a/engine/server/sv_main.c +++ b/engine/server/sv_main.c @@ -306,7 +306,7 @@ void VARGS SV_Error (char *error, ...) if (svprogfuncs && pr_ssqc_coreonerror.value && svprogfuncs->save_ents) { - int size = 1024*1024*8; + size_t size = 1024*1024*8; char *buffer = BZ_Malloc(size); svprogfuncs->save_ents(svprogfuncs, buffer, &size, size, 3); COM_WriteFile("ssqccore.txt", FS_GAMEONLY, buffer, size); @@ -1842,7 +1842,9 @@ void SV_ClientProtocolExtensionsChanged(client_t *client) if ((client->fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS))// || ISDPCLIENT(&temp)) { char *ptr; - int maxents = /*client->max_net_ents;//*/maxpacketentities; /*this is the max number of ents updated per frame. we can't track more, so...*/ + int maxents = maxpacketentities*4; /*this is the max number of ents updated per frame. we can't track more, so...*/ + if (maxents > client->max_net_ents) + maxents = client->max_net_ents; ptr = Z_Malloc( sizeof(client_frame_t)*UPDATE_BACKUP+ sizeof(*client->pendingentbits)*client->max_net_ents+ sizeof(unsigned int)*maxents*UPDATE_BACKUP+ diff --git a/engine/server/sv_mvd.c b/engine/server/sv_mvd.c index c2632725..72b201f4 100644 --- a/engine/server/sv_mvd.c +++ b/engine/server/sv_mvd.c @@ -1013,6 +1013,14 @@ void SV_WriteMVDMessage (sizebuf_t *msg, int type, int to, float time) void SV_MVD_WriteReliables(void) { int i; + + //chuck in the broadcast reliables + ClientReliableCheckBlock(&demo.recorder, sv.reliable_datagram.cursize); + ClientReliableWrite_SZ(&demo.recorder, sv.reliable_datagram.data, sv.reliable_datagram.cursize); + //and the broadcast unreliables. everything is reliables when it comes to mvds + ClientReliableCheckBlock(&demo.recorder, sv.datagram.cursize); + ClientReliableWrite_SZ(&demo.recorder, sv.datagram.data, sv.datagram.cursize); + if (demo.recorder.netchan.message.cursize) { SV_WriteMVDMessage(&demo.recorder.netchan.message, dem_all, 0, sv.time); @@ -1022,7 +1030,8 @@ void SV_MVD_WriteReliables(void) { demo.recorder.backbuf.data = demo.recorder.backbuf_data[i]; demo.recorder.backbuf.cursize = demo.recorder.backbuf_size[i]; - SV_WriteMVDMessage(&demo.recorder.backbuf, dem_all, 0, sv.time); + if (demo.recorder.backbuf.cursize) + SV_WriteMVDMessage(&demo.recorder.backbuf, dem_all, 0, sv.time); demo.recorder.backbuf_size[i] = 0; } demo.recorder.num_backbuf = 0; diff --git a/engine/server/sv_phys.c b/engine/server/sv_phys.c index 1942beb9..80d9d4c2 100644 --- a/engine/server/sv_phys.c +++ b/engine/server/sv_phys.c @@ -2282,14 +2282,6 @@ void World_Physics_Frame(world_t *w) wedict_t *ent; extern cvar_t sv_nqplayerphysics; - if (w->g.defaultgravitydir) - { - w->g.defaultgravitydir[0] = 0; - w->g.defaultgravitydir[1] = 0; - w->g.defaultgravitydir[2] = -1; - VectorNormalize(w->g.defaultgravitydir); - } - w->framenum++; i = *w->g.physics_mode; diff --git a/engine/server/sv_send.c b/engine/server/sv_send.c index 7125502e..fe915b3c 100644 --- a/engine/server/sv_send.c +++ b/engine/server/sv_send.c @@ -1648,7 +1648,7 @@ typedef struct { } eval; int statnum; } qcstat_t; -qcstat_t qcstats[MAX_CL_STATS-32]; +qcstat_t qcstats[MAX_CL_STATS]; int numqcstats; void SV_QCStatEval(int type, char *name, evalc_t *field, eval_t *global, int statnum) { @@ -2205,11 +2205,10 @@ qboolean SV_SendClientDatagram (client_t *client) qbyte buf[MAX_OVERALLMSGLEN]; sizebuf_t msg; unsigned int sentbytes; - client_frame_t *frame = NULL; if (ISQWCLIENT(client) || ISNQCLIENT(client)) { - frame = &client->frameunion.frames[client->netchan.outgoing_sequence & UPDATE_MASK]; + client_frame_t *frame = &client->frameunion.frames[client->netchan.outgoing_sequence & UPDATE_MASK]; frame->numresendstats = 0; } @@ -2248,6 +2247,7 @@ qboolean SV_SendClientDatagram (client_t *client) { int pnum=1; client_t *c; + client_frame_t *frame = &client->frameunion.frames[client->netchan.outgoing_sequence & UPDATE_MASK]; SV_UpdateClientStats (client, 0, &msg, frame); for (c = client->controlled; c; c = c->controlled,pnum++) @@ -2286,8 +2286,11 @@ qboolean SV_SendClientDatagram (client_t *client) // send the datagram sentbytes = Netchan_Transmit (&client->netchan, msg.cursize, buf, SV_RateForClient(client)); - if (frame) + if (ISQWCLIENT(client) || ISNQCLIENT(client)) + { + client_frame_t *frame = &client->frameunion.frames[client->netchan.outgoing_sequence & UPDATE_MASK]; frame->packetsizeout += sentbytes; + } return true; } diff --git a/engine/server/sv_user.c b/engine/server/sv_user.c index eb39b313..00840a4e 100644 --- a/engine/server/sv_user.c +++ b/engine/server/sv_user.c @@ -1804,7 +1804,7 @@ void SV_Begin_Core(client_t *split) if (eval && eval->function && split->spawninfo) { globalvars_t *pr_globals = PR_globals(svprogfuncs, PR_CURRENT); - int j; + size_t j; edict_t *ent; ent = split->edict; j = strlen(split->spawninfo); @@ -3745,7 +3745,7 @@ void SV_Drop_f (void) if (!host_client->drop) { if (host_client->redirect == 2) - SV_BroadcastPrintf (PRINT_HIGH, "%s transfered to %s\n", host_client->name, Info_ValueForKey(host_client->userinfo, "*transfer")); + SV_BroadcastPrintf (PRINT_HIGH, "%s transfered to %s\n", host_client->name, host_client->transfer); else if (host_client->redirect) SV_BroadcastPrintf (PRINT_HIGH, "%s redirected to %s\n", host_client->name, sv_fullredirect.string); else @@ -5680,6 +5680,9 @@ void SV_ExecuteUserCommand (char *s, qboolean fromQC) client_t *oldhost = host_client; char adr[MAX_ADR_SIZE]; + if (host_client->state < cs_connected) + return; + Con_DPrintf("Client command: %s\n", s); Cmd_TokenizeString (s, false, false); diff --git a/plugins/ezhud/ezquakeisms.c b/plugins/ezhud/ezquakeisms.c index 179e4c55..dd2530b8 100644 --- a/plugins/ezhud/ezquakeisms.c +++ b/plugins/ezhud/ezquakeisms.c @@ -112,10 +112,12 @@ void Draw_SAlphaSubPic2(float x, float y, mpic_t *pic, float s1, float t1, float pDraw_Colour4f(1, 1, 1, 1); } -void Draw_AlphaFill(float x, float y, float w, float h, qbyte pal, float alpha) +void Draw_AlphaFill(float x, float y, float w, float h, unsigned int pal, float alpha) { - pDraw_Colour4f(1, 1, 1, alpha * alphamul); - pDraw_Colourp(pal); + if (pal >= 256) + pDraw_Colour4f(((pal>>16)&0xff)/255.0, ((pal>>8)&0xff)/255.0, ((pal>>0)&0xff)/255.0, alpha * alphamul); + else + pDraw_Colourpa(pal, alpha * alphamul); pDraw_Fill(x, y, w, h); pDraw_Colour4f(1, 1, 1, 1); } diff --git a/plugins/ezhud/ezquakeisms.h b/plugins/ezhud/ezquakeisms.h index b9f04672..20d1d026 100644 --- a/plugins/ezhud/ezquakeisms.h +++ b/plugins/ezhud/ezquakeisms.h @@ -111,7 +111,7 @@ void SCR_DrawWadString(float x, float y, float scale, char *str); void Draw_SAlphaSubPic2(float x, float y, mpic_t *pic, float s1, float t1, float s2, float t2, float w, float h, float alpha); -void Draw_AlphaFill(float x, float y, float w, float h, qbyte pal, float alpha); +void Draw_AlphaFill(float x, float y, float w, float h, unsigned int pal, float alpha); void Draw_AlphaPic(float x, float y, mpic_t *pic, float alpha); void Draw_AlphaSubPic(float x, float y, mpic_t *pic, float s1, float t1, float s2, float t2, float alpha); void SCR_HUD_DrawBar(int direction, int value, float max_value, float *rgba, int x, int y, int width, int height); diff --git a/plugins/ezhud/hud.c b/plugins/ezhud/hud.c index 58d994f8..be7c77d7 100644 --- a/plugins/ezhud/hud.c +++ b/plugins/ezhud/hud.c @@ -785,6 +785,43 @@ void HUD_Recalculate_f(void) HUD_Recalculate(); } +void HUD_Export_f(void) +{ + char line[8192]; + qhandle_t handle; + hud_t *hud; + cvar_t *var; + int i; + + char *fname = "foo"; + char *fdesc = "OMG ITS FOO"; + + snprintf(line, sizeof(line), "configs/hud_%s.cfg", fname); + + if (pFS_Open(line, &handle, 0) < 0) + Com_Printf("Couldn't open %s\n", line); + else + { + //FIXME: should print the result of an flocate, but plugins are not really aware of that stuff. + Com_Printf("Writing %s\n", line); + snprintf(line, sizeof(line), "//desc:%s\n\n//hud cvar settings, for use with FTEQW's ezhud plugin.\n", fdesc); + pFS_Write(handle, line, strlen(line)); + + for (hud = hud_huds; hud; hud = hud->next) + { + for (i = 0; i < hud->num_params; i++) + { + var = hud->params[i]; + //fixme: deal with " and \n + snprintf(line, sizeof(line), "set %s \"%s\"\n", var->name, var->string); + pFS_Write(handle, line, strlen(line)); + } + } + + pFS_Close(handle); + } +} + // // Initialize HUD. // @@ -794,18 +831,19 @@ void HUD_Init(void) void HUD_Inputlag_hit_f(void); // Commands. - Cmd_AddCommand ("show", HUD_Show_f); - Cmd_AddCommand ("hide", HUD_Hide_f); - Cmd_AddCommand ("move", HUD_Move_f); - Cmd_AddCommand ("place", HUD_Place_f); + Cmd_AddCommand ("show", HUD_Show_f); + Cmd_AddCommand ("hide", HUD_Hide_f); + Cmd_AddCommand ("move", HUD_Move_f); + Cmd_AddCommand ("place", HUD_Place_f); Cmd_AddCommand ("reset", HUD_Reset_f); Cmd_AddCommand ("order", HUD_Order_f); - Cmd_AddCommand ("togglehud", HUD_Toggle_f); - Cmd_AddCommand ("align", HUD_Align_f); - Cmd_AddCommand ("hud_recalculate", HUD_Recalculate_f); + Cmd_AddCommand ("togglehud", HUD_Toggle_f); + Cmd_AddCommand ("align", HUD_Align_f); + Cmd_AddCommand ("hud_recalculate", HUD_Recalculate_f); + Cmd_AddCommand ("hud_export", HUD_Export_f); // Register the hud items. - CommonDraw_Init(); + CommonDraw_Init(); // Sort the elements. HUD_Sort(); diff --git a/plugins/ezhud/hud_common.c b/plugins/ezhud/hud_common.c index 79d0309f..fc84f717 100644 --- a/plugins/ezhud/hud_common.c +++ b/plugins/ezhud/hud_common.c @@ -6364,20 +6364,21 @@ void SCR_HUD_DrawOwnFrags(hud_t *hud) width *= hud_ownfrags_scale->value; height *= hud_ownfrags_scale->value; - alpha = 2 - hud_ownfrags_timeout->value / age * 2; + alpha = 2 - age / hud_ownfrags_timeout->value * 2; alpha = bound(0, alpha, 1); - if (!HUD_PrepareDraw(hud, width , height, &x, &y)) + if (!HUD_PrepareDraw(hud, width, height, &x, &y)) return; if (!width) return; - if (age > hud_ownfrags_timeout->value) + if (age >= hud_ownfrags_timeout->value) return; - if (age < hud_ownfrags_timeout->value) - Draw_SString(x, y, ownfragtext, hud_ownfrags_scale->value); + pDraw_Colour4f(1, 1, 1, alpha); + Draw_SString(x, y, ownfragtext, hud_ownfrags_scale->value); + pDraw_Colour4f(1, 1, 1, 1); } static struct wstats_s *findweapon(struct wstats_s *w, size_t wc, char *wn) diff --git a/plugins/plugin.c b/plugins/plugin.c index dcae00c4..f2c3aec8 100644 --- a/plugins/plugin.c +++ b/plugins/plugin.c @@ -150,9 +150,11 @@ BUILTIN(void, GetServerInfo, (char *info, int infolen)); #define ARGNAMES ,key,value BUILTIN(void, SetUserInfo, (const char *key, const char *value)); #undef ARGNAMES +#ifdef FTEPLUGIN #define ARGNAMES ,seat,playercmd BUILTINR(int, GetLastInputFrame, (int seat, usercmd_t *playercmd)); #undef ARGNAMES +#endif #define ARGNAMES ,seat,text,textsize BUILTINR(float, GetTrackerOwnFrags, (int seat, char *text, size_t textsize)); #undef ARGNAMES diff --git a/plugins/plugin.h b/plugins/plugin.h index 70b91b2d..a30bff23 100644 --- a/plugins/plugin.h +++ b/plugins/plugin.h @@ -235,7 +235,9 @@ EBUILTIN(int, GetLocalPlayerNumbers, (int firstseat, int numseats, int *playernu EBUILTIN(void, GetServerInfo, (char *info, int infolen)); EBUILTIN(void, SetUserInfo, (const char *key, const char *value)); EBUILTIN(void, GetLocationName, (const float *pos, char *buffer, int bufferlen)); +#ifdef FTEPLUGIN EBUILTIN(int, GetLastInputFrame, (int seat, usercmd_t *playercmd)); +#endif EBUILTIN(float, GetTrackerOwnFrags, (int seat, char *text, size_t textsize)); typedef struct