qcc: Add unsigned int, long/__int64, unsigned long/__uint64, and double datatypes to qcc+qcvm.

qcc: Add '#pragma opcode enable|disable NAME' to override whether an individual opcode may be generated for the current target.
nq: Fix smartjump on nq servers.
nq: Fix enemyskin/teamskin stuff on nq servers.
Rework show_fps cvar to give a greater focus on the timings graph.
Update updates menu to allow enabling/disabling specific sources.
Add separate settings for ef_red+ef_green+ef_blue.



git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5768 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2020-09-29 07:09:01 +00:00
parent 24a9634ccc
commit e3fdbfcdbd
46 changed files with 3320 additions and 1071 deletions

View file

@ -196,7 +196,7 @@ qboolean CDAudio_Startup(void)
cd_dev[sizeof(cd_dev) - 1] = 0; cd_dev[sizeof(cd_dev) - 1] = 0;
} }
if ((cdfile = open(cd_dev, O_RDONLY)) == -1) if ((cdfile = open(cd_dev, O_RDONLY|O_NONBLOCK)) == -1)
{ {
Con_Printf("CDAudio_Init: open of \"%s\" failed (%i)\n", cd_dev, errno); Con_Printf("CDAudio_Init: open of \"%s\" failed (%i)\n", cd_dev, errno);
cdfile = -1; cdfile = -1;

View file

@ -30,6 +30,7 @@ extern cvar_t cl_predict_players_latency;
extern cvar_t cl_predict_players_nudge; extern cvar_t cl_predict_players_nudge;
extern cvar_t cl_lerp_players; extern cvar_t cl_lerp_players;
extern cvar_t cl_lerp_maxinterval; extern cvar_t cl_lerp_maxinterval;
extern cvar_t cl_lerp_maxdistance;
extern cvar_t cl_solid_players; extern cvar_t cl_solid_players;
extern cvar_t cl_item_bobbing; extern cvar_t cl_item_bobbing;
@ -37,6 +38,9 @@ extern cvar_t r_rocketlight;
extern cvar_t r_lightflicker; extern cvar_t r_lightflicker;
extern cvar_t r_dimlight_colour; extern cvar_t r_dimlight_colour;
extern cvar_t r_brightlight_colour; extern cvar_t r_brightlight_colour;
extern cvar_t r_redlight_colour;
extern cvar_t r_greenlight_colour;
extern cvar_t r_bluelight_colour;
extern cvar_t cl_r2g; extern cvar_t cl_r2g;
extern cvar_t r_powerupglow; extern cvar_t r_powerupglow;
extern cvar_t v_powerupshell; extern cvar_t v_powerupshell;
@ -3449,6 +3453,7 @@ static void CL_TransitionPacketEntities(int newsequence, packet_entities_t *newp
vec3_t move; vec3_t move;
float a1, a2; float a1, a2;
float maxdist = cl_lerp_maxdistance.value*cl_lerp_maxdistance.value;
/* /*
seeing as how dropped packets cannot be filled in due to the reliable networking stuff, seeing as how dropped packets cannot be filled in due to the reliable networking stuff,
@ -3576,7 +3581,7 @@ static void CL_TransitionPacketEntities(int newsequence, packet_entities_t *newp
} }
VectorSubtract(snew__origin, sold__origin, move); VectorSubtract(snew__origin, sold__origin, move);
if (DotProduct(move, move) > 200*200 || cos_theta < 0.707 || snew->modelindex != sold->modelindex || ((sold->effects ^ snew->effects) & EF_TELEPORT_BIT)) if (DotProduct(move, move) > maxdist || cos_theta < 0.707 || snew->modelindex != sold->modelindex || ((sold->effects ^ snew->effects) & EF_TELEPORT_BIT))
{ {
isnew = true; //disable lerping (and indirectly trails) isnew = true; //disable lerping (and indirectly trails)
// VectorClear(move); // VectorClear(move);
@ -4005,8 +4010,8 @@ void CL_LinkPacketEntities (void)
if (state->effects & EF_BRIGHTLIGHT) if (state->effects & EF_BRIGHTLIGHT)
{ {
radius = max(radius,r_dimlight_colour.vec4[3]); radius = max(radius,r_brightlight_colour.vec4[3]);
VectorAdd(colour, r_dimlight_colour.vec4, colour); VectorAdd(colour, r_brightlight_colour.vec4, colour);
} }
if (state->effects & EF_DIMLIGHT) if (state->effects & EF_DIMLIGHT)
{ {
@ -4015,24 +4020,18 @@ void CL_LinkPacketEntities (void)
} }
if (state->effects & EF_BLUE) if (state->effects & EF_BLUE)
{ {
radius = max(radius,200); radius = max(radius,r_bluelight_colour.vec4[3]);
colour[0] += 0.5; VectorAdd(colour, r_bluelight_colour.vec4, colour);
colour[1] += 0.5;
colour[2] += 3.0;
} }
if (state->effects & EF_RED) if (state->effects & EF_RED)
{ {
radius = max(radius,200); radius = max(radius,r_redlight_colour.vec4[3]);
colour[0] += 3.0; VectorAdd(colour, r_redlight_colour.vec4, colour);
colour[1] += 0.5;
colour[2] += 0.5;
} }
if (state->effects & EF_GREEN) if (state->effects & EF_GREEN)
{ {
radius = max(radius,200); radius = max(radius,r_greenlight_colour.vec4[3]);
colour[0] += 0.5; VectorAdd(colour, r_greenlight_colour.vec4, colour);
colour[1] += 3.0;
colour[2] += 0.5;
} }
if (radius) if (radius)
@ -5235,7 +5234,7 @@ void CL_LinkPlayers (void)
// spawn light flashes, even ones coming from invisible objects // spawn light flashes, even ones coming from invisible objects
if (r_powerupglow.value && !(r_powerupglow.value == 2 && j == cl.playerview[0].playernum) if (r_powerupglow.value && !(r_powerupglow.value == 2 && j == cl.playerview[0].playernum)
&& (state->effects & (EF_BLUE|EF_RED|EF_BRIGHTLIGHT|EF_DIMLIGHT))) && (state->effects & (EF_BLUE|EF_RED|EF_GREEN|EF_BRIGHTLIGHT|EF_DIMLIGHT)))
{ {
vec3_t colour; vec3_t colour;
float radius; float radius;
@ -5246,31 +5245,28 @@ void CL_LinkPlayers (void)
if (state->effects & EF_BRIGHTLIGHT) if (state->effects & EF_BRIGHTLIGHT)
{ {
radius = max(radius,400); radius = max(radius,r_brightlight_colour.vec4[3]);
colour[0] += 0.2; VectorAdd(colour, r_brightlight_colour.vec4, colour);
colour[1] += 0.1;
colour[2] += 0.05;
} }
if (state->effects & EF_DIMLIGHT) if (state->effects & EF_DIMLIGHT)
{ {
radius = max(radius,200); radius = max(radius,r_dimlight_colour.vec4[3]);
colour[0] += 2.0; VectorAdd(colour, r_dimlight_colour.vec4, colour);
colour[1] += 1.0;
colour[2] += 0.5;
} }
if (state->effects & EF_BLUE) if (state->effects & EF_BLUE)
{ {
radius = max(radius,200); radius = max(radius,r_bluelight_colour.vec4[3]);
colour[0] += 0.5; VectorAdd(colour, r_bluelight_colour.vec4, colour);
colour[1] += 0.5;
colour[2] += 3.0;
} }
if (state->effects & EF_RED) if (state->effects & EF_RED)
{ {
radius = max(radius,200); radius = max(radius,r_redlight_colour.vec4[3]);
colour[0] += 5.0; VectorAdd(colour, r_redlight_colour.vec4, colour);
colour[1] += 0.5; }
colour[2] += 0.5; if (state->effects & EF_GREEN)
{
radius = max(radius,r_greenlight_colour.vec4[3]);
VectorAdd(colour, r_greenlight_colour.vec4, colour);
} }
if (radius) if (radius)

View file

@ -105,6 +105,7 @@ cvar_t m_forward = CVARF("m_forward","1", CVAR_ARCHIVE);
cvar_t m_side = CVARF("m_side","0.8", CVAR_ARCHIVE); cvar_t m_side = CVARF("m_side","0.8", CVAR_ARCHIVE);
cvar_t cl_lerp_maxinterval = CVARD("cl_lerp_maxinterval", "0.3", "Maximum interval between keyframes, in seconds. Larger values can result in entities drifting very slowly when they move sporadically."); cvar_t cl_lerp_maxinterval = CVARD("cl_lerp_maxinterval", "0.3", "Maximum interval between keyframes, in seconds. Larger values can result in entities drifting very slowly when they move sporadically.");
cvar_t cl_lerp_maxdistance = CVARD("cl_lerp_maxdistance", "200", "Maximum distance that an entity may move between snapshots without being considered as having teleported.");
cvar_t cl_lerp_players = CVARD("cl_lerp_players", "0", "Set this to make other players smoother, though it may increase effective latency. Affects only QuakeWorld."); cvar_t cl_lerp_players = CVARD("cl_lerp_players", "0", "Set this to make other players smoother, though it may increase effective latency. Affects only QuakeWorld.");
cvar_t cl_predict_players = CVARD("cl_predict_players", "1", "Clear this cvar to see ents exactly how they are on the server."); cvar_t cl_predict_players = CVARD("cl_predict_players", "1", "Clear this cvar to see ents exactly how they are on the server.");
cvar_t cl_predict_players_frac = CVARD("cl_predict_players_frac", "0.9", "How much of other players to predict. Values less than 1 will help minimize overruns."); cvar_t cl_predict_players_frac = CVARD("cl_predict_players_frac", "0.9", "How much of other players to predict. Values less than 1 will help minimize overruns.");
@ -4805,6 +4806,7 @@ void CL_Init (void)
Cvar_Register (&rcon_address, cl_controlgroup); Cvar_Register (&rcon_address, cl_controlgroup);
Cvar_Register (&cl_lerp_maxinterval, cl_controlgroup); Cvar_Register (&cl_lerp_maxinterval, cl_controlgroup);
Cvar_Register (&cl_lerp_maxdistance, cl_controlgroup);
Cvar_Register (&cl_lerp_players, cl_controlgroup); Cvar_Register (&cl_lerp_players, cl_controlgroup);
Cvar_Register (&cl_predict_players, cl_predictiongroup); Cvar_Register (&cl_predict_players, cl_predictiongroup);
Cvar_Register (&cl_predict_players_frac, cl_predictiongroup); Cvar_Register (&cl_predict_players_frac, cl_predictiongroup);

View file

@ -3908,6 +3908,35 @@ static void CLNQ_ParseServerData(void) //Doesn't change gamedir - use with caut
strcpy (cl.model_name[nummodels], str); strcpy (cl.model_name[nummodels], str);
if (*str != '*' && strcmp(str, "null")) //not inline models! if (*str != '*' && strcmp(str, "null")) //not inline models!
CL_CheckOrEnqueDownloadFile(str, NULL, ((nummodels==1)?DLLF_REQUIRED|DLLF_ALLOWWEB:0)); CL_CheckOrEnqueDownloadFile(str, NULL, ((nummodels==1)?DLLF_REQUIRED|DLLF_ALLOWWEB:0));
//qw has a special network protocol for spikes.
if (!strcmp(cl.model_name[nummodels],"progs/spike.mdl"))
cl_spikeindex = nummodels;
if (!strcmp(cl.model_name[nummodels],"progs/player.mdl"))
cl_playerindex = nummodels;
#ifdef HAVE_LEGACY
if (*cl.model_name_vwep[0] && !strcmp(cl.model_name[nummodels],cl.model_name_vwep[0]) && cl_playerindex == -1)
cl_playerindex = nummodels;
#endif
if (!strcmp(cl.model_name[nummodels],"progs/h_player.mdl"))
cl_h_playerindex = nummodels;
if (!strcmp(cl.model_name[nummodels],"progs/flag.mdl"))
cl_flagindex = nummodels;
//rocket to grenade
if (!strcmp(cl.model_name[nummodels],"progs/missile.mdl"))
cl_rocketindex = nummodels;
if (!strcmp(cl.model_name[nummodels],"progs/grenade.mdl"))
cl_grenadeindex = nummodels;
//cl_gibfilter
if (!strcmp(cl.model_name[nummodels],"progs/gib1.mdl"))
cl_gib1index = nummodels;
if (!strcmp(cl.model_name[nummodels],"progs/gib2.mdl"))
cl_gib2index = nummodels;
if (!strcmp(cl.model_name[nummodels],"progs/gib3.mdl"))
cl_gib3index = nummodels;
Mod_TouchModel (str); Mod_TouchModel (str);
} }
@ -4099,7 +4128,10 @@ static void CLNQ_ParseClientdata (void)
CL_SetStatInt(0, STAT_ITEMS, MSG_ReadLong()); CL_SetStatInt(0, STAT_ITEMS, MSG_ReadLong());
pl->onground = (bits & SU_ONGROUND) != 0; pl->onground = (bits & SU_ONGROUND) != 0;
// cl.inwater = (bits & SU_INWATER) != 0; if (bits & SU_INWATER)
pl->flags |= PF_INWATER; //mostly just means smartjump should be used.
else
pl->flags &= ~PF_INWATER;
if (cls.protocol_nq == CPNQ_DP5) if (cls.protocol_nq == CPNQ_DP5)
{ {
@ -5246,7 +5278,7 @@ void CL_NewTranslation (int slot)
s = Skin_FindName (player); s = Skin_FindName (player);
COM_StripExtension(s, s, MAX_QPATH); COM_StripExtension(s, s, MAX_QPATH);
if (player->qwskin && !stricmp(s, player->qwskin->name)) if (player->qwskin && stricmp(s, player->qwskin->name))
player->qwskin = NULL; player->qwskin = NULL;
player->skinid = 0; player->skinid = 0;
player->model = NULL; player->model = NULL;
@ -8243,9 +8275,9 @@ void CLNQ_ParseServerMessage (void)
// cl.players[i].rbottomcolor = (a&0xf0)>>4; // cl.players[i].rbottomcolor = (a&0xf0)>>4;
// sprintf(cl.players[i].team, "%2d", cl.players[i].rbottomcolor); // sprintf(cl.players[i].team, "%2d", cl.players[i].rbottomcolor);
InfoBuf_SetValueForKey(&cl.players[i].userinfo, "topcolor", va("%i", a&0x0f)); InfoBuf_SetValueForKey(&cl.players[i].userinfo, "topcolor", va("%i", (a&0xf0)>>4));
InfoBuf_SetValueForKey(&cl.players[i].userinfo, "bottomcolor", va("%i", (a&0xf0)>>4)); InfoBuf_SetValueForKey(&cl.players[i].userinfo, "bottomcolor", va("%i", (a&0x0f)));
InfoBuf_SetValueForKey(&cl.players[i].userinfo, "team", va("%i", (a&0xf0)>>4)); InfoBuf_SetValueForKey(&cl.players[i].userinfo, "team", va("%i", (a&0x0f)+1));
CL_ProcessUserInfo (i, &cl.players[i]); CL_ProcessUserInfo (i, &cl.players[i]);
// CLNQ_CheckPlayerIsSpectator(i); // CLNQ_CheckPlayerIsSpectator(i);

View file

@ -776,6 +776,7 @@ static void CL_EntStateToPlayerState(player_state_t *plstate, entity_state_t *st
{ {
vec3_t a; vec3_t a;
int pmtype; int pmtype;
unsigned int flags = plstate->flags;
qboolean onground = plstate->onground; qboolean onground = plstate->onground;
qboolean jumpheld = plstate->jump_held; qboolean jumpheld = plstate->jump_held;
vec3_t vel; vec3_t vel;
@ -827,6 +828,7 @@ static void CL_EntStateToPlayerState(player_state_t *plstate, entity_state_t *st
plstate->jump_held = !!(state->u.q1.pmovetype&64); plstate->jump_held = !!(state->u.q1.pmovetype&64);
} }
plstate->pm_type = pmtype; plstate->pm_type = pmtype;
plstate->flags = flags & PF_INWATER;
plstate->viewangles[0] = SHORT2ANGLE(state->u.q1.vangle[0]); plstate->viewangles[0] = SHORT2ANGLE(state->u.q1.vangle[0]);
plstate->viewangles[1] = SHORT2ANGLE(state->u.q1.vangle[1]); plstate->viewangles[1] = SHORT2ANGLE(state->u.q1.vangle[1]);
@ -1383,7 +1385,19 @@ void CL_PredictMovePNum (int seat)
} }
} }
if (cls.protocol == CP_NETQUAKE && nopred) if (cls.protocol == CP_NETQUAKE && nopred)
{
pv->onground = to.state->onground; pv->onground = to.state->onground;
if (to.state->flags & PF_INWATER)
{
pmove.watertype = FTECONTENTS_WATER; //don't really know.
pmove.waterlevel = 3; //pick one at random.
}
else
{
pmove.watertype = FTECONTENTS_EMPTY;
pmove.waterlevel = 0;
}
}
else else
CL_CatagorizePosition(pv, to.state->origin); CL_CatagorizePosition(pv, to.state->origin);

View file

@ -222,7 +222,7 @@ qboolean scr_drawloading;
float scr_disabled_time; float scr_disabled_time;
cvar_t con_stayhidden = CVARFD("con_stayhidden", "1", CVAR_NOTFROMSERVER, "0: allow console to pounce on the user\n1: console stays hidden unless explicitly invoked\n2:toggleconsole command no longer works\n3: shift+escape key no longer works"); cvar_t con_stayhidden = CVARFD("con_stayhidden", "1", CVAR_NOTFROMSERVER, "0: allow console to pounce on the user\n1: console stays hidden unless explicitly invoked\n2:toggleconsole command no longer works\n3: shift+escape key no longer works");
cvar_t show_fps = CVARFD("show_fps", "0", CVAR_ARCHIVE, "Displays the current framerate on-screen.\n1: framerate average over a second.\n2: Slowest frame over the last second (the game will play like shit if this is significantly lower than the average).\n3: Shows the rate of the fastest frame (not very useful).\n4: Shows the current frame's timings (this depends upon timer precision).\n5: Display a graph of how long it took to render each frame, large spikes are BAD BAD BAD.\n6: Displays the standard deviation of the frame times, if its greater than 3 then something is probably badly made, or you've a virus scanner running...\n7: Framegraph, for use with slower frames."); cvar_t show_fps = CVARFD("show_fps", "0", CVAR_ARCHIVE, "Displays the current framerate on-screen.\n0: Off.\n1: framerate average over a second.\n2: Show a frametimes graph (with additional timing info).\n-1: Normalized graph that focuses on the variation ignoring base times.");
cvar_t show_fps_x = CVAR("show_fps_x", "-1"); cvar_t show_fps_x = CVAR("show_fps_x", "-1");
cvar_t show_fps_y = CVAR("show_fps_y", "-1"); cvar_t show_fps_y = CVAR("show_fps_y", "-1");
cvar_t show_clock = CVAR("cl_clock", "0"); cvar_t show_clock = CVAR("cl_clock", "0");
@ -1720,11 +1720,7 @@ void SCR_DrawFPS (void)
double t; double t;
extern int fps_count; extern int fps_count;
static float lastfps; static float lastfps;
static double deviationtimes[64];
static int deviationframe;
char str[80]; char str[80];
int sfps, frame;
qboolean usemsecs = false;
float frametime; float frametime;
@ -1741,75 +1737,10 @@ void SCR_DrawFPS (void)
frametime = t - lastsystemtime; frametime = t - lastsystemtime;
lastsystemtime = t; lastsystemtime = t;
sfps = show_fps.ival; if (show_fps.value < 0)
if (sfps < 0) R_FrameTimeGraph(frametime, 0);
{ else if (show_fps.value > 1)
sfps = -sfps; R_FrameTimeGraph(frametime, show_fps.value-1);
usemsecs = true;
}
switch (sfps)
{
case 1:
default:
break;
case 2: // lowest FPS, highest MS encountered
if (lastfps > 1/frametime)
{
lastfps = 1/frametime;
fps_count = 0;
lastupdatetime = t;
}
break;
case 3: // highest FPS, lowest MS encountered
if (lastfps < 1/frametime)
{
lastfps = 1/frametime;
fps_count = 0;
lastupdatetime = t;
}
break;
case 4: // immediate FPS/MS
lastfps = 1/frametime;
lastupdatetime = t;
break;
case 5:
R_FrameTimeGraph(1000.0*2*frametime);
break;
case 7:
R_FrameTimeGraph(1000.0*1*frametime);
break;
case 6:
{
float mean, deviation;
deviationtimes[deviationframe++&63] = frametime*1000;
mean = 0;
for (frame = 0; frame < 64; frame++)
{
mean += deviationtimes[frame];
}
mean /= 64;
deviation = 0;
for (frame = 0; frame < 64; frame++)
{
deviation += (deviationtimes[frame] - mean)*(deviationtimes[frame] - mean);
}
deviation /= 64;
deviation = sqrt(deviation);
SCR_StringXY(va("%f deviation", deviation), show_fps_x.value, show_fps_y.value-8);
}
break;
case 8:
if (cls.timedemo)
Con_Printf("%f\n", frametime);
break;
}
if (usemsecs)
sprintf(str, "%4.1f MS", 1000.0/lastfps);
else
sprintf(str, "%3.1f FPS", lastfps); sprintf(str, "%3.1f FPS", lastfps);
SCR_StringXY(str, show_fps_x.value, show_fps_y.value); SCR_StringXY(str, show_fps_x.value, show_fps_y.value);
} }

View file

@ -281,13 +281,16 @@ sfx_t *cl_sfx_r_exp3;
cvar_t cl_expsprite = CVARFD("cl_expsprite", "1", CVAR_ARCHIVE, "Display a central sprite in explosion effects. QuakeWorld typically does so, NQ mods should not (which is problematic when played with the qw protocol)."); cvar_t cl_expsprite = CVARFD("cl_expsprite", "1", CVAR_ARCHIVE, "Display a central sprite in explosion effects. QuakeWorld typically does so, NQ mods should not (which is problematic when played with the qw protocol).");
cvar_t r_explosionlight = CVARFC("r_explosionlight", "1", CVAR_ARCHIVE, Cvar_Limiter_ZeroToOne_Callback); cvar_t r_explosionlight = CVARFC("r_explosionlight", "1", CVAR_ARCHIVE, Cvar_Limiter_ZeroToOne_Callback);
static cvar_t r_explosionlight_colour = CVARF("r_explosionlight_colour", "4.0 2.0 0.5", CVAR_ARCHIVE); static cvar_t r_explosionlight_colour = CVARFD("r_explosionlight_colour", "4.0 2.0 0.5", CVAR_ARCHIVE, "This controls the initial RGB values of EF_EXPLOSION effects.");
static cvar_t r_explosionlight_fade = CVARF("r_explosionlight_fade", "0.784 0.92 0.48", CVAR_ARCHIVE); static cvar_t r_explosionlight_fade = CVARFD("r_explosionlight_fade", "0.784 0.92 0.48", CVAR_ARCHIVE, "This controls the per-second RGB decay values of EF_EXPLOSION effects.");
cvar_t r_dimlight_colour = CVARF("r_dimlight_colour", "2.0 1.0 0.5 200", CVAR_ARCHIVE); cvar_t r_dimlight_colour = CVARFD("r_dimlight_colour", "2.0 1.0 0.5 200", CVAR_ARCHIVE, "The red, green, blue, radius values for EF_DIMLIGHT effects (used for quad+pent in vanilla quake).");
cvar_t r_brightlight_colour = CVARF("r_brightlight_colour", "2.0 1.0 0.5 400", CVAR_ARCHIVE); cvar_t r_brightlight_colour = CVARFD("r_brightlight_colour", "2.0 1.0 0.5 400", CVAR_ARCHIVE, "The red, green, blue, radius values for EF_BRIGHTLIGHT effects (unused in vanilla quake).");
cvar_t r_rocketlight_colour = CVARF("r_rocketlight_colour", "2.0 1.0 0.25 200", CVAR_ARCHIVE); cvar_t r_redlight_colour = CVARFD("r_redlight_colour", "3.0 0.5 0.5 200", CVAR_ARCHIVE, "The red, green, blue, radius values for EF_RED effects (typically used for pentagram in quakeworld).");
cvar_t r_muzzleflash_colour = CVARF("r_muzzleflash_colour", "1.5 1.3 1.0 200", CVAR_ARCHIVE); cvar_t r_greenlight_colour = CVARFD("r_greenlight_colour", "0.5 3.0 0.5 200", CVAR_ARCHIVE, "The red, green, blue, radius values for EF_GREEN effects (rarely used).");
cvar_t r_muzzleflash_fade = CVARF("r_muzzleflash_fade", "1.5 0.75 0.375 1000", CVAR_ARCHIVE); cvar_t r_bluelight_colour = CVARFD("r_bluelight_colour", "0.5 0.5 3.0 200", CVAR_ARCHIVE, "The red, green, blue, radius values for EF_BLUE effects (typically used for quad-damage in quakeworld)");
cvar_t r_rocketlight_colour = CVARFD("r_rocketlight_colour", "2.0 1.0 0.25 200", CVAR_ARCHIVE, "This controls the RGB+radius values of MF_ROCKET effects.");
cvar_t r_muzzleflash_colour = CVARFD("r_muzzleflash_colour", "1.5 1.3 1.0 200", CVAR_ARCHIVE, "This controls the initial RGB+radius of EF_MUZZLEFLASH/svc_muzzleflash effects.");
cvar_t r_muzzleflash_fade = CVARFD("r_muzzleflash_fade", "1.5 0.75 0.375 1000", CVAR_ARCHIVE, "This controls the per-second RGB+radius decay of EF_MUZZLEFLASH/svc_muzzleflash effects.");
cvar_t cl_truelightning = CVARF("cl_truelightning", "0", CVAR_SEMICHEAT); cvar_t cl_truelightning = CVARF("cl_truelightning", "0", CVAR_SEMICHEAT);
static cvar_t cl_beam_trace = CVAR("cl_beam_trace", "0"); static cvar_t cl_beam_trace = CVAR("cl_beam_trace", "0");
static cvar_t cl_legacystains = CVARD("cl_legacystains", "1", "WARNING: this cvar will default to 0 and later removed at some point"); //FIXME: do as the description says! static cvar_t cl_legacystains = CVARD("cl_legacystains", "1", "WARNING: this cvar will default to 0 and later removed at some point"); //FIXME: do as the description says!
@ -424,6 +427,9 @@ void CL_InitTEnts (void)
Cvar_Register (&r_muzzleflash_colour, "Temporary entity control"); Cvar_Register (&r_muzzleflash_colour, "Temporary entity control");
Cvar_Register (&r_muzzleflash_fade, "Temporary entity control"); Cvar_Register (&r_muzzleflash_fade, "Temporary entity control");
Cvar_Register (&r_dimlight_colour, "Temporary entity control"); Cvar_Register (&r_dimlight_colour, "Temporary entity control");
Cvar_Register (&r_redlight_colour, "Temporary entity control");
Cvar_Register (&r_greenlight_colour, "Temporary entity control");
Cvar_Register (&r_bluelight_colour, "Temporary entity control");
Cvar_Register (&r_brightlight_colour, "Temporary entity control"); Cvar_Register (&r_brightlight_colour, "Temporary entity control");
Cvar_Register (&r_rocketlight_colour, "Temporary entity control"); Cvar_Register (&r_rocketlight_colour, "Temporary entity control");
Cvar_Register (&cl_legacystains, "Temporary entity control"); Cvar_Register (&cl_legacystains, "Temporary entity control");

View file

@ -2,6 +2,10 @@
#include "shader.h" #include "shader.h"
#include "glquake.h" //we need some of the gl format enums #include "glquake.h" //we need some of the gl format enums
#ifdef __GNUC__
#pragma
#endif
#ifndef HAVE_CLIENT #ifndef HAVE_CLIENT
//#define Con_Printf(f, ...) //#define Con_Printf(f, ...)
//hope you're on a littleendian machine //hope you're on a littleendian machine
@ -2449,6 +2453,7 @@ qboolean screenshotJPEG(char *filename, enum fs_relative fsroot, int compression
int ic; int ic;
qboolean byteswap; qboolean byteswap;
switch(fmt) switch(fmt)
{ {
case PTI_RGB8: //yay! nothing to do. case PTI_RGB8: //yay! nothing to do.

View file

@ -216,8 +216,14 @@ static struct
{ {
char *url; char *url;
char *prefix; char *prefix;
qboolean trustworthy; //trusted enum
char received; //says if we got a response yet or not {
SRCSTAT_UNKNOWN, //we don't know whether the user wants to allow or block this source.
SRCSTAT_DISABLED, //do NOT query this source
SRCSTAT_FAILED, //tried but failed. FIXME: add some reasons.
SRCSTAT_PENDING, //waiting for response (or queued). don't show package list yet.
SRCSTAT_OBTAINED, //we got a response.
} status;
qboolean save; //written into our local file qboolean save; //written into our local file
struct dl_download *curdl; //the download context struct dl_download *curdl; //the download context
} downloadablelist[32]; } downloadablelist[32];
@ -832,7 +838,7 @@ static qboolean PM_CheckFile(const char *filename, enum fs_relative base)
return false; return false;
} }
static void PM_AddSubList(const char *url, const char *prefix, qboolean save, qboolean trustworthy) static void PM_AddSubList(const char *url, const char *prefix, qboolean save, qboolean enabled)
{ {
int i; int i;
if (!*url) if (!*url)
@ -849,10 +855,10 @@ static void PM_AddSubList(const char *url, const char *prefix, qboolean save, qb
} }
if (i == numdownloadablelists && i < countof(downloadablelist)) if (i == numdownloadablelists && i < countof(downloadablelist))
{ {
if (!strncmp(url, "https:", 6)) if (enabled)
downloadablelist[i].trustworthy = trustworthy; downloadablelist[i].status = SRCSTAT_PENDING;
else else
downloadablelist[i].trustworthy = false; //if its not a secure url, never consider it as trustworthy downloadablelist[i].status = SRCSTAT_DISABLED;
downloadablelist[i].save = save; downloadablelist[i].save = save;
downloadablelist[i].url = BZ_Malloc(strlen(url)+1); downloadablelist[i].url = BZ_Malloc(strlen(url)+1);
@ -974,6 +980,7 @@ static qboolean PM_ParsePackageList(const char *f, int parseflags, const char *u
{ {
char *subprefix; char *subprefix;
char url[MAX_OSPATH]; char url[MAX_OSPATH];
char enablement[MAX_OSPATH];
tokstart = COM_StringParse (tokstart, url, sizeof(url), false, false); tokstart = COM_StringParse (tokstart, url, sizeof(url), false, false);
tokstart = COM_StringParse (tokstart, com_token, sizeof(com_token), false, false); tokstart = COM_StringParse (tokstart, com_token, sizeof(com_token), false, false);
if (*prefix) if (*prefix)
@ -981,7 +988,11 @@ static qboolean PM_ParsePackageList(const char *f, int parseflags, const char *u
else else
subprefix = com_token; subprefix = com_token;
PM_AddSubList(url, subprefix, (parseflags & DPF_ENABLED)?true:false, (parseflags&DPF_TRUSTED)); tokstart = COM_StringParse (tokstart, enablement, sizeof(enablement), false, false);
if (!Q_strcasecmp(enablement, "enabled") && (parseflags & DPF_ENABLED))
PM_AddSubList(url, subprefix, (parseflags & DPF_ENABLED)?true:false, true);
else
PM_AddSubList(url, subprefix, (parseflags & DPF_ENABLED)?true:false, false);
continue; continue;
} }
if (!strcmp(com_token, "set")) if (!strcmp(com_token, "set"))
@ -1594,7 +1605,7 @@ void PM_Shutdown(qboolean soft)
downloadablelist[numdownloadablelists].curdl = NULL; downloadablelist[numdownloadablelists].curdl = NULL;
} }
#endif #endif
downloadablelist[numdownloadablelists].received = 0; downloadablelist[numdownloadablelists].status = SRCSTAT_UNKNOWN;
Z_Free(downloadablelist[numdownloadablelists].url); Z_Free(downloadablelist[numdownloadablelists].url);
downloadablelist[numdownloadablelists].url = NULL; downloadablelist[numdownloadablelists].url = NULL;
Z_Free(downloadablelist[numdownloadablelists].prefix); Z_Free(downloadablelist[numdownloadablelists].prefix);
@ -2110,12 +2121,12 @@ static void PM_ListDownloaded(struct dl_download *dl)
if (f) if (f)
{ {
downloadablelist[listidx].received = 1; downloadablelist[listidx].status = SRCSTAT_OBTAINED;
PM_ParsePackageList(f, 0, dl->url, downloadablelist[listidx].prefix); PM_ParsePackageList(f, 0, dl->url, downloadablelist[listidx].prefix);
BZ_Free(f); BZ_Free(f);
} }
else else
downloadablelist[listidx].received = -1; downloadablelist[listidx].status = SRCSTAT_FAILED;
if (!doautoupdate && !domanifestinstall) if (!doautoupdate && !domanifestinstall)
return; //don't spam this. return; //don't spam this.
@ -2123,7 +2134,7 @@ static void PM_ListDownloaded(struct dl_download *dl)
//check if we're still waiting //check if we're still waiting
for (listidx = 0; listidx < numdownloadablelists; listidx++) for (listidx = 0; listidx < numdownloadablelists; listidx++)
{ {
if (!downloadablelist[listidx].received) if (downloadablelist[listidx].status == SRCSTAT_PENDING)
break; break;
} }
/* /*
@ -2189,8 +2200,8 @@ static void PM_AllowPackageListQuery_Callback(void *ctx, promptbutton_t opt)
//something changed, let it download now. //something changed, let it download now.
for (i = 0; i < numdownloadablelists; i++) for (i = 0; i < numdownloadablelists; i++)
{ {
if (downloadablelist[i].received == -2) if (downloadablelist[i].status == SRCSTAT_UNKNOWN)
downloadablelist[i].received = 0; downloadablelist[i].status = SRCSTAT_PENDING;
} }
PM_UpdatePackageList(false, 0); PM_UpdatePackageList(false, 0);
} }
@ -2207,7 +2218,7 @@ static void PM_UpdatePackageList(qboolean autoupdate, int retry)
//make sure our sources are okay. //make sure our sources are okay.
if (*pkg_downloads_url.string) if (*pkg_downloads_url.string)
PM_AddSubList(pkg_downloads_url.string, "", false, true); PM_AddSubList(pkg_downloads_url.string, "", false, pkg_autoupdate.ival>=0);
#ifndef WEBCLIENT #ifndef WEBCLIENT
for (i = 0; i < numdownloadablelists; i++) for (i = 0; i < numdownloadablelists; i++)
@ -2230,7 +2241,7 @@ static void PM_UpdatePackageList(qboolean autoupdate, int retry)
//kick off the initial tier of list-downloads. //kick off the initial tier of list-downloads.
for (i = 0; i < numdownloadablelists; i++) for (i = 0; i < numdownloadablelists; i++)
{ {
if (downloadablelist[i].received && allowphonehome>=0) if (downloadablelist[i].status != SRCSTAT_PENDING && allowphonehome>=0)
continue; continue;
autoupdate = false; autoupdate = false;
if (downloadablelist[i].curdl) if (downloadablelist[i].curdl)
@ -2238,7 +2249,7 @@ static void PM_UpdatePackageList(qboolean autoupdate, int retry)
if (allowphonehome<=0) if (allowphonehome<=0)
{ {
downloadablelist[i].received = -2; downloadablelist[i].status = SRCSTAT_UNKNOWN;
continue; continue;
} }
downloadablelist[i].curdl = HTTP_CL_Get(va("%s%s"DOWNLOADABLESARGS, downloadablelist[i].url, strchr(downloadablelist[i].url,'?')?"&":"?"), NULL, PM_ListDownloaded); downloadablelist[i].curdl = HTTP_CL_Get(va("%s%s"DOWNLOADABLESARGS, downloadablelist[i].url, strchr(downloadablelist[i].url,'?')?"&":"?"), NULL, PM_ListDownloaded);
@ -2253,7 +2264,7 @@ static void PM_UpdatePackageList(qboolean autoupdate, int retry)
else else
{ {
Con_Printf("Could not contact updates server - %s\n", downloadablelist[i].url); Con_Printf("Could not contact updates server - %s\n", downloadablelist[i].url);
downloadablelist[i].received = -1; downloadablelist[i].status = SRCSTAT_FAILED;
} }
} }
@ -2322,6 +2333,11 @@ static void PM_WriteInstalledPackages(void)
{ {
if (downloadablelist[i].save) if (downloadablelist[i].save)
{ {
if (downloadablelist[i].status == SRCSTAT_DISABLED)
s = va("sublist \"%s\" \"%s\" \"disabled\"\n", downloadablelist[i].url, downloadablelist[i].prefix);
else if (downloadablelist[i].status != SRCSTAT_UNKNOWN)
s = va("sublist \"%s\" \"%s\" \"enabled\"\n", downloadablelist[i].url, downloadablelist[i].prefix);
else
s = va("sublist \"%s\" \"%s\"\n", downloadablelist[i].url, downloadablelist[i].prefix); s = va("sublist \"%s\" \"%s\"\n", downloadablelist[i].url, downloadablelist[i].prefix);
VFS_WRITE(f, s, strlen(s)); VFS_WRITE(f, s, strlen(s));
} }
@ -3835,7 +3851,7 @@ void PM_Command_f(void)
{ //flush package cache, make a new request even if we already got a response from the server. { //flush package cache, make a new request even if we already got a response from the server.
int i; int i;
for (i = 0; i < numdownloadablelists; i++) for (i = 0; i < numdownloadablelists; i++)
downloadablelist[i].received = 0; downloadablelist[i].status = SRCSTAT_PENDING;
if (!allowphonehome) if (!allowphonehome)
allowphonehome = -1; //trigger a prompt, instead of ignoring it. allowphonehome = -1; //trigger a prompt, instead of ignoring it.
PM_UpdatePackageList(false, 0); PM_UpdatePackageList(false, 0);
@ -4506,6 +4522,50 @@ static qboolean MD_Key (struct menucustom_s *c, struct emenu_s *m, int key, unsi
} }
#ifdef WEBCLIENT #ifdef WEBCLIENT
static void MD_Source_Draw (int x, int y, struct menucustom_s *c, struct emenu_s *m)
{
char *text;
switch(downloadablelist[c->dint].status)
{
case SRCSTAT_OBTAINED:
case SRCSTAT_PENDING:
Draw_FunStringWidth (x, y, "^&02 ", 48, 2, false); //green
break;
case SRCSTAT_FAILED:
case SRCSTAT_UNKNOWN:
Draw_FunStringWidth (x, y, "^&0E ", 48, 2, false); //yellow
break;
case SRCSTAT_DISABLED:
Draw_FunStringWidth (x, y, "^&04 ", 48, 2, false); //red
break;
}
text = va("Source %s", downloadablelist[c->dint].url);
Draw_FunString (x+48, y, text);
}
static qboolean MD_Source_Key (struct menucustom_s *c, struct emenu_s *m, int key, unsigned int unicode)
{
if (key == K_ENTER || key == K_KP_ENTER || key == K_GP_START || key == K_MOUSE1)
{
switch(downloadablelist[c->dint].status)
{
case SRCSTAT_OBTAINED:
case SRCSTAT_PENDING:
case SRCSTAT_FAILED:
case SRCSTAT_UNKNOWN:
downloadablelist[c->dint].status = SRCSTAT_DISABLED;
break;
case SRCSTAT_DISABLED:
downloadablelist[c->dint].status = SRCSTAT_PENDING;
break;
}
downloadablelist[c->dint].save = true;
PM_WriteInstalledPackages();
PM_UpdatePackageList(true, 2);
}
return false;
}
static void MD_AutoUpdate_Draw (int x, int y, struct menucustom_s *c, struct emenu_s *m) static void MD_AutoUpdate_Draw (int x, int y, struct menucustom_s *c, struct emenu_s *m)
{ {
char *settings[] = char *settings[] =
@ -4794,7 +4854,7 @@ static void MD_Download_UpdateStatus(struct emenu_s *m)
{ {
for (i = 0; i < numdownloadablelists; i++) for (i = 0; i < numdownloadablelists; i++)
{ {
if (!downloadablelist[i].received) if (downloadablelist[i].status == SRCSTAT_PENDING)
{ {
Draw_FunStringWidth(0, vid.height - 8, "Querying for package list", vid.width, 2, false); Draw_FunStringWidth(0, vid.height - 8, "Querying for package list", vid.width, 2, false);
return; return;
@ -4804,6 +4864,18 @@ static void MD_Download_UpdateStatus(struct emenu_s *m)
info->populated = true; info->populated = true;
MC_AddFrameStart(m, 48); MC_AddFrameStart(m, 48);
y = 48; y = 48;
#ifdef WEBCLIENT
for (i = 0; i < numdownloadablelists; i++)
{
c = MC_AddCustom(m, 0, y, p, i, NULL);
c->draw = MD_Source_Draw;
c->key = MD_Source_Key;
c->common.width = 320-48-16;
c->common.height = 8;
y += 8;
}
y+=4; //small gap
#endif
b = MC_AddCommand(m, 48, 320-16, y, info->applymessage, MD_ApplyDownloads); b = MC_AddCommand(m, 48, 320-16, y, info->applymessage, MD_ApplyDownloads);
b->rightalign = false; b->rightalign = false;
b->common.tooltip = "Enable/Disable/Download/Delete packages to match any changes made (you will be prompted with a list of the changes that will be made)."; b->common.tooltip = "Enable/Disable/Download/Delete packages to match any changes made (you will be prompted with a list of the changes that will be made).";

View file

@ -688,6 +688,9 @@ void CD_f (void)
if (Q_strcasecmp(command, "eject") == 0) if (Q_strcasecmp(command, "eject") == 0)
{ {
if (Cmd_IsInsecure())
return;
if (cdplayingtrack || cdpausedtrack) if (cdplayingtrack || cdpausedtrack)
CDAudio_Stop(); CDAudio_Stop();
CDAudio_Eject(); CDAudio_Eject();

View file

@ -1313,16 +1313,10 @@ void M_Menu_FPS_f (void)
{ {
"Disabled", "Disabled",
"Average FPS", "Average FPS",
"Worst FPS", "Timing Graph",
"Best FPS",
"Immediate FPS",
"Average MSEC",
"Worst MSEC",
"Best MSEC",
"Immediate MSEC",
NULL NULL
}; };
static const char *fpsvalues[] = {"0", "1", "2", "3", "4", "-1", "-2", "-3", "-4", NULL}; static const char *fpsvalues[] = {"0", "1", "2", NULL};
static const char *entlerpopts[] = static const char *entlerpopts[] =
{ {
"Enabled (always)", "Enabled (always)",

View file

@ -3387,6 +3387,16 @@ static void QCBUILTIN PF_ReadFloat(pubprogfuncs_t *prinst, struct globalvars_s *
} }
G_FLOAT(OFS_RETURN) = MSG_ReadFloat(); G_FLOAT(OFS_RETURN) = MSG_ReadFloat();
} }
static void QCBUILTIN PF_ReadDouble(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
if (!csqc_mayread)
{
CSQC_Abort("PF_ReadDouble is not valid at this time");
G_FLOAT(OFS_RETURN) = -1;
return;
}
G_DOUBLE(OFS_RETURN) = MSG_ReadDouble();
}
static void QCBUILTIN PF_ReadInt(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) static void QCBUILTIN PF_ReadInt(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{ {
if (!csqc_mayread) if (!csqc_mayread)
@ -3397,6 +3407,16 @@ static void QCBUILTIN PF_ReadInt(pubprogfuncs_t *prinst, struct globalvars_s *pr
} }
G_INT(OFS_RETURN) = MSG_ReadLong(); G_INT(OFS_RETURN) = MSG_ReadLong();
} }
static void QCBUILTIN PF_ReadInt64(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
if (!csqc_mayread)
{
CSQC_Abort("PF_ReadInt is not valid at this time");
G_INT(OFS_RETURN) = -1;
return;
}
G_INT64(OFS_RETURN) = MSG_ReadInt64();
}
static void QCBUILTIN PF_ReadString(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) static void QCBUILTIN PF_ReadString(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{ {
@ -3681,11 +3701,31 @@ static void QCBUILTIN PF_cs_sendevent (pubprogfuncs_t *prinst, struct globalvars
MSG_WriteByte(&cls.netchan.message, ev_float); MSG_WriteByte(&cls.netchan.message, ev_float);
MSG_WriteFloat(&cls.netchan.message, G_FLOAT(OFS_PARM2+i*3)); MSG_WriteFloat(&cls.netchan.message, G_FLOAT(OFS_PARM2+i*3));
} }
else if (argtypes[i] == 'F')
{
MSG_WriteByte(&cls.netchan.message, ev_double);
MSG_WriteDouble(&cls.netchan.message, G_DOUBLE(OFS_PARM2+i*3));
}
else if (argtypes[i] == 'i') else if (argtypes[i] == 'i')
{ {
MSG_WriteByte(&cls.netchan.message, ev_integer); MSG_WriteByte(&cls.netchan.message, ev_integer);
MSG_WriteLong(&cls.netchan.message, G_INT(OFS_PARM2+i*3)); MSG_WriteLong(&cls.netchan.message, G_INT(OFS_PARM2+i*3));
} }
else if (argtypes[i] == 'u')
{
MSG_WriteByte(&cls.netchan.message, ev_uint);
MSG_WriteLong(&cls.netchan.message, G_UINT(OFS_PARM2+i*3));
}
else if (argtypes[i] == 'I')
{
MSG_WriteByte(&cls.netchan.message, ev_int64);
MSG_WriteInt64(&cls.netchan.message, G_INT64(OFS_PARM2+i*3));
}
else if (argtypes[i] == 'U')
{
MSG_WriteByte(&cls.netchan.message, ev_uint64);
MSG_WriteInt64(&cls.netchan.message, G_UINT64(OFS_PARM2+i*3));
}
else if (argtypes[i] == 'v') else if (argtypes[i] == 'v')
{ {
MSG_WriteByte(&cls.netchan.message, ev_vector); MSG_WriteByte(&cls.netchan.message, ev_vector);
@ -6936,8 +6976,10 @@ static struct {
{"readangle", PF_ReadAngle, 365}, // #365 float() readangle (EXT_CSQC) {"readangle", PF_ReadAngle, 365}, // #365 float() readangle (EXT_CSQC)
{"readstring", PF_ReadString, 366}, // #366 string() readstring (EXT_CSQC) {"readstring", PF_ReadString, 366}, // #366 string() readstring (EXT_CSQC)
{"readfloat", PF_ReadFloat, 367}, // #367 string() readfloat (EXT_CSQC) {"readfloat", PF_ReadFloat, 367}, // #367 float() readfloat (EXT_CSQC)
{"readint", PF_ReadInt, 0}, // #0 string() readint {"readdouble", PF_ReadDouble, 0}, // #367 __double() readdouble (EXT_CSQC)
{"readint", PF_ReadInt, 0}, // #0 int() readint
{"readint64", PF_ReadInt64, 0}, // #0 __int64() readint64
{"readentitynum", PF_ReadEntityNum, 368}, // #368 float() readentitynum (EXT_CSQC) {"readentitynum", PF_ReadEntityNum, 368}, // #368 float() readentitynum (EXT_CSQC)
// {"readserverentitystate", PF_ReadServerEntityState, 369}, // #369 void(float flags, float simtime) readserverentitystate (EXT_CSQC_1) // {"readserverentitystate", PF_ReadServerEntityState, 369}, // #369 void(float flags, float simtime) readserverentitystate (EXT_CSQC_1)

View file

@ -397,7 +397,7 @@ void COM_AssertMainThread(const char *msg);
#define COM_HasWork() false #define COM_HasWork() false
#define COM_DoWork(t,l) false #define COM_DoWork(t,l) false
#define COM_AssertMainThread(msg) #define COM_AssertMainThread(msg)
#define COM_MainThreadWork() #define COM_MainThreadWork() while(0)
#define COM_MainThreadFlush() #define COM_MainThreadFlush()
#define COM_DestroyWorkerThread() #define COM_DestroyWorkerThread()
#define COM_WorkerAbort(m) #define COM_WorkerAbort(m)

View file

@ -30,6 +30,7 @@ int r_regsequence;
int rspeeds[RSPEED_MAX]; int rspeeds[RSPEED_MAX];
int rquant[RQUANT_MAX]; int rquant[RQUANT_MAX];
static void R_RegisterBuiltinRenderers(void);
void R_InitParticleTexture (void); void R_InitParticleTexture (void);
void R_RestartRenderer (rendererstate_t *newr); void R_RestartRenderer (rendererstate_t *newr);
static void R_UpdateRendererOpts(void); static void R_UpdateRendererOpts(void);
@ -1080,6 +1081,9 @@ void Renderer_Init(void)
P_InitParticleSystem(); P_InitParticleSystem();
R_InitTextures(); R_InitTextures();
R_RegisterBuiltinRenderers();
} }
qboolean Renderer_Started(void) qboolean Renderer_Started(void)
@ -1128,9 +1132,49 @@ qboolean (*SCR_UpdateScreen) (void);
r_qrenderer_t qrenderer; r_qrenderer_t qrenderer;
char *q_renderername = "Non-Selected renderer"; char *q_renderername = "Non-Selected renderer";
static struct
{
void *module;
rendererinfo_t *ri;
} rendererinfo[16];
qboolean R_RegisterRenderer(void *module, rendererinfo_t *ri)
{
size_t i;
for (i = 0; i < countof(rendererinfo); i++)
{ //already registered
if (rendererinfo[i].ri == ri)
return true;
}
for (i = 0; i < countof(rendererinfo); i++)
{ //register it in the first empty slot
if (!rendererinfo[i].ri)
{
rendererinfo[i].module = module;
rendererinfo[i].ri = ri;
return true;
}
}
Sys_Printf("unable to register renderer %s\n", ri->description);
return false;
}
static plugvrfuncs_t *vrfuncs;
qboolean R_RegisterVRDriver(void *module, plugvrfuncs_t *vr)
{
if (!vrfuncs)
{
vrfuncs = vr;
return true;
}
Sys_Printf("unable to register renderer %s\n", vr->description);
return false;
}
rendererinfo_t dedicatedrendererinfo = {
static rendererinfo_t dedicatedrendererinfo = {
//ALL builds need a 'none' renderer, as 0. //ALL builds need a 'none' renderer, as 0.
"No renderer", "No renderer",
{ {
@ -1188,138 +1232,104 @@ rendererinfo_t dedicatedrendererinfo = {
"" ""
}; };
static void R_RegisterBuiltinRenderers(void)
#ifdef GLQUAKE
extern rendererinfo_t openglrendererinfo;
#ifdef USE_EGL
extern rendererinfo_t eglrendererinfo;
#endif
extern rendererinfo_t rpirendererinfo;
#ifdef WAYLANDQUAKE
extern rendererinfo_t rendererinfo_wayland_gl;
#endif
rendererinfo_t fbdevrendererinfo;
#endif
#ifdef D3D8QUAKE
extern rendererinfo_t d3d8rendererinfo;
#endif
#ifdef D3D9QUAKE
extern rendererinfo_t d3d9rendererinfo;
#endif
#ifdef D3D11QUAKE
extern rendererinfo_t d3d11rendererinfo;
#endif
#ifdef SWQUAKE
extern rendererinfo_t swrendererinfo;
#endif
#ifdef VKQUAKE
extern rendererinfo_t vkrendererinfo;
//rendererinfo_t headlessvkrendererinfo;
#if defined(_WIN32) && defined(GLQUAKE) && !defined(FTE_SDL)
extern rendererinfo_t nvvkrendererinfo;
#endif
#ifdef WAYLANDQUAKE
extern rendererinfo_t rendererinfo_wayland_vk;
#endif
#endif
#ifdef HEADLESSQUAKE
extern rendererinfo_t headlessrenderer;
#endif
#if defined(GLQUAKE) && defined(USE_EGL)
extern rendererinfo_t rendererinfo_headless_egl;
#endif
static struct
{ {
void *module;
rendererinfo_t *ri;
} rendererinfo[16] =
{
#ifdef GLQUAKE
#ifdef FTE_RPI
{NULL, &rpirendererinfo},
#endif
{NULL, &openglrendererinfo},
#ifdef USE_EGL
{NULL, &eglrendererinfo},
#endif
#endif
#ifdef D3D9QUAKE
{NULL, &d3d9rendererinfo},
#endif
#ifdef VKQUAKE
{NULL, &vkrendererinfo},
#if defined(_WIN32) && defined(GLQUAKE) && !defined(FTE_SDL)
{NULL, &nvvkrendererinfo},
#endif
#endif
#ifdef D3D11QUAKE
{NULL, &d3d11rendererinfo},
#endif
#ifdef SWQUAKE
{NULL, &swrendererinfo},
#endif
#ifdef D3D8QUAKE
{NULL, &d3d8rendererinfo},
#endif
#ifdef WAYLANDQUAKE
#ifdef GLQUAKE #ifdef GLQUAKE
{NULL, &rendererinfo_wayland_gl}, {
extern rendererinfo_t openglrendererinfo;
#ifdef FTE_RPI
{
extern rendererinfo_t rpirendererinfo;
R_RegisterRenderer(NULL, &rpirendererinfo);
}
#endif
R_RegisterRenderer(NULL, &openglrendererinfo);
#ifdef USE_EGL
{
extern rendererinfo_t eglrendererinfo;
R_RegisterRenderer(NULL, &eglrendererinfo);
}
#endif
}
#endif
#ifdef D3D9QUAKE
{
extern rendererinfo_t d3d9rendererinfo;
R_RegisterRenderer(NULL, &d3d9rendererinfo);
}
#endif #endif
#ifdef VKQUAKE #ifdef VKQUAKE
{NULL, &rendererinfo_wayland_vk}, {
extern rendererinfo_t vkrendererinfo;
R_RegisterRenderer(NULL, &vkrendererinfo);
#if defined(_WIN32) && defined(GLQUAKE) && !defined(FTE_SDL)
{
extern rendererinfo_t nvvkrendererinfo;
R_RegisterRenderer(NULL, &nvvkrendererinfo);
}
#endif
}
#endif
#ifdef D3D11QUAKE
{
extern rendererinfo_t d3d11rendererinfo;
R_RegisterRenderer(NULL, &d3d11rendererinfo);
}
#endif
#ifdef SWQUAKE
{
extern rendererinfo_t swrendererinfo;
R_RegisterRenderer(NULL, &swrendererinfo);
}
#endif
#ifdef D3D8QUAKE
{
extern rendererinfo_t d3d8rendererinfo;
R_RegisterRenderer(NULL, &d3d8rendererinfo);
}
#endif
#ifdef WAYLANDQUAKE
#ifdef GLQUAKE
{
extern rendererinfo_t rendererinfo_wayland_gl;
R_RegisterRenderer(NULL, &rendererinfo_wayland_gl);
}
#endif #endif
#endif
#ifdef GLQUAKE
{NULL, &fbdevrendererinfo}, //direct stuff that doesn't interact well with the system should always be low priority
#endif
#ifndef NPQTV
{NULL, &dedicatedrendererinfo},
#endif
#ifdef HEADLESSQUAKE
{NULL, &headlessrenderer},
#ifdef VKQUAKE #ifdef VKQUAKE
//{NULL, &headlessvkrendererinfo}, {
extern rendererinfo_t rendererinfo_wayland_vk;
R_RegisterRenderer(NULL, &rendererinfo_wayland_vk);
}
#endif #endif
#endif #endif
#if defined(GLQUAKE) && defined(USE_EGL) #if defined(GLQUAKE) && defined(USE_FBDEV)
{NULL, &rendererinfo_headless_egl},
#endif
};
qboolean R_RegisterRenderer(void *module, rendererinfo_t *ri)
{
size_t i;
for (i = 0; i < countof(rendererinfo); i++)
{ //already registered
if (rendererinfo[i].ri == ri)
return true;
}
for (i = 0; i < countof(rendererinfo); i++)
{ //register it in the first empty slot
if (!rendererinfo[i].ri)
{ {
rendererinfo[i].module = module; extern rendererinfo_t fbdevrendererinfo;
rendererinfo[i].ri = ri; R_RegisterRenderer(NULL, &fbdevrendererinfo); //direct stuff that doesn't interact well with the system should always be low priority
return true;
} }
#endif
#ifndef NPQTV
R_RegisterRenderer(NULL, &dedicatedrendererinfo);
#endif
#ifdef HEADLESSQUAKE
{
extern rendererinfo_t headlessrenderer;
R_RegisterRenderer(NULL, &headlessrenderer);
#ifdef VKQUAKE
//R_RegisterRenderer(NULL, &headlessvkrendererinfo);
#endif
} }
Sys_Printf("unable to register renderer %s\n", ri->description); #endif
return false; #if defined(GLQUAKE) && defined(USE_EGL)
{
extern rendererinfo_t rendererinfo_headless_egl;
R_RegisterRenderer(NULL, &rendererinfo_headless_egl);
}
#endif
} }
static plugvrfuncs_t *vrfuncs;
qboolean R_RegisterVRDriver(void *module, plugvrfuncs_t *vr)
{
if (!vrfuncs)
{
vrfuncs = vr;
return true;
}
Sys_Printf("unable to register renderer %s\n", vr->description);
return false;
}
void R_SetRenderer(rendererinfo_t *ri) void R_SetRenderer(rendererinfo_t *ri)
{ {
@ -2282,7 +2292,7 @@ void R_RestartRenderer (rendererstate_t *newr)
//if we ended up resorting to our last choice (dedicated) then print some informative message about it //if we ended up resorting to our last choice (dedicated) then print some informative message about it
//fixme: on unixy systems, we should make sure we're actually printing to something (ie: that we're not running via some x11 shortcut with our stdout redirected to /dev/nul //fixme: on unixy systems, we should make sure we're actually printing to something (ie: that we're not running via some x11 shortcut with our stdout redirected to /dev/nul
if (!failed && newr->renderer == &dedicatedrendererinfo) if (!failed && (!newr->renderer || newr->renderer->rtype == QR_NONE))
{ {
Con_Printf(CON_ERROR "Video mode switch failed. Console forced.\n\nPlease change the following vars to something useable, and then use the setrenderer command.\n"); Con_Printf(CON_ERROR "Video mode switch failed. Console forced.\n\nPlease change the following vars to something useable, and then use the setrenderer command.\n");
Con_Printf("%s: %s\n", vid_width.name, vid_width.string); Con_Printf("%s: %s\n", vid_width.name, vid_width.string);

View file

@ -3020,7 +3020,7 @@ void Sbar_IntermissionNumber (float x, float y, int num, int digits, int color,
else else
frame = *ptr -'0'; frame = *ptr -'0';
R2D_ScalePicAtlas (x,y, 16, 24, sb_nums[color][frame]); R2D_ScalePicAtlas (x,y, 24, 24, sb_nums[color][frame]);
x += 24; x += 24;
ptr++; ptr++;
} }
@ -3800,17 +3800,17 @@ void Sbar_CoopIntermission (playerview_t *pv)
dig = cl.completed_time/60; dig = cl.completed_time/60;
Sbar_IntermissionNumber ((sbar_rect.width - 320)/2 + 230 - 24*4, (sbar_rect.height - 200)/2 + 64, dig, 4, 0, false); Sbar_IntermissionNumber ((sbar_rect.width - 320)/2 + 230 - 24*4, (sbar_rect.height - 200)/2 + 64, dig, 4, 0, false);
num = cl.completed_time - dig*60; num = cl.completed_time - dig*60;
R2D_ScalePicAtlas ((sbar_rect.width - 320)/2 + 230,(sbar_rect.height - 200)/2 + 64, 16, 24, sb_colon); R2D_ScalePicAtlas ((sbar_rect.width - 320)/2 + 230,(sbar_rect.height - 200)/2 + 64, 24, 24, sb_colon);
R2D_ScalePicAtlas ((sbar_rect.width - 320)/2 + 254,(sbar_rect.height - 200)/2 + 64, 16, 26, sb_nums[0][num/10]); R2D_ScalePicAtlas ((sbar_rect.width - 320)/2 + 254,(sbar_rect.height - 200)/2 + 64, 24, 24, sb_nums[0][num/10]);
R2D_ScalePicAtlas ((sbar_rect.width - 320)/2 + 278,(sbar_rect.height - 200)/2 + 64, 16, 24, sb_nums[0][num%10]); R2D_ScalePicAtlas ((sbar_rect.width - 320)/2 + 278,(sbar_rect.height - 200)/2 + 64, 24, 24, sb_nums[0][num%10]);
//it is assumed that secrits/monsters are going to be constant for any player... //it is assumed that secrits/monsters are going to be constant for any player...
Sbar_IntermissionNumber ((sbar_rect.width - 320)/2 + 230 - 24*4, (sbar_rect.height - 200)/2 + 104, pv->stats[STAT_SECRETS], 4, 0, false); Sbar_IntermissionNumber ((sbar_rect.width - 320)/2 + 230 - 24*4, (sbar_rect.height - 200)/2 + 104, pv->stats[STAT_SECRETS], 4, 0, false);
R2D_ScalePicAtlas ((sbar_rect.width - 320)/2 + 230, (sbar_rect.height - 200)/2 + 104, 16, 24, sb_slash); R2D_ScalePicAtlas ((sbar_rect.width - 320)/2 + 230, (sbar_rect.height - 200)/2 + 104, 24, 24, sb_slash);
Sbar_IntermissionNumber ((sbar_rect.width - 320)/2 + 254, (sbar_rect.height - 200)/2 + 104, pv->stats[STAT_TOTALSECRETS], 4, 0, true); Sbar_IntermissionNumber ((sbar_rect.width - 320)/2 + 254, (sbar_rect.height - 200)/2 + 104, pv->stats[STAT_TOTALSECRETS], 4, 0, true);
Sbar_IntermissionNumber ((sbar_rect.width - 320)/2 + 230 - 24*4, (sbar_rect.height - 200)/2 + 144, pv->stats[STAT_MONSTERS], 4, 0, false); Sbar_IntermissionNumber ((sbar_rect.width - 320)/2 + 230 - 24*4, (sbar_rect.height - 200)/2 + 144, pv->stats[STAT_MONSTERS], 4, 0, false);
R2D_ScalePicAtlas ((sbar_rect.width - 320)/2 + 230,(sbar_rect.height - 200)/2 + 144, 16, 24, sb_slash); R2D_ScalePicAtlas ((sbar_rect.width - 320)/2 + 230,(sbar_rect.height - 200)/2 + 144, 24, 24, sb_slash);
Sbar_IntermissionNumber ((sbar_rect.width - 320)/2 + 254, (sbar_rect.height - 200)/2 + 144, pv->stats[STAT_TOTALMONSTERS], 4, 0, true); Sbar_IntermissionNumber ((sbar_rect.width - 320)/2 + 254, (sbar_rect.height - 200)/2 + 144, pv->stats[STAT_TOTALMONSTERS], 4, 0, true);
} }
/* /*

View file

@ -387,4 +387,4 @@ fte_inline float M_LinearToSRGB(float x, float mag)
void R_NetgraphInit(void); void R_NetgraphInit(void);
void R_NetGraph (void); void R_NetGraph (void);
void R_FrameTimeGraph (float frametime); void R_FrameTimeGraph (float frametime, float scale);

View file

@ -157,7 +157,7 @@ static cvar_t v_depthsortentities = CVARAD("v_depthsortentities", "0", "v_reord
#ifdef QUAKESTATS #ifdef QUAKESTATS
static cvar_t scr_autoid = CVARD("scr_autoid", "1", "Display nametags above all players while spectating."); static cvar_t scr_autoid = CVARD("scr_autoid", "1", "Display nametags above all players while spectating.");
static cvar_t scr_autoid_team = CVARD("scr_autoid_team", "2", "Display nametags above team members. 0: off. 1: display with half-alpha if occluded. 2: hide when occluded."); static cvar_t scr_autoid_team = CVARD("scr_autoid_team", "0", "Display nametags above team members. 0: off. 1: display with half-alpha if occluded. 2: hide when occluded.");
static cvar_t scr_autoid_health = CVARD("scr_autoid_health", "1", "Display health as part of nametags (when known)."); static cvar_t scr_autoid_health = CVARD("scr_autoid_health", "1", "Display health as part of nametags (when known).");
static cvar_t scr_autoid_armour = CVARD("scr_autoid_armor", "1", "Display armour as part of nametags (when known)."); static cvar_t scr_autoid_armour = CVARD("scr_autoid_armor", "1", "Display armour as part of nametags (when known).");
static cvar_t scr_autoid_weapon = CVARD("scr_autoid_weapon", "1", "Display the player's best weapon as part of their nametag (when known)."); static cvar_t scr_autoid_weapon = CVARD("scr_autoid_weapon", "1", "Display the player's best weapon as part of their nametag (when known).");

View file

@ -746,6 +746,21 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define fte_alignof(type) sizeof(qintptr_t) #define fte_alignof(type) sizeof(qintptr_t)
#endif #endif
//safeswitch(foo){safedefault: break;}
//switch, but errors for any omitted enum values despite the presence of a default case.
//(gcc will generally give warnings without the default, but sometimes you don't have control over the source of your enumeration values)
#if (__GNUC__ >= 4)
#define safeswitch \
_Pragma("GCC diagnostic push") \
_Pragma("GCC diagnostic error \"-Wswitch-enum\"") \
_Pragma("GCC diagnostic error \"-Wswitch-default\"") \
switch
#define safedefault _Pragma("GCC diagnostic pop") default
#else
#define safeswitch switch
#define safedefault default
#endif
//fte_inline must only be used in headers, and requires one and ONLY one fte_inlinebody elsewhere. //fte_inline must only be used in headers, and requires one and ONLY one fte_inlinebody elsewhere.
//fte_inlinebody must be used on a prototype OUTSIDE of a header. //fte_inlinebody must be used on a prototype OUTSIDE of a header.
//fte_inlinestatic must not be used inside any headers at all. //fte_inlinestatic must not be used inside any headers at all.

View file

@ -887,7 +887,7 @@ void MSG_WriteByte (sizebuf_t *sb, int c)
#endif #endif
buf = (qbyte*)SZ_GetSpace (sb, 1); buf = (qbyte*)SZ_GetSpace (sb, 1);
buf[0] = c; buf[0] = c&0xff;
} }
void MSG_WriteShort (sizebuf_t *sb, int c) void MSG_WriteShort (sizebuf_t *sb, int c)
@ -901,7 +901,7 @@ void MSG_WriteShort (sizebuf_t *sb, int c)
buf = (qbyte*)SZ_GetSpace (sb, 2); buf = (qbyte*)SZ_GetSpace (sb, 2);
buf[0] = c&0xff; buf[0] = c&0xff;
buf[1] = c>>8; buf[1] = (c>>8)&0xff;
} }
void MSG_WriteLong (sizebuf_t *sb, int c) void MSG_WriteLong (sizebuf_t *sb, int c)
@ -912,7 +912,21 @@ void MSG_WriteLong (sizebuf_t *sb, int c)
buf[0] = c&0xff; buf[0] = c&0xff;
buf[1] = (c>>8)&0xff; buf[1] = (c>>8)&0xff;
buf[2] = (c>>16)&0xff; buf[2] = (c>>16)&0xff;
buf[3] = c>>24; buf[3] = (c>>24)&0xff;
}
void MSG_WriteInt64 (sizebuf_t *sb, qint64_t c)
{
qbyte *buf;
buf = (qbyte*)SZ_GetSpace (sb, 8);
buf[0] = c&0xff;
buf[1] = (c>>8)&0xff;
buf[2] = (c>>16)&0xff;
buf[3] = (c>>24)&0xff;
buf[4] = (c>>32)&0xff;
buf[5] = (c>>40)&0xff;
buf[6] = (c>>48)&0xff;
buf[7] = (c>>52)&0xff;
} }
void MSG_WriteFloat (sizebuf_t *sb, float f) void MSG_WriteFloat (sizebuf_t *sb, float f)
@ -929,6 +943,17 @@ void MSG_WriteFloat (sizebuf_t *sb, float f)
SZ_Write (sb, &dat.l, 4); SZ_Write (sb, &dat.l, 4);
} }
void MSG_WriteDouble (sizebuf_t *sb, double f)
{
union
{
double f;
qint64_t l;
} dat;
dat.f = f;
MSG_WriteInt64(sb, dat.l);
}
void MSG_WriteString (sizebuf_t *sb, const char *s) void MSG_WriteString (sizebuf_t *sb, const char *s)
{ {
@ -1586,6 +1611,36 @@ int MSG_ReadLong (void)
return c; return c;
} }
qint64_t MSG_ReadInt64 (void)
{
qint64_t c;
if (net_message.packing!=SZ_RAWBYTES)
{
c = (unsigned int)MSG_ReadBits(32)
| ((qint64_t)(unsigned int)MSG_ReadBits(32)<<32);
return c;
}
if (msg_readcount+4 > net_message.cursize)
{
msg_badread = true;
return -1;
}
c = (net_message.data[msg_readcount+0]<<0)
| (net_message.data[msg_readcount+1]<<8)
| (net_message.data[msg_readcount+2]<<16)
| (net_message.data[msg_readcount+3]<<24)
| ((qint64_t)net_message.data[msg_readcount+5]<<32)
| ((qint64_t)net_message.data[msg_readcount+6]<<40)
| ((qint64_t)net_message.data[msg_readcount+7]<<48)
| ((qint64_t)net_message.data[msg_readcount+8]<<52);
msg_readcount += 8;
return c;
}
float MSG_ReadFloat (void) float MSG_ReadFloat (void)
{ {
@ -1614,10 +1669,21 @@ float MSG_ReadFloat (void)
dat.b[3] = net_message.data[msg_readcount+3]; dat.b[3] = net_message.data[msg_readcount+3];
msg_readcount += 4; msg_readcount += 4;
if (bigendian)
dat.l = LittleLong (dat.l); dat.l = LittleLong (dat.l);
return dat.f; return dat.f;
} }
double MSG_ReadDouble (void)
{ //type-pun it as an int64 over the network for easier handling of endian.
union
{
double d;
qint64_t l;
} dat;
dat.l = MSG_ReadInt64();
return dat.d;
}
char *MSG_ReadStringBuffer (char *out, size_t outsize) char *MSG_ReadStringBuffer (char *out, size_t outsize)
{ {
@ -5188,6 +5254,7 @@ static cvar_t worker_sleeptime = CVARFD("worker_sleeptime", "0", CVAR_NOTFROMSER
void *com_resourcemutex; void *com_resourcemutex;
static int com_liveworkers[WG_COUNT]; static int com_liveworkers[WG_COUNT];
static void *com_workercondition[WG_COUNT]; static void *com_workercondition[WG_COUNT];
int com_hadwork[WG_COUNT];
static volatile int com_workeracksequence; static volatile int com_workeracksequence;
static struct com_worker_s static struct com_worker_s
{ {
@ -5332,6 +5399,7 @@ qboolean COM_DoWork(int tg, qboolean leavelocked)
if (work) if (work)
{ {
com_hadwork[tg]++;
// Sys_Printf("%x: Doing work %p (%s)\n", thread, work->ctx, work->ctx?(char*)work->ctx:"?"); // Sys_Printf("%x: Doing work %p (%s)\n", thread, work->ctx, work->ctx?(char*)work->ctx:"?");
Sys_UnlockConditional(com_workercondition[tg]); Sys_UnlockConditional(com_workercondition[tg]);

View file

@ -277,8 +277,10 @@ void MSG_WriteChar (sizebuf_t *sb, int c);
void MSG_WriteByte (sizebuf_t *sb, int c); void MSG_WriteByte (sizebuf_t *sb, int c);
void MSG_WriteShort (sizebuf_t *sb, int c); void MSG_WriteShort (sizebuf_t *sb, int c);
void MSG_WriteLong (sizebuf_t *sb, int c); void MSG_WriteLong (sizebuf_t *sb, int c);
void MSG_WriteInt64 (sizebuf_t *sb, qint64_t c);
void MSG_WriteEntity (sizebuf_t *sb, unsigned int e); void MSG_WriteEntity (sizebuf_t *sb, unsigned int e);
void MSG_WriteFloat (sizebuf_t *sb, float f); void MSG_WriteFloat (sizebuf_t *sb, float f);
void MSG_WriteDouble (sizebuf_t *sb, double f);
void MSG_WriteString (sizebuf_t *sb, const char *s); void MSG_WriteString (sizebuf_t *sb, const char *s);
void MSG_WriteCoord (sizebuf_t *sb, float f); void MSG_WriteCoord (sizebuf_t *sb, float f);
void MSG_WriteBigCoord (sizebuf_t *sb, float f); void MSG_WriteBigCoord (sizebuf_t *sb, float f);
@ -300,10 +302,12 @@ int MSG_ReadBits(int bits);
int MSG_ReadByte (void); int MSG_ReadByte (void);
int MSG_ReadShort (void); int MSG_ReadShort (void);
int MSG_ReadLong (void); int MSG_ReadLong (void);
qint64_t MSG_ReadInt64 (void);
struct client_s; struct client_s;
unsigned int MSGSV_ReadEntity (struct client_s *fromclient); unsigned int MSGSV_ReadEntity (struct client_s *fromclient);
unsigned int MSGCL_ReadEntity (void); unsigned int MSGCL_ReadEntity (void);
float MSG_ReadFloat (void); float MSG_ReadFloat (void);
double MSG_ReadDouble (void);
char *MSG_ReadStringBuffer (char *out, size_t outsize); char *MSG_ReadStringBuffer (char *out, size_t outsize);
char *MSG_ReadString (void); char *MSG_ReadString (void);
char *MSG_ReadStringLine (void); char *MSG_ReadStringLine (void);

View file

@ -1154,6 +1154,8 @@ qboolean Cvar_Register (cvar_t *variable, const char *groupname)
// check to see if it has already been defined // check to see if it has already been defined
old = Cvar_FindVar (variable->name); old = Cvar_FindVar (variable->name);
if (old && variable->name2)
old = Cvar_FindVar (variable->name2);
if (old) if (old)
{ {
if ((old->flags & CVAR_POINTER) && !(variable->flags & CVAR_POINTER)) if ((old->flags & CVAR_POINTER) && !(variable->flags & CVAR_POINTER))

View file

@ -891,8 +891,9 @@ vfsfile_t *SSL_OpenPrivKey(char *nativename, size_t nativesize)
} }
vfsfile_t *SSL_OpenPubKey(char *nativename, size_t nativesize) vfsfile_t *SSL_OpenPubKey(char *nativename, size_t nativesize)
{ {
#define fullchainname "fullchain.pem"
#define pubname "cert.pem" #define pubname "cert.pem"
vfsfile_t *pubf; vfsfile_t *pubf = NULL;
const char *mode = nativename?"wb":"rb"; const char *mode = nativename?"wb":"rb";
int i = COM_CheckParm("-pubkey"); int i = COM_CheckParm("-pubkey");
if (i++) if (i++)
@ -903,9 +904,9 @@ vfsfile_t *SSL_OpenPubKey(char *nativename, size_t nativesize)
} }
else else
{ {
if (nativename) if (!pubf && (!nativename || FS_NativePath(fullchainname, FS_ROOT, nativename, nativesize)))
if (!FS_NativePath(pubname, FS_ROOT, nativename, nativesize)) pubf = FS_OpenVFS(fullchainname, mode, FS_ROOT);
return NULL; if (!pubf && (!nativename || FS_NativePath(pubname, FS_ROOT, nativename, nativesize)))
pubf = FS_OpenVFS(pubname, mode, FS_ROOT); pubf = FS_OpenVFS(pubname, mode, FS_ROOT);
} }
return pubf; return pubf;

View file

@ -1230,7 +1230,8 @@ void QCBUILTIN PF_touchtriggers(pubprogfuncs_t *prinst, struct globalvars_s *pr_
//chained search for float reference fields //chained search for float reference fields
void QCBUILTIN PF_findchainflags (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) void QCBUILTIN PF_findchainflags (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{ {
int i, ff, cf; int i;
unsigned int ff, cf;
int s; int s;
wedict_t *ent, *chain; wedict_t *ent, *chain;
@ -1242,6 +1243,11 @@ void QCBUILTIN PF_findchainflags (pubprogfuncs_t *prinst, struct globalvars_s *p
cf = G_INT(OFS_PARM2)+prinst->fieldadjust; cf = G_INT(OFS_PARM2)+prinst->fieldadjust;
else else
cf = &((comentvars_t*)NULL)->chain - (pint_t*)NULL; cf = &((comentvars_t*)NULL)->chain - (pint_t*)NULL;
if (ff >= prinst->activefieldslots || cf >= prinst->activefieldslots)
{
PR_BIError (prinst, "PF_FindChain: bad field reference");
return;
}
for (i = 1; i < *prinst->parms->num_edicts; i++) for (i = 1; i < *prinst->parms->num_edicts; i++)
{ {
@ -1262,7 +1268,8 @@ void QCBUILTIN PF_findchainflags (pubprogfuncs_t *prinst, struct globalvars_s *p
//chained search for float, int, and entity reference fields //chained search for float, int, and entity reference fields
void QCBUILTIN PF_findchainfloat (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) void QCBUILTIN PF_findchainfloat (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{ {
int i, ff, cf; int i;
unsigned int ff, cf;
float s; float s;
wedict_t *ent, *chain; wedict_t *ent, *chain;
@ -1274,6 +1281,11 @@ void QCBUILTIN PF_findchainfloat (pubprogfuncs_t *prinst, struct globalvars_s *p
cf = G_INT(OFS_PARM2)+prinst->fieldadjust; cf = G_INT(OFS_PARM2)+prinst->fieldadjust;
else else
cf = &((comentvars_t*)NULL)->chain - (pint_t*)NULL; cf = &((comentvars_t*)NULL)->chain - (pint_t*)NULL;
if (ff >= prinst->activefieldslots || cf >= prinst->activefieldslots)
{
PR_BIError (prinst, "PF_FindChain: bad field reference");
return;
}
for (i = 1; i < *prinst->parms->num_edicts; i++) for (i = 1; i < *prinst->parms->num_edicts; i++)
{ {
@ -1294,7 +1306,8 @@ void QCBUILTIN PF_findchainfloat (pubprogfuncs_t *prinst, struct globalvars_s *p
//chained search for strings in entity fields //chained search for strings in entity fields
void QCBUILTIN PF_findchain (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) void QCBUILTIN PF_findchain (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{ {
int i, ff, cf; int i;
unsigned int ff, cf;
const char *s; const char *s;
string_t t; string_t t;
wedict_t *ent, *chain; wedict_t *ent, *chain;
@ -1307,6 +1320,11 @@ void QCBUILTIN PF_findchain (pubprogfuncs_t *prinst, struct globalvars_s *pr_glo
cf = G_INT(OFS_PARM2)+prinst->fieldadjust; cf = G_INT(OFS_PARM2)+prinst->fieldadjust;
else else
cf = &((comentvars_t*)NULL)->chain - (int*)NULL; cf = &((comentvars_t*)NULL)->chain - (int*)NULL;
if (ff >= prinst->activefieldslots || cf >= prinst->activefieldslots)
{
PR_BIError (prinst, "PF_FindChain: bad field reference");
return;
}
for (i = 1; i < *prinst->parms->num_edicts; i++) for (i = 1; i < *prinst->parms->num_edicts; i++)
{ {
@ -1330,12 +1348,18 @@ void QCBUILTIN PF_findchain (pubprogfuncs_t *prinst, struct globalvars_s *pr_glo
//entity(entity start, float fld, float match) findflags = #449 //entity(entity start, float fld, float match) findflags = #449
void QCBUILTIN PF_FindFlags (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) void QCBUILTIN PF_FindFlags (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{ {
int e, f; int e;
unsigned int f;
int s; int s;
wedict_t *ed; wedict_t *ed;
e = G_EDICTNUM(prinst, OFS_PARM0); e = G_EDICTNUM(prinst, OFS_PARM0);
f = G_INT(OFS_PARM1)+prinst->fieldadjust; f = G_INT(OFS_PARM1)+prinst->fieldadjust;
if (f >= prinst->activefieldslots)
{
PR_BIError (prinst, "PF_FindFlags: bad field reference");
return;
}
s = G_FLOAT(OFS_PARM2); s = G_FLOAT(OFS_PARM2);
for (e++; e < *prinst->parms->num_edicts; e++) for (e++; e < *prinst->parms->num_edicts; e++)
@ -1356,7 +1380,8 @@ void QCBUILTIN PF_FindFlags (pubprogfuncs_t *prinst, struct globalvars_s *pr_glo
//entity(entity start, float fld, float match) findfloat = #98 //entity(entity start, float fld, float match) findfloat = #98
void QCBUILTIN PF_FindFloat (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) void QCBUILTIN PF_FindFloat (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{ {
int e, f; int e;
unsigned int f;
int s; int s;
wedict_t *ed; wedict_t *ed;
@ -1370,6 +1395,11 @@ void QCBUILTIN PF_FindFloat (pubprogfuncs_t *prinst, struct globalvars_s *pr_glo
e = G_EDICTNUM(prinst, OFS_PARM0); e = G_EDICTNUM(prinst, OFS_PARM0);
f = G_INT(OFS_PARM1)+prinst->fieldadjust; f = G_INT(OFS_PARM1)+prinst->fieldadjust;
if (f >= prinst->activefieldslots)
{
PR_BIError (prinst, "PF_FindFloat: bad field reference");
return;
}
s = G_INT(OFS_PARM2); s = G_INT(OFS_PARM2);
for (e++; e < *prinst->parms->num_edicts; e++) for (e++; e < *prinst->parms->num_edicts; e++)
@ -1391,13 +1421,18 @@ void QCBUILTIN PF_FindFloat (pubprogfuncs_t *prinst, struct globalvars_s *pr_glo
void QCBUILTIN PF_FindString (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) void QCBUILTIN PF_FindString (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{ {
int e; int e;
int f; unsigned int f;
const char *s; const char *s;
string_t t; string_t t;
wedict_t *ed; wedict_t *ed;
e = G_EDICTNUM(prinst, OFS_PARM0); e = G_EDICTNUM(prinst, OFS_PARM0);
f = G_INT(OFS_PARM1)+prinst->fieldadjust; f = G_INT(OFS_PARM1)+prinst->fieldadjust;
if (f >= prinst->activefieldslots)
{
PR_BIError (prinst, "PF_FindString: bad field reference");
return;
}
s = PR_GetStringOfs(prinst, OFS_PARM2); s = PR_GetStringOfs(prinst, OFS_PARM2);
if (!s) if (!s)
{ {
@ -1430,8 +1465,7 @@ void QCBUILTIN PF_FindList (pubprogfuncs_t *prinst, struct globalvars_s *pr_glob
{ {
world_t *w = prinst->parms->user; world_t *w = prinst->parms->user;
int e; int e;
int f = G_INT(OFS_PARM0)+prinst->fieldadjust; unsigned int f = G_INT(OFS_PARM0)+prinst->fieldadjust;
string_t t;
wedict_t *ed; wedict_t *ed;
etype_t type = G_INT(OFS_PARM2); etype_t type = G_INT(OFS_PARM2);
@ -1439,11 +1473,25 @@ void QCBUILTIN PF_FindList (pubprogfuncs_t *prinst, struct globalvars_s *pr_glob
int *retlist; int *retlist;
unsigned found = 0; unsigned found = 0;
//FIXME: bound f if (type <= ev_double)
{
extern const unsigned int type_size[];
if (f < 0 || f+type_size[type] > prinst->activefieldslots)
{ //invalid field.
G_INT(OFS_PARM3) = G_INT(OFS_RETURN) = 0;
return;
}
}
else
{ //unsupported field type.
G_INT(OFS_PARM3) = G_INT(OFS_RETURN) = 0;
return;
}
if (type == ev_string) if (type == ev_string)
{ {
const char *s = PR_GetStringOfs(prinst, OFS_PARM1); const char *s = PR_GetStringOfs(prinst, OFS_PARM1);
string_t t;
if (!s) if (!s)
s = ""; /* o.O */ s = ""; /* o.O */
for (e=1 ; e < *prinst->parms->num_edicts ; e++) for (e=1 ; e < *prinst->parms->num_edicts ; e++)
@ -1460,39 +1508,63 @@ void QCBUILTIN PF_FindList (pubprogfuncs_t *prinst, struct globalvars_s *pr_glob
} }
else if (type == ev_float) else if (type == ev_float)
{ //handling -0 properly requires care { //handling -0 properly requires care
float s = G_FLOAT(OFS_PARM1); pvec_t s = G_FLOAT(OFS_PARM1);
for (e=1 ; e < *prinst->parms->num_edicts ; e++) for (e=1 ; e < *prinst->parms->num_edicts ; e++)
{ {
ed = WEDICT_NUM_PB(prinst, e); ed = WEDICT_NUM_PB(prinst, e);
if (ED_ISFREE(ed)) if (ED_ISFREE(ed))
continue; continue;
if (((float*)ed->v)[f] == s) if (((pvec_t*)ed->v)[f] == s)
list[found++] = EDICT_TO_PROG(prinst, ed);
}
}
else if (type == ev_double)
{ //handling 64bit -0 properly requires care
double s = G_DOUBLE(OFS_PARM1);
for (e=1 ; e < *prinst->parms->num_edicts ; e++)
{
ed = WEDICT_NUM_PB(prinst, e);
if (ED_ISFREE(ed))
continue;
if (*(double*)((pvec_t*)ed->v+f) == s)
list[found++] = EDICT_TO_PROG(prinst, ed);
}
}
else if (type == ev_int64 || type == ev_uint64)
{ //handling -0 properly requires care
pint64_t s = G_INT64(OFS_PARM1);
for (e=1 ; e < *prinst->parms->num_edicts ; e++)
{
ed = WEDICT_NUM_PB(prinst, e);
if (ED_ISFREE(ed))
continue;
if (*(pint64_t*)((pint_t*)ed->v+f) == s)
list[found++] = EDICT_TO_PROG(prinst, ed); list[found++] = EDICT_TO_PROG(prinst, ed);
} }
} }
else if (type == ev_vector) else if (type == ev_vector)
{ //big types... { //big types...
float *s = G_VECTOR(OFS_PARM1); pvec_t *s = G_VECTOR(OFS_PARM1);
for (e=1 ; e < *prinst->parms->num_edicts ; e++) for (e=1 ; e < *prinst->parms->num_edicts ; e++)
{ {
ed = WEDICT_NUM_PB(prinst, e); ed = WEDICT_NUM_PB(prinst, e);
if (ED_ISFREE(ed)) if (ED_ISFREE(ed))
continue; continue;
if (((float*)ed->v)[f+0] == s[0]&& if (((pvec_t*)ed->v)[f+0] == s[0]&&
((float*)ed->v)[f+1] == s[1]&& ((pvec_t*)ed->v)[f+1] == s[1]&&
((float*)ed->v)[f+2] == s[2]) ((pvec_t*)ed->v)[f+2] == s[2])
list[found++] = EDICT_TO_PROG(prinst, ed); list[found++] = EDICT_TO_PROG(prinst, ed);
} }
} }
else else
{ //generic references and other stuff that can just be treated as ints { //generic references and other stuff that can just be treated as ints
int s = G_INT(OFS_PARM1); pint_t s = G_INT(OFS_PARM1);
for (e=1 ; e < *prinst->parms->num_edicts ; e++) for (e=1 ; e < *prinst->parms->num_edicts ; e++)
{ {
ed = WEDICT_NUM_PB(prinst, e); ed = WEDICT_NUM_PB(prinst, e);
if (ED_ISFREE(ed)) if (ED_ISFREE(ed))
continue; continue;
if (((int*)ed->v)[f] == s) if (((pint_t*)ed->v)[f] == s)
list[found++] = EDICT_TO_PROG(prinst, ed); list[found++] = EDICT_TO_PROG(prinst, ed);
} }
} }
@ -6497,7 +6569,7 @@ void QCBUILTIN PF_gettime (pubprogfuncs_t *prinst, struct globalvars_s *pr_globa
G_FLOAT(OFS_RETURN) = realtime; G_FLOAT(OFS_RETURN) = realtime;
break; break;
case 1: //actual time, ish. we round to milliseconds to reduce spectre exposure case 1: //actual time, ish. we round to milliseconds to reduce spectre exposure
G_FLOAT(OFS_RETURN) = (qint64_t)(Sys_DoubleTime()*1000) / 1000.0; G_FLOAT(OFS_RETURN) = (qint64_t)Sys_Milliseconds();
break; break;
//case 2: //highres.. looks like time into the frame //case 2: //highres.. looks like time into the frame
//case 3: //uptime //case 3: //uptime

View file

@ -539,6 +539,7 @@ enum {
#define PF_GIB (1<<10) // offset the view height differently #define PF_GIB (1<<10) // offset the view height differently
//ZQuake. //ZQuake.
#define PF_PMC_SHIFT 11
#define PF_PMC_MASK ((1<<11) | \ #define PF_PMC_MASK ((1<<11) | \
(1<<12) | \ (1<<12) | \
(1<<13)) (1<<13))
@ -565,7 +566,8 @@ enum {
#define PF_SOLID (1<<23) //or 15, depending on extensions... messy. #define PF_SOLID (1<<23) //or 15, depending on extensions... messy.
#define PF_PMC_SHIFT 11 //not networked
#define PF_INWATER (1u<<31) //for network smartjump.

View file

@ -627,7 +627,7 @@ void Mod_ClipDecal(struct model_s *mod, vec3_t center, vec3_t normal, vec3_t tan
Q1BSP_ClipDecalToNodes(mod, &dec, mod->rootnode); Q1BSP_ClipDecalToNodes(mod, &dec, mod->rootnode);
#endif #endif
#ifdef Q3BSPS #ifdef Q3BSPS
else if (cl.worldmodel->fromgame == fg_quake3) else if (mod->fromgame == fg_quake3)
{ {
if (mod->submodelof) if (mod->submodelof)
{ {
@ -641,7 +641,7 @@ void Mod_ClipDecal(struct model_s *mod, vec3_t center, vec3_t normal, vec3_t tan
#endif #endif
#ifdef TERRAIN #ifdef TERRAIN
if (cl.worldmodel && cl.worldmodel->terrain) if (mod->terrain)
Terrain_ClipDecal(&dec, center, dec.radius, mod); Terrain_ClipDecal(&dec, center, dec.radius, mod);
#endif #endif
} }

View file

@ -218,58 +218,118 @@ void R_NetGraph (void)
#endif #endif
} }
void R_FrameTimeGraph (float frametime) void R_FrameTimeGraph (float frametime, float scale)
{ {
int a, x, i, y; float bias = 0;
int a, x, i, y, h, col;
vec2_t p[4]; vec2_t p[4];
vec2_t tc[4]; vec2_t tc[4];
vec4_t rgba[4]; vec4_t rgba[4];
extern shader_t *shader_draw_fill; extern shader_t *shader_draw_fill;
timehistory[findex++&NET_TIMINGSMASK] = frametime; conchar_t line[128];
int textheight;
float minv=FLT_MAX, maxv=FLT_MIN, avg=0, dev=0;
static struct
{
float time;
int col;
} history[NET_TIMINGS];
static unsigned int findex;
extern int com_hadwork[WG_COUNT];
history[findex&NET_TIMINGSMASK].time = frametime;
history[findex&NET_TIMINGSMASK].col = 0xffffffff;
findex++;
#ifdef LOADERTHREAD
if (com_hadwork[WG_MAIN])
{ //recolour the graph red if the main thread processed something from a worker.
//show three, because its not so easy to see when its whizzing past.
com_hadwork[WG_MAIN] = 0;
history[(findex-1)&NET_TIMINGSMASK].col = 0xff0000ff;
history[(findex-2)&NET_TIMINGSMASK].col = 0xff0000ff;
history[(findex-3)&NET_TIMINGSMASK].col = 0xff0000ff;
}
#endif
x = 0; x = 0;
for (a=0 ; a<NET_TIMINGS ; a++) for (a=0 ; a<NET_TIMINGS ; a++)
{ {
i = (findex-a) & NET_TIMINGSMASK; avg += history[a].time;
R_LineGraph (NET_TIMINGS-1-a, timehistory[i]); if (minv > history[a].time)
minv = history[a].time;
if (maxv < history[a].time)
maxv = history[a].time;
} }
if (!scale)
{
bias = minv;
scale = NET_GRAPHHEIGHT/(maxv-minv);
}
else
scale *= 1000;
avg/=a;
for (a = 0; a < NET_TIMINGS; a++)
dev += 1000*1000*(history[a].time - avg)*(history[a].time - avg);
dev /= a;
dev = sqrt(dev);
x = ((vid.width - 320)>>1); x = ((vid.width - 320)>>1);
x=-x; x=-x;
y = vid.height - sb_lines - 16 - NET_GRAPHHEIGHT;
M_DrawTextBox (x, y, NET_TIMINGS/8, NET_GRAPHHEIGHT/8); textheight = 4;
textheight = ceil(textheight*Font_CharVHeight(font_console)/8)*8; //might have a small gap underneath
y = vid.height - sb_lines - 16 - NET_GRAPHHEIGHT - textheight;
M_DrawTextBox (x, y, NET_TIMINGS/8, (textheight + NET_GRAPHHEIGHT)/8);
x=8; x=8;
y += 8; y += 8;
#ifdef GRAPHTEX COM_ParseFunString(CON_WHITEMASK, va("mean: %.3ffps (%.3fms)", 1/avg, 1000*avg), line, sizeof(line), false);
Image_Upload(netgraphtexture, TF_RGBA32, ngraph_texels, NULL, NET_TIMINGS, NET_GRAPHHEIGHT, IF_UIPIC|IF_NOMIPMAP|IF_NOPICMIP); Draw_ExpandedString(font_console, x, y, line);
x=8; y += Font_CharVHeight(font_console);
R2D_Image(x, y, NET_TIMINGS, NET_GRAPHHEIGHT, 0, 0, 1, 1, netgraphshader); COM_ParseFunString(CON_WHITEMASK, va("fastest: %.3ffps (%.3fms)", 1/minv, 1000*minv), line, sizeof(line), false);
#else Draw_ExpandedString(font_console, x, y, line);
y += Font_CharVHeight(font_console);
COM_ParseFunString(CON_WHITEMASK, va("slowest: %.3ffps (%.3fms)", 1/maxv, 1000*maxv), line, sizeof(line), false);
Draw_ExpandedString(font_console, x, y, line);
y += Font_CharVHeight(font_console);
COM_ParseFunString(CON_WHITEMASK, va("deviation: %.3fms (max %.3fms)", dev, (maxv-minv)*1000/2), line, sizeof(line), false);
Draw_ExpandedString(font_console, x, y, line);
y += Font_CharVHeight(font_console);
Vector2Set(p[2], 0,0); Vector2Set(p[2], 0,0);
Vector2Set(p[3], 0,0); Vector2Set(p[3], 0,0);
Vector4Set(rgba[2], 0,0,0,0); Vector4Set(rgba[2], 0,0,0,0);
Vector4Set(rgba[3], 0,0,0,0); Vector4Set(rgba[3], 0,0,0,0);
for (a=0 ; a<NET_TIMINGS ; a++) for (a=0 ; a<NET_TIMINGS ; a++)
{ {
i = (findex-NET_TIMINGS+a)&(NET_TIMINGS-1);
h = (history[i].time - bias) * scale;
col = history[i].col;
if (h > NET_GRAPHHEIGHT)
h = NET_GRAPHHEIGHT;
Vector2Copy(p[3], p[0]); Vector4Copy(rgba[3], rgba[0]); Vector2Copy(p[3], p[0]); Vector4Copy(rgba[3], rgba[0]);
Vector2Copy(p[2], p[1]); Vector4Copy(rgba[2], rgba[1]); Vector2Copy(p[2], p[1]); Vector4Copy(rgba[2], rgba[1]);
Vector2Set(p[2+0], x+a, y+(1-ngraph[a].height)*NET_GRAPHHEIGHT); Vector2Set(p[2+0], x+a, y+(NET_GRAPHHEIGHT-h));
Vector2Set(p[2+1], x+a, y+NET_GRAPHHEIGHT); Vector2Set(p[2+1], x+a, y+NET_GRAPHHEIGHT);
Vector2Set(tc[2+0], x/(float)NET_TIMINGS, (1-ngraph[a].height)); Vector2Set(tc[2+0], x/(float)NET_TIMINGS, (NET_GRAPHHEIGHT-h)/NET_GRAPHHEIGHT);
Vector2Set(tc[2+1], x/(float)NET_TIMINGS, 1); Vector2Set(tc[2+1], x/(float)NET_TIMINGS, 1);
Vector4Set(rgba[2+0], ((ngraph[a].col>>0)&0xff)/255.0, ((ngraph[a].col>>8)&0xff)/255.0, ((ngraph[a].col>>16)&0xff)/255.0, ((ngraph[a].col>>24)&0xff)/255.0); Vector4Set(rgba[2+0], ((col>>0)&0xff)/255.0, ((col>>8)&0xff)/255.0, ((col>>16)&0xff)/255.0, ((col>>24)&0xff)/255.0);
Vector4Copy(rgba[2+0], rgba[2+1]); Vector4Copy(rgba[2+0], rgba[2+1]);
if (a) if (a)
R2D_Image2dQuad((const vec2_t*)p, (const vec2_t*)tc, (const vec4_t*)rgba, shader_draw_fill); R2D_Image2dQuad((const vec2_t*)p, (const vec2_t*)tc, (const vec4_t*)rgba, shader_draw_fill);
} }
#endif
} }
void R_NetgraphInit(void) void R_NetgraphInit(void)

View file

@ -74,6 +74,23 @@ static void VARGS QC_snprintfz (char *dest, size_t size, const char *fmt, ...)
#define LIKEPRINTF(x) #define LIKEPRINTF(x)
#endif #endif
#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
#define FTE_DEPRECATED __attribute__((__deprecated__)) //no idea about the actual gcc version
#ifdef _WIN32
#define LIKEPRINTF(x) __attribute__((format(ms_printf,x,x+1)))
#else
#define LIKEPRINTF(x) __attribute__((format(printf,x,x+1)))
#endif
#endif
#if (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5))
#define NORETURN __attribute__((noreturn))
#endif
#ifndef NORETURN
#define NORETURN
#endif
double I_FloatTime (void); double I_FloatTime (void);
void VARGS QCC_Error (int errortype, const char *error, ...) LIKEPRINTF(2); void VARGS QCC_Error (int errortype, const char *error, ...) LIKEPRINTF(2);
@ -114,7 +131,6 @@ char *QCC_COM_Parse2 (char *data);
unsigned int utf8_check(const void *in, unsigned int *value); unsigned int utf8_check(const void *in, unsigned int *value);
extern char qcc_token[1024]; extern char qcc_token[1024];
extern int qcc_eof;
#define qcc_iswhite(c) ((c) == ' ' || (c) == '\r' || (c) == '\n' || (c) == '\t' || (c) == '\v') #define qcc_iswhite(c) ((c) == ' ' || (c) == '\r' || (c) == '\n' || (c) == '\t' || (c) == '\v')

View file

@ -58,6 +58,14 @@ QCC_ddef_t *GetField(const char *name);
return p; return p;
}*/ }*/
const char *GetString(dstring_t str)
{
if (str >= strofs)
return "INVALIDSTRING";
else
return strings+str;
}
extern QCC_opcode_t pr_opcodes []; extern QCC_opcode_t pr_opcodes [];
int endofsystemfields; int endofsystemfields;
@ -137,7 +145,7 @@ const char *temp_type (int temp, dstatement_t *start, dfunction_t *df)
} }
} }
printf("warning: Could not determine return type for %s\n", df->s_name + strings); printf("warning: Could not determine return type for %s\n", GetString(df->s_name));
return "float"; return "float";
@ -172,13 +180,6 @@ pbool IsConstant(QCC_ddef_t *def)
return true; return true;
} }
const char *qcstring(int str)
{
if ((unsigned)str >= strofs)
return "";
return strings+str;
}
char *type_name (QCC_ddef_t *def) char *type_name (QCC_ddef_t *def)
{ {
QCC_ddef_t *j; QCC_ddef_t *j;
@ -187,7 +188,7 @@ char *type_name (QCC_ddef_t *def)
{ {
case ev_field: case ev_field:
case ev_pointer: case ev_pointer:
j = GetField(def->s_name + strings); j = GetField(GetString(def->s_name));
if (j) if (j)
return qcva(".%s",type_names[j->type]); return qcva(".%s",type_names[j->type]);
else else
@ -280,7 +281,7 @@ static char *PR_ValueString (etype_t type, void *val)
switch (type) switch (type)
{ {
case ev_string: case ev_string:
QC_snprintfz(line, sizeof(line), "%s", PR_String(strings + *(int *)val)); QC_snprintfz(line, sizeof(line), "%s", PR_String(GetString(*(int *)val)));
break; break;
case ev_entity: case ev_entity:
QC_snprintfz(line, sizeof(line), "entity %i", *(int *)val); QC_snprintfz(line, sizeof(line), "entity %i", *(int *)val);
@ -290,7 +291,7 @@ static char *PR_ValueString (etype_t type, void *val)
if (!f) if (!f)
QC_snprintfz(line, sizeof(line), "undefined function"); QC_snprintfz(line, sizeof(line), "undefined function");
else else
QC_snprintfz(line, sizeof(line), "%s()", strings + f->s_name); QC_snprintfz(line, sizeof(line), "%s()", GetString(f->s_name));
break; break;
/* /*
case ev_field: case ev_field:
@ -822,7 +823,7 @@ int DecompileReadData(char *srcfilename, char *buf, size_t bufsize)
// fix up the functions // fix up the functions
for (i = 1; i < numfunctions; i++) for (i = 1; i < numfunctions; i++)
{ {
if ((unsigned)functions[i].s_name >= (unsigned)strofs || strlen(functions[i].s_name + strings) <= 0) if ((unsigned)functions[i].s_name >= (unsigned)strofs || strlen(GetString(functions[i].s_name)) <= 0)
{ {
fd = DecompileFunctionGlobal(i); fd = DecompileFunctionGlobal(i);
if (fd) if (fd)
@ -853,7 +854,7 @@ DecompileGetFunctionIdxByName(const char *name)
int i; int i;
for (i = 1; i < numfunctions; i++) for (i = 1; i < numfunctions; i++)
if (!strcmp(name, strings + functions[i].s_name)) if (!strcmp(name, GetString(functions[i].s_name)))
{ {
return i; return i;
} }
@ -868,7 +869,7 @@ const etype_t DecompileGetFieldTypeByDef(QCC_ddef_t *def)
for (i = 1; i < numfielddefs; i++) for (i = 1; i < numfielddefs; i++)
if (fields[i].ofs == ofs) if (fields[i].ofs == ofs)
{ {
if (!strcmp(strings+def->s_name, strings+fields[i].s_name)) if (!strcmp(GetString(def->s_name), GetString(fields[i].s_name)))
return fields[i].type; return fields[i].type;
} }
return ev_void; return ev_void;
@ -880,7 +881,7 @@ const char *DecompileGetFieldNameIdxByFinalOffset(int ofs)
for (i = 1; i < numfielddefs; i++) for (i = 1; i < numfielddefs; i++)
if (fields[i].ofs == ofs) if (fields[i].ofs == ofs)
{ {
return fields[i].s_name+strings; return GetString(fields[i].s_name);
} }
return "UNKNOWN FIELD"; return "UNKNOWN FIELD";
} }
@ -892,17 +893,17 @@ void DecompileGetFieldNameIdxByFinalOffset2(char *out, size_t outsize, int ofs)
{ {
if (fields[i].ofs == ofs) if (fields[i].ofs == ofs)
{ {
QC_snprintfz(out, outsize, "%s", fields[i].s_name+strings); QC_snprintfz(out, outsize, "%s", GetString(fields[i].s_name));
return; return;
} }
else if (fields[i].type == ev_vector && fields[i].ofs+1 == ofs) else if (fields[i].type == ev_vector && fields[i].ofs+1 == ofs)
{ {
QC_snprintfz(out, outsize, "%s_y", fields[i].s_name+strings); QC_snprintfz(out, outsize, "%s_y", GetString(fields[i].s_name));
return; return;
} }
else if (fields[i].type == ev_vector && fields[i].ofs+2 == ofs) else if (fields[i].type == ev_vector && fields[i].ofs+2 == ofs)
{ {
QC_snprintfz(out, outsize, "%s_z", fields[i].s_name+strings); QC_snprintfz(out, outsize, "%s_z", GetString(fields[i].s_name));
return; return;
} }
} }
@ -975,9 +976,9 @@ static unsigned int DecompileBuiltin(dfunction_t *df)
bi = -df->first_statement; bi = -df->first_statement;
//okay, so this is kinda screwy, different mods have different sets of builtins, and a load of fte's are #0 too //okay, so this is kinda screwy, different mods have different sets of builtins, and a load of fte's are #0 too
//so just try to match by name first... lots of scanning. :( //so just try to match by name first... lots of scanning. :(
if (df->s_name>0) if (df->s_name>0 && df->s_name < strofs)
{ {
char *biname = strings + df->s_name; const char *biname = GetString(df->s_name);
for (i = 0; i < (sizeof(builtins)/sizeof(builtins[0])); i++) for (i = 0; i < (sizeof(builtins)/sizeof(builtins[0])); i++)
{ {
if (!builtins[i].name) if (!builtins[i].name)
@ -1100,11 +1101,11 @@ void DecompileCalcProfiles(void)
{ {
unsigned int bi = DecompileBuiltin(df); unsigned int bi = DecompileBuiltin(df);
if (bi && builtins[bi].text) if (bi && builtins[bi].text)
QC_snprintfz(fname, sizeof(fname), "%s %s", builtins[bi].text, strings + functions[i].s_name); QC_snprintfz(fname, sizeof(fname), "%s %s", builtins[bi].text, GetString(functions[i].s_name));
else else
{ {
QC_snprintfz(fname, sizeof(fname), "__variant(...) %s", strings + functions[i].s_name); QC_snprintfz(fname, sizeof(fname), "__variant(...) %s", GetString(functions[i].s_name));
printf("warning: unknown builtin %s\n", strings + functions[i].s_name); printf("warning: unknown builtin %s\n", GetString(functions[i].s_name));
} }
} }
else else
@ -1178,7 +1179,7 @@ void DecompileCalcProfiles(void)
} }
strcat(fname, ") "); strcat(fname, ") ");
line[0] = '\0'; line[0] = '\0';
QC_snprintfz(line, sizeof(line), "%s", strings + functions[i].s_name); QC_snprintfz(line, sizeof(line), "%s", GetString(functions[i].s_name));
strcat(fname, line); strcat(fname, line);
} }
@ -1206,7 +1207,7 @@ QCC_ddef_t *GlobalAtOffset(dfunction_t *df, gofs_t ofs)
if (def->ofs == ofs) if (def->ofs == ofs)
{ {
/*if (!strings[def->s_name]) /*if (!GetString(def->s_name))
{ {
char line[16]; char line[16];
char *buf; char *buf;
@ -1241,7 +1242,7 @@ QCC_ddef_t *GlobalAtOffset(dfunction_t *df, gofs_t ofs)
if (def->ofs == ofs) if (def->ofs == ofs)
{ {
char line[256], *buf; char line[256], *buf;
sprintf(line, "%s_%c", strings+def->s_name, 'x'+parmofs); //globals, which are defined after the locals of the function they are first used in... sprintf(line, "%s_%c", GetString(def->s_name), 'x'+parmofs); //globals, which are defined after the locals of the function they are first used in...
def = malloc(sizeof(*def)+strlen(line)+1); //must be static variables, but we can't handle them very well def = malloc(sizeof(*def)+strlen(line)+1); //must be static variables, but we can't handle them very well
buf = (char*)(def+1); buf = (char*)(def+1);
strcpy(buf, line); strcpy(buf, line);
@ -1290,7 +1291,7 @@ char *DecompileGlobal(dfunction_t *df, gofs_t ofs, QCC_type_t * req_t)
if (def) if (def)
{ {
const char *defname = qcstring(def->s_name); const char *defname = GetString(def->s_name);
if (!strcmp(defname, "IMMEDIATE") || !strcmp(defname, ".imm") || !def->s_name) if (!strcmp(defname, "IMMEDIATE") || !strcmp(defname, ".imm") || !def->s_name)
{ {
@ -1316,14 +1317,14 @@ char *DecompileGlobal(dfunction_t *df, gofs_t ofs, QCC_type_t * req_t)
goto lookslikealocal; goto lookslikealocal;
else if ((parent = GlobalAtOffset(df, ofs-1)) && parent->type == ev_vector) else if ((parent = GlobalAtOffset(df, ofs-1)) && parent->type == ev_vector)
{ // _y { // _y
QC_snprintfz(line, sizeof(line), "%s_y", strings+parent->s_name); //globals, which are defined after the locals of the function they are first used in... QC_snprintfz(line, sizeof(line), "%s_y", GetString(parent->s_name)); //globals, which are defined after the locals of the function they are first used in...
buf = malloc(strlen(line)+1); //must be static variables, but we can't handle them very well buf = malloc(strlen(line)+1); //must be static variables, but we can't handle them very well
strcpy(buf, line); strcpy(buf, line);
def->s_name = buf - strings; def->s_name = buf - strings;
} }
else if ((parent = GlobalAtOffset(df, ofs-2)) && parent->type == ev_vector) else if ((parent = GlobalAtOffset(df, ofs-2)) && parent->type == ev_vector)
{ // _z { // _z
QC_snprintfz(line, sizeof(line), "%s_z", strings+parent->s_name); //globals, which are defined after the locals of the function they are first used in... QC_snprintfz(line, sizeof(line), "%s_z", GetString(parent->s_name)); //globals, which are defined after the locals of the function they are first used in...
buf = malloc(strlen(line)+1); //must be static variables, but we can't handle them very well buf = malloc(strlen(line)+1); //must be static variables, but we can't handle them very well
strcpy(buf, line); strcpy(buf, line);
def->s_name = buf - strings; def->s_name = buf - strings;
@ -1337,7 +1338,7 @@ char *DecompileGlobal(dfunction_t *df, gofs_t ofs, QCC_type_t * req_t)
} }
} }
QC_snprintfz(line, sizeof(line), "%s", strings + def->s_name); QC_snprintfz(line, sizeof(line), "%s", GetString(def->s_name));
if (def->type == ev_field && req_t == type_field && req_t->aux_type == type_float && DecompileGetFieldTypeByDef(def) == ev_vector) if (def->type == ev_field && req_t == type_field && req_t->aux_type == type_float && DecompileGetFieldTypeByDef(def) == ev_vector)
strcat(line, "_x"); strcat(line, "_x");
else if (def->type == ev_vector && req_t == type_float) else if (def->type == ev_vector && req_t == type_float)
@ -1442,7 +1443,7 @@ void DecompileImmediate_Insert(dfunction_t *df, gofs_t ofs, char *knew, QCC_type
d = GlobalAtOffset(df, ofs); d = GlobalAtOffset(df, ofs);
if (d && d->s_name)// && strcmp(strings+d->s_name, "IMMEDIATE")) if (d && d->s_name)// && strcmp(GetString(d->s_name), "IMMEDIATE"))
{ //every operator has a src (or two) and a dest. { //every operator has a src (or two) and a dest.
//many compilers optimise by using the dest of a maths/logic operator to store to a local/global //many compilers optimise by using the dest of a maths/logic operator to store to a local/global
//they then skip off the storeopcode. //they then skip off the storeopcode.
@ -1450,7 +1451,7 @@ void DecompileImmediate_Insert(dfunction_t *df, gofs_t ofs, char *knew, QCC_type
IMMEDIATES[nofs].text = NULL; IMMEDIATES[nofs].text = NULL;
IMMEDIATES[nofs].type = NULL; IMMEDIATES[nofs].type = NULL;
QCC_CatVFile(Decompileofile, "%s = %s;\n", strings + d->s_name, knew); QCC_CatVFile(Decompileofile, "%s = %s;\n", GetString(d->s_name), knew);
} }
else else
{ {
@ -1538,11 +1539,11 @@ char *DecompileImmediate_Get(dfunction_t *df, gofs_t ofs, QCC_type_t *req_t)
char *out; char *out;
if (((int*)pr_globals)[ofs] < 0 || ((int*)pr_globals)[ofs] > strofs) if (((int*)pr_globals)[ofs] < 0 || ((int*)pr_globals)[ofs] > strofs)
{ {
printf("Hey! That's not a string! error in %s\n", strings + df->s_name); printf("Hey! That's not a string! error in %s\n", GetString(df->s_name));
QC_snprintfz(temp, sizeof(temp), "%f", pr_globals[ofs]); QC_snprintfz(temp, sizeof(temp), "%f", pr_globals[ofs]);
break; break;
} }
in = &strings[((int*)pr_globals)[ofs]]; in = GetString(((int*)pr_globals)[ofs]);
out = temp; out = temp;
if (req_t->type != ev_string) if (req_t->type != ev_string)
{ {
@ -1639,7 +1640,7 @@ char *DecompileImmediate_Get(dfunction_t *df, gofs_t ofs, QCC_type_t *req_t)
if (!((int*)pr_globals)[ofs]) if (!((int*)pr_globals)[ofs])
QC_snprintfz(temp, sizeof(temp), "__NULL__/*func*/"); QC_snprintfz(temp, sizeof(temp), "__NULL__/*func*/");
else if (((int*)pr_globals)[ofs] > 0 && ((int*)pr_globals)[ofs] < numfunctions && functions[((int*)pr_globals)[ofs]].s_name>0) else if (((int*)pr_globals)[ofs] > 0 && ((int*)pr_globals)[ofs] < numfunctions && functions[((int*)pr_globals)[ofs]].s_name>0)
QC_snprintfz(temp, sizeof(temp), "%s/*immediate*/", strings+functions[((int*)pr_globals)[ofs]].s_name); QC_snprintfz(temp, sizeof(temp), "%s/*immediate*/", GetString(functions[((int*)pr_globals)[ofs]].s_name));
else else
QC_snprintfz(temp, sizeof(temp), "((__variant(...))%i)", ((int*)pr_globals)[ofs]); QC_snprintfz(temp, sizeof(temp), "((__variant(...))%i)", ((int*)pr_globals)[ofs]);
break; break;
@ -2317,7 +2318,7 @@ void DecompileDecompileStatement(dfunction_t * df, dstatement_t * s, int *indent
if (s->c) if (s->c)
QCC_CatVFile(Decompileofile, ", %s", DecompileGet(df, s->c, typ1)); QCC_CatVFile(Decompileofile, ", %s", DecompileGet(df, s->c, typ1));
QCC_CatVFile(Decompileofile, "]\n"); QCC_CatVFile(Decompileofile, "]\n");
printf("warning: Unknown opcode %i in %s\n", op, strings + df->s_name); printf("warning: Unknown opcode %i in %s\n", op, GetString(df->s_name));
} }
} }
@ -2367,7 +2368,7 @@ pbool DecompileDecompileFunction(dfunction_t * df, dstatement_t *altdone)
if (indent != 1) if (indent != 1)
{ {
printf("warning: Indentation structure corrupt (in func %s)\n", strings+df->s_name); printf("warning: Indentation structure corrupt (in func %s)\n", GetString(df->s_name));
return false; return false;
} }
return true; return true;
@ -2378,7 +2379,7 @@ char *DecompileString(int qcstring)
static char buf[8192]; static char buf[8192];
char *s; char *s;
int c = 1; int c = 1;
const char *string = strings+qcstring; const char *string = GetString(qcstring);
if (qcstring < 0 || qcstring >= strofs) if (qcstring < 0 || qcstring >= strofs)
return "Invalid String"; return "Invalid String";
@ -2468,7 +2469,7 @@ char *DecompileValueString(etype_t type, void *val)
break; break;
case ev_function: case ev_function:
if (*(int *)val>0 && *(int *)val<numfunctions) if (*(int *)val>0 && *(int *)val<numfunctions)
QC_snprintfz(line, sizeof(line), "(/*func 0x%x*/%s)", *(int *)val, strings+functions[*(int *)val].s_name); QC_snprintfz(line, sizeof(line), "(/*func 0x%x*/%s)", *(int *)val, GetString(functions[*(int *)val].s_name));
else else
QC_snprintfz(line, sizeof(line), "((void())0x%xi)", *(int *)val); QC_snprintfz(line, sizeof(line), "((void())0x%xi)", *(int *)val);
break; break;
@ -2498,13 +2499,13 @@ char *DecompilePrintParameter(QCC_ddef_t * def)
{ {
QC_snprintfz(line, sizeof(line), "%s _p_%i%s", type_name(def), def->ofs, debug); QC_snprintfz(line, sizeof(line), "%s _p_%i%s", type_name(def), def->ofs, debug);
} }
else if (!strcmp(strings + def->s_name, "IMMEDIATE") || !strcmp(strings + def->s_name, ".imm")) else if (!strcmp(GetString(def->s_name), "IMMEDIATE") || !strcmp(GetString(def->s_name), ".imm"))
{ {
QC_snprintfz(line, sizeof(line), "%s%s", DecompileValueString((etype_t)(def->type), &pr_globals[def->ofs]), debug); QC_snprintfz(line, sizeof(line), "%s%s", DecompileValueString((etype_t)(def->type), &pr_globals[def->ofs]), debug);
} }
else else
{ {
QC_snprintfz(line, sizeof(line), "%s %s%s", type_name(def), strings + def->s_name, debug); QC_snprintfz(line, sizeof(line), "%s %s%s", type_name(def), GetString(def->s_name), debug);
} }
return line; return line;
} }
@ -2527,18 +2528,18 @@ const char *GetMatchingField(QCC_ddef_t *field)
{ {
if (((int*)pr_globals)[def->ofs] == field->ofs) if (((int*)pr_globals)[def->ofs] == field->ofs)
{ {
if (!strcmp(strings+def->s_name, strings+field->s_name)) if (!strcmp(GetString(def->s_name), GetString(field->s_name)))
return NULL; //found ourself, give up. return NULL; //found ourself, give up.
lf = strlen(strings + field->s_name); lf = strlen(GetString(field->s_name));
ld = strlen(strings + def->s_name); ld = strlen(GetString(def->s_name));
if (lf - 2 == ld) if (lf - 2 == ld)
{ {
if ((strings + field->s_name)[lf-2] == '_' && (strings + field->s_name)[lf-1] == 'x') if ((GetString(field->s_name)[lf-2]) == '_' && (GetString(field->s_name)[lf-1]) == 'x')
if (!strncmp(strings + field->s_name, strings + def->s_name, ld)) if (!strncmp(GetString(field->s_name), GetString(def->s_name), ld))
return NULL; //vector found foo_x return NULL; //vector found foo_x
} }
if (!ret) if (!ret)
ret = def->s_name+strings; ret = GetString(def->s_name);
} }
} }
} }
@ -2560,7 +2561,7 @@ QCC_ddef_t *GetField(const char *name)
{ {
d = &fields[i]; d = &fields[i];
if (!strcmp(strings + d->s_name, name)) if (!strcmp(GetString(d->s_name), name))
return d; return d;
} }
return NULL; return NULL;
@ -2595,7 +2596,7 @@ QCC_ddef_t *DecompileFindGlobal(const char *findname)
for (i = 0; i < numglobaldefs; i++) for (i = 0; i < numglobaldefs; i++)
{ {
def = &globals[i]; def = &globals[i];
defname = strings + def->s_name; defname = GetString(def->s_name);
if (!strcmp(findname, defname)) if (!strcmp(findname, defname))
{ {
@ -2651,19 +2652,19 @@ void DecompilePreceedingGlobals(int start, int end, const char *name)
if (par->type == ev_function) if (par->type == ev_function)
{ {
if (strcmp(strings + par->s_name, "IMMEDIATE") && strcmp(strings + par->s_name, ".imm")) if (strcmp(GetString(par->s_name), "IMMEDIATE") && strcmp(GetString(par->s_name), ".imm"))
{ {
if (strcmp(strings + par->s_name, name)) if (strcmp(GetString(par->s_name), name))
{ {
int f = ((int*)pr_globals)[par->ofs]; int f = ((int*)pr_globals)[par->ofs];
//DecompileGetFunctionIdxByName(strings + par->s_name); //DecompileGetFunctionIdxByName(strings + par->s_name);
if (f && strcmp(strings+functions[f].s_name, strings + par->s_name)) if (f && strcmp(GetString(functions[f].s_name), GetString(par->s_name)))
{ {
char *s = strrchr(DecompileProfiles[f], ' '); char *s = strrchr(DecompileProfiles[f], ' ');
//happens with void() func = otherfunc; //happens with void() func = otherfunc;
//such functions thus don't have their own type+body //such functions thus don't have their own type+body
*s = 0; *s = 0;
QCC_CatVFile(Decompileofile, "var %s %s = %s;\n", DecompileProfiles[f], strings + par->s_name, s+1); QCC_CatVFile(Decompileofile, "var %s %s = %s;\n", DecompileProfiles[f], GetString(par->s_name), s+1);
*s = ' '; *s = ' ';
} }
else else
@ -2673,18 +2674,18 @@ void DecompilePreceedingGlobals(int start, int end, const char *name)
} }
else if (par->type != ev_pointer) else if (par->type != ev_pointer)
{ {
if (strcmp(strings + par->s_name, "IMMEDIATE") && strcmp(strings + par->s_name, ".imm") && par->s_name) if (strcmp(GetString(par->s_name), "IMMEDIATE") && strcmp(GetString(par->s_name), ".imm") && par->s_name)
{ {
if (par->type == ev_field) if (par->type == ev_field)
{ {
ef = GetField(strings + par->s_name); ef = GetField(GetString(par->s_name));
if (!ef) if (!ef)
{ {
QCC_CatVFile(Decompileofile, "var .unknowntype %s;\n", strings + par->s_name); QCC_CatVFile(Decompileofile, "var .unknowntype %s;\n", GetString(par->s_name));
printf("Fatal Error: Could not locate a field named \"%s\"\n", strings + par->s_name); printf("Fatal Error: Could not locate a field named \"%s\"\n", GetString(par->s_name));
} }
else else
{ {
@ -2694,7 +2695,7 @@ void DecompilePreceedingGlobals(int start, int end, const char *name)
matchingfield = GetMatchingField(ef); matchingfield = GetMatchingField(ef);
#ifndef DONT_USE_DIRTY_TRICKS //could try scanning for an op_address+op_storep_fnc pair #ifndef DONT_USE_DIRTY_TRICKS //could try scanning for an op_address+op_storep_fnc pair
if ((ef->type == ev_function) && !strcmp(strings + ef->s_name, "th_pain")) if ((ef->type == ev_function) && !strcmp(GetString(ef->s_name), "th_pain"))
{ {
QCC_CatVFile(Decompileofile, ".void(entity attacker, float damage) th_pain;\n"); QCC_CatVFile(Decompileofile, ".void(entity attacker, float damage) th_pain;\n");
} }
@ -2702,9 +2703,9 @@ void DecompilePreceedingGlobals(int start, int end, const char *name)
#endif #endif
{ {
if (matchingfield) if (matchingfield)
QCC_CatVFile(Decompileofile, "var .%s %s = %s;\n", type_name(ef), strings + ef->s_name, matchingfield); QCC_CatVFile(Decompileofile, "var .%s %s = %s;\n", type_name(ef), GetString(ef->s_name), matchingfield);
else else
QCC_CatVFile(Decompileofile, ".%s %s;\n", type_name(ef), strings + ef->s_name); QCC_CatVFile(Decompileofile, ".%s %s;\n", type_name(ef), GetString(ef->s_name));
// fprintf(Decompileofile, "//%i %i %i %i\n", ef->ofs, ((int*)pr_globals)[ef->ofs], par->ofs, ((int*)pr_globals)[par->ofs]); // fprintf(Decompileofile, "//%i %i %i %i\n", ef->ofs, ((int*)pr_globals)[ef->ofs], par->ofs, ((int*)pr_globals)[par->ofs]);
} }
@ -2719,7 +2720,7 @@ void DecompilePreceedingGlobals(int start, int end, const char *name)
if (par->type == ev_entity || par->type == ev_void) if (par->type == ev_entity || par->type == ev_void)
{ {
QCC_CatVFile(Decompileofile, "%s %s;\n", type_name(par), strings + par->s_name); QCC_CatVFile(Decompileofile, "%s %s;\n", type_name(par), GetString(par->s_name));
} }
else else
@ -2730,14 +2731,14 @@ void DecompilePreceedingGlobals(int start, int end, const char *name)
if (IsConstant(par)) if (IsConstant(par))
{ {
QCC_CatVFile(Decompileofile, "%s %s = %s;\n", type_name(par), strings + par->s_name, line); QCC_CatVFile(Decompileofile, "%s %s = %s;\n", type_name(par), GetString(par->s_name), line);
} }
else else
{ {
if (pr_globals[par->ofs] != 0) if (pr_globals[par->ofs] != 0)
QCC_CatVFile(Decompileofile, "%s %s /* = %s */;\n", type_name(par), strings + par->s_name, line); QCC_CatVFile(Decompileofile, "%s %s /* = %s */;\n", type_name(par), GetString(par->s_name), line);
else else
QCC_CatVFile(Decompileofile, "%s %s;\n", type_name(par), strings + par->s_name, line); QCC_CatVFile(Decompileofile, "%s %s;\n", type_name(par), GetString(par->s_name), line);
} }
} }
} }
@ -2763,7 +2764,7 @@ void DecompileFunction(const char *name, int *lastglobal)
for (i = 1; i < numfunctions; i++) for (i = 1; i < numfunctions; i++)
if (!strcmp(name, strings + functions[i].s_name)) if (!strcmp(name, GetString(functions[i].s_name)))
break; break;
if (i == numfunctions) if (i == numfunctions)
{ {
@ -3032,10 +3033,10 @@ void DecompileFunction(const char *name, int *lastglobal)
} }
else else
{ {
if (!strcmp(strings + par->s_name, "IMMEDIATE") || !strcmp(strings + par->s_name, ".imm")) if (!strcmp(GetString(par->s_name), "IMMEDIATE") || !strcmp(GetString(par->s_name), ".imm"))
continue; // immediates don't belong continue; // immediates don't belong
if (!strings[par->s_name]) if (!GetString(par->s_name))
{ {
QC_snprintfz(line, sizeof(line), "_l_%i", par->ofs); QC_snprintfz(line, sizeof(line), "_l_%i", par->ofs);
arg2 = malloc(strlen(line)+1); arg2 = malloc(strlen(line)+1);
@ -3069,7 +3070,7 @@ void DecompileFunction(const char *name, int *lastglobal)
if (!DecompileDecompileFunction(df, altdone)) if (!DecompileDecompileFunction(df, altdone))
{ {
QCC_InsertVFile(Decompileofile, startpos, "#error Corrupt Function: %s\n#if 0\n", strings+df->s_name); QCC_InsertVFile(Decompileofile, startpos, "#error Corrupt Function: %s\n#if 0\n", GetString(df->s_name));
QCC_CatVFile(Decompileofile, "#endif\n"); QCC_CatVFile(Decompileofile, "#endif\n");
} }
@ -3157,7 +3158,7 @@ void DecompileDecompileFunctions(const char *origcopyright)
lastfileofs = d->s_file; lastfileofs = d->s_file;
fname[0] = '\0'; fname[0] = '\0';
if (d->s_file <= strofs && d->s_file >= 0) if (d->s_file <= strofs && d->s_file >= 0)
sprintf(fname, "%s", strings + d->s_file); sprintf(fname, "%s", GetString(d->s_file));
// FrikaC -- not sure if this is cool or what? // FrikaC -- not sure if this is cool or what?
bogusname = false; bogusname = false;
if (strlen(fname) <= 0) if (strlen(fname) <= 0)
@ -3187,7 +3188,7 @@ void DecompileDecompileFunctions(const char *origcopyright)
{ {
synth_name[0] = 0; synth_name[0] = 0;
} }
if(!TrySynthName(qcva("%s", strings + d->s_name)) && !synth_name[0]) if(!TrySynthName(qcva("%s", GetString(d->s_name))) && !synth_name[0])
QC_snprintfz(synth_name, sizeof(synth_name), "frik%i.qc", fake_name++); QC_snprintfz(synth_name, sizeof(synth_name), "frik%i.qc", fake_name++);
QC_snprintfz(fname, sizeof(fname), "%s", synth_name); QC_snprintfz(fname, sizeof(fname), "%s", synth_name);
@ -3210,7 +3211,7 @@ void DecompileDecompileFunctions(const char *origcopyright)
} }
} }
Decompileofile = f; Decompileofile = f;
DecompileFunction(strings + d->s_name, &lastglob); DecompileFunction(GetString(d->s_name), &lastglob);
} }
} }
@ -3266,7 +3267,7 @@ char *DecompileGlobalStringNoContents(gofs_t ofs)
if (def->ofs == ofs) if (def->ofs == ofs)
{ {
line[0] = '0'; line[0] = '0';
QC_snprintfz(line, sizeof(line), "%i(%s)", def->ofs, strings + def->s_name); QC_snprintfz(line, sizeof(line), "%i(%s)", def->ofs, GetString(def->s_name));
break; break;
} }
} }
@ -3297,13 +3298,13 @@ char *DecompileGlobalString(gofs_t ofs)
{ {
line[0] = '0'; line[0] = '0';
if (!strcmp(strings + def->s_name, "IMMEDIATE") || !strcmp(strings + def->s_name, ".imm")) if (!strcmp(GetString(def->s_name), "IMMEDIATE") || !strcmp(GetString(def->s_name), ".imm"))
{ {
s = PR_ValueString((etype_t)(def->type), &pr_globals[ofs]); s = PR_ValueString((etype_t)(def->type), &pr_globals[ofs]);
QC_snprintfz(line, sizeof(line), "%i(%s)", def->ofs, s); QC_snprintfz(line, sizeof(line), "%i(%s)", def->ofs, s);
} }
else else
QC_snprintfz(line, sizeof(line), "%i(%s)", def->ofs, strings + def->s_name); QC_snprintfz(line, sizeof(line), "%i(%s)", def->ofs, GetString(def->s_name));
} }
} }
@ -3356,7 +3357,7 @@ void DecompilePrintFunction(char *name)
dfunction_t *df; dfunction_t *df;
for (i = 0; i < numfunctions; i++) for (i = 0; i < numfunctions; i++)
if (!strcmp(name, strings + functions[i].s_name)) if (!strcmp(name, GetString(functions[i].s_name)))
break; break;
if (i == numfunctions) if (i == numfunctions)
{ {

View file

@ -411,6 +411,24 @@ reeval:
ptr = QCPOINTERM(i); ptr = QCPOINTERM(i);
ptr->_int = OPA->_int; ptr->_int = OPA->_int;
break; break;
case OP_STOREP_I64: // 64bit
i = OPB->_int + OPC->_int*sizeof(ptr->_int);
errorif (QCPOINTERWRITEFAIL(i, sizeof(ptr->_int64)))
{
if (!(ptr=PR_GetWriteTempStringPtr(progfuncs, OPB->_int, OPC->_int*sizeof(ptr->_int), sizeof(ptr->_int64))))
{
if (i == -1)
break;
if (i == 0)
QCFAULT(&progfuncs->funcs, "bad pointer write in %s (null pointer)", PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name));
else
QCFAULT(&progfuncs->funcs, "bad pointer write in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name), i, prinst.addressableused);
}
}
else
ptr = QCPOINTERM(i);
ptr->_int64 = OPA->_int64;
break;
case OP_STOREP_V: case OP_STOREP_V:
i = OPB->_int + (OPC->_int*sizeof(ptr->_int)); i = OPB->_int + (OPC->_int*sizeof(ptr->_int));
errorif (QCPOINTERWRITEFAIL(i, sizeof(pvec3_t))) errorif (QCPOINTERWRITEFAIL(i, sizeof(pvec3_t)))
@ -504,6 +522,48 @@ reeval:
ptr = (eval_t *)(((int *)edvars(ed)) + i); ptr = (eval_t *)(((int *)edvars(ed)) + i);
ptr->_int = OPC->_int; ptr->_int = OPC->_int;
break; break;
case OP_STOREF_I64:
errorif ((unsigned)OPA->edict >= (unsigned)num_edicts)
{
if (PR_ExecRunWarning (&progfuncs->funcs, st-pr_statements, "OP_STOREF_? references invalid entity in %s\n", PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name)))
return prinst.pr_xstatement;
break;
}
ed = PROG_TO_EDICT_PB(progfuncs, OPA->edict);
errorif (!ed || ed->readonly)
{ //boot it over to the debugger
#if INTSIZE == 16
ddef16_t *d = ED_GlobalAtOfs16(progfuncs, st->a);
#else
ddef32_t *d = ED_GlobalAtOfs32(progfuncs, st->a);
#endif
fdef_t *f = ED_FieldAtOfs(progfuncs, OPB->_int + progfuncs->funcs.fieldadjust);
if (PR_ExecRunWarning(&progfuncs->funcs, st-pr_statements, "assignment to read-only entity %i in %s (%s.%s)\n", OPA->edict, PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name), d?PR_StringToNative(&progfuncs->funcs, d->s_name):"??", f?f->name:"??"))
return prinst.pr_xstatement;
break;
}
//Whilst the next block would technically be correct, we don't use it as it breaks too many quake mods.
#ifdef NOLEGACY
errorif (ed->ereftype == ER_FREE)
{
if (PR_ExecRunWarning (&progfuncs->funcs, st-pr_statements, "assignment to free entity in %s", PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name)))
return prinst.pr_xstatement;
break;
}
#endif
i = OPB->_int + progfuncs->funcs.fieldadjust;
errorif ((unsigned int)i*4 >= ed->fieldsize) //FIXME:lazy size check
{
if (PR_ExecRunWarning (&progfuncs->funcs, st-pr_statements, "OP_STOREF_? references invalid field %i in %s\n", OPB->_int, PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name)))
return prinst.pr_xstatement;
break;
}
ptr = (eval_t *)(((int *)edvars(ed)) + i);
ptr->_int64 = OPC->_int64;
break;
case OP_STOREF_V: case OP_STOREF_V:
errorif ((unsigned)OPA->edict >= (unsigned)num_edicts) errorif ((unsigned)OPA->edict >= (unsigned)num_edicts)
{ {
@ -634,7 +694,7 @@ reeval:
#endif #endif
{ {
i = OPB->_int + progfuncs->funcs.fieldadjust; i = OPB->_int + progfuncs->funcs.fieldadjust;
errorif ((unsigned int)i*4 >= ed->fieldsize) //FIXME:lazy size check errorif ((unsigned int)(i+1)*4 > ed->fieldsize) //FIXME:lazy size check
{ {
if (PR_ExecRunWarning (&progfuncs->funcs, st-pr_statements, "OP_LOAD references invalid field %i in %s\n", OPB->_int, PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name))) if (PR_ExecRunWarning (&progfuncs->funcs, st-pr_statements, "OP_LOAD references invalid field %i in %s\n", OPB->_int, PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name)))
return prinst.pr_xstatement; return prinst.pr_xstatement;
@ -645,7 +705,44 @@ reeval:
OPC->_int = ptr->_int; OPC->_int = ptr->_int;
} }
break; break;
case OP_LOAD_I64:
errorif ((unsigned)OPA->edict >= (unsigned)num_edicts)
{
if (PR_ExecRunWarning (&progfuncs->funcs, st-pr_statements, "OP_LOAD_V references invalid entity %i in %s\n", OPA->edict, PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name)))
return prinst.pr_xstatement;
OPC->_vector[0] = 0;
OPC->_vector[1] = 0;
OPC->_vector[2] = 0;
break;
}
ed = PROG_TO_EDICT_PB(progfuncs, OPA->edict);
#ifdef PARANOID
NUM_FOR_EDICT(ed); // make sure it's in range
#endif
#ifdef NOLEGACY
if (ed->ereftype == ER_FREE)
{
if (PR_ExecRunWarning (&progfuncs->funcs, st-pr_statements, "OP_LOAD references free entity %i in %s\n", OPA->edict, PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name)))
return prinst.pr_xstatement;
OPC->_vector[0] = 0;
OPC->_vector[1] = 0;
OPC->_vector[2] = 0;
}
else
#endif
{
i = OPB->_int + progfuncs->funcs.fieldadjust;
errorif ((unsigned int)(i+2)*4 > ed->fieldsize) //FIXME:lazy size check
{
if (PR_ExecRunWarning (&progfuncs->funcs, st-pr_statements, "OP_LOAD references invalid field %i in %s\n", OPB->_int, PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name)))
return prinst.pr_xstatement;
OPC->_int = 0;
break;
}
ptr = (eval_t *)(((int *)edvars(ed)) + i);
OPC->_int64 = ptr->_int64;
}
break;
case OP_LOAD_V: case OP_LOAD_V:
errorif ((unsigned)OPA->edict >= (unsigned)num_edicts) errorif ((unsigned)OPA->edict >= (unsigned)num_edicts)
{ {
@ -673,7 +770,7 @@ reeval:
#endif #endif
{ {
i = OPB->_int + progfuncs->funcs.fieldadjust; i = OPB->_int + progfuncs->funcs.fieldadjust;
errorif ((unsigned int)i*4 >= ed->fieldsize) //FIXME:lazy size check errorif ((unsigned int)(i+3)*4 > ed->fieldsize) //FIXME:lazy size check
{ {
if (PR_ExecRunWarning (&progfuncs->funcs, st-pr_statements, "OP_LOAD references invalid field %i in %s\n", OPB->_int, PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name))) if (PR_ExecRunWarning (&progfuncs->funcs, st-pr_statements, "OP_LOAD references invalid field %i in %s\n", OPB->_int, PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name)))
return prinst.pr_xstatement; return prinst.pr_xstatement;
@ -948,7 +1045,15 @@ reeval:
else else
OPC->_int = ((eval_t *)&glob[i])->_int; OPC->_int = ((eval_t *)&glob[i])->_int;
break; break;
case OP_LOADA_I64:
i = st->a + OPB->_int;
if ((size_t)i >= (size_t)(current_progstate->globals_bytes>>2))
{
QCFAULT(&progfuncs->funcs, "bad array read in %s (index %i)", PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name), OPB->_int);
}
else
OPC->_int64 = ((eval_t *)&glob[i])->_int64;
break;
case OP_LOADA_V: case OP_LOADA_V:
i = st->a + OPB->_int; i = st->a + OPB->_int;
if ((size_t)(i) >= (size_t)(current_progstate->globals_bytes>>2)-2u) if ((size_t)(i) >= (size_t)(current_progstate->globals_bytes>>2)-2u)
@ -1480,6 +1585,48 @@ reeval:
} }
break; break;
*/ */
//[u]int64+double opcodes
case OP_ADD_I64: OPC->_int64 = OPA->_int64 + OPB->_int64; break;
case OP_SUB_I64: OPC->_int64 = OPA->_int64 - OPB->_int64; break;
case OP_MUL_I64: OPC->_int64 = OPA->_int64 * OPB->_int64; break;
case OP_DIV_I64: OPC->_int64 = OPA->_int64 / OPB->_int64; break;
case OP_BITAND_I64: OPC->_int64 = OPA->_int64 & OPB->_int64; break;
case OP_BITOR_I64: OPC->_int64 = OPA->_int64 | OPB->_int64; break;
case OP_BITXOR_I64: OPC->_int64 = OPA->_int64 ^ OPB->_int64; break;
case OP_LSHIFT_I64I: OPC->_int64 = OPA->_int64 << OPB->_int; break;
case OP_RSHIFT_I64I: OPC->_int64 = OPA->_int64 >> OPB->_int; break;
case OP_LT_I64: OPC->_int = OPA->_int64 < OPB->_int64; break;
case OP_LE_I64: OPC->_int = OPA->_int64 <= OPB->_int64; break;
case OP_EQ_I64: OPC->_int = OPA->_int64 == OPB->_int64; break;
case OP_NE_I64: OPC->_int = OPA->_int64 != OPB->_int64; break;
case OP_LT_U64: OPC->_int = OPA->_uint64 < OPB->_uint64; break;
case OP_LE_U64: OPC->_int = OPA->_uint64 <= OPB->_uint64; break;
case OP_DIV_U64: OPC->_uint64 = OPA->_uint64 / OPB->_uint64; break;
case OP_RSHIFT_U64I: OPC->_uint64 = OPA->_uint64 >> OPB->_int; break;
case OP_STORE_I64: OPB->_int64 = OPA->_int64;
// case OP_LOADF_I64: OPC->_int64 = OPA->_int64 X OPB->_int64; break;
// case OP_LOADP_I64: OPC->_int64 = OPA->_int64 X OPB->_int64; break;
case OP_CONV_UI64: OPC->_int64 = OPA->_uint; break;
case OP_CONV_II64: OPC->_int64 = OPA->_int; break;
case OP_CONV_I64I: OPC->_int = OPA->_int64; break;
case OP_CONV_FD: OPC->_double = OPA->_float; break;
case OP_CONV_DF: OPC->_float = OPA->_double; break;
case OP_CONV_I64F: OPC->_float = OPA->_int64; break;
case OP_CONV_FI64: OPC->_int64 = OPA->_float; break;
case OP_CONV_I64D: OPC->_double = OPA->_int64; break;
case OP_CONV_DI64: OPC->_int64 = OPA->_double; break;
case OP_ADD_D: OPC->_double = OPA->_double + OPB->_double; break;
case OP_SUB_D: OPC->_double = OPA->_double - OPB->_double; break;
case OP_MUL_D: OPC->_double = OPA->_double * OPB->_double; break;
case OP_DIV_D: OPC->_double = OPA->_double / OPB->_double; break;
case OP_LT_D: OPC->_double = OPA->_double < OPB->_double; break;
case OP_LE_D: OPC->_double = OPA->_double <= OPB->_double; break;
case OP_EQ_D: OPC->_double = OPA->_double == OPB->_double; break;
case OP_NE_D: OPC->_double = OPA->_double != OPB->_double; break;
default: default:
if (op & OP_BIT_BREAKPOINT) //break point! if (op & OP_BIT_BREAKPOINT) //break point!
{ {

View file

@ -1574,6 +1574,7 @@ static pubprogfuncs_t deffuncs = {
0, //string table size 0, //string table size
0, //max size 0, //max size
0, //field adjust(aditional field offset) 0, //field adjust(aditional field offset)
0, //field slots allocated (for builtins to clamp field reference args).
PR_ForkStack, PR_ForkStack,
PR_ResumeThread, PR_ResumeThread,

View file

@ -342,6 +342,62 @@ enum qcop_e {
OP_STOREP_B,//((char*)b)[(int)c] = (int)a OP_STOREP_B,//((char*)b)[(int)c] = (int)a
OP_LOADP_B, //(int)c = *(char*) OP_LOADP_B, //(int)c = *(char*)
//r5768+
//opcodes for 32bit uints
OP_LE_U, //aka GT
OP_LT_U, //aka GE
OP_DIV_U, //don't need mul+add+sub
OP_RSHIFT_U, //lshift is the same for signed+unsigned
//opcodes for 64bit ints
OP_ADD_I64,
OP_SUB_I64,
OP_MUL_I64,
OP_DIV_I64,
OP_BITAND_I64,
OP_BITOR_I64,
OP_BITXOR_I64,
OP_LSHIFT_I64I,
OP_RSHIFT_I64I,
OP_LE_I64, //aka GT
OP_LT_I64, //aka GE
OP_EQ_I64,
OP_NE_I64,
//extra opcodes for 64bit uints
OP_LE_U64, //aka GT
OP_LT_U64, //aka GE
OP_DIV_U64,
OP_RSHIFT_U64I,
//general 64bitness
OP_STORE_I64,
OP_STOREP_I64,
OP_STOREF_I64,
OP_LOAD_I64,
OP_LOADA_I64,
OP_LOADP_I64,
//various conversions for our 64bit types (yay type promotion)
OP_CONV_UI64, //zero extend
OP_CONV_II64, //sign extend
OP_CONV_I64I, //truncate
OP_CONV_FD, //extension
OP_CONV_DF, //truncation
OP_CONV_I64F, //logically a promotion (always signed)
OP_CONV_FI64, //demotion (always signed)
OP_CONV_I64D, //'promotion' (always signed)
OP_CONV_DI64, //demotion (always signed)
//opcodes for doubles.
OP_ADD_D,
OP_SUB_D,
OP_MUL_D,
OP_DIV_D,
OP_LE_D,
OP_LT_D,
OP_EQ_D,
OP_NE_D,
OP_NUMREALOPS, OP_NUMREALOPS,
/* /*
@ -453,13 +509,61 @@ enum qcop_e {
OP_SPACESHIP_F, //lame OP_SPACESHIP_F, //lame
OP_SPACESHIP_S, //basically strcmp. OP_SPACESHIP_S, //basically strcmp.
//uint32 opcodes. they match the int32 ones so emulation is basically swapping them over.
OP_ADD_U,
OP_SUB_U,
OP_MUL_U,
OP_MOD_U, //complex
OP_BITAND_U,
OP_BITOR_U,
OP_BITXOR_U,
OP_BITNOT_U, //BITXOR ~0
OP_BITCLR_U,
OP_LSHIFT_U, //same as signed (unlike rshift)
OP_GE_U, //LT_U
OP_GT_U, //LE_U
// OP_AND_U,
// OP_OR_U,
OP_EQ_U,
OP_NE_U,
//uint64 opcodes. they match the int32 ones so emulation is basically swapping them over.
OP_BITNOT_I64, //BITXOR ~0
OP_BITCLR_I64,
OP_GE_I64, //LT_I64
OP_GT_I64, //LE_I64
OP_ADD_U64,
OP_SUB_U64,
OP_MUL_U64,
OP_MOD_U64, //complex
OP_BITAND_U64,
OP_BITOR_U64,
OP_BITXOR_U64,
OP_BITNOT_U64, //BITXOR ~0
OP_BITCLR_U64,
OP_LSHIFT_U64I,
OP_GE_U64, //LT_U64
OP_GT_U64, //LE_U64
OP_EQ_U64,
OP_NE_U64,
//generally implemented by forcing to int64.
OP_BITAND_D,
OP_BITOR_D,
OP_BITXOR_D,
OP_BITNOT_D,
OP_BITCLR_D,
OP_LSHIFT_DI,
OP_RSHIFT_DI,
//special/fake opcodes used by the decompiler. //special/fake opcodes used by the decompiler.
OPD_GOTO_FORSTART, OPD_GOTO_FORSTART,
OPD_GOTO_WHILE1, OPD_GOTO_WHILE1,
OP_NUMOPS,
OP_BIT_BREAKPOINT = 0x8000, OP_BIT_BREAKPOINT = 0x8000,
OP_NUMOPS
}; };
#define MAX_PARMS 8 #define MAX_PARMS 8

View file

@ -610,8 +610,20 @@ char *PR_ValueString (progfuncs_t *progfuncs, etype_t type, eval_t *val, pbool v
case ev_float: case ev_float:
QC_snprintfz (line, sizeof(line), "%g", val->_float); QC_snprintfz (line, sizeof(line), "%g", val->_float);
break; break;
case ev_double:
QC_snprintfz (line, sizeof(line), "%g", val->_double);
break;
case ev_integer: case ev_integer:
QC_snprintfz (line, sizeof(line), "%i", val->_int); QC_snprintfz (line, sizeof(line), "%"pPRIi, val->_int);
break;
case ev_uint:
QC_snprintfz (line, sizeof(line), "%"pPRIu, val->_uint);
break;
case ev_int64:
QC_snprintfz (line, sizeof(line), "%"pPRIi64, val->_int64);
break;
case ev_uint64:
QC_snprintfz (line, sizeof(line), "%"pPRIu64, val->_uint64);
break; break;
case ev_vector: case ev_vector:
QC_snprintfz (line, sizeof(line), "'%g %g %g'", val->_vector[0], val->_vector[1], val->_vector[2]); QC_snprintfz (line, sizeof(line), "'%g %g %g'", val->_vector[0], val->_vector[1], val->_vector[2]);
@ -749,8 +761,23 @@ char *PDECL PR_UglyValueString (pubprogfuncs_t *ppf, etype_t type, eval_t *val)
else else
sprintf (line, "%f", val->_float); sprintf (line, "%f", val->_float);
break; break;
case ev_double:
if (val->_double == (pint64_t)val->_double)
sprintf (line, "%"pPRIi64, (pint64_t)val->_double); //an attempt to cut down on the number of .000000 vars..
else
sprintf (line, "%f", val->_double);
break;
case ev_integer: case ev_integer:
sprintf (line, "%i", val->_int); sprintf (line, "%"pPRIi, val->_int);
break;
case ev_uint:
sprintf (line, "%"pPRIu, val->_uint);
break;
case ev_int64:
sprintf (line, "%"pPRIi64, val->_int64);
break;
case ev_uint64:
sprintf (line, "%"pPRIu64, val->_int64);
break; break;
case ev_vector: case ev_vector:
if (val->_vector[0] == (int)val->_vector[0] && val->_vector[1] == (int)val->_vector[1] && val->_vector[2] == (int)val->_vector[2]) if (val->_vector[0] == (int)val->_vector[0] && val->_vector[1] == (int)val->_vector[1] && val->_vector[2] == (int)val->_vector[2])
@ -815,8 +842,23 @@ char *PR_UglyOldValueString (progfuncs_t *progfuncs, etype_t type, eval_t *val)
else else
QC_snprintfz (line, sizeof(line), "%f", val->_float); QC_snprintfz (line, sizeof(line), "%f", val->_float);
break; break;
case ev_double:
if (val->_double == (int)val->_double)
QC_snprintfz (line, sizeof(line), "%i", (int)val->_double); //an attempt to cut down on the number of .000000 vars..
else
QC_snprintfz (line, sizeof(line), "%f", val->_double);
break;
case ev_integer: case ev_integer:
QC_snprintfz (line, sizeof(line), "%i", val->_int); QC_snprintfz (line, sizeof(line), "%"pPRIi, val->_int);
break;
case ev_uint:
QC_snprintfz (line, sizeof(line), "%"pPRIu, val->_uint);
break;
case ev_int64:
QC_snprintfz (line, sizeof(line), "%"pPRIi64, val->_int64);
break;
case ev_uint64:
QC_snprintfz (line, sizeof(line), "%"pPRIu64, val->_uint64);
break; break;
case ev_vector: case ev_vector:
if (val->_vector[0] == (int)val->_vector[0] && val->_vector[1] == (int)val->_vector[1] && val->_vector[2] == (int)val->_vector[2]) if (val->_vector[0] == (int)val->_vector[0] && val->_vector[1] == (int)val->_vector[1] && val->_vector[2] == (int)val->_vector[2])
@ -862,10 +904,18 @@ char *PR_TypeString(progfuncs_t *progfuncs, etype_t type)
return "void"; return "void";
case ev_float: case ev_float:
return "float"; return "float";
case ev_double:
return "double";
case ev_vector: case ev_vector:
return "vector"; return "vector";
case ev_integer: case ev_integer:
return "integer"; return "integer";
case ev_uint:
return "uint";
case ev_int64:
return "int64";
case ev_uint64:
return "uint64";
default: default:
return "BAD TYPE"; return "BAD TYPE";
} }
@ -1192,9 +1242,21 @@ pbool PDECL ED_ParseEval (pubprogfuncs_t *ppf, eval_t *eval, int type, const cha
case ev_float: case ev_float:
eval->_float = (float)atof (s); eval->_float = (float)atof (s);
break; break;
case ev_double:
eval->_double = atof (s);
break;
case ev_integer: case ev_integer:
eval->_int = atoi (s); eval->_int = strtol (s, NULL, 0);
break;
case ev_uint:
eval->_uint = strtoul (s, NULL, 0);
break;
case ev_int64:
eval->_int64 = strtoll (s, NULL, 0);
break;
case ev_uint64:
eval->_uint64 = strtoull (s, NULL, 0);
break; break;
case ev_vector: case ev_vector:
@ -1259,14 +1321,15 @@ pbool PDECL ED_ParseEval (pubprogfuncs_t *ppf, eval_t *eval, int type, const cha
pbool ED_ParseEpair (progfuncs_t *progfuncs, size_t qcptr, unsigned int fldofs, int fldtype, char *s) pbool ED_ParseEpair (progfuncs_t *progfuncs, size_t qcptr, unsigned int fldofs, int fldtype, char *s)
{ {
int i; pint64_t i;
puint64_t u;
progsnum_t module; progsnum_t module;
fdef_t *def; fdef_t *def;
string_t st; string_t st;
mfunction_t *func; mfunction_t *func;
int type = fldtype & ~DEF_SAVEGLOBAL; int type = fldtype & ~DEF_SAVEGLOBAL;
double d; double d;
qcptr += fldofs*sizeof(int); eval_t *eval = (eval_t *)(progfuncs->funcs.stringtable + qcptr + (fldofs*sizeof(int)));
switch (type) switch (type)
{ {
@ -1276,7 +1339,7 @@ pbool ED_ParseEpair (progfuncs_t *progfuncs, size_t qcptr, unsigned int fldofs,
#else #else
st = PR_StringToProgs(&progfuncs->funcs, ED_NewString (&progfuncs->funcs, s, 0, true)); st = PR_StringToProgs(&progfuncs->funcs, ED_NewString (&progfuncs->funcs, s, 0, true));
#endif #endif
*(string_t *)(progfuncs->funcs.stringtable + qcptr) = st; eval->string = st;
break; break;
case ev_float: case ev_float:
@ -1285,19 +1348,60 @@ pbool ED_ParseEpair (progfuncs_t *progfuncs, size_t qcptr, unsigned int fldofs,
d = strtod(s, &s); d = strtod(s, &s);
while(*s == ' ' || *s == '\t') while(*s == ' ' || *s == '\t')
s++; s++;
*(float *)(progfuncs->funcs.stringtable + qcptr) = d; eval->_float = d;
if (*s)
return false; //some kind of junk in there.
break;
case ev_double:
while(*s == ' ' || *s == '\t')
s++;
d = strtod(s, &s);
while(*s == ' ' || *s == '\t')
s++;
eval->_double = d;
if (*s) if (*s)
return false; //some kind of junk in there. return false; //some kind of junk in there.
break; break;
case ev_entity: //ent references are simple ints for us.
case ev_integer: case ev_integer:
while(*s == ' ' || *s == '\t') while(*s == ' ' || *s == '\t')
s++; s++;
i = strtol(s, &s, 0); i = strtol(s, &s, 0);
while(*s == ' ' || *s == '\t') while(*s == ' ' || *s == '\t')
s++; s++;
*(int *)(progfuncs->funcs.stringtable + qcptr) = i; eval->_int = i;
if (*s)
return false; //some kind of junk in there.
break;
case ev_entity: //ent references are simple ints for us.
case ev_uint:
while(*s == ' ' || *s == '\t')
s++;
u = strtoul(s, &s, 0);
while(*s == ' ' || *s == '\t')
s++;
eval->_uint = u;
if (*s)
return false; //some kind of junk in there.
break;
case ev_int64:
while(*s == ' ' || *s == '\t')
s++;
i = strtoll(s, &s, 0);
while(*s == ' ' || *s == '\t')
s++;
eval->_int64 = i;
if (*s)
return false; //some kind of junk in there.
break;
case ev_uint64:
while(*s == ' ' || *s == '\t')
s++;
u = strtoull(s, &s, 0);
while(*s == ' ' || *s == '\t')
s++;
eval->_uint64 = u;
if (*s) if (*s)
return false; //some kind of junk in there. return false; //some kind of junk in there.
break; break;
@ -1308,7 +1412,7 @@ pbool ED_ParseEpair (progfuncs_t *progfuncs, size_t qcptr, unsigned int fldofs,
while(*s == ' ' || *s == '\t') while(*s == ' ' || *s == '\t')
s++; s++;
d = strtod(s, &s); d = strtod(s, &s);
((float *)(progfuncs->funcs.stringtable + qcptr))[i] = d; eval->_vector[i] = d;
} }
while(*s == ' ' || *s == '\t') while(*s == ' ' || *s == '\t')
s++; s++;
@ -1323,13 +1427,13 @@ pbool ED_ParseEpair (progfuncs_t *progfuncs, size_t qcptr, unsigned int fldofs,
externs->Printf ("Can't find field %s\n", s); externs->Printf ("Can't find field %s\n", s);
return false; return false;
} }
*(int *)(progfuncs->funcs.stringtable + qcptr) = def->ofs; eval->_int = def->ofs;
break; break;
case ev_function: case ev_function:
if (s[0] && s[1]==':'&&s[2]=='\0') //this isn't right... if (s[0] && s[1]==':'&&s[2]=='\0') //this isn't right...
{ {
*(func_t *)(progfuncs->funcs.stringtable + qcptr) = 0; eval->function = 0;
return true; return true;
} }
func = ED_FindFunction (progfuncs, s, &module, -1); func = ED_FindFunction (progfuncs, s, &module, -1);
@ -1338,7 +1442,7 @@ pbool ED_ParseEpair (progfuncs_t *progfuncs, size_t qcptr, unsigned int fldofs,
externs->Printf ("Can't find function %s\n", s); externs->Printf ("Can't find function %s\n", s);
return false; return false;
} }
*(func_t *)(progfuncs->funcs.stringtable + qcptr) = (func - pr_progstate[module].functions) | (module<<24); eval->function = (func - pr_progstate[module].functions) | (module<<24);
break; break;
default: default:
@ -1564,7 +1668,11 @@ char *ED_WriteGlobals(progfuncs_t *progfuncs, char *buf, size_t *bufofs, size_t
} }
else if (type != ev_string //anything other than these is not saved else if (type != ev_string //anything other than these is not saved
&& type != ev_float && type != ev_float
&& type != ev_double
&& type != ev_integer && type != ev_integer
&& type != ev_uint
&& type != ev_int64
&& type != ev_uint64
&& type != ev_entity && type != ev_entity
&& type != ev_vector) && type != ev_vector)
continue; continue;
@ -1621,7 +1729,11 @@ char *ED_WriteGlobals(progfuncs_t *progfuncs, char *buf, size_t *bufofs, size_t
} }
else if (type != ev_string //anything other than these is not saved else if (type != ev_string //anything other than these is not saved
&& type != ev_float && type != ev_float
&& type != ev_double
&& type != ev_integer && type != ev_integer
&& type != ev_uint
&& type != ev_int64
&& type != ev_uint64
&& type != ev_entity && type != ev_entity
&& type != ev_vector) && type != ev_vector)
continue; continue;
@ -3098,8 +3210,11 @@ retry:
nf->progsofs = fld16[i].ofs; nf->progsofs = fld16[i].ofs;
nf->ofs = fld16[i].ofs; nf->ofs = fld16[i].ofs;
if (prinst.fields_size < (nf->ofs+type_size[nf->type])*4) if (prinst.fields_size < (nf->ofs+type_size[nf->type])*sizeof(pvec_t))
prinst.fields_size = (nf->ofs+type_size[nf->type])*4; {
prinst.fields_size = (nf->ofs+type_size[nf->type])*sizeof(pvec_t);
progfuncs->funcs.activefieldslots = nf->ofs+type_size[nf->type];
}
prinst.numfields++; prinst.numfields++;
} }

View file

@ -244,7 +244,7 @@ int PDECL QC_RegisterFieldVar(pubprogfuncs_t *ppf, unsigned int type, const char
prinst.reorganisefields = 2; prinst.reorganisefields = 2;
else if (engineofs) else if (engineofs)
{ {
progfuncs->funcs.fieldadjust = prinst.fields_size/4; progfuncs->funcs.fieldadjust = prinst.fields_size/sizeof(pvec_t);
#ifdef MAPPING_DEBUG #ifdef MAPPING_DEBUG
externs->Printf("FIELD ADJUST: %i %i %i\n", progfuncs->funcs.fieldadjust, prinst.fields_size, (int)prinst.fields_size/4); externs->Printf("FIELD ADJUST: %i %i %i\n", progfuncs->funcs.fieldadjust, prinst.fields_size, (int)prinst.fields_size/4);
#endif #endif
@ -329,7 +329,7 @@ int PDECL QC_RegisterFieldVar(pubprogfuncs_t *ppf, unsigned int type, const char
} }
else else
{ //we just found a new fieldname inside a progs { //we just found a new fieldname inside a progs
prinst.field[fnum].ofs = ofs = prinst.fields_size/4; //add on the end prinst.field[fnum].ofs = ofs = prinst.fields_size/sizeof(pvec_t); //add on the end
//if the progs field offset matches annother offset in the same progs, make it match up with the earlier one. //if the progs field offset matches annother offset in the same progs, make it match up with the earlier one.
if (progsofs>=0) if (progsofs>=0)
@ -368,8 +368,11 @@ int PDECL QC_RegisterFieldVar(pubprogfuncs_t *ppf, unsigned int type, const char
} }
} }
// if (type != ev_vector) // if (type != ev_vector)
if (prinst.fields_size < (ofs+type_size[type])*4) if (prinst.fields_size < (ofs+type_size[type])*sizeof(pvec_t))
prinst.fields_size = (ofs+type_size[type])*4; {
prinst.fields_size = (ofs+type_size[type])*sizeof(pvec_t);
progfuncs->funcs.activefieldslots = prinst.fields_size/sizeof(pvec_t);
}
if (prinst.max_fields_size && prinst.fields_size > prinst.max_fields_size) if (prinst.max_fields_size && prinst.fields_size > prinst.max_fields_size)
externs->Sys_Error("Allocated too many additional fields after ents were inited."); externs->Sys_Error("Allocated too many additional fields after ents were inited.");

View file

@ -67,7 +67,30 @@ typedef struct {
int spare[2]; int spare[2];
} evalc_t; } evalc_t;
#define sizeofevalc sizeof(evalc_t) #define sizeofevalc sizeof(evalc_t)
typedef enum {ev_void, ev_string, ev_float, ev_vector, ev_entity, ev_field, ev_function, ev_pointer, ev_integer, ev_variant, ev_struct, ev_union, ev_accessor, ev_enum, ev_boolean} etype_t; typedef enum {
//vanilla types
ev_void,
ev_string, //offset into the string table - but if the high bit is set then its probably some special thing.
ev_float, //can hold up to 24 bits... sucks, but this is our basic numeric type.
ev_vector, //3 floats.
ev_entity, //index into the edicts array (vanilla used byte offsets from world).
ev_field, //index into the per-entity field table.
ev_function,//all functions are called via reference.
ev_pointer, //exists in vanilla - *(&ent.fld) opcodes are valid there - how else would you store to a field?
//extended types
ev_integer, //our first extended type... probably won't help performance much but at least it doesn't have the imprecision issue of floats.
ev_uint, //mostly just reuses int opcodes.
ev_int64, //large int type, because we can. might be useful for system handles perhaps? dunno, probably not that useful.
ev_uint64, //mostly just reuses int64 opcodes.
ev_double, //useful for timers, for the extra precision.
//qc-only types
ev_variant, //used primarily for builtin args, or for type punning casts without using pointers. should never be used for a global.
ev_struct, //big complex type
ev_union, //not really sure why this is separate from struct
ev_accessor,//some weird type to provide class-like functions over a basic type.
ev_enum, //just a numeric type
ev_boolean //exists to optimise if(-0) workarounds.
} etype_t;
enum { enum {
DEBUG_TRACE_OFF, //debugging should be off. DEBUG_TRACE_OFF, //debugging should be off.
DEBUG_TRACE_INTO, //debug into functions DEBUG_TRACE_INTO, //debug into functions
@ -154,6 +177,8 @@ struct pubprogfuncs_s
int stringtablesize; int stringtablesize;
int stringtablemaxsize; int stringtablemaxsize;
int fieldadjust; //FrikQCC style arrays can cause problems due to field remapping. This causes us to leave gaps but offsets identical. except for system fields, qc-addressable variables use their old offsets, this is the bias so that the offset pokes the correct memory. int fieldadjust; //FrikQCC style arrays can cause problems due to field remapping. This causes us to leave gaps but offsets identical. except for system fields, qc-addressable variables use their old offsets, this is the bias so that the offset pokes the correct memory.
unsigned int activefieldslots; //f+=fieldadjust; invalidfield = (f<0)||(f+fldsize>=activefieldslots); note that this does NOT apply to 'object' entities which are variable sized, use ed->fieldsize for those.
struct qcthread_s *(PDECL *Fork) (pubprogfuncs_t *prinst); //returns a pointer to a thread which can be resumed via RunThread. struct qcthread_s *(PDECL *Fork) (pubprogfuncs_t *prinst); //returns a pointer to a thread which can be resumed via RunThread.
void (PDECL *RunThread) (pubprogfuncs_t *prinst, struct qcthread_s *thread); void (PDECL *RunThread) (pubprogfuncs_t *prinst, struct qcthread_s *thread);
@ -260,12 +285,16 @@ pubprogfuncs_t * PDECL InitProgs(progparms_t *ext);
typedef union eval_s typedef union eval_s
{ {
string_t string; string_t string;
float _float; pvec_t _float;
float _vector[3]; pvec_t _vector[3];
func_t function; func_t function; //module=0xff000000, func=0x00ffffff
int _int; pint_t _int;
int edict; puint_t _uint;
float prog; //so it can easily be changed pint64_t _int64;
puint64_t _uint64;
double _double;
pint_t edict;
pvec_t prog; //so it can easily be changed
} eval_t; } eval_t;
#define PR_CURRENT -1 #define PR_CURRENT -1
@ -334,7 +363,11 @@ typedef union eval_s
//To use these outside of builtins, you will likly have to use the 'globals' method. //To use these outside of builtins, you will likly have to use the 'globals' method.
#define G_FLOAT(o) (((pvec_t *)pr_globals)[o]) #define G_FLOAT(o) (((pvec_t *)pr_globals)[o])
#define G_FLOAT2(o) (((pvec_t *)pr_globals)[OFS_PARM0 + o*3]) #define G_FLOAT2(o) (((pvec_t *)pr_globals)[OFS_PARM0 + o*3])
#define G_DOUBLE(o) (*(double *)(((pvec_t *)pr_globals+(o))))
#define G_INT(o) (((pint_t *)pr_globals)[o]) #define G_INT(o) (((pint_t *)pr_globals)[o])
#define G_UINT(o) (((puint_t *)pr_globals)[o])
#define G_INT64(o) (*(pint64_t *)((pint_t *)pr_globals+(o)))
#define G_UINT64(o) (*(puint64_t *)((puint_t *)pr_globals+(o)))
#define G_EDICT(pf, o) PROG_TO_EDICT(pf, G_INT(o)) //((edict_t *)((char *) sv.edicts+ *(int *)&((float *)pr_globals)[o])) #define G_EDICT(pf, o) PROG_TO_EDICT(pf, G_INT(o)) //((edict_t *)((char *) sv.edicts+ *(int *)&((float *)pr_globals)[o]))
#define G_EDICTNUM(pf, o) NUM_FOR_EDICT(pf, G_EDICT(pf, o)) #define G_EDICTNUM(pf, o) NUM_FOR_EDICT(pf, G_EDICT(pf, o))
#define G_VECTOR(o) (&((pvec_t *)pr_globals)[o]) #define G_VECTOR(o) (&((pvec_t *)pr_globals)[o])

View file

@ -23,10 +23,30 @@ typedef uint64_t puint_t;
typedef float pvec_t; typedef float pvec_t;
typedef int pint_t; typedef int pint_t;
typedef unsigned int puint_t; typedef unsigned int puint_t;
#define pPRId "d" #ifdef _MSC_VER
#define pPRIi "i" typedef __int64 pint64_t;
#define pPRIu "u" typedef unsigned __int64 puint64_t;
#define pPRIx "x"
#define pPRId "d"
#define pPRIi "i"
#define pPRIu "u"
#define pPRIx "x"
#define pPRIi64 "I64i"
#define pPRIu64 "I64u"
#define pPRIx64 "I64x"
#else
#include <inttypes.h>
typedef int64_t pint64_t;
typedef uint64_t puint64_t;
#define pPRId PRId32
#define pPRIi PRIi32
#define pPRIu PRIu32
#define pPRIx PRIx32
#define pPRIi64 PRIi64
#define pPRIu64 PRIu64
#define pPRIx64 PRIx64
#endif
#define QCVM_32 #define QCVM_32
#endif #endif

View file

@ -317,7 +317,7 @@ typedef struct QCC_function_s QCC_function_t;
#define MAX_PARMS 8 #define MAX_PARMS 8
//keep this sizeof(float) //keep this sizeof(float)
typedef union QCC_eval_s typedef union QCC_eval_basic_s
{ {
QCC_string_t string; QCC_string_t string;
pvec_t _float; pvec_t _float;
@ -328,19 +328,24 @@ typedef union QCC_eval_s
#endif #endif
func_t function; func_t function;
pint_t _int; pint_t _int;
puint_t _uint;
// union QCC_eval_s *ptr; // union QCC_eval_s *ptr;
} QCC_eval_t; } QCC_eval_basic_t;
//must be the maximum size possible for a single basic type. //must be the maximum size possible for a single basic type.
typedef union QCC_evalstorage_s typedef union QCC_eval_s
{ {
QCC_string_t string; QCC_string_t string;
pvec_t _float; pvec_t _float;
double _double;
pvec_t vector[3]; pvec_t vector[3];
func_t function; func_t function;
pint_t _int; pint_t _int;
puint_t _uint;
pint64_t _int64;
puint64_t _uint64;
// union QCC_eval_s *ptr; // union QCC_eval_s *ptr;
} QCC_evalstorage_t; } QCC_eval_t;
struct QCC_typeparam_s struct QCC_typeparam_s
{ {
@ -349,7 +354,7 @@ struct QCC_typeparam_s
pbool optional:1; //argument may safely be omitted, for builtin functions. for qc functions use the defltvalue instead. pbool optional:1; //argument may safely be omitted, for builtin functions. for qc functions use the defltvalue instead.
pbool isvirtual:1; //const, with implicit initialisation only. valid for structs pbool isvirtual:1; //const, with implicit initialisation only. valid for structs
unsigned char out; //0=in,1==inout,2=out unsigned char out; //0=in,1==inout,2=out
unsigned int ofs; unsigned int ofs; //FIXME: make byte offsets, for bytes/shorts.
unsigned int arraysize; unsigned int arraysize;
char *paramname; char *paramname;
}; };
@ -375,8 +380,8 @@ typedef struct QCC_type_s
struct QCC_typeparam_s *params; //[num_parms] struct QCC_typeparam_s *params; //[num_parms]
unsigned int num_parms; unsigned int num_parms;
unsigned int size; unsigned int size; //FIXME: make bytes, for bytes+shorts
pbool typedefed:1; pbool typedefed:1; //name is in the typenames list.
pbool vargs:1; //function has vargs pbool vargs:1; //function has vargs
pbool vargcount:1; //function has special varg count param pbool vargcount:1; //function has special varg count param
const char *name; const char *name;
@ -412,7 +417,7 @@ typedef struct QCC_def_s
struct QCC_def_s *reloc; //the symbol that we're a reloc for struct QCC_def_s *reloc; //the symbol that we're a reloc for
struct QCC_def_s *gaddress; //a def that holds our offset. struct QCC_def_s *gaddress; //a def that holds our offset.
struct QCC_def_s *symbolheader; //this is the original symbol within which the def is stored. struct QCC_def_s *symbolheader; //this is the original symbol within which the def is stored.
union QCC_eval_s *symboldata; //null if uninitialised. use sym->symboldata[sym->ofs] to index. union QCC_eval_basic_s *symboldata; //null if uninitialised. use sym->symboldata[sym->ofs] to index.
unsigned int symbolsize; //total byte size of symbol unsigned int symbolsize; //total byte size of symbol
int refcount; //if 0, temp can be reused. tracked on globals too in order to catch bugs that would otherwise be a little too obscure. int refcount; //if 0, temp can be reused. tracked on globals too in order to catch bugs that would otherwise be a little too obscure.
@ -497,7 +502,7 @@ extern int QCC_packid;
extern const unsigned int type_size[]; extern const unsigned int type_size[];
//extern QCC_def_t *def_for_type[9]; //extern QCC_def_t *def_for_type[9];
extern QCC_type_t *type_void, *type_string, *type_float, *type_vector, *type_entity, *type_field, *type_function, *type_floatfunction, *type_pointer, *type_floatpointer, *type_intpointer, *type_integer, *type_variant, *type_floatfield; extern QCC_type_t *type_void, *type_string, *type_float, *type_double, *type_vector, *type_entity, *type_field, *type_function, *type_floatfunction, *type_pointer, *type_floatpointer, *type_intpointer, *type_bint, *type_bfloat, *type_integer, *type_uint, *type_int64, *type_uint64, *type_variant, *type_floatfield;
extern char *basictypenames[]; extern char *basictypenames[];
struct QCC_function_s struct QCC_function_s
@ -581,7 +586,7 @@ extern token_type_t pr_token_type;
extern int pr_token_line; extern int pr_token_line;
extern int pr_token_line_last; extern int pr_token_line_last;
extern QCC_type_t *pr_immediate_type; extern QCC_type_t *pr_immediate_type;
extern QCC_evalstorage_t pr_immediate; extern QCC_eval_t pr_immediate;
extern pbool keyword_asm; extern pbool keyword_asm;
extern pbool keyword_break; extern pbool keyword_break;
@ -596,10 +601,17 @@ extern pbool keyword_default;
extern pbool keyword_do; extern pbool keyword_do;
extern pbool keyword_entity; extern pbool keyword_entity;
extern pbool keyword_float; extern pbool keyword_float;
extern pbool keyword_double;
extern pbool keyword_for; extern pbool keyword_for;
extern pbool keyword_goto; extern pbool keyword_goto;
extern pbool keyword_char;
extern pbool keyword_byte;
extern pbool keyword_short;
extern pbool keyword_int; extern pbool keyword_int;
extern pbool keyword_integer; extern pbool keyword_integer;
extern pbool keyword_long;
extern pbool keyword_signed;
extern pbool keyword_unsigned;
extern pbool keyword_state; extern pbool keyword_state;
extern pbool keyword_string; extern pbool keyword_string;
extern pbool keyword_struct; extern pbool keyword_struct;
@ -642,6 +654,7 @@ extern pbool flag_laxcasts;
extern pbool flag_hashonly; extern pbool flag_hashonly;
extern pbool flag_fasttrackarrays; extern pbool flag_fasttrackarrays;
extern pbool flag_assume_integer; extern pbool flag_assume_integer;
extern pbool flag_assume_double;
extern pbool flag_msvcstyle; extern pbool flag_msvcstyle;
extern pbool flag_debugmacros; extern pbool flag_debugmacros;
extern pbool flag_filetimes; extern pbool flag_filetimes;
@ -656,6 +669,7 @@ extern pbool flag_assumevar;
extern pbool flag_dblstarexp; extern pbool flag_dblstarexp;
extern pbool flag_allowuninit; extern pbool flag_allowuninit;
extern pbool flag_cpriority; extern pbool flag_cpriority;
extern pbool flag_qcfuncs;
extern pbool flag_embedsrc; extern pbool flag_embedsrc;
extern pbool flag_nopragmafileline; extern pbool flag_nopragmafileline;
extern pbool flag_utf8strings; extern pbool flag_utf8strings;
@ -740,14 +754,14 @@ void QCC_PR_Expect (const char *string);
pbool QCC_PR_CheckKeyword(int keywordenabled, const char *string); pbool QCC_PR_CheckKeyword(int keywordenabled, const char *string);
#endif #endif
pbool QCC_PR_CheckTokenComment(const char *string, char **comment); pbool QCC_PR_CheckTokenComment(const char *string, char **comment);
void VARGS QCC_PR_ParseError (int errortype, const char *error, ...); NORETURN void VARGS QCC_PR_ParseError (int errortype, const char *error, ...);
pbool VARGS QCC_PR_ParseWarning (int warningtype, const char *error, ...); pbool VARGS QCC_PR_ParseWarning (int warningtype, const char *error, ...);
pbool VARGS QCC_PR_Warning (int type, const char *file, int line, const char *error, ...); pbool VARGS QCC_PR_Warning (int type, const char *file, int line, const char *error, ...);
void VARGS QCC_PR_Note (int type, const char *file, int line, const char *error, ...); void VARGS QCC_PR_Note (int type, const char *file, int line, const char *error, ...);
void QCC_PR_ParsePrintDef (int warningtype, QCC_def_t *def); void QCC_PR_ParsePrintDef (int warningtype, QCC_def_t *def);
void QCC_PR_ParsePrintSRef (int warningtype, QCC_sref_t sref); void QCC_PR_ParsePrintSRef (int warningtype, QCC_sref_t sref);
void VARGS QCC_PR_ParseErrorPrintDef (int errortype, QCC_def_t *def, const char *error, ...); NORETURN void VARGS QCC_PR_ParseErrorPrintDef (int errortype, QCC_def_t *def, const char *error, ...);
void VARGS QCC_PR_ParseErrorPrintSRef (int errortype, QCC_sref_t sref, const char *error, ...); NORETURN void VARGS QCC_PR_ParseErrorPrintSRef (int errortype, QCC_sref_t sref, const char *error, ...);
QCC_type_t *QCC_PR_MakeThiscall(QCC_type_t *orig, QCC_type_t *thistype); QCC_type_t *QCC_PR_MakeThiscall(QCC_type_t *orig, QCC_type_t *thistype);
@ -845,6 +859,7 @@ enum {
WARN_REDECLARATIONMISMATCH, WARN_REDECLARATIONMISMATCH,
WARN_PARAMWITHNONAME, WARN_PARAMWITHNONAME,
WARN_ARGUMENTCHECK, WARN_ARGUMENTCHECK,
WARN_IGNOREDKEYWORD, //use of a keyword that fteqcc does not support at this time.
ERR_PARSEERRORS, //caused by qcc_pr_parseerror being called. ERR_PARSEERRORS, //caused by qcc_pr_parseerror being called.
@ -1066,6 +1081,7 @@ void QCC_PR_EmitArraySetFunction(QCC_def_t *defscope, QCC_def_t *thearray, char
void QCC_PR_EmitClassFromFunction(QCC_def_t *defscope, QCC_type_t *basetype); void QCC_PR_EmitClassFromFunction(QCC_def_t *defscope, QCC_type_t *basetype);
void QCC_PR_ParseDefs (char *classname, pbool fatal); void QCC_PR_ParseDefs (char *classname, pbool fatal);
void QCC_PR_ParseTypedef(void);
QCC_def_t *QCC_PR_DummyDef(QCC_type_t *type, const char *name, QCC_function_t *scope, int arraysize, QCC_def_t *rootsymbol, unsigned int ofs, int referable, unsigned int flags); QCC_def_t *QCC_PR_DummyDef(QCC_type_t *type, const char *name, QCC_function_t *scope, int arraysize, QCC_def_t *rootsymbol, unsigned int ofs, int referable, unsigned int flags);
void QCC_PR_ParseInitializerDef(QCC_def_t *def, unsigned int flags); void QCC_PR_ParseInitializerDef(QCC_def_t *def, unsigned int flags);
void QCC_PR_FinaliseFunctions(void); void QCC_PR_FinaliseFunctions(void);
@ -1084,7 +1100,7 @@ void QCC_Cleanup(void);
extern char pr_immediate_string[8192]; extern char pr_immediate_string[8192];
extern size_t pr_immediate_strlen; extern size_t pr_immediate_strlen;
extern QCC_eval_t *qcc_pr_globals; extern QCC_eval_basic_t *qcc_pr_globals;
extern unsigned int numpr_globals; extern unsigned int numpr_globals;
extern char *strings; extern char *strings;

View file

@ -19,7 +19,7 @@ const char **myargv;
char qcc_token[1024]; char qcc_token[1024];
int qcc_eof; int qcc_eof;
const unsigned int type_size[12] = {1, //void const unsigned int type_size[] = {1, //void
sizeof(string_t)/4, //string sizeof(string_t)/4, //string
1, //float 1, //float
3, //vector 3, //vector
@ -28,12 +28,18 @@ const unsigned int type_size[12] = {1, //void
sizeof(func_t)/4,//function sizeof(func_t)/4,//function
1, //pointer (its an int index) 1, //pointer (its an int index)
1, //integer 1, //integer
1, //uint
2, //long
2, //ulong
2, //double
3, //fixme: how big should a variant be? 3, //fixme: how big should a variant be?
0, //ev_struct. variable sized. 0, //ev_struct. variable sized.
0 //ev_union. variable sized. 0, //ev_union. variable sized.
0, //ev_accessor...
0, //ev_enum...
1, //ev_bool...
}; };
char *basictypenames[] = { char *basictypenames[] = {
"void", "void",
"string", "string",
@ -44,11 +50,16 @@ char *basictypenames[] = {
"function", "function",
"pointer", "pointer",
"integer", "integer",
"uint",
"long",
"ulong",
"double",
"variant", "variant",
"struct", "struct",
"union", "union",
"accessor", "accessor",
"enum" "enum",
"bool"
}; };
/* /*
@ -291,10 +302,7 @@ skipwhite:
while ((c = *data) && qcc_iswhite(c)) while ((c = *data) && qcc_iswhite(c))
data++; data++;
if (!c) if (!c)
{
qcc_eof = true;
return NULL; return NULL;
}
// skip // comments // skip // comments
if (c=='/' && data[1] == '/') if (c=='/' && data[1] == '/')
@ -415,10 +423,7 @@ skipwhite:
while ((c = *data) && qcc_iswhite(c)) while ((c = *data) && qcc_iswhite(c))
data++; data++;
if (!c) if (!c)
{
qcc_eof = true;
return NULL; return NULL;
}
// skip // comments // skip // comments
if (c=='/' && data[1] == '/') if (c=='/' && data[1] == '/')

File diff suppressed because it is too large Load diff

View file

@ -41,7 +41,7 @@ token_type_t pr_token_type;
int pr_token_line; int pr_token_line;
int pr_token_line_last; int pr_token_line_last;
QCC_type_t *pr_immediate_type; QCC_type_t *pr_immediate_type;
QCC_evalstorage_t pr_immediate; QCC_eval_t pr_immediate;
char pr_immediate_string[8192]; char pr_immediate_string[8192];
size_t pr_immediate_strlen; size_t pr_immediate_strlen;
@ -84,16 +84,22 @@ char *pr_punctuationremap[] = //a nice bit of evilness.
QCC_type_t *type_void; //void QCC_type_t *type_void; //void
QCC_type_t *type_string; //string QCC_type_t *type_string; //string
QCC_type_t *type_float; //float QCC_type_t *type_float; //float
QCC_type_t *type_double; //double
QCC_type_t *type_vector; //vector QCC_type_t *type_vector; //vector
QCC_type_t *type_entity; //entity QCC_type_t *type_entity; //entity
QCC_type_t *type_field; //.void QCC_type_t *type_field; //.void
QCC_type_t *type_function; //void() QCC_type_t *type_function; //void()
QCC_type_t *type_floatfunction; //float() QCC_type_t *type_floatfunction; //float()
QCC_type_t *type_pointer; //??? * - careful with this one QCC_type_t *type_pointer; //??? * - careful with this one
QCC_type_t *type_integer; //int QCC_type_t *type_integer; //int32
QCC_type_t *type_uint; //uint32
QCC_type_t *type_int64; //int64
QCC_type_t *type_uint64; //uint64
QCC_type_t *type_variant; //__variant QCC_type_t *type_variant; //__variant
QCC_type_t *type_floatpointer; //float * QCC_type_t *type_floatpointer; //float *
QCC_type_t *type_intpointer; //int * QCC_type_t *type_intpointer; //int *
QCC_type_t *type_bint; //int (0 or 1)
QCC_type_t *type_bfloat; //float (0.0 or 1.0, and never -0.0)
QCC_type_t *type_floatfield;// = {ev_field/*, &def_field*/, NULL, &type_float}; QCC_type_t *type_floatfield;// = {ev_field/*, &def_field*/, NULL, &type_float};
@ -1306,7 +1312,8 @@ static pbool QCC_PR_Precompiler(void)
} }
else if (!QC_strcasecmp(qcc_token, "sourcefile")) else if (!QC_strcasecmp(qcc_token, "sourcefile"))
{ {
QCC_COM_Parse(msg); char *s = msg;
while ((s = QCC_COM_Parse(s)))
QCC_RegisterSourceFile(qcc_token); QCC_RegisterSourceFile(qcc_token);
} }
else if (!QC_strcasecmp(qcc_token, "TARGET")) else if (!QC_strcasecmp(qcc_token, "TARGET"))
@ -1330,6 +1337,41 @@ static pbool QCC_PR_Precompiler(void)
if (strcmp(destfile, olddest)) if (strcmp(destfile, olddest))
externs->Printf("Outputfile: %s\n", destfile); externs->Printf("Outputfile: %s\n", destfile);
} }
else if (!QC_strcasecmp(qcc_token, "opcode"))
{
int st;
char *s = QCC_COM_Parse(msg);
if (!QC_strcasecmp(qcc_token, "enable") || !QC_strcasecmp(qcc_token, "on"))
st = 1;
else if (!QC_strcasecmp(qcc_token, "disable") || !QC_strcasecmp(qcc_token, "off"))
st = 0;
else
{
QCC_PR_ParseWarning(WARN_BADPRAGMA, "opcode state not recognised");
st = -1;
}
if (st >= 0)
{
int f;
while ((s = QCC_COM_Parse(s)))
{
for (f = 0; pr_opcodes[f].opname; f++)
{
if (!QC_strcasecmp(pr_opcodes[f].opname, qcc_token))
{
if (st)
pr_opcodes[f].flags |= OPF_VALID;
else
pr_opcodes[f].flags &= ~OPF_VALID;
break;
}
}
if (!pr_opcodes[f].opname)
QCC_PR_ParseWarning(WARN_BADPRAGMA, "opcode %s not recognised", qcc_token);
}
}
}
else if (!QC_strcasecmp(qcc_token, "keyword") || !QC_strcasecmp(qcc_token, "flag")) else if (!QC_strcasecmp(qcc_token, "keyword") || !QC_strcasecmp(qcc_token, "flag"))
{ {
char *s; char *s;
@ -1344,13 +1386,11 @@ static pbool QCC_PR_Precompiler(void)
QCC_PR_ParseWarning(WARN_BADPRAGMA, "compiler flag state not recognised"); QCC_PR_ParseWarning(WARN_BADPRAGMA, "compiler flag state not recognised");
st = -1; st = -1;
} }
if (st < 0) if (st >= 0)
QCC_PR_ParseWarning(WARN_BADPRAGMA, "warning id not recognised");
else
{ {
int f; int f;
s = QCC_COM_Parse(s); while ((s = QCC_COM_Parse(s)))
{
for (f = 0; compiler_flag[f].enabled; f++) for (f = 0; compiler_flag[f].enabled; f++)
{ {
if (!QC_strcasecmp(compiler_flag[f].abbrev, qcc_token)) if (!QC_strcasecmp(compiler_flag[f].abbrev, qcc_token))
@ -1368,7 +1408,7 @@ static pbool QCC_PR_Precompiler(void)
} }
if (!compiler_flag[f].enabled) if (!compiler_flag[f].enabled)
QCC_PR_ParseWarning(WARN_BADPRAGMA, "keyword/flag %s not recognised", qcc_token); QCC_PR_ParseWarning(WARN_BADPRAGMA, "keyword/flag %s not recognised", qcc_token);
}
} }
} }
else if (!QC_strcasecmp(qcc_token, "warning")) else if (!QC_strcasecmp(qcc_token, "warning"))
@ -1392,7 +1432,8 @@ static pbool QCC_PR_Precompiler(void)
if (st>=0) if (st>=0)
{ {
int wn; int wn;
s = QCC_COM_Parse(s); while ((s = QCC_COM_Parse(s)))
{
wn = QCC_WarningForName(qcc_token); wn = QCC_WarningForName(qcc_token);
if (wn < 0) if (wn < 0)
QCC_PR_ParseWarning(WARN_BADPRAGMA, "warning id not recognised"); QCC_PR_ParseWarning(WARN_BADPRAGMA, "warning id not recognised");
@ -1405,9 +1446,15 @@ static pbool QCC_PR_Precompiler(void)
} }
} }
} }
}
else else
{
QCC_PR_SkipToEndOfLine(false);
QCC_PR_ParseWarning(WARN_BADPRAGMA, "Unknown pragma \'%s\'", qcc_token); QCC_PR_ParseWarning(WARN_BADPRAGMA, "Unknown pragma \'%s\'", qcc_token);
} }
QCC_PR_SkipToEndOfLine(true);
}
return true; return true;
} }
@ -1445,98 +1492,6 @@ PR_LexString
Parses a quoted string Parses a quoted string
============== ==============
*/ */
#if 0
void QCC_PR_LexString (void)
{
int c;
int len;
char tmpbuf[2048];
char *text;
char *oldf;
int oldline;
bool fromfile = true;
len = 0;
text = pr_file_p;
do
{
QCC_COM_Parse(text);
// print("Next token is \"%s\"\n", com_token);
if (*text == '\"')
{
text++;
if (fromfile) pr_file_p++;
}
do
{
c = *text++;
if (fromfile) pr_file_p++;
if (!c)
QCC_PR_ParseError ("EOF inside quote");
if (c=='\n')
QCC_PR_ParseError ("newline inside quote");
if (c=='\\')
{ // escape char
c = *text++;
if (fromfile) pr_file_p++;
if (!c)
QCC_PR_ParseError ("EOF inside quote");
if (c == 'n')
c = '\n';
else if (c == '"')
c = '"';
else if (c == '\\')
c = '\\';
else
QCC_PR_ParseError ("Unknown escape char");
}
else if (c=='\"')
{
if (fromfile) pr_file_p++;
break;
}
tmpbuf[len] = c;
len++;
} while (1);
tmpbuf[len] = 0;
// if (fromfile) pr_file_p++;
pr_immediate_type=NULL;
oldline=pr_source_line;
oldf=pr_file_p;
QCC_PR_Lex();
if (pr_immediate_type == &type_string)
{
// print("Appending \"%s\" to \"%s\"\n", pr_immediate_string, tmpbuf);
strcat(tmpbuf, pr_immediate_string);
len+=strlen(pr_immediate_string);
}
else
{
pr_source_line = oldline;
pr_file_p = oldf-1;
QCC_PR_LexWhitespace();
if (*pr_file_p != '\"') //annother string
break;
}
QCC_PR_LexWhitespace();
text = pr_file_p;
} while (1);
strcpy(pr_token, tmpbuf);
pr_token_type = tt_immediate;
pr_immediate_type = &type_string;
strcpy (pr_immediate_string, pr_token);
pr_immediate_strlen = strlen(pr_immediate_string);
// print("Found \"%s\"\n", pr_immediate_string);
}
#else
int QCC_PR_LexEscapedCodepoint(void) int QCC_PR_LexEscapedCodepoint(void)
{ //for "\foo" or '\foo' handling. { //for "\foo" or '\foo' handling.
//caller will have read the \ already. //caller will have read the \ already.
@ -1759,7 +1714,7 @@ void QCC_PR_LexString (void)
} }
else if ((*pr_file_p == 'U' || *pr_file_p == 'u' || *pr_file_p == 'L') && pr_file_p[1] == '\"') else if ((*pr_file_p == 'U' || *pr_file_p == 'u' || *pr_file_p == 'L') && pr_file_p[1] == '\"')
{ //unicode string, char32_t, char16_t, wchar_t respectively. we spit out utf-8 regardless. { //unicode string, char32_t, char16_t, wchar_t respectively. we spit out utf-8 regardless.
QCC_PR_ParseWarning(WARN_NOTUTF8, "interpretting char32_t/char16_t/wchar_t as utf-8"); QCC_PR_ParseWarning(WARN_NOTUTF8, "char32_t/char16_t/wchar_t strings are not supported, treating as u8 prefix (as utf-8)");
stringtype = 2; stringtype = 2;
pr_file_p+=2; pr_file_p+=2;
} }
@ -1823,22 +1778,22 @@ void QCC_PR_LexString (void)
c = 0xe01c | texttype; c = 0xe01c | texttype;
} }
else if (c == 'u' || c == 'U') else if (c == 'u' || c == 'U')
{ { //special hack, \u is a utf-8 code regardless of output encoding...
c = QCC_PR_LexEscapedCodepoint(); c = QCC_PR_LexEscapedCodepoint();
goto forceutf8; goto forceutf8;
} }
else if (c == 'x' || c == 'X') else if (c == 'x' || c == 'X')
{ { //special hack, \xXX in a string is an explicit byte regardless of encoding.
c = QCC_PR_LexEscapedCodepoint(); c = QCC_PR_LexEscapedCodepoint();
if (c > 0xff) // if (c > 0xff)
QCC_PR_ParseWarning(ERR_BADCHARACTERCODE, "Bad unicode character code - codepoint %u is above 0xFF", c); // QCC_PR_ParseWarning(ERR_BADCHARACTERCODE, "Bad unicode character code - codepoint %#x is above 0xFF", c);
goto forcebyte; goto forcebyte;
} }
else else
{ {
c = QCC_PR_LexEscapedCodepoint(); c = QCC_PR_LexEscapedCodepoint();
if (stringtype != 2 && c > 0xff) // if (stringtype != 2 && c > 0xff)
QCC_PR_ParseWarning(ERR_BADCHARACTERCODE, "Bad legacy character code - codepoint %u is above 0xFF", c); // QCC_PR_ParseWarning(ERR_BADCHARACTERCODE, "Bad legacy character code - codepoint %#x is above 0xFF", c);
} }
} }
else if (c=='\"') else if (c=='\"')
@ -2019,7 +1974,6 @@ forcebyte:
} }
}*/ }*/
} }
#endif
/* /*
============== ==============
@ -2120,7 +2074,7 @@ static void QCC_PR_LexNumber (void)
{ {
pr_token[tokenlen++] = c; pr_token[tokenlen++] = c;
pr_file_p++; pr_file_p++;
pr_immediate_type = type_float; pr_immediate_type = flag_assume_double?type_double:type_float;
while(1) while(1)
{ {
c = *pr_file_p; c = *pr_file_p;
@ -2128,11 +2082,17 @@ static void QCC_PR_LexNumber (void)
{ {
pr_token[tokenlen++] = c; pr_token[tokenlen++] = c;
} }
else if (c == 'f') else if (c == 'f' || c == 'F')
{ {
pr_file_p++; pr_file_p++;
break; break;
} }
else if (c == 'd' || c == 'D')
{
pr_immediate_type = type_double;
pr_file_p++;
break;
}
else else
{ {
break; break;
@ -2140,10 +2100,13 @@ static void QCC_PR_LexNumber (void)
pr_file_p++; pr_file_p++;
} }
pr_token[tokenlen++] = 0; pr_token[tokenlen++] = 0;
if (pr_immediate_type == type_double)
pr_immediate._double = atof(pr_token);
else
pr_immediate._float = (float)atof(pr_token); pr_immediate._float = (float)atof(pr_token);
return; goto checkjunk;
} }
else if (c == 'f') else if (c == 'f' || c == 'F')
{ {
pr_token[tokenlen++] = c; pr_token[tokenlen++] = c;
pr_token[tokenlen++] = 0; pr_token[tokenlen++] = 0;
@ -2154,23 +2117,71 @@ static void QCC_PR_LexNumber (void)
num*=sign; num*=sign;
if ((longlong)pr_immediate._float != (longlong)num) if ((longlong)pr_immediate._float != (longlong)num)
QCC_PR_ParseWarning(WARN_OVERFLOW, "numerical overflow"); QCC_PR_ParseWarning(WARN_OVERFLOW, "numerical overflow");
return; goto checkjunk;
} }
else if (c == 'i' || c == 'u') else if (c == 'd' || c == 'D')
{ { //note: conflicts with hex. add a dot before it or something.
pr_token[tokenlen++] = c; pr_token[tokenlen++] = c;
pr_token[tokenlen++] = 0; pr_token[tokenlen++] = 0;
pr_file_p++; pr_file_p++;
pr_immediate_type = type_integer; pr_immediate_type = type_double;
pr_immediate._int = num*sign; pr_immediate._double = num*sign;
num*=sign; num*=sign;
if ((longlong)pr_immediate._double != (longlong)num)
QCC_PR_ParseWarning(WARN_OVERFLOW, "numerical overflow");
goto checkjunk;
}
else if (c == 'i' || c == 'u' || c == 'l' || c == 'I' || c == 'U' || c == 'L')
{ //length and sign flags can be any order. LL suffix must have the same case (but not necessarily match the sign suffix)
int isunsigned;
int islong = (c == 'l')||(c == 'L');
pr_token[tokenlen++] = c;
pr_file_p++;
if (islong)
{ //length suffix was first.
//long-long?
if (*pr_file_p == c)
pr_token[tokenlen++] = *pr_file_p++;
//check for signed suffix...
c = *pr_file_p;
isunsigned = (c == 'u')||(c=='U');
if (c == 'i' || c == 'I' || isunsigned) //ignore an explicit redundant 'i' char, for not-a-float.
pr_token[tokenlen++] = *pr_file_p++;
}
else
{
isunsigned = (c == 'u')||(c=='U');
//we already made sure it u or i, and its not an l
c = *pr_file_p;
if (c == 'l' || c == 'L')
{
pr_token[tokenlen++] = *pr_file_p++;
islong = true;
//long-long?
if (*pr_file_p == c)
pr_token[tokenlen++] = *pr_file_p++;
}
}
pr_token[tokenlen++] = 0;
num *= sign;
if (islong)
{
pr_immediate_type = (isunsigned)?type_uint64:type_int64;
pr_immediate._int64 = num;
}
else
{
pr_immediate_type = (isunsigned)?type_uint:type_integer;
pr_immediate._int = num;
if ((longlong)pr_immediate._int != (longlong)num) if ((longlong)pr_immediate._int != (longlong)num)
{ {
if (((longlong)pr_immediate._int & LL(0xffffffff80000000)) != LL(0xffffffff80000000)) if (((longlong)pr_immediate._int & LL(0xffffffff80000000)) != LL(0xffffffff80000000))
QCC_PR_ParseWarning(WARN_OVERFLOW, "numerical overflow"); QCC_PR_ParseWarning(WARN_OVERFLOW, "numerical overflow");
} }
return; }
goto checkjunk;
} }
else else
break; break;
@ -2217,6 +2228,11 @@ qccxhex:
if ((longlong)pr_immediate._float != (longlong)num && base == 16) if ((longlong)pr_immediate._float != (longlong)num && base == 16)
QCC_PR_ParseWarning(WARN_OVERFLOW, "numerical overflow %lld will be rounded to %f", num, pr_immediate._float); QCC_PR_ParseWarning(WARN_OVERFLOW, "numerical overflow %lld will be rounded to %f", num, pr_immediate._float);
} }
checkjunk:
c = *pr_file_p;
if ( (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || (c >= '0' && c <= '9') || (c & 0x80))
QCC_PR_ParseWarning(ERR_NOTANUMBER, "bad suffix on number %s", pr_token);
} }
@ -3960,7 +3976,7 @@ Aborts the current file load
void editbadfile(const char *file, int line); void editbadfile(const char *file, int line);
#endif #endif
//will abort. //will abort.
void VARGS QCC_PR_ParseError (int errortype, const char *error, ...) NORETURN void VARGS QCC_PR_ParseError (int errortype, const char *error, ...)
{ {
va_list argptr; va_list argptr;
char string[1024]; char string[1024];
@ -3982,7 +3998,7 @@ void VARGS QCC_PR_ParseError (int errortype, const char *error, ...)
longjmp (pr_parse_abort, 1); longjmp (pr_parse_abort, 1);
} }
//will abort. //will abort.
void VARGS QCC_PR_ParseErrorPrintDef (int errortype, QCC_def_t *def, const char *error, ...) NORETURN void VARGS QCC_PR_ParseErrorPrintDef (int errortype, QCC_def_t *def, const char *error, ...)
{ {
va_list argptr; va_list argptr;
char string[1024]; char string[1024];
@ -4005,7 +4021,7 @@ void VARGS QCC_PR_ParseErrorPrintDef (int errortype, QCC_def_t *def, const char
longjmp (pr_parse_abort, 1); longjmp (pr_parse_abort, 1);
} }
void VARGS QCC_PR_ParseErrorPrintSRef (int errortype, QCC_sref_t def, const char *error, ...) NORETURN void VARGS QCC_PR_ParseErrorPrintSRef (int errortype, QCC_sref_t def, const char *error, ...)
{ {
va_list argptr; va_list argptr;
char string[1024]; char string[1024];
@ -4632,6 +4648,35 @@ char *TypeName(QCC_type_t *type, char *buffer, int buffersize)
Q_strlcat(buffer, "void", buffersize); Q_strlcat(buffer, "void", buffersize);
return buffer; return buffer;
} }
if (type->type == ev_enum)
{
if (buffersize < 0)
return buffer;
*buffer = 0;
Q_strlcat(buffer, "enum ", buffersize);
Q_strlcat(buffer, type->name, buffersize);
Q_strlcat(buffer, ":", buffersize);
TypeName(type->aux_type, buffer+strlen(buffer), buffersize-strlen(buffer));
return buffer;
}
if (type->type == ev_struct)
{
if (buffersize < 0)
return buffer;
*buffer = 0;
Q_strlcat(buffer, "struct ", buffersize);
Q_strlcat(buffer, type->name, buffersize);
return buffer;
}
if (type->type == ev_union)
{
if (buffersize < 0)
return buffer;
*buffer = 0;
Q_strlcat(buffer, "union ", buffersize);
Q_strlcat(buffer, type->name, buffersize);
return buffer;
}
if (type->type == ev_pointer) if (type->type == ev_pointer)
{ {
@ -4953,10 +4998,20 @@ QCC_type_t *QCC_PR_ParseFunctionType (int newtype, QCC_type_t *returntype)
if (QCC_PR_CheckToken("[")) if (QCC_PR_CheckToken("["))
{ {
QCC_PR_ParseError(0, "Array arguments are not supported\n"); if (QCC_PR_CheckToken("]")) //length omitted. just treat it as a pointer...?
{
QCC_PR_ParseError(0, "unsized array argument\n");
paramlist[numparms].type = QCC_PointerTypeTo(paramlist[numparms].type);
}
else
{ //proper array
paramlist[numparms].arraysize = QCC_PR_IntConstExpr();
if (!paramlist[numparms].arraysize)
QCC_PR_ParseError(ERR_NOTANAME, "cannot cope with 0-sized arrays");
QCC_PR_Expect("]"); QCC_PR_Expect("]");
} }
} }
}
else if (definenames) else if (definenames)
strcpy (pr_parm_names[numparms], ""); strcpy (pr_parm_names[numparms], "");
@ -5153,6 +5208,12 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
// int ofs; // int ofs;
if (QCC_PR_CheckKeyword(keyword_const, "const"))
{
QCC_PR_ParseWarning (WARN_IGNOREDKEYWORD, "ignoring unsupported const keyword");
silentfail = false; //FIXME
}
if (QCC_PR_PeekToken ("...") ) //this is getting stupid if (QCC_PR_PeekToken ("...") ) //this is getting stupid
{ {
QCC_PR_LexWhitespace (false); QCC_PR_LexWhitespace (false);
@ -5875,20 +5936,13 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
return NULL; return NULL;
} }
//FIXME: these should be moved into parsetype
if (QCC_PR_CheckKeyword(keyword_enum, "enum")) if (QCC_PR_CheckKeyword(keyword_enum, "enum"))
{ {
newt = QCC_PR_ParseEnum(false); return QCC_PR_ParseEnum(false);
if (QCC_PR_CheckToken(";"))
return NULL;
return newt;
} }
if (QCC_PR_CheckKeyword(keyword_enumflags, "enumflags")) if (QCC_PR_CheckKeyword(keyword_enumflags, "enumflags"))
{ {
newt = QCC_PR_ParseEnum(true); return QCC_PR_ParseEnum(true);
if (QCC_PR_CheckToken(";"))
return NULL;
return newt;
} }
structtype = ev_void; structtype = ev_void;
@ -6039,6 +6093,15 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
QCC_PR_ParseError(ERR_NOTANAME, "cannot cope with 0-sized arrays"); QCC_PR_ParseError(ERR_NOTANAME, "cannot cope with 0-sized arrays");
QCC_PR_Expect("]"); QCC_PR_Expect("]");
} }
while (QCC_PR_CheckToken("["))
{
int nsize=QCC_PR_IntConstExpr();
if (!nsize)
QCC_PR_ParseError(ERR_NOTANAME, "cannot cope with 0-sized arrays");
QCC_PR_Expect("]");
arraysize *= nsize;
QCC_PR_ParseWarning(WARN_IGNOREDKEYWORD, "multi-dimensional arrays are not supported. flattening to single array.");
}
if (QCC_PR_CheckToken("(")) if (QCC_PR_CheckToken("("))
type = QCC_PR_ParseFunctionType(false, type); type = QCC_PR_ParseFunctionType(false, type);
@ -6050,6 +6113,12 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
continue; continue;
} }
if (QCC_PR_CheckToken(":"))
{
QCC_PR_IntConstExpr();
QCC_PR_ParseWarning(WARN_IGNOREDKEYWORD, "bitfields are not supported");
}
if ((isnonvirt || isvirt) && type->type != ev_function) if ((isnonvirt || isvirt) && type->type != ev_function)
QCC_PR_ParseWarning(ERR_INTERNAL, "[non]virtual members must be functions", type->name); QCC_PR_ParseWarning(ERR_INTERNAL, "[non]virtual members must be functions", type->name);
@ -6175,6 +6244,78 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
type = type_function; type = type_function;
else else
{ {
//try and handle C's types, which have weird and obtuse combinations (like long long, long int, short int).
pbool isokay = false;
pbool issigned = false;
pbool isunsigned = false;
pbool islong = false;
pbool isfloat = false;
int bits = 0;
while(true)
{
if (!isunsigned && !issigned && QCC_PR_CheckKeyword(keyword_signed, "signed"))
issigned = isokay = true;
else if (!issigned && !isunsigned && QCC_PR_CheckKeyword(keyword_unsigned, "unsigned"))
isunsigned = isokay = true;
else if (!bits && QCC_PR_CheckKeyword(keyword_long, "long"))
{
if (islong)
bits = 128;
islong = isokay = true;
}
else if ((!bits || bits==16) && (QCC_PR_CheckKeyword(keyword_int, "int") || QCC_PR_CheckKeyword(keyword_integer, "integer")))
{ //long int, short int, etc are allowed
if (!bits)
bits = 32;
isokay = true;
}
else if (!bits && QCC_PR_CheckKeyword(keyword_short, "short"))
bits = 16, isokay = true;
else if (!bits && QCC_PR_CheckKeyword(keyword_char, "char"))
bits = 8, isokay = true;
else if (!bits && QCC_PR_CheckKeyword(keyword_int, "_Bool")) //c99
bits = 1, isokay = true;
else if (!bits && !islong && QCC_PR_CheckKeyword(keyword_float, "float"))
bits = 32, isfloat = isokay = true;
else if ((!bits||islong) && QCC_PR_CheckKeyword(keyword_double, "double"))
bits = islong?128:64, islong=false, isfloat = isokay = true;
else
break;
}
if (isokay)
{
if (!bits)
bits = islong?64:32; //<signed|unsigned|long> [int]
if (isfloat)
{
if (isunsigned)
QCC_PR_ParseWarning (WARN_IGNOREDKEYWORD, "ignoring unsupported unsigned keyword, type will be signed");
if (bits > 64)
type = type_double, QCC_PR_ParseWarning (WARN_IGNOREDKEYWORD, "long doubles are not supported, using double"); //permitted
else if (bits == 64)
type = type_double;
else
type = type_float;
}
else
{
if (bits > 64)
type = (isunsigned?type_uint64:type_int64), QCC_PR_ParseWarning (WARN_IGNOREDKEYWORD, "long longs are not supported, using long"); //permitted
else if (bits == 64)
type = (isunsigned?type_uint64:type_int64);
else if (bits == 16)
type = (isunsigned?type_uint:type_integer), QCC_PR_ParseWarning (WARN_IGNOREDKEYWORD, "shorts are not supported, using int"); //permitted
else if (bits == 8)
type = (isunsigned?type_uint:type_integer), QCC_PR_ParseWarning (WARN_IGNOREDKEYWORD, "chars are not supported, using int"); //permitted
else
type = (isunsigned?type_uint:type_integer);
}
goto wasctype;
}
if (silentfail) if (silentfail)
return NULL; return NULL;
@ -6183,11 +6324,16 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
} }
} }
QCC_PR_Lex (); QCC_PR_Lex ();
wasctype:
while (QCC_PR_CheckToken("*")) while (QCC_PR_CheckToken("*"))
{
if (QCC_PR_CheckKeyword(keyword_const, "const"))
QCC_PR_ParseWarning (WARN_IGNOREDKEYWORD, "ignoring unsupported const keyword");
type = QCC_PointerTypeTo(type); type = QCC_PointerTypeTo(type);
}
if (QCC_PR_CheckToken ("(")) //this is followed by parameters. Must be a function. if (flag_qcfuncs && QCC_PR_CheckToken ("(")) //this is followed by parameters. Must be a function.
{ {
type_inlinefunction = true; type_inlinefunction = true;
type = QCC_PR_ParseFunctionType(newtype, type); type = QCC_PR_ParseFunctionType(newtype, type);

View file

@ -1701,6 +1701,7 @@ private:
connect(fileopen, &QAction::triggered, [=]() connect(fileopen, &QAction::triggered, [=]()
{ {
GUIprintf("Ctrl+O hit\n"); GUIprintf("Ctrl+O hit\n");
QMessageBox::critical(nullptr, "Error", QString::asprintf("Not yet implemented"));
}); });
auto filesave = new QAction(tr("Save"), this); auto filesave = new QAction(tr("Save"), this);
fileMenu->addAction(filesave); fileMenu->addAction(filesave);

View file

@ -77,7 +77,7 @@ pbool newstylesource;
char destfile[1024]; //the file we're going to output to char destfile[1024]; //the file we're going to output to
pbool destfile_explicit; //destfile was override on the commandline, don't let qc change it. pbool destfile_explicit; //destfile was override on the commandline, don't let qc change it.
QCC_eval_t *qcc_pr_globals; QCC_eval_basic_t *qcc_pr_globals;
unsigned int numpr_globals; unsigned int numpr_globals;
char *strings; char *strings;
@ -235,6 +235,7 @@ struct {
{" F330", WARN_MUTEDEPRECATEDVARIABLE}, {" F330", WARN_MUTEDEPRECATEDVARIABLE},
{" F331", WARN_SELFNOTTHIS}, {" F331", WARN_SELFNOTTHIS},
{" F332", WARN_DIVISIONBY0}, {" F332", WARN_DIVISIONBY0},
{" F333", WARN_ARGUMENTCHECK},
{" F207", WARN_NOTREFERENCEDFIELD}, {" F207", WARN_NOTREFERENCEDFIELD},
{" F208", WARN_NOTREFERENCEDCONST}, {" F208", WARN_NOTREFERENCEDCONST},
@ -342,6 +343,12 @@ compiler_flag_t compiler_flag[] = {
{&keyword_goto, defaultkeyword, "goto", "Keyword: goto", "Disables the 'goto' keyword."}, {&keyword_goto, defaultkeyword, "goto", "Keyword: goto", "Disables the 'goto' keyword."},
{&keyword_int, typekeyword, "int", "Keyword: int", "Disables the 'int' keyword."}, {&keyword_int, typekeyword, "int", "Keyword: int", "Disables the 'int' keyword."},
{&keyword_integer, typekeyword, "integer", "Keyword: integer", "Disables the 'integer' keyword."}, {&keyword_integer, typekeyword, "integer", "Keyword: integer", "Disables the 'integer' keyword."},
{&keyword_double, defaultkeyword, "double", "Keyword: double", "Disables the 'double' keyword."},
{&keyword_long, defaultkeyword, "long", "Keyword: long", "Disables the 'long' keyword."},
{&keyword_short, defaultkeyword, "short", "Keyword: short", "Disables the 'short' keyword."},
{&keyword_char, defaultkeyword, "char", "Keyword: char", "Disables the 'char' keyword."},
{&keyword_signed, defaultkeyword, "signed", "Keyword: signed", "Disables the 'signed' keyword."},
{&keyword_unsigned, defaultkeyword, "unsigned", "Keyword: unsigned", "Disables the 'unsigned' keyword."},
{&keyword_noref, defaultkeyword, "noref", "Keyword: noref", "Disables the 'noref' keyword."}, //nowhere else references this, don't warn about it. {&keyword_noref, defaultkeyword, "noref", "Keyword: noref", "Disables the 'noref' keyword."}, //nowhere else references this, don't warn about it.
{&keyword_unused, nondefaultkeyword, "unused", "Keyword: unused", "Disables the 'unused' keyword. 'unused' means that the variable is unused, you're aware that its unused, and you'd rather not know about all the warnings this results in."}, {&keyword_unused, nondefaultkeyword, "unused", "Keyword: unused", "Disables the 'unused' keyword. 'unused' means that the variable is unused, you're aware that its unused, and you'd rather not know about all the warnings this results in."},
{&keyword_used, nondefaultkeyword, "used", "Keyword: used", "Disables the 'used' keyword. 'used' means that the variable is used even if the qcc can't see how - thus preventing it from ever being stripped."}, {&keyword_used, nondefaultkeyword, "used", "Keyword: used", "Disables the 'used' keyword. 'used' means that the variable is used even if the qcc can't see how - thus preventing it from ever being stripped."},
@ -374,7 +381,7 @@ compiler_flag_t compiler_flag[] = {
//options //options
{&flag_acc, 0, "acc", "Reacc support", "Reacc is a pascall like compiler. It was released before the Quake source was released. This flag has a few effects. It sorts all qc files in the current directory into alphabetical order to compile them. It also allows Reacc global/field distinctions, as well as allows | for linebreaks. Whilst case insensitivity and lax type checking are supported by reacc, they are seperate compiler flags in fteqcc."}, //reacc like behaviour of src files. {&flag_acc, 0, "acc", "Reacc support", "Reacc is a pascall like compiler. It was released before the Quake source was released. This flag has a few effects. It sorts all qc files in the current directory into alphabetical order to compile them. It also allows Reacc global/field distinctions, as well as allows | for linebreaks. Whilst case insensitivity and lax type checking are supported by reacc, they are seperate compiler flags in fteqcc."}, //reacc like behaviour of src files.
{&flag_qccx, FLAG_MIDCOMPILE,"qccx", "QCCX syntax", "WARNING: This syntax makes mods inherantly engine specific.\nDo NOT use unless you know what you're doing.This is provided for compatibility only\nAny entity hacks will be unsupported in FTEQW, DP, and others, resulting in engine crashes if the code in question is executed."}, {&flag_qccx, FLAG_MIDCOMPILE,"qccx", "QCCX syntax", "WARNING: This syntax makes mods inherantly engine specific.\nDo NOT use unless you know what you're doing.This is provided for compatibility only\nAny entity hacks will be unsupported in FTEQW, DP, and others, resulting in engine crashes if the code in question is executed."},
{&keywords_coexist, FLAG_ASDEFAULT, "kce", "Keywords Coexist", "If you want keywords to NOT be disabled when they a variable by the same name is defined, check here."}, {&keywords_coexist, defaultflag, "kce", "Keywords Coexist", "If you want keywords to NOT be disabled when they a variable by the same name is defined, check here."},
// {&flag_lno, defaultflag, "lno", "Write Line Numbers", "Writes line number information. This is required for any real kind of debugging. Will be ignored if filenames were stripped."}, // {&flag_lno, defaultflag, "lno", "Write Line Numbers", "Writes line number information. This is required for any real kind of debugging. Will be ignored if filenames were stripped."},
{&output_parms, 0, "parms", "Define offset parms", "if PARM0 PARM1 etc should be defined by the compiler. These are useful if you make use of the asm keyword for function calls, or you wish to create your own variable arguments. This is an easy way to break decompilers."}, //controls weather to define PARMx for the parms (note - this can screw over some decompilers) {&output_parms, 0, "parms", "Define offset parms", "if PARM0 PARM1 etc should be defined by the compiler. These are useful if you make use of the asm keyword for function calls, or you wish to create your own variable arguments. This is an easy way to break decompilers."}, //controls weather to define PARMx for the parms (note - this can screw over some decompilers)
{&autoprototype, 0, "autoproto", "Automatic Prototyping","Causes compilation to take two passes instead of one. The first pass, only the definitions are read. The second pass actually compiles your code. This means you never have to remember to prototype functions again."}, //so you no longer need to prototype functions and things in advance. {&autoprototype, 0, "autoproto", "Automatic Prototyping","Causes compilation to take two passes instead of one. The first pass, only the definitions are read. The second pass actually compiles your code. This means you never have to remember to prototype functions again."}, //so you no longer need to prototype functions and things in advance.
@ -404,6 +411,8 @@ compiler_flag_t compiler_flag[] = {
{&flag_assumevar, hideflag, "assumevar", "explicit consts", "Initialised globals will be considered non-const by default."}, {&flag_assumevar, hideflag, "assumevar", "explicit consts", "Initialised globals will be considered non-const by default."},
{&flag_dblstarexp, hideflag, "ssp", "** exponent", "Treat ** as an operator for exponents, instead of multiplying by a dereferenced pointer."}, {&flag_dblstarexp, hideflag, "ssp", "** exponent", "Treat ** as an operator for exponents, instead of multiplying by a dereferenced pointer."},
{&flag_cpriority, hideflag, "cpriority", "C Operator Priority", "QC treats !a&&b as equivelent to !(a&&b). When this is set, behaviour will be (!a)&&b as in C. Other operators are also affected in similar ways."}, {&flag_cpriority, hideflag, "cpriority", "C Operator Priority", "QC treats !a&&b as equivelent to !(a&&b). When this is set, behaviour will be (!a)&&b as in C. Other operators are also affected in similar ways."},
{&flag_assume_double, hideflag, "assumedouble", "Assume Doubles", "Floating point immediates will be treated as doubles, for C compat."},
{&flag_qcfuncs, hidedefaultflag,"qcfuncs", "Parse QC-style funcs", "Recognise void() as a function type. Required for QC compat."},
{&flag_allowuninit, hideflag, "allowuninit", "Uninitialised Locals", "Permit optimisations that may result in locals being uninitialised. This may allow for greater reductions in temps."}, {&flag_allowuninit, hideflag, "allowuninit", "Uninitialised Locals", "Permit optimisations that may result in locals being uninitialised. This may allow for greater reductions in temps."},
{&flag_nopragmafileline,FLAG_MIDCOMPILE,"nofileline", "Ignore #pragma file", "Ignores #pragma file(foo) and #pragma line(foo), so that errors and symbols reflect the actual lines, instead of the original source."}, {&flag_nopragmafileline,FLAG_MIDCOMPILE,"nofileline", "Ignore #pragma file", "Ignores #pragma file(foo) and #pragma line(foo), so that errors and symbols reflect the actual lines, instead of the original source."},
// {&flag_lno, hidedefaultflag,"lno", "Gen Debugging Info", "Writes debugging info."}, // {&flag_lno, hidedefaultflag,"lno", "Gen Debugging Info", "Writes debugging info."},
@ -711,7 +720,7 @@ static void QCC_DumpAutoCvars (const char *outputname)
if (!strncmp(n, "autocvar_", 9)) if (!strncmp(n, "autocvar_", 9))
{ {
char *desc; char *desc;
QCC_eval_t *val = &qcc_pr_globals[d->ofs]; const QCC_eval_t *val = (const QCC_eval_t*)&qcc_pr_globals[d->ofs];
QCC_def_t *def = QCC_PR_GetDef(NULL, n, NULL, false, 0, 0); QCC_def_t *def = QCC_PR_GetDef(NULL, n, NULL, false, 0, 0);
n += 9; n += 9;
@ -725,12 +734,24 @@ static void QCC_DumpAutoCvars (const char *outputname)
case ev_float: case ev_float:
snprintf(line, sizeof(line), "set %s\t%g%s%s\n", n, val->_float, desc?"\t//":"", desc?desc:""); snprintf(line, sizeof(line), "set %s\t%g%s%s\n", n, val->_float, desc?"\t//":"", desc?desc:"");
break; break;
case ev_double:
snprintf(line, sizeof(line), "set %s\t%g%s%s\n", n, val->_double, desc?"\t//":"", desc?desc:"");
break;
case ev_vector: case ev_vector:
snprintf(line, sizeof(line), "set %s\t\"%g %g %g\"%s%s\n", n, val->vector[0], val->vector[1], val->vector[2], desc?"\t//":"", desc?desc:""); snprintf(line, sizeof(line), "set %s\t\"%g %g %g\"%s%s\n", n, val->vector[0], val->vector[1], val->vector[2], desc?"\t//":"", desc?desc:"");
break; break;
case ev_integer: case ev_integer:
snprintf(line, sizeof(line), "set %s\t%"pPRIi"%s%s\n", n, val->_int, desc?"\t//":"", desc?desc:""); snprintf(line, sizeof(line), "set %s\t%"pPRIi"%s%s\n", n, val->_int, desc?"\t//":"", desc?desc:"");
break; break;
case ev_uint:
snprintf(line, sizeof(line), "set %s\t%"pPRIu"%s%s\n", n, val->_uint, desc?"\t//":"", desc?desc:"");
break;
case ev_int64:
snprintf(line, sizeof(line), "set %s\t%"pPRIi64"%s%s\n", n, val->_int64, desc?"\t//":"", desc?desc:"");
break;
case ev_uint64:
snprintf(line, sizeof(line), "set %s\t%"pPRIu64"%s%s\n", n, val->_uint64, desc?"\t//":"", desc?desc:"");
break;
case ev_string: case ev_string:
snprintf(line, sizeof(line), "set %s\t\"%s\"%s%s\n", n, strings + val->_int, desc?"\t//":"", desc?desc:""); snprintf(line, sizeof(line), "set %s\t\"%s\"%s%s\n", n, strings + val->_int, desc?"\t//":"", desc?desc:"");
break; break;
@ -2640,7 +2661,7 @@ strofs = (strofs+3)&~3;
externs->Printf("Compile finished: %s (uhexen2 format)\n", destfile); externs->Printf("Compile finished: %s (uhexen2 format)\n", destfile);
break; break;
case QCF_DARKPLACES: case QCF_DARKPLACES:
externs->Printf("Compile finished: %s (patched-dp format)\n", destfile); externs->Printf("Compile finished: %s (fte+dp format)\n", destfile);
break; break;
case QCF_QSS: case QCF_QSS:
externs->Printf("Compile finished: %s (fte+qss format)\n", destfile); externs->Printf("Compile finished: %s (fte+qss format)\n", destfile);
@ -3273,6 +3294,7 @@ static void QCC_PR_BeginCompilation (void *memory, int memsize)
type_void = QCC_PR_NewType("void", ev_void, true); type_void = QCC_PR_NewType("void", ev_void, true);
type_string = QCC_PR_NewType("string", ev_string, true); type_string = QCC_PR_NewType("string", ev_string, true);
type_float = QCC_PR_NewType("float", ev_float, true); type_float = QCC_PR_NewType("float", ev_float, true);
type_double = QCC_PR_NewType("__double", ev_double, true);
type_vector = QCC_PR_NewType("vector", ev_vector, true); type_vector = QCC_PR_NewType("vector", ev_vector, true);
type_entity = QCC_PR_NewType("entity", ev_entity, true); type_entity = QCC_PR_NewType("entity", ev_entity, true);
type_field = QCC_PR_NewType("__field", ev_field, false); type_field = QCC_PR_NewType("__field", ev_field, false);
@ -3280,6 +3302,9 @@ static void QCC_PR_BeginCompilation (void *memory, int memsize)
type_function->aux_type = type_void; type_function->aux_type = type_void;
type_pointer = QCC_PR_NewType("__pointer", ev_pointer, false); type_pointer = QCC_PR_NewType("__pointer", ev_pointer, false);
type_integer = QCC_PR_NewType("__int", ev_integer, true); type_integer = QCC_PR_NewType("__int", ev_integer, true);
type_uint = QCC_PR_NewType("__uint", ev_uint, true);
type_int64 = QCC_PR_NewType("__int64", ev_int64, true);
type_uint64 = QCC_PR_NewType("__uint64", ev_int64, true);
type_variant = QCC_PR_NewType("__variant", ev_variant, true); type_variant = QCC_PR_NewType("__variant", ev_variant, true);
type_floatfield = QCC_PR_NewType("__fieldfloat", ev_field, false); type_floatfield = QCC_PR_NewType("__fieldfloat", ev_field, false);
@ -3293,6 +3318,11 @@ static void QCC_PR_BeginCompilation (void *memory, int memsize)
type_floatfunction = QCC_PR_NewType("__floatfunction", ev_function, false); type_floatfunction = QCC_PR_NewType("__floatfunction", ev_function, false);
type_floatfunction->aux_type = type_float; type_floatfunction->aux_type = type_float;
type_bfloat = QCC_PR_NewType("__bfloat", ev_boolean, false);
type_bfloat->parentclass = type_float;
type_bint = QCC_PR_NewType("__bint", ev_boolean, false);
type_bint->parentclass = type_integer;
//type_field->aux_type = type_float; //type_field->aux_type = type_float;
// QCC_PR_NewType("_Bool", ev_boolean, true); // QCC_PR_NewType("_Bool", ev_boolean, true);
@ -3300,8 +3330,6 @@ static void QCC_PR_BeginCompilation (void *memory, int memsize)
// QCC_PR_NewType("__int", ev_integer, keyword_integer?true:false); // QCC_PR_NewType("__int", ev_integer, keyword_integer?true:false);
QCC_PR_NewType("variant", ev_variant, true); QCC_PR_NewType("variant", ev_variant, true);
QCC_PR_NewType("integer", ev_integer, keyword_integer?true:false);
QCC_PR_NewType("int", ev_integer, keyword_int?true:false);
@ -4297,7 +4325,7 @@ static void QCC_PR_CommandLinePrecompilerOptions (void)
else else
*compiler_flag[p].enabled = false; *compiler_flag[p].enabled = false;
} }
if (!stricmp(myargv[i]+5, "C")) if (!stricmp(myargv[i]+5, "C") || !stricmp(myargv[i]+5, "c89") || !stricmp(myargv[i]+5, "c90") || !stricmp(myargv[i]+5, "c99") || !stricmp(myargv[i]+5, "c11") || !stricmp(myargv[i]+5, "c17"))
{ //set up for greatest C compatibility... variations from C are bugs, not features. { //set up for greatest C compatibility... variations from C are bugs, not features.
keyword_asm = false; keyword_asm = false;
keyword_break = keyword_continue = keyword_for = keyword_goto = keyword_const = keyword_extern = keyword_static = true; keyword_break = keyword_continue = keyword_for = keyword_goto = keyword_const = keyword_extern = keyword_static = true;
@ -4315,13 +4343,32 @@ static void QCC_PR_CommandLinePrecompilerOptions (void)
flag_assumevar = true; //const only if explicitly const. flag_assumevar = true; //const only if explicitly const.
pr_subscopedlocals = true; //locals shadow other locals rather than being the same one. pr_subscopedlocals = true; //locals shadow other locals rather than being the same one.
flag_cpriority = true; //fiddle with operator precedence. flag_cpriority = true; //fiddle with operator precedence.
flag_assume_integer = true; flag_assume_integer = true; //unqualified numeric constants are assumed to be ints, consistent with C.
flag_assume_double = true; //and any immediates with a decimal points are assumed to be doubles, consistent with C.
flag_qcfuncs = false;
qccwarningaction[WARN_UNINITIALIZED] = WA_WARN; //C doesn't like that, might as well warn here too. qccwarningaction[WARN_UNINITIALIZED] = WA_WARN; //C doesn't like that, might as well warn here too.
qccwarningaction[WARN_TOOMANYPARAMS] = WA_ERROR; //too many args to function is weeeeird. qccwarningaction[WARN_TOOMANYPARAMS] = WA_ERROR; //too many args to function is weeeeird.
qccwarningaction[WARN_TOOFEWPARAMS] = WA_ERROR; //missing args should be fatal. qccwarningaction[WARN_TOOFEWPARAMS] = WA_ERROR; //missing args should be fatal.
qccwarningaction[WARN_ASSIGNMENTTOCONSTANT] = WA_ERROR; //const is const. at least its not const by default. qccwarningaction[WARN_ASSIGNMENTTOCONSTANT] = WA_ERROR; //const is const. at least its not const by default.
qccwarningaction[WARN_SAMENAMEASGLOBAL] = WA_IGNORE; //shadowing of globals. qccwarningaction[WARN_SAMENAMEASGLOBAL] = WA_IGNORE; //shadowing of globals.
if (!stricmp(myargv[i]+5, "c89") || !stricmp(myargv[i]+5, "c90"))
val = "199409L"; //it was ammended, apparently.
else if (!stricmp(myargv[i]+5, "c99"))
val = "199901L";
else if (!stricmp(myargv[i]+5, "c11"))
val = "201112L";
else if (!stricmp(myargv[i]+5, "c17"))
val = "201710L";
else
val = NULL;
cnst = QCC_PR_DefineName("__STDC_VERSION__");
if (val)
{
cnst->value = qccHunkAlloc(strlen(val)+1);
memcpy(cnst->value, val, strlen(val)+1);
}
} }
else if (!strcmp(myargv[i]+5, "qccx")) else if (!strcmp(myargv[i]+5, "qccx"))
{ {
@ -4647,6 +4694,7 @@ static void QCC_SetDefaultProperties (void)
QCC_PR_CloseProcessor(); QCC_PR_CloseProcessor();
QCC_PR_DefineName("FTEQCC"); QCC_PR_DefineName("FTEQCC");
QCC_PR_DefineName("__FTEQCC__");
if ((FWDSLASHARGS && QCC_CheckParm("/O0")) || QCC_CheckParm("-O0")) if ((FWDSLASHARGS && QCC_CheckParm("/O0")) || QCC_CheckParm("-O0"))
level = 0; level = 0;

View file

@ -5395,6 +5395,59 @@ void QCBUILTIN PF_WriteInt (pubprogfuncs_t *prinst, struct globalvars_s *pr_glob
} }
} }
void QCBUILTIN PF_WriteInt64 (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
int dest = G_FLOAT(OFS_PARM0);
pint64_t val = G_INT64(OFS_PARM1);
if (dest == MSG_CSQC)
{ //csqc buffers are always written.
MSG_WriteInt64(&csqcmsgbuffer, val);
return;
}
if (pr_nonetaccess.value)
return;
#ifdef SERVER_DEMO_PLAYBACK
if (sv.demofile)
return;
#endif
#ifdef NETPREPARSE
if (dpcompat_nopreparse.ival)
;
else if (progstype != PROG_QW)
{
NPP_NQWriteLong(dest, val&0xffffffff);
NPP_NQWriteLong(dest, (val>>32)&0xffffffff);
return;
}
#ifdef NQPROT
else
{
NPP_QWWriteLong(dest, val&0xffffffff);
NPP_QWWriteLong(dest, (val>>32)&0xffffffff);
return;
}
#endif
#endif
if (dest == MSG_ONE)
{
client_t *cl = Write_GetClient();
if (!cl)
return;
ClientReliableCheckBlock(cl, 8);
ClientReliableWrite_Int64(cl, val);
}
else
{
if (progstype != PROG_QW)
MSG_WriteInt64 (NQWriteDest(dest), val);
else
MSG_WriteInt64 (QWWriteDest(dest), val);
}
}
void QCBUILTIN PF_WriteAngle (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) void QCBUILTIN PF_WriteAngle (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{ {
int dest = G_FLOAT(OFS_PARM0); int dest = G_FLOAT(OFS_PARM0);
@ -5559,6 +5612,63 @@ void QCBUILTIN PF_WriteFloat (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl
} }
} }
void QCBUILTIN PF_WriteDouble (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
int dest = G_FLOAT(OFS_PARM0);
double val = G_DOUBLE(OFS_PARM1);
union {
double val;
quint64_t ival;
} u = {val};
if (dest == MSG_CSQC)
{ //csqc buffers are always written.
MSG_WriteDouble(&csqcmsgbuffer, val);
return;
}
if (pr_nonetaccess.value)
return;
#ifdef SERVER_DEMO_PLAYBACK
if (sv.demofile)
return;
#endif
#ifdef NETPREPARSE
if (dpcompat_nopreparse.ival)
;
else if (progstype != PROG_QW)
{
NPP_NQWriteLong(dest, u.ival&0xffffffff);
NPP_NQWriteLong(dest, (u.ival>>32)&0xffffffff);
return;
}
#ifdef NQPROT
else
{
NPP_QWWriteLong(dest, u.ival&0xffffffff);
NPP_QWWriteLong(dest, (u.ival>>32)&0xffffffff);
return;
}
#endif
#endif
if (dest == MSG_ONE)
{
client_t *cl = Write_GetClient();
if (!cl)
return;
ClientReliableCheckBlock(cl, 8);
ClientReliableWrite_Double(cl, val);
}
else
{
if (progstype != PROG_QW)
MSG_WriteDouble (NQWriteDest(dest), val);
else
MSG_WriteDouble (QWWriteDest(dest), val);
}
}
void PF_WriteString_Internal (int target, const char *str) void PF_WriteString_Internal (int target, const char *str)
{ {
if (target == MSG_CSQC) if (target == MSG_CSQC)
@ -11006,7 +11116,9 @@ static BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
{"touchtriggers", PF_touchtriggers, 0, 0, 0, 279, D("void(optional entity ent, optional vector neworigin)", "Triggers a touch events between self and every SOLID_TRIGGER entity that it is in contact with. This should typically just be the triggers touch functions. Also optionally updates the origin of the moved entity.")},// {"touchtriggers", PF_touchtriggers, 0, 0, 0, 279, D("void(optional entity ent, optional vector neworigin)", "Triggers a touch events between self and every SOLID_TRIGGER entity that it is in contact with. This should typically just be the triggers touch functions. Also optionally updates the origin of the moved entity.")},//
{"WriteFloat", PF_WriteFloat, 0, 0, 0, 280, D("void(float buf, float fl)", "Writes a full 32bit float without any data conversions at all, for full precision.")},// {"WriteFloat", PF_WriteFloat, 0, 0, 0, 280, D("void(float buf, float fl)", "Writes a full 32bit float without any data conversions at all, for full precision.")},//
{"WriteInt", PF_WriteInt, 0, 0, 0, 0, D("void(float buf, int fl)", "Equivelent to WriteLong, but doesn't truncate to a float first before converting back to an int.")},// {"WriteDouble", PF_WriteDouble, 0, 0, 0, 0, D("void(float buf, __double dbl)", "Writes a full 64bit double-precision float without any data conversions at all, for excessive precision.")},//
{"WriteInt", PF_WriteInt, 0, 0, 0, 0, D("void(float buf, int fl)", "Writes all 4 bytes of a 32bit integer without truncating to a float first before converting back to an int (unlike WriteLong does, but otherwise equivelent).")},//
{"WriteInt64", PF_WriteInt64, 0, 0, 0, 0, D("void(float buf, __int64 fl)", "Writes all 8 bytes of a 64bit integer.")},//
{"skel_ragupdate", PF_skel_ragedit, 0, 0, 0, 281, D("float(entity skelent, string dollcmd, float animskel)", "Updates the skeletal object attached to the entity according to its origin and other properties.\nif animskel is non-zero, the ragdoll will animate towards the bone state in the animskel skeletal object, otherwise they will pick up the model's base pose which may not give nice results.\nIf dollcmd is not set, the ragdoll will update (this should be done each frame).\nIf the doll is updated without having a valid doll, the model's default .doll will be instanciated.\ncommands:\n doll foo.doll : sets up the entity to use the named doll file\n dollstring TEXT : uses the doll file directly embedded within qc, with that extra prefix.\n cleardoll : uninstanciates the doll without destroying the skeletal object.\n animate 0.5 : specifies the strength of the ragdoll as a whole \n animatebody somebody 0.5 : specifies the strength of the ragdoll on a specific body (0 will disable ragdoll animations on that body).\n enablejoint somejoint 1 : enables (or disables) a joint. Disabling joints will allow the doll to shatter.")}, // (FTE_CSQC_RAGDOLL) {"skel_ragupdate", PF_skel_ragedit, 0, 0, 0, 281, D("float(entity skelent, string dollcmd, float animskel)", "Updates the skeletal object attached to the entity according to its origin and other properties.\nif animskel is non-zero, the ragdoll will animate towards the bone state in the animskel skeletal object, otherwise they will pick up the model's base pose which may not give nice results.\nIf dollcmd is not set, the ragdoll will update (this should be done each frame).\nIf the doll is updated without having a valid doll, the model's default .doll will be instanciated.\ncommands:\n doll foo.doll : sets up the entity to use the named doll file\n dollstring TEXT : uses the doll file directly embedded within qc, with that extra prefix.\n cleardoll : uninstanciates the doll without destroying the skeletal object.\n animate 0.5 : specifies the strength of the ragdoll as a whole \n animatebody somebody 0.5 : specifies the strength of the ragdoll on a specific body (0 will disable ragdoll animations on that body).\n enablejoint somejoint 1 : enables (or disables) a joint. Disabling joints will allow the doll to shatter.")}, // (FTE_CSQC_RAGDOLL)
{"skel_mmap", PF_skel_mmap, 0, 0, 0, 282, D("float*(float skel)", "Map the bones in VM memory. They can then be accessed via pointers. Each bone is 12 floats, the four vectors interleaved (sadly).")},// (FTE_QC_RAGDOLL) {"skel_mmap", PF_skel_mmap, 0, 0, 0, 282, D("float*(float skel)", "Map the bones in VM memory. They can then be accessed via pointers. Each bone is 12 floats, the four vectors interleaved (sadly).")},// (FTE_QC_RAGDOLL)
{"skel_set_bone_world",PF_skel_set_bone_world,0,0, 0, 283, D("void(entity ent, float bonenum, vector org, optional vector angorfwd, optional vector right, optional vector up)", "Sets the world position of a bone within the given entity's attached skeletal object. The world position is dependant upon the owning entity's position. If no orientation argument is specified, v_forward+v_right+v_up are used for the orientation instead. If 1 is specified, it is understood as angles. If 3 are specified, they are the forawrd/right/up vectors to use.")}, {"skel_set_bone_world",PF_skel_set_bone_world,0,0, 0, 283, D("void(entity ent, float bonenum, vector org, optional vector angorfwd, optional vector right, optional vector up)", "Sets the world position of a bone within the given entity's attached skeletal object. The world position is dependant upon the owning entity's position. If no orientation argument is specified, v_forward+v_right+v_up are used for the orientation instead. If 1 is specified, it is understood as angles. If 3 are specified, they are the forawrd/right/up vectors to use.")},
@ -11147,7 +11259,9 @@ static BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
{"readangle", PF_Fixme, 0, 0, 0, 365, D("float()", "Reads a value matching the unspecified precision written ONLY by WriteAngle.")},// (EXT_CSQC) {"readangle", PF_Fixme, 0, 0, 0, 365, D("float()", "Reads a value matching the unspecified precision written ONLY by WriteAngle.")},// (EXT_CSQC)
{"readstring", PF_Fixme, 0, 0, 0, 366, D("string()", "Reads a null-terminated string.")},// (EXT_CSQC) {"readstring", PF_Fixme, 0, 0, 0, 366, D("string()", "Reads a null-terminated string.")},// (EXT_CSQC)
{"readfloat", PF_Fixme, 0, 0, 0, 367, D("float()", "Reads a float without any truncation nor conversions. Data MUST have originally been written with WriteFloat.")},// (EXT_CSQC) {"readfloat", PF_Fixme, 0, 0, 0, 367, D("float()", "Reads a float without any truncation nor conversions. Data MUST have originally been written with WriteFloat.")},// (EXT_CSQC)
{"readdouble", PF_Fixme, 0, 0, 0, 0, D("__double()", "Reads a double-precision float without any truncation nor conversions. Data MUST have originally been written with WriteDouble.")},// (EXT_CSQC)
{"readint", PF_Fixme, 0, 0, 0, 0, D("int()", "Reads a 32bit int without any conversions to float, otherwise interchangable with readlong.")},// (EXT_CSQC) {"readint", PF_Fixme, 0, 0, 0, 0, D("int()", "Reads a 32bit int without any conversions to float, otherwise interchangable with readlong.")},// (EXT_CSQC)
{"readint64", PF_Fixme, 0, 0, 0, 0, D("__int64()", "Reads a 64bit int. Paired with WriteInt64.")},// (EXT_CSQC)
{"readentitynum", PF_Fixme, 0, 0, 0, 368, D("float()", "Reads the serverside index of an entity, paired with WriteEntity. There may be nothing else known about the entity yet, so the result typically needs to be saved as-is and re-looked up each frame. This can be done via getentity(NUM, GE_*) for non-csqc ents, or findentity(world,entnum,NUM) - both of which can fail due to latency.")},// (EXT_CSQC) {"readentitynum", PF_Fixme, 0, 0, 0, 368, D("float()", "Reads the serverside index of an entity, paired with WriteEntity. There may be nothing else known about the entity yet, so the result typically needs to be saved as-is and re-looked up each frame. This can be done via getentity(NUM, GE_*) for non-csqc ents, or findentity(world,entnum,NUM) - both of which can fail due to latency.")},// (EXT_CSQC)
// {"readserverentitystate",PF_Fixme,0, 0, 0, 369, "void(float flags, float simtime)"},// (EXT_CSQC_1) // {"readserverentitystate",PF_Fixme,0, 0, 0, 369, "void(float flags, float simtime)"},// (EXT_CSQC_1)
@ -11330,7 +11444,7 @@ static BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
{"strlennocol", PF_strlennocol, 0, 0, 0, 476, D("float(string s)", "Returns the number of characters in the string after any colour codes or other markup has been parsed.")},//DP_QC_STRINGCOLORFUNCTIONS {"strlennocol", PF_strlennocol, 0, 0, 0, 476, D("float(string s)", "Returns the number of characters in the string after any colour codes or other markup has been parsed.")},//DP_QC_STRINGCOLORFUNCTIONS
{"strdecolorize", PF_strdecolorize, 0, 0, 0, 477, D("string(string s)", "Flattens any markup/colours, removing them from the string.")},//DP_QC_STRINGCOLORFUNCTIONS {"strdecolorize", PF_strdecolorize, 0, 0, 0, 477, D("string(string s)", "Flattens any markup/colours, removing them from the string.")},//DP_QC_STRINGCOLORFUNCTIONS
{"strftime", PF_strftime, 0, 0, 0, 478, "string(float uselocaltime, string format, ...)"}, //DP_QC_STRFTIME {"strftime", PF_strftime, 0, 0, 0, 478, "string(float uselocaltime, string format, ...)"}, //DP_QC_STRFTIME
{"tokenizebyseparator",PF_tokenizebyseparator,0,0, 0, 479, "float(string s, string separator1, ...)"}, //DP_QC_TOKENIZEBYSEPARATOR {"tokenizebyseparator",PF_tokenizebyseparator,0,0, 0, 479, D("float(string s, string separator1, ...)", "Splits up the string using only the specified delimiters/separators. Multiple delimiters can be given, they are each considered equivelent (though should start with the longest if you want to do weird subseparator stuff).\nThe resulting tokens can be queried via argv (and argv_start|end_index builtins, if you want to determine which of the separators was present between two tokens).\nNote that while an input string containing JUST a separator will return 2, a string with no delimiter will return 1, while (in FTE) an empty string will ALWAYS return 0.")}, //DP_QC_TOKENIZEBYSEPARATOR
{"strtolower", PF_strtolower, 0, 0, 0, 480, "string(string s)"}, //DP_QC_STRING_CASE_FUNCTIONS {"strtolower", PF_strtolower, 0, 0, 0, 480, "string(string s)"}, //DP_QC_STRING_CASE_FUNCTIONS
{"strtoupper", PF_strtoupper, 0, 0, 0, 481, "string(string s)"}, //DP_QC_STRING_CASE_FUNCTIONS {"strtoupper", PF_strtoupper, 0, 0, 0, 481, "string(string s)"}, //DP_QC_STRING_CASE_FUNCTIONS
{"cvar_defstring", PF_cvar_defstring, 0, 0, 0, 482, "string(string s)"}, //DP_QC_CVAR_DEFSTRING {"cvar_defstring", PF_cvar_defstring, 0, 0, 0, 482, "string(string s)"}, //DP_QC_CVAR_DEFSTRING
@ -12954,7 +13068,7 @@ void PR_DumpPlatform_f(void)
{"PFLAGS_FULLDYNAMIC", "const float", QW|NQ, D("When set in self.pflags, enables fully-customised dynamic lights. Custom rtlight information is not otherwise used."), PFLAGS_FULLDYNAMIC}, {"PFLAGS_FULLDYNAMIC", "const float", QW|NQ, D("When set in self.pflags, enables fully-customised dynamic lights. Custom rtlight information is not otherwise used."), PFLAGS_FULLDYNAMIC},
//including these for csqc stat types, hash tables, etc. //including these for csqc stat types, hash tables, etc.
// {"EV_VOID", "const float", QW|NQ|CS, NULL, ev_void}, // {"EV_VOID", "const float", ALL, NULL, ev_void},
{"EV_STRING", "const float", ALL, NULL, ev_string}, {"EV_STRING", "const float", ALL, NULL, ev_string},
{"EV_FLOAT", "const float", ALL, NULL, ev_float}, {"EV_FLOAT", "const float", ALL, NULL, ev_float},
{"EV_VECTOR", "const float", ALL, NULL, ev_vector}, {"EV_VECTOR", "const float", ALL, NULL, ev_vector},
@ -12963,9 +13077,10 @@ void PR_DumpPlatform_f(void)
{"EV_FUNCTION", "const float", ALL, NULL, ev_function}, {"EV_FUNCTION", "const float", ALL, NULL, ev_function},
{"EV_POINTER", "const float", ALL, NULL, ev_pointer}, {"EV_POINTER", "const float", ALL, NULL, ev_pointer},
{"EV_INTEGER", "const float", ALL, NULL, ev_integer}, {"EV_INTEGER", "const float", ALL, NULL, ev_integer},
{"EV_VARIANT", "const float", ALL, NULL, ev_variant}, {"EV_UINT", "const float", ALL, NULL, ev_uint},
// {"EV_STRUCT", "const float", QW|NQ|CS, NULL, ev_struct}, {"EV_INT64", "const float", ALL, NULL, ev_int64},
// {"EV_UNION", "const float", QW|NQ|CS, NULL, ev_union}, {"EV_UINT64", "const float", ALL, NULL, ev_uint64},
{"EV_DOUBLE", "const float", ALL, NULL, ev_double},
{"gamestate", "hashtable", ALL, D("Special hash table index for hash_add and hash_get. Entries in this table will persist over map changes (and doesn't need to be created/deleted)."), 0}, {"gamestate", "hashtable", ALL, D("Special hash table index for hash_add and hash_get. Entries in this table will persist over map changes (and doesn't need to be created/deleted)."), 0},
{"HASH_REPLACE", "const float", ALL, D("Used with hash_add. Attempts to remove the old value instead of adding two values for a single key."), 256}, {"HASH_REPLACE", "const float", ALL, D("Used with hash_add. Attempts to remove the old value instead of adding two values for a single key."), 256},

View file

@ -1432,7 +1432,9 @@ void ClientReliableWrite_Angle16(client_t *cl, float f);
void ClientReliableWrite_Byte(client_t *cl, int c); void ClientReliableWrite_Byte(client_t *cl, int c);
void ClientReliableWrite_Char(client_t *cl, int c); void ClientReliableWrite_Char(client_t *cl, int c);
void ClientReliableWrite_Float(client_t *cl, float f); void ClientReliableWrite_Float(client_t *cl, float f);
void ClientReliableWrite_Double(client_t *cl, double f);
void ClientReliableWrite_Coord(client_t *cl, float f); void ClientReliableWrite_Coord(client_t *cl, float f);
void ClientReliableWrite_Int64(client_t *cl, qint64_t c);
void ClientReliableWrite_Long(client_t *cl, int c); void ClientReliableWrite_Long(client_t *cl, int c);
void ClientReliableWrite_Short(client_t *cl, int c); void ClientReliableWrite_Short(client_t *cl, int c);
void ClientReliableWrite_Entity(client_t *cl, int c); void ClientReliableWrite_Entity(client_t *cl, int c);

View file

@ -37,7 +37,7 @@ qboolean SV_MayCheat(void)
} }
#ifdef SUBSERVERS #ifdef SUBSERVERS
cvar_t sv_autooffload = CVARD("sv_autooffload", "0", "Automatically start the server in a separate process, so that sporadic or persistent gamecode slowdowns do not affect visual framerates. Note: Offloaded servers have separate cvar states which may complicate usage."); cvar_t sv_autooffload = CVARD("sv_autooffload", "0", "Automatically start the server in a separate process, so that sporadic or persistent gamecode slowdowns do not affect visual framerates (equivelent to the mapcluster command). Note: Offloaded servers have separate cvar+command states which may complicate usage.");
#endif #endif
extern cvar_t cl_warncmd; extern cvar_t cl_warncmd;
cvar_t sv_cheats = CVARF("sv_cheats", "0", CVAR_LATCH); cvar_t sv_cheats = CVARF("sv_cheats", "0", CVAR_LATCH);

View file

@ -187,6 +187,17 @@ void ClientReliableWrite_Char(client_t *cl, int c)
MSG_WriteChar(&cl->netchan.message, c); MSG_WriteChar(&cl->netchan.message, c);
} }
void ClientReliableWrite_Double(client_t *cl, double f)
{
if (cl->num_backbuf)
{
MSG_WriteDouble(&cl->backbuf, f);
ClientReliable_FinishWrite(cl);
}
else
MSG_WriteDouble(&cl->netchan.message, f);
}
void ClientReliableWrite_Float(client_t *cl, float f) void ClientReliableWrite_Float(client_t *cl, float f)
{ {
if (cl->num_backbuf) if (cl->num_backbuf)
@ -209,6 +220,16 @@ void ClientReliableWrite_Coord(client_t *cl, float f)
MSG_WriteCoord(&cl->netchan.message, f); MSG_WriteCoord(&cl->netchan.message, f);
} }
void ClientReliableWrite_Int64(client_t *cl, qint64_t c)
{
if (cl->num_backbuf)
{
MSG_WriteInt64(&cl->backbuf, c);
ClientReliable_FinishWrite(cl);
}
else
MSG_WriteInt64(&cl->netchan.message, c);
}
void ClientReliableWrite_Long(client_t *cl, int c) void ClientReliableWrite_Long(client_t *cl, int c)
{ {
if (cl->num_backbuf) if (cl->num_backbuf)

View file

@ -7785,6 +7785,10 @@ void SV_ReadQCRequest(void)
args[i] = 'f'; args[i] = 'f';
G_FLOAT(OFS_PARM0+i*3) = MSG_ReadFloat(); G_FLOAT(OFS_PARM0+i*3) = MSG_ReadFloat();
break; break;
case ev_double:
args[i] = 'F';
G_FLOAT(OFS_PARM0+i*3) = MSG_ReadDouble();
break;
case ev_vector: case ev_vector:
args[i] = 'v'; args[i] = 'v';
G_FLOAT(OFS_PARM0+i*3+0) = MSG_ReadFloat(); G_FLOAT(OFS_PARM0+i*3+0) = MSG_ReadFloat();
@ -7795,6 +7799,18 @@ void SV_ReadQCRequest(void)
args[i] = 'i'; args[i] = 'i';
G_INT(OFS_PARM0+i*3) = MSG_ReadLong(); G_INT(OFS_PARM0+i*3) = MSG_ReadLong();
break; break;
case ev_uint:
args[i] = 'u';
G_UINT(OFS_PARM0+i*3) = MSG_ReadLong();
break;
case ev_int64:
args[i] = 'I';
G_INT64(OFS_PARM0+i*3) = MSG_ReadInt64();
break;
case ev_uint64:
args[i] = 'U';
G_UINT64(OFS_PARM0+i*3) = MSG_ReadInt64();
break;
case ev_string: case ev_string:
args[i] = 's'; args[i] = 's';
G_INT(OFS_PARM0+i*3) = PR_TempString(svprogfuncs, MSG_ReadString()); G_INT(OFS_PARM0+i*3) = PR_TempString(svprogfuncs, MSG_ReadString());