add hud_miniscores_show cvar to hide the mini deathmatch overlay

fix some issues with ezhud. ownfrags, text alphas, RGB player colours.
tweak gamecontroller input a little, to make axis slightly more usable.
fix issue with menuqc/csqc not being able to query binds reliably.
fix csqc gravitydir.
bump r_particle_tracelimit so that its no longer a limitation by default.
tweak fog to allow far-clip-plane culling on entities (but still not on world, due to issues with glClear).
fix performance issue with q1bspx BRUSHLIST lump.
fix mvd recording bug.
fix limitation that becomes apparent on maps with lots of ents visible at once. will now use more bandwidth in such cases, however.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4994 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2015-11-18 07:37:39 +00:00
parent e03a8d9d41
commit 71319a8852
60 changed files with 1342 additions and 407 deletions

View file

@ -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;

View file

@ -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);

View file

@ -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;

View file

@ -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);

View file

@ -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))

View file

@ -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);

View file

@ -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);

View file

@ -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)

View file

@ -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;
}
}

View file

@ -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)

View file

@ -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);

View file

@ -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;

View file

@ -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 ; j<K_MAX ; j++)
{
for (m = firstmod; m < lastmod; m++)
{

View file

@ -285,7 +285,7 @@ int MP_TranslateQCtoFTECodes(int code)
void QCBUILTIN PF_cl_findkeysforcommand (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[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];

View file

@ -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)

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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");

View file

@ -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<<r_refdef.frustum_numplanes)-1);
Surf_RecursiveQ3WorldNode (cl.worldmodel->nodes, (1<<r_refdef.frustum_numworldplanes)-1);
//Surf_LeafWorldNode ();
}
else

View file

@ -238,7 +238,8 @@ typedef struct
float m_view[16];
mplane_t frustum[MAXFRUSTUMPLANES];
int frustum_numplanes;
int frustum_numworldplanes; //all but far, which isn't culled because this wouldn't cover the entire screen.
int frustum_numplanes; //includes far plane (which is reduced with fog).
fogstate_t globalfog;
float hdr_value;

View file

@ -2494,15 +2494,11 @@ void R_SetFrustum (float projmat[16], float viewmat[16])
r_refdef.frustum_numplanes++;
r_refdef.frustum_numworldplanes = r_refdef.frustum_numplanes;
//do far plane
//fog will logically not actually reach 0, though precision issues will force it. we cut off at an exponant of -500
if (r_refdef.globalfog.density
#ifdef TERRAIN
&& cl.worldmodel && cl.worldmodel->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;

View file

@ -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];

View file

@ -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)
{

View file

@ -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",

View file

@ -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.

View file

@ -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
{

View file

@ -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));

View file

@ -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
};

View file

@ -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;

View file

@ -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

View file

@ -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;
}
}

View file

@ -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)

View file

@ -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)
{

View file

@ -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++)

View file

@ -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);
}

View file

@ -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;

View file

@ -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], &current_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

View file

@ -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;

View file

@ -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)

View file

@ -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

View file

@ -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

View file

@ -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},

View file

@ -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");

View file

@ -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;

View file

@ -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

View file

@ -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;

View file

@ -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)
{

View file

@ -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)

View file

@ -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 ; j<NUM_SPAWN_PARMS ; j++)
client->spawn_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
{

View file

@ -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+

View file

@ -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;

View file

@ -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;

View file

@ -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;
}

View file

@ -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);

View file

@ -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);
}

View file

@ -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);

View file

@ -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();

View file

@ -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)

View file

@ -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

View file

@ -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