Fix some omissions with splitscreen+csqc:

unicast svc_cgamepackets will now report which seat they were unicast to.
sendevent will now reveal the seat that was active at the time of the call.
csqc console commands will now reveal any p2 etc commands that were used.
added 144hz refresh rate option to the built-in menu
added sv_demo_write_csqc cvar to write csprogs.dat into mvds. I still need to read them...
make irc client not create new accounts if there's already a connection registered for the given server.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5169 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2017-11-16 22:20:40 +00:00
parent 27e8e812a2
commit 0dbb57dd5c
20 changed files with 255 additions and 82 deletions

View File

@ -7073,7 +7073,7 @@ void CLQW_ParseServerMessage (void)
break;
#endif
#ifdef CSQC_DAT
if (CSQC_ParseGamePacket())
if (CSQC_ParseGamePacket(destsplit))
break;
#endif
Con_Printf("Unable to parse gamecode packet\n");
@ -7721,7 +7721,7 @@ void CLNQ_ParseServerMessage (void)
break;
#endif
#ifdef CSQC_DAT
if (CSQC_ParseGamePacket())
if (CSQC_ParseGamePacket(destsplit))
break;
#endif
Con_Printf("Unable to parse gamecode packet\n");

View File

@ -1384,14 +1384,14 @@ qboolean CSQC_StuffCmd(int lplayernum, char *cmd, char *cmdend);
void CSQC_MapEntityEdited(int modelindex, int idx, const char *newe);
qboolean CSQC_LoadResource(char *resname, char *restype);
qboolean CSQC_ParsePrint(char *message, int printlevel);
qboolean CSQC_ParseGamePacket(void);
qboolean CSQC_ParseGamePacket(int seat);
qboolean CSQC_CenterPrint(int seat, const char *cmd);
qboolean CSQC_Parse_Damage(int seat, float save, float take, vec3_t source);
qboolean CSQC_Parse_SetAngles(int seat, vec3_t newangles, qboolean wasdelta);
void CSQC_Input_Frame(int seat, usercmd_t *cmd);
void CSQC_WorldLoaded(void);
qboolean CSQC_ParseTempEntity(void);
qboolean CSQC_ConsoleCommand(const char *cmd);
qboolean CSQC_ConsoleCommand(int seat, const char *cmd);
qboolean CSQC_KeyPress(int key, int unicode, qboolean down, unsigned int devid);
qboolean CSQC_MouseMove(float xdelta, float ydelta, unsigned int devid);
qboolean CSQC_MousePosition(float xabs, float yabs, unsigned int devid);

View File

@ -557,7 +557,7 @@ void Con_ToggleConsole_f (void)
}
#ifdef CSQC_DAT
if (!(key_dest_mask & kdm_editor) && CSQC_ConsoleCommand("toggleconsole"))
if (!(key_dest_mask & kdm_editor) && CSQC_ConsoleCommand(-1, "toggleconsole"))
{
Key_Dest_Remove(kdm_console);
return;

View File

@ -1944,7 +1944,7 @@ void M_Menu_Main_f (void)
static menuresel_t resel;
#ifdef CSQC_DAT
if (CSQC_ConsoleCommand(va("%s %s", Cmd_Argv(0), Cmd_Args())))
if (CSQC_ConsoleCommand(-1, va("%s %s", Cmd_Argv(0), Cmd_Args())))
return;
#endif

View File

@ -2624,9 +2624,10 @@ void M_Menu_Video_f (void)
"85Hz",
"100Hz",
"120Hz",
"144Hz",
NULL
};
static const char *refreshvalues[] = {"", "59", "60", "70", "72", "75", "85", "100", "120", NULL};
static const char *refreshvalues[] = {"", "59", "60", "70", "72", "75", "85", "100", "120", "144", NULL};
static const char *res2dmodeopts[] = {
ASPECT_LIST

View File

@ -331,7 +331,7 @@ void M_ToggleMenu_f (void)
}
#ifdef CSQC_DAT
if (CSQC_ConsoleCommand("togglemenu"))
if (CSQC_ConsoleCommand(-1, "togglemenu"))
{
Key_Dest_Remove(kdm_console|kdm_cwindows);
return;

View File

@ -1012,6 +1012,22 @@ static void QCBUILTIN PF_R_AddEntity(pubprogfuncs_t *prinst, struct globalvars_s
V_AddAxisEntity(&ent);
}
}
static void QCBUILTIN PF_R_RemoveEntity(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
csqcedict_t *in = (void*)G_EDICT(prinst, OFS_PARM0);
entity_t ent;
if (ED_ISFREE(in) || in->entnum == 0)
{
csqc_deprecated("Tried drawing a free/removed/world entity\n");
return;
}
if (CopyCSQCEdictToEntity(in, &ent))
{
CLQ1_AddShadow(&ent);
V_AddAxisEntity(&ent);
}
}
void CL_AddDecal(shader_t *shader, vec3_t origin, vec3_t up, vec3_t side, vec3_t rgbvalue, float alphavalue);
static void QCBUILTIN PF_R_AddDecal(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
@ -3097,6 +3113,7 @@ static void QCBUILTIN PF_cs_sendevent (pubprogfuncs_t *prinst, struct globalvars
return;
MSG_WriteByte(&cls.netchan.message, clcfte_qcrequest);
for (i = 0; i < 6; i++)
{
if (argtypes[i] == 's')
@ -3130,6 +3147,8 @@ static void QCBUILTIN PF_cs_sendevent (pubprogfuncs_t *prinst, struct globalvars
else
break;
}
if (csqc_playerseat > 0)
MSG_WriteByte(&cls.netchan.message, 200+csqc_playerseat);
MSG_WriteByte(&cls.netchan.message, 0);
MSG_WriteString(&cls.netchan.message, eventname);
}
@ -3239,24 +3258,17 @@ static void QCBUILTIN PF_cs_getinputstate (pubprogfuncs_t *prinst, struct global
/*outgoing_sequence says how many packets have actually been sent, but there's an extra pending packet which has not been sent yet - be warned though, its data will change in the coming frames*/
if (f == cl.movesequence)
{
// int i;
// usercmd_t tmp;
int i;
usercmd_t tmp;
cmd = &cl_pendingcmd[seat];
/*
tmp = *cmd;
cmd = &tmp;
for (i=0 ; i<3 ; i++)
cmd->angles[i] = ((int)(csqc_playerview->viewangles[i]*65536.0/360)&65535);
if (!cmd->msec)
{
// *cmd = cl.outframes[(f-1)&UPDATE_MASK].cmd[seat];
CL_BaseMove (cmd, seat, cmd->msec, newtime);
}
// if (cl.predservertimes)
// cmd->msec = (cl.time - cl.outframes[(f-1)&UPDATE_MASK].cmd[seat].fservertime)*1000;
// else
cmd->msec = (realtime - cl.outframes[(f-1)&UPDATE_MASK].senttime)*1000;
*/
*cmd = cl.outframes[(f-1)&UPDATE_MASK].cmd[seat];
cmd->msec = (realtime - cl.outframes[(f-1)&UPDATE_MASK].senttime)*1000;
}
else
{
@ -3337,6 +3349,7 @@ static void QCBUILTIN PF_cs_runplayerphysics (pubprogfuncs_t *prinst, struct glo
}
pmove.jump_held = (int)ent->xv->pmove_flags & PMF_JUMP_HELD;
pmove.waterjumptime = 0;
pmove.onground = (int)ent->v->flags & FL_ONGROUND;
VectorCopy(ent->v->origin, pmove.origin);
VectorCopy(ent->v->velocity, pmove.velocity);
VectorCopy(ent->v->maxs, pmove.player_maxs);
@ -3357,6 +3370,10 @@ static void QCBUILTIN PF_cs_runplayerphysics (pubprogfuncs_t *prinst, struct glo
ent->v->angles[0] *= r_meshpitch.value * 1/3.0f; //FIXME
VectorCopy(pmove.origin, ent->v->origin);
VectorCopy(pmove.velocity, ent->v->velocity);
if (pmove.onground)
ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
else
ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
ent->xv->pmove_flags = 0;
ent->xv->pmove_flags += pmove.jump_held ? PMF_JUMP_HELD : 0;
ent->xv->pmove_flags += pmove.onladder ? PMF_LADDER : 0;
@ -4633,8 +4650,9 @@ static void QCBUILTIN PF_cs_movetogoal (pubprogfuncs_t *prinst, struct globalvar
static void CS_ConsoleCommand_f(void)
{
char cmd[2048];
int seat = CL_TargettedSplit(false);
Q_snprintfz(cmd, sizeof(cmd), "%s %s", Cmd_Argv(0), Cmd_Args());
CSQC_ConsoleCommand(cmd);
CSQC_ConsoleCommand(seat, cmd);
}
static void QCBUILTIN PF_cs_registercommand (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
@ -6033,7 +6051,8 @@ static struct {
//300
{"clearscene", PF_R_ClearScene, 300}, // #300 void() clearscene (EXT_CSQC)
{"addentities", PF_R_AddEntityMask, 301}, // #301 void(float mask) addentities (EXT_CSQC)
{"addentity", PF_R_AddEntity, 302}, // #302 void(entity ent) addentity (EXT_CSQC)
{"addentity", PF_R_AddEntity, 302}, // #302 void(entity ent) addentity (EXT_CSQC)
// {"removeentity", PF_R_RemoveEntity, 0},
{"setproperty", PF_R_SetViewFlag, 303}, // #303 float(float property, ...) setproperty (EXT_CSQC)
{"renderscene", PF_R_RenderScene, 304}, // #304 void() renderscene (EXT_CSQC)
@ -7856,7 +7875,7 @@ qboolean CSQC_ConsoleLink(char *text, char *info)
return G_FLOAT(OFS_RETURN);
}
qboolean CSQC_ConsoleCommand(const char *cmd)
qboolean CSQC_ConsoleCommand(int seat, const char *cmd)
{
void *pr_globals;
if (!csqcprogs || !csqcg.console_command)
@ -7866,6 +7885,10 @@ qboolean CSQC_ConsoleCommand(const char *cmd)
return false;
#endif
if (seat < 0)
seat = CL_TargettedSplit(false);
CSQC_ChangeLocalPlayer(seat);
pr_globals = PR_globals(csqcprogs, PR_CURRENT);
(((string_t *)pr_globals)[OFS_PARM0] = PR_TempString(csqcprogs, cmd));
@ -7904,7 +7927,7 @@ qboolean CSQC_ParseTempEntity(void)
return false;
}
qboolean CSQC_ParseGamePacket(void)
qboolean CSQC_ParseGamePacket(int seat)
{
int parsefnc = csqcg.parse_event?csqcg.parse_event:csqcg.parse_tempentity;
@ -7920,6 +7943,7 @@ qboolean CSQC_ParseGamePacket(void)
}
csqc_mayread = true;
CSQC_ChangeLocalPlayer(seat);
PR_ExecuteProgram (csqcprogs, parsefnc);
if (msg_readcount != start + len)
@ -7936,6 +7960,7 @@ qboolean CSQC_ParseGamePacket(void)
return false;
}
csqc_mayread = true;
CSQC_ChangeLocalPlayer(seat);
PR_ExecuteProgram (csqcprogs, parsefnc);
}
csqc_mayread = false;

View File

@ -720,7 +720,7 @@ void Sbar_ShowTeamScores (void)
return;
#ifdef CSQC_DAT
if (CSQC_ConsoleCommand(Cmd_Argv(0)))
if (CSQC_ConsoleCommand(seat, Cmd_Argv(0)))
return;
#endif
@ -742,7 +742,7 @@ void Sbar_DontShowTeamScores (void)
sb_updates = 0;
#ifdef CSQC_DAT
if (CSQC_ConsoleCommand(Cmd_Argv(0)))
if (CSQC_ConsoleCommand(seat, Cmd_Argv(0)))
return;
#endif
}
@ -767,7 +767,7 @@ void Sbar_ShowScores (void)
return;
#ifdef CSQC_DAT
if (CSQC_ConsoleCommand(Cmd_Argv(0)))
if (CSQC_ConsoleCommand(seat, Cmd_Argv(0)))
return;
#endif
@ -778,8 +778,9 @@ void Sbar_ShowScores (void)
#ifdef HEXEN2
static void Sbar_Hexen2InvLeft_f(void)
{
int seat = CL_TargettedSplit(false);
#ifdef CSQC_DAT
if (CSQC_ConsoleCommand(Cmd_Argv(0)))
if (CSQC_ConsoleCommand(seat, Cmd_Argv(0)))
return;
#endif
if (cls.protocol == CP_QUAKE2)
@ -789,8 +790,7 @@ static void Sbar_Hexen2InvLeft_f(void)
else
{
int tries = 15;
int pnum = CL_TargettedSplit(false);
playerview_t *pv = &cl.playerview[pnum];
playerview_t *pv = &cl.playerview[seat];
pv->sb_hexen2_item_time = realtime;
while (tries-- > 0)
{
@ -805,8 +805,9 @@ static void Sbar_Hexen2InvLeft_f(void)
}
static void Sbar_Hexen2InvRight_f(void)
{
int seat = CL_TargettedSplit(false);
#ifdef CSQC_DAT
if (CSQC_ConsoleCommand(Cmd_Argv(0)))
if (CSQC_ConsoleCommand(seat, Cmd_Argv(0)))
return;
#endif
if (cls.protocol == CP_QUAKE2)
@ -816,8 +817,7 @@ static void Sbar_Hexen2InvRight_f(void)
else
{
int tries = 15;
int pnum = CL_TargettedSplit(false);
playerview_t *pv = &cl.playerview[pnum];
playerview_t *pv = &cl.playerview[seat];
pv->sb_hexen2_item_time = realtime;
while (tries-- > 0)
{
@ -832,8 +832,9 @@ static void Sbar_Hexen2InvRight_f(void)
}
static void Sbar_Hexen2InvUse_f(void)
{
int seat = CL_TargettedSplit(false);
#ifdef CSQC_DAT
if (CSQC_ConsoleCommand(Cmd_Argv(0)))
if (CSQC_ConsoleCommand(seat, Cmd_Argv(0)))
return;
#endif
@ -843,43 +844,46 @@ static void Sbar_Hexen2InvUse_f(void)
}
else
{
int pnum = CL_TargettedSplit(false);
playerview_t *pv = &cl.playerview[pnum];
playerview_t *pv = &cl.playerview[seat];
Cmd_ExecuteString(va("impulse %d\n", 100+pv->sb_hexen2_cur_item), Cmd_ExecLevel);
}
}
static void Sbar_Hexen2ShowInfo_f(void)
{
playerview_t *pv = &cl.playerview[CL_TargettedSplit(false)];
int seat = CL_TargettedSplit(false);
playerview_t *pv = &cl.playerview[seat];
#ifdef CSQC_DAT
if (CSQC_ConsoleCommand(Cmd_Argv(0)))
if (CSQC_ConsoleCommand(seat, Cmd_Argv(0)))
return;
#endif
pv->sb_hexen2_extra_info = true;
}
static void Sbar_Hexen2DontShowInfo_f(void)
{
playerview_t *pv = &cl.playerview[CL_TargettedSplit(false)];
int seat = CL_TargettedSplit(false);
playerview_t *pv = &cl.playerview[seat];
#ifdef CSQC_DAT
if (CSQC_ConsoleCommand(Cmd_Argv(0)))
if (CSQC_ConsoleCommand(seat, Cmd_Argv(0)))
return;
#endif
pv->sb_hexen2_extra_info = false;
}
static void Sbar_Hexen2PInfoPlaque_f(void)
{
playerview_t *pv = &cl.playerview[CL_TargettedSplit(false)];
int seat = CL_TargettedSplit(false);
playerview_t *pv = &cl.playerview[seat];
#ifdef CSQC_DAT
if (CSQC_ConsoleCommand(Cmd_Argv(0)))
if (CSQC_ConsoleCommand(seat, Cmd_Argv(0)))
return;
#endif
pv->sb_hexen2_infoplaque = true;
}
static void Sbar_Hexen2MInfoPlaque_f(void)
{
playerview_t *pv = &cl.playerview[CL_TargettedSplit(false)];
int seat = CL_TargettedSplit(false);
playerview_t *pv = &cl.playerview[seat];
#ifdef CSQC_DAT
if (CSQC_ConsoleCommand(Cmd_Argv(0)))
if (CSQC_ConsoleCommand(seat, Cmd_Argv(0)))
return;
#endif
pv->sb_hexen2_infoplaque = false;
@ -906,7 +910,7 @@ void Sbar_DontShowScores (void)
sb_updates = 0;
#ifdef CSQC_DAT
if (CSQC_ConsoleCommand(Cmd_Argv(0)))
if (CSQC_ConsoleCommand(seat, Cmd_Argv(0)))
return;
#endif
}

View File

@ -2518,7 +2518,7 @@ void Cmd_ExecuteString (const char *text, int level)
if (Cmd_AliasExist(cmd_argv[0], level))
break; //server stuffed an alias for a command that it would already have received. use that instead.
#if defined(CSQC_DAT) && !defined(SERVERONLY)
if (CSQC_ConsoleCommand(text))
if (CSQC_ConsoleCommand(-1, text))
return; //let the csqc handle it if it wants.
#endif
#if defined(MENU_DAT) && !defined(SERVERONLY)
@ -2679,7 +2679,7 @@ void Cmd_ExecuteString (const char *text, int level)
}
#if defined(CSQC_DAT) && !defined(SERVERONLY)
if (CSQC_ConsoleCommand(text))
if (CSQC_ConsoleCommand(-1, text))
return;
#endif
#if defined(MENU_DAT) && !defined(SERVERONLY)

View File

@ -2868,7 +2868,6 @@ void Mod_LoadAliasShaders(model_t *mod)
}
for (i = 0; i < numskins; i++)
{
shader_t *result = NULL;
skinid_t skinid;
skinfile_t *skinfile;
char *filedata;

View File

@ -1001,6 +1001,7 @@ void QCC_PR_EmitArrayGetFunction(QCC_def_t *defscope, QCC_def_t *thearray, char
void QCC_PR_EmitArraySetFunction(QCC_def_t *defscope, QCC_def_t *thearray, char *arrayname);
void QCC_PR_EmitClassFromFunction(QCC_def_t *defscope, QCC_type_t *basetype);
void QCC_PR_ParseDefs (char *classname, pbool fatal);
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_FinaliseFunctions(void);

View File

@ -269,8 +269,6 @@ unsigned int locals_marshalled; // largest local block size that needs to be a
jmp_buf pr_parse_abort; // longjump with this on parse error
void QCC_PR_ParseDefs (char *classname, pbool fatal);
pbool qcc_usefulstatement;
pbool debug_armour_defined;

View File

@ -5282,8 +5282,6 @@ void QCC_FinishCompile(void)
extern char *pr_file_p;
extern int pr_source_line;
void QCC_PR_ParseDefs (char *classname);
@ -5386,7 +5384,7 @@ void new_QCC_ContinueCompile(void)
pr_scope = NULL; // outside all functions
QCC_PR_ParseDefs (NULL);
QCC_PR_ParseDefs (NULL, false);
}
/*void new_QCC_ContinueCompile(void)

View File

@ -10387,6 +10387,7 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
{"clearscene", PF_Fixme, 0, 0, 0, 300, D("void()", "Forgets all rentities, polygons, and temporary dlights. Resets all view properties to their default values.")},// (EXT_CSQC)
{"addentities", PF_Fixme, 0, 0, 0, 301, D("void(float mask)", "Walks through all entities effectively doing this:\n if (ent.drawmask&mask){ if (!ent.predaw()) addentity(ent); }\nIf mask&MASK_DELTA, non-csqc entities, particles, and related effects will also be added to the rentity list.\n If mask&MASK_STDVIEWMODEL then the default view model will also be added.")},// (EXT_CSQC)
{"addentity", PF_Fixme, 0, 0, 0, 302, D("void(entity ent)", "Copies the entity fields into a new rentity for later rendering via addscene.")},// (EXT_CSQC)
{"removeentity", PF_Fixme, 0, 0, 0, 0, D("void(entity ent)", "Undoes all addentities with that entity, without removing ALL entities (useful for splitscreen).")},// (EXT_CSQC)
{"addtrisoup_simple",PF_Fixme, 0, 0, 0, 0, D("typedef float vec2[2];\ntypedef float vec3[3];\ntypedef float vec4[4];\ntypedef struct trisoup_simple_vert_s {vec3 xyz;vec2 st;vec4 rgba;} trisoup_simple_vert_t;\nvoid(string texturename, int flags, struct trisoup_simple_vert_s *verts, int *indexes, int numindexes)", "Adds the specified trisoup into the scene as additional geometry. This permits caching geometry to reduce builtin spam. Indexes are a triangle list (so eg quads will need 6 indicies to form two triangles). NOTE: this is not going to be a speedup over polygons if you're still generating lots of new data every frame.")},
{"setproperty", PF_Fixme, 0, 0, 0, 303, D("#define setviewprop setproperty\nfloat(float property, ...)", "Allows you to override default view properties like viewport, fov, and whether the engine hud will be drawn. Different VF_ values have slightly different arguments, some are vectors, some floats.")},// (EXT_CSQC)
{"renderscene", PF_Fixme, 0, 0, 0, 304, D("void()", "Draws all entities, polygons, and particles on the rentity list (which were added via addentities or addentity), using the various view properties set via setproperty. There is no ordering dependancy.\nThe scene must generally be cleared again before more entities are added, as entities will persist even over to the next frame.\nYou may call this builtin multiple times per frame, but should only be called from CSQC_UpdateView.")},// (EXT_CSQC)

View File

@ -403,10 +403,11 @@ enum
PRESPAWN_INVALID=0,
PRESPAWN_PROTOCOLSWITCH, //nq drops unreliables until reliables are acked. this gives us a chance to drop any clc_move packets with formats from the previous map
PRESPAWN_SERVERINFO,
PRESPAWN_SOUNDLIST, //nq skips these
PRESPAWN_VWEPMODELLIST, //qw ugly extension.
PRESPAWN_CSPROGS, //demos contain a copy of the csprogs.
PRESPAWN_SOUNDLIST, //nq skips these
PRESPAWN_VWEPMODELLIST, //qw ugly extension.
PRESPAWN_MODELLIST,
PRESPAWN_MAPCHECK, //wait for old prespawn command
PRESPAWN_MAPCHECK, //wait for old prespawn command
PRESPAWN_PARTICLES,
PRESPAWN_CUSTOMTENTS,
PRESPAWN_SIGNON_BUF,

View File

@ -3567,7 +3567,7 @@ qboolean SVC_ThrottleInfo (void)
{
#define THROTTLE_PPS 20
static unsigned int blockuntil;
unsigned int curtime, i, inc = 1000/THROTTLE_PPS;
unsigned int curtime, inc = 1000/THROTTLE_PPS;
if (Net_AddressIsMaster(&net_from))
return true; //allow it without contributing to any throttling.

View File

@ -43,6 +43,7 @@ cvar_t sv_demoMaxSize = CVARD("sv_demoMaxSize", "", "Demos will be truncated to
cvar_t sv_demoExtraNames = CVAR("sv_demoExtraNames", "");
cvar_t sv_demoExtensions = CVARD("sv_demoExtensions", "", "Enables protocol extensions within MVDs. This will cause older/non-fte clients to error upon playback.\n0: off.\n1: all extensions.\n2: extensions also supported by a certain other engine.");
cvar_t sv_demoAutoCompress = CVARD("sv_demoAutoCompress", "", "Specifies whether to compress demos as they're recorded.\n0 = no compression.\n1 = gzip compression.");
cvar_t sv_demo_write_csqc = CVARD("sv_demo_write_csqc", "", "Writes a copy of the csprogs into recorded demos. This ensures that the demo can be played back despite future gamecode changes.");
cvar_t qtv_password = CVAR( "qtv_password", "");
cvar_t qtv_maxstreams = CVARAFD( "qtv_maxstreams", "0",
@ -1181,6 +1182,7 @@ void MVD_Init (void)
Cvar_Register (&sv_demoExtraNames, MVDVARGROUP);
Cvar_Register (&sv_demoExtensions, MVDVARGROUP);
Cvar_Register (&sv_demoAutoCompress,MVDVARGROUP);
Cvar_Register (&sv_demo_write_csqc,MVDVARGROUP);
}
static char *SV_PrintTeams(void)
@ -1646,7 +1648,7 @@ void SV_MVD_SendInitialGamestate(mvddest_t *dest)
demo.resetdeltas = true;
host_client = &demo.recorder;
if (host_client->fteprotocolextensions & PEXT_CSQC)
if (demo.recorder.fteprotocolextensions & PEXT_CSQC)
SV_EnableClientsCSQC();
@ -1670,6 +1672,19 @@ void SV_MVD_SendInitialGamestate(mvddest_t *dest)
if (!gamedir[0])
gamedir = FS_GetGamedir(true);
//generate some meta info so the file can be identified later
{
char timestr[64];
time_t t;
MSG_WriteByte (&buf, svc_stufftext);
MSG_WriteString(&buf, va("//protocolname %s\n", com_protocolname.string)); //so that the game is known when playing back, to deal with games that conventionally have entirely separate installations.
MSG_WriteByte (&buf, svc_stufftext);
t = time(NULL);
strftime(timestr, sizeof(timestr), "%Y-%m-%dT%H:%M:%SZ", gmtime(&t));
MSG_WriteString(&buf, va("//recorddate %s\n", timestr)); //in order to avoid needing to depend upon file times that get destroyed in many different ways.
}
MSG_WriteByte (&buf, svc_serverdata);
//fix up extensions to match sv_bigcoords correctly. sorry for old clients not working.

View File

@ -705,6 +705,10 @@ void SV_MulticastProtExt(vec3_t origin, multicast_t to, int dimension_mask, int
int j;
qboolean reliable;
client_t *oneclient = NULL, *split;
int seat;
if (!sv.multicast.cursize)
return;
if (to == MULTICAST_INIT)
{
@ -807,7 +811,7 @@ void SV_MulticastProtExt(vec3_t origin, multicast_t to, int dimension_mask, int
if (client->controller)
continue; //FIXME: send if at least one of the players is near enough.
for (split = client; split; split = split->controlled)
for (split = client, seat = 0; split; split = split->controlled, seat++)
{
if (client->protocol == SCP_QUAKEWORLD)
{
@ -902,11 +906,26 @@ void SV_MulticastProtExt(vec3_t origin, multicast_t to, int dimension_mask, int
case SCP_QUAKEWORLD:
if (reliable)
{
ClientReliableCheckBlock(client, sv.multicast.cursize);
if (oneclient && seat)
{
ClientReliableCheckBlock(client, 2+sv.multicast.cursize);
ClientReliableWrite_Byte(client, svcfte_choosesplitclient);
ClientReliableWrite_Byte(client, seat);
}
else
ClientReliableCheckBlock(client, sv.multicast.cursize);
ClientReliableWrite_SZ(client, sv.multicast.data, sv.multicast.cursize);
}
else
{
if (oneclient && seat)
{
MSG_WriteByte (&client->datagram, svcfte_choosesplitclient);
MSG_WriteByte (&client->datagram, seat);
}
SZ_Write (&client->datagram, sv.multicast.data, sv.multicast.cursize);
}
break;
}
}
@ -976,7 +995,7 @@ void SV_MulticastProtExt(vec3_t origin, multicast_t to, int dimension_mask, int
if (client->controller)
continue;
for (split = client; split; split = split->controlled)
for (split = client, seat = 0; split; split = split->controlled, seat++)
{
if (split->protocol == SCP_QUAKEWORLD)
{
@ -1078,11 +1097,26 @@ void SV_MulticastProtExt(vec3_t origin, multicast_t to, int dimension_mask, int
case SCP_QUAKEWORLD:
if (reliable)
{
ClientReliableCheckBlock(client, sv.multicast.cursize);
if (oneclient && seat)
{
ClientReliableCheckBlock(client, 2+sv.multicast.cursize);
ClientReliableWrite_Byte(client, svcfte_choosesplitclient);
ClientReliableWrite_Byte(client, seat);
}
else
ClientReliableCheckBlock(client, sv.multicast.cursize);
ClientReliableWrite_SZ(client, sv.multicast.data, sv.multicast.cursize);
}
else
{
if (oneclient && seat)
{
MSG_WriteByte (&client->datagram, svcfte_choosesplitclient);
MSG_WriteByte (&client->datagram, seat);
}
SZ_Write (&client->datagram, sv.multicast.data, sv.multicast.cursize);
}
break;
}
}

View File

@ -1056,6 +1056,71 @@ void SV_SendClientPrespawnInfo(client_t *client)
}
}
if (client->prespawn_stage == PRESPAWN_CSPROGS)
{
extern cvar_t sv_demo_write_csqc;
if (client == &demo.recorder && sv_demo_write_csqc.ival) //we only really want to do this for demos. actual clients can make the request themselves.
if (client->fteprotocolextensions & PEXT_CHUNKEDDOWNLOADS) //there's many different download mechanisms...
{
if (!client->prespawn_idx && !client->download)
{
extern cvar_t sv_csqc_progname;
Q_strncpyz(client->downloadfn, sv_csqc_progname.string, sizeof(client->downloadfn));
client->download = FS_OpenVFS(sv_csqc_progname.string, "rb", FS_GAME);
client->downloadcount = 0;
client->prespawn_idx = 1;
if (client->download)
{
client->downloadsize = VFS_GETLEN(client->download);
//send the size+filename
ClientReliableWrite_Begin (client, svc_download, 18+strlen(client->downloadfn));
ClientReliableWrite_Long (client, -1); //offset
if (client->downloadsize >= 0x7fffffff)
{ //avoid unsigned values.
ClientReliableWrite_Long (client, 0x80000000); //signal that its 64bit
ClientReliableWrite_Long (client, qofs_Low(client->downloadsize));
ClientReliableWrite_Long (client, qofs_High(client->downloadsize));
}
else
ClientReliableWrite_Long (client, client->downloadsize);
ClientReliableWrite_String (client, client->downloadfn);
}
}
//send the data while possible+needed
if (client->prespawn_idx && client->download)
{
while (client->downloadcount < client->downloadsize)
{
qbyte chunk[DLBLOCKSIZE];
int sz;
if (client->netchan.message.maxsize - client->netchan.message.cursize < 1100)
return; //don't flood...
sz = VFS_READ(client->download, chunk, DLBLOCKSIZE);
if (sz <= 0)
break;
if (sz < DLBLOCKSIZE)
{
memset(chunk+sz, 0, DLBLOCKSIZE-sz); //zero-fill if the chunk is at the end.
sz = DLBLOCKSIZE;
}
ClientReliableWrite_Begin (client, svc_download, 5+sz);
ClientReliableWrite_Long(client, client->downloadcount/DLBLOCKSIZE);
ClientReliableWrite_SZ(client, chunk, sz);
client->downloadcount += sz;
}
//don't need to write completion. the client should be tracking that itself with chunks.
VFS_CLOSE(client->download);
client->download = NULL;
}
}
client->prespawn_stage++;
client->prespawn_idx = 0;
}
if (client->prespawn_stage == PRESPAWN_SOUNDLIST)
{
if (!ISQWCLIENT(client))
@ -2239,9 +2304,8 @@ void SV_DarkPlacesDownloadAck(client_t *cl)
static void SV_NextChunkedDownload(unsigned int chunknum, int ezpercent, int ezfilenum, int chunks)
{
#define CHUNKSIZE 1024
char buffer[CHUNKSIZE];
qbyte oobdata[1+ (sizeof("\\chunk")-1) + 4 + 1 + 4 + CHUNKSIZE];
char buffer[DLBLOCKSIZE];
qbyte oobdata[1+ (sizeof("\\chunk")-1) + 4 + 1 + 4 + DLBLOCKSIZE];
sizebuf_t *msg, msg_oob;
int i;
int error = false;
@ -2252,24 +2316,24 @@ static void SV_NextChunkedDownload(unsigned int chunknum, int ezpercent, int ezf
if (chunknum == -1)
error = 2; //silent, don't report it
else if (chunknum*CHUNKSIZE > host_client->downloadsize)
else if (chunknum*DLBLOCKSIZE > host_client->downloadsize)
{
SV_ClientTPrintf (host_client, PRINT_HIGH, "Warning: Invalid file chunk requested %u to %u of %u.\n", chunknum*CHUNKSIZE, (chunknum+1)*CHUNKSIZE, host_client->downloadsize);
SV_ClientTPrintf (host_client, PRINT_HIGH, "Warning: Invalid file chunk requested %u to %u of %u.\n", chunknum*DLBLOCKSIZE, (chunknum+1)*DLBLOCKSIZE, host_client->downloadsize);
error = 2;
}
if (!error && VFS_SEEK (host_client->download, (qofs_t)chunknum*CHUNKSIZE) == false)
if (!error && VFS_SEEK (host_client->download, (qofs_t)chunknum*DLBLOCKSIZE) == false)
error = true;
else
{
if (host_client->downloadcount < chunknum*CHUNKSIZE)
host_client->downloadcount = chunknum*CHUNKSIZE;
if (host_client->downloadcount < chunknum*DLBLOCKSIZE)
host_client->downloadcount = chunknum*DLBLOCKSIZE;
}
while (!error && chunks > 0)
{
if ((host_client->datagram.cursize + CHUNKSIZE+5+50 > host_client->datagram.maxsize) || (host_client->datagram.cursize + CHUNKSIZE+5 > 1400))
if ((host_client->datagram.cursize + DLBLOCKSIZE+5+50 > host_client->datagram.maxsize) || (host_client->datagram.cursize + DLBLOCKSIZE+5 > 1400))
{
//would overflow the packet, or result in (ethernet) fragmentation and high packet loss.
msg = &msg_oob;
@ -2284,7 +2348,7 @@ static void SV_NextChunkedDownload(unsigned int chunknum, int ezpercent, int ezf
return;
}
i = VFS_READ (host_client->download, buffer, CHUNKSIZE);
i = VFS_READ (host_client->download, buffer, DLBLOCKSIZE);
if (i > 0)
{
@ -2303,12 +2367,12 @@ static void SV_NextChunkedDownload(unsigned int chunknum, int ezpercent, int ezf
MSG_WriteLong(msg, ezfilenum); //echoing the file num is used so the packets don't go out of sync.
}
if (i != CHUNKSIZE)
memset(buffer+i, 0, CHUNKSIZE-i);
if (i != DLBLOCKSIZE)
memset(buffer+i, 0, DLBLOCKSIZE-i);
MSG_WriteByte(msg, svc_download);
MSG_WriteLong(msg, chunknum);
SZ_Write(msg, buffer, CHUNKSIZE);
SZ_Write(msg, buffer, DLBLOCKSIZE);
if (msg == &msg_oob)
{
@ -3422,8 +3486,7 @@ void SV_BeginDownload_f(void)
}
else
#endif
if (ISNQCLIENT(host_client))
if (ISNQCLIENT(host_client))
{
//FIXME support 64bit files
char *s = va("\ncl_downloadbegin %u %s\n", (unsigned int)host_client->downloadsize, host_client->downloadfn);
@ -7363,6 +7426,7 @@ void SV_ReadQCRequest(void)
func_t f;
int i;
globalvars_t *pr_globals;
client_t *cl = host_client;
if (!svprogfuncs)
{
@ -7372,19 +7436,31 @@ void SV_ReadQCRequest(void)
pr_globals = PR_globals(svprogfuncs, PR_CURRENT);
for (i = 0; ; i++)
for (i = 0; ; )
{
qbyte ev = MSG_ReadByte();
if (ev >= 200 && ev < 200+MAX_SPLITS)
{
ev -= 200;
while (ev-- && cl)
cl = cl->controlled;
continue;
}
if (i >= sizeof(args)-1)
{
if (MSG_ReadByte() != ev_void)
if (ev != ev_void)
{
msg_badread = true;
return;
}
goto done;
}
switch(MSG_ReadByte())
switch(ev)
{
default:
args[i] = '?';
G_INT(OFS_PARM0+i*3) = MSG_ReadLong();
break;
case ev_void:
goto done;
case ev_float:
@ -7413,6 +7489,7 @@ void SV_ReadQCRequest(void)
G_INT(OFS_PARM0+i*3) = EDICT_TO_PROG(svprogfuncs, EDICT_NUM(svprogfuncs, e));
break;
}
i++;
}
done:
@ -7431,9 +7508,11 @@ done:
rname = va("Cmd_%s", rname);
f = PR_FindFunction(svprogfuncs, rname, PR_ANY);
}
if (f)
if (!cl)
; //bad seat! not going to warn as they might have been removed recently
else if (f)
{
pr_global_struct->self = EDICT_TO_PROG(svprogfuncs, sv_player);
pr_global_struct->self = EDICT_TO_PROG(svprogfuncs, cl->edict);
PR_ExecuteProgram(svprogfuncs, f);
}
else

View File

@ -475,6 +475,17 @@ void IRC_AddClientMessage(ircclient_t *irc, char *msg)
if (irc_debug.value == 1) { IRC_Printf(irc, DEFAULTCONSOLE,COLOURYELLOW "<< %s \n",msg); }
}
ircclient_t *IRC_FindAccount(const char *server)
{
ircclient_t *irc;
for (irc = ircclients; irc; irc = irc->next)
{
if (!strcmp(irc->server, server))
return irc;
}
return NULL; //no match
}
ircclient_t *IRC_Create(const char *server, const char *nick, const char *realname, const char *hostname, const char *password, const char *channels)
{
ircclient_t *irc;
@ -2328,6 +2339,12 @@ void IRC_Command(ircclient_t *ircclient, char *dest)
if (!*nick)
pCvar_GetString("name", nick, sizeof(nick));
if (IRC_FindAccount(server))
{
IRC_Printf(ircclient, dest, "IRC connection to %s already registered\n");
return; //silently ignore it if the account already exists
}
ircclient = IRC_Create(server, nick, defaultuser, irc_hostname.string, password, channels);
if (ircclient)
{