svs.serverflags = 0; // haven't completed an episode yet
strlcpy(level, Cmd_Argv(cmd, 1), sizeof(level));
SV_SpawnServer(level);
- if (sv.active && cls.state == ca_disconnected)
- CL_EstablishConnection("local:1", -2);
+
+ if(sv.active && host.hook.ConnectLocal != NULL)
+ host.hook.ConnectLocal();
}
/*
SV_SaveSpawnparms ();
strlcpy(level, Cmd_Argv(cmd, 1), sizeof(level));
SV_SpawnServer(level);
- if (sv.active && cls.state == ca_disconnected)
- CL_EstablishConnection("local:1", -2);
+
+ if(sv.active && host.hook.ConnectLocal != NULL)
+ host.hook.ConnectLocal();
}
/*
strlcpy(mapname, sv.name, sizeof(mapname));
SV_SpawnServer(mapname);
- if (sv.active && cls.state == ca_disconnected)
- CL_EstablishConnection("local:1", -2);
+
+ if(sv.active && host.hook.ConnectLocal != NULL)
+ host.hook.ConnectLocal();
}
//===========================================================================
{
void (*print) (const char *fmt, ...);
if (cmd->source == src_command)
- {
- // if running a client, try to send over network so the pause is handled by the server
- if (cls.state == ca_connected)
- {
- CL_ForwardToServer_f(cmd);
- return;
- }
print = Con_Printf;
- }
else
print = SV_ClientPrintf;
char qcstatus[256];
client_t *client;
int seconds = 0, minutes = 0, hours = 0, i, j, k, in, players, ping = 0, packetloss = 0;
+ void (*print) (const char *fmt, ...);
char ip[48]; // can contain a full length v6 address with [] and a port
int frags;
char vabuf[1024];
+ if (cmd->source == src_command)
+ print = Con_Printf;
+ else
+ print = SV_ClientPrintf;
+
if (!sv.active)
return;
for (players = 0, i = 0;i < svs.maxclients;i++)
if (svs.clients[i].active)
players++;
- SV_ClientPrintf ("host: %s\n", Cvar_VariableString (&cvars_all, "hostname", CVAR_SERVER));
- SV_ClientPrintf ("version: %s build %s (gamename %s)\n", gamename, buildstring, gamenetworkfiltername);
- SV_ClientPrintf ("protocol: %i (%s)\n", Protocol_NumberForEnum(sv.protocol), Protocol_NameForEnum(sv.protocol));
- SV_ClientPrintf ("map: %s\n", sv.name);
- SV_ClientPrintf ("timing: %s\n", Host_TimingReport(vabuf, sizeof(vabuf)));
- SV_ClientPrintf ("players: %i active (%i max)\n\n", players, svs.maxclients);
+ print ("host: %s\n", Cvar_VariableString (&cvars_all, "hostname", CVAR_SERVER));
+ print ("version: %s build %s (gamename %s)\n", gamename, buildstring, gamenetworkfiltername);
+ print ("protocol: %i (%s)\n", Protocol_NumberForEnum(sv.protocol), Protocol_NameForEnum(sv.protocol));
+ print ("map: %s\n", sv.name);
+ print ("timing: %s\n", Host_TimingReport(vabuf, sizeof(vabuf)));
+ print ("players: %i active (%i max)\n\n", players, svs.maxclients);
if (in == 1)
- SV_ClientPrintf ("^2IP %%pl ping time frags no name\n");
+ print ("^2IP %%pl ping time frags no name\n");
else if (in == 2)
- SV_ClientPrintf ("^5IP no name\n");
+ print ("^5IP no name\n");
for (i = 0, k = 0, client = svs.clients;i < svs.maxclients;i++, client++)
{
if (sv.protocol == PROTOCOL_QUAKE && svs.maxclients <= 99)
{
// LadyHavoc: this is very touchy because we must maintain ProQuake compatible status output
- SV_ClientPrintf ("#%-2u %-16.16s %3i %2i:%02i:%02i\n", i+1, client->name, frags, hours, minutes, seconds);
- SV_ClientPrintf (" %s\n", ip);
+ print ("#%-2u %-16.16s %3i %2i:%02i:%02i\n", i+1, client->name, frags, hours, minutes, seconds);
+ print (" %s\n", ip);
}
else
{
// LadyHavoc: no real restrictions here, not a ProQuake-compatible protocol anyway...
- SV_ClientPrintf ("#%-3u %-16.16s %4i %2i:%02i:%02i\n", i+1, client->name, frags, hours, minutes, seconds);
- SV_ClientPrintf (" %s\n", ip);
+ print ("#%-3u %-16.16s %4i %2i:%02i:%02i\n", i+1, client->name, frags, hours, minutes, seconds);
+ print (" %s\n", ip);
}
}
else if (in == 1) // extended layout
{
- SV_ClientPrintf ("%s%-47s %2i %4i %2i:%02i:%02i %4i #%-3u ^7%s\n", k%2 ? "^3" : "^7", ip, packetloss, ping, hours, minutes, seconds, frags, i+1, client->name);
+ print ("%s%-47s %2i %4i %2i:%02i:%02i %4i #%-3u ^7%s\n", k%2 ? "^3" : "^7", ip, packetloss, ping, hours, minutes, seconds, frags, i+1, client->name);
}
else if (in == 2) // reduced layout
{
- SV_ClientPrintf ("%s%-47s #%-3u ^7%s\n", k%2 ? "^3" : "^7", ip, i+1, client->name);
+ print ("%s%-47s #%-3u ^7%s\n", k%2 ? "^3" : "^7", ip, i+1, client->name);
}
}
}
+void SV_Name(int clientnum)
+{
+ prvm_prog_t *prog = SVVM_prog;
+ PRVM_serveredictstring(host_client->edict, netname) = PRVM_SetEngineString(prog, host_client->name);
+ if (strcmp(host_client->old_name, host_client->name))
+ {
+ if (host_client->begun)
+ SV_BroadcastPrintf("\003%s ^7changed name to ^3%s\n", host_client->old_name, host_client->name);
+ strlcpy(host_client->old_name, host_client->name, sizeof(host_client->old_name));
+ // send notification to all clients
+ MSG_WriteByte (&sv.reliable_datagram, svc_updatename);
+ MSG_WriteByte (&sv.reliable_datagram, clientnum);
+ MSG_WriteString (&sv.reliable_datagram, host_client->name);
+ SV_WriteNetnameIntoDemo(host_client);
+ }
+}
+
/*
======================
SV_Name_f
*/
static void SV_Name_f(cmd_state_t *cmd)
{
- prvm_prog_t *prog = SVVM_prog;
int i, j;
qboolean valid_colors;
const char *newNameSource;
if (j >= 0 && strlen(host_client->name) < sizeof(host_client->name) - 2)
memcpy(host_client->name + strlen(host_client->name), STRING_COLOR_DEFAULT_STR, strlen(STRING_COLOR_DEFAULT_STR) + 1);
- PRVM_serveredictstring(host_client->edict, netname) = PRVM_SetEngineString(prog, host_client->name);
- if (strcmp(host_client->old_name, host_client->name))
- {
- if (host_client->begun)
- SV_BroadcastPrintf("%s ^7changed name to %s\n", host_client->old_name, host_client->name);
- strlcpy(host_client->old_name, host_client->name, sizeof(host_client->old_name));
- // send notification to all clients
- MSG_WriteByte (&sv.reliable_datagram, svc_updatename);
- MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
- MSG_WriteString (&sv.reliable_datagram, host_client->name);
- SV_WriteNetnameIntoDemo(host_client);
- }
+ SV_Name(host_client - svs.clients);
}
static void SV_Rate_f(cmd_state_t *cmd)
host_client = old;
}
+static void SV_Ent_Create_f(cmd_state_t *cmd)
+{
+ prvm_prog_t *prog = SVVM_prog;
+ prvm_edict_t *ed;
+ ddef_t *key;
+ int i;
+ qboolean haveorigin;
+
+ qboolean expectval = false;
+ void (*print)(const char *, ...) = (cmd->source == src_client ? SV_ClientPrintf : Con_Printf);
+
+ if(!Cmd_Argc(cmd))
+ return;
+
+ ed = PRVM_ED_Alloc(SVVM_prog);
+
+ PRVM_ED_ParseEpair(prog, ed, PRVM_ED_FindField(prog, "classname"), Cmd_Argv(cmd, 1), false);
+
+ // Spawn where the player is aiming. We need a view matrix first.
+ if(cmd->source == src_client)
+ {
+ vec3_t org, temp, dest;
+ matrix4x4_t view;
+ trace_t trace;
+ char buf[128];
+
+ SV_GetEntityMatrix(prog, host_client->edict, &view, true);
+
+ Matrix4x4_OriginFromMatrix(&view, org);
+ VectorSet(temp, 65536, 0, 0);
+ Matrix4x4_Transform(&view, temp, dest);
+
+ trace = SV_TraceLine(org, dest, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, 0, 0, collision_extendmovelength.value);
+
+ dpsnprintf(buf, sizeof(buf), "%g %g %g", trace.endpos[0], trace.endpos[1], trace.endpos[2]);
+ PRVM_ED_ParseEpair(prog, ed, PRVM_ED_FindField(prog, "origin"), buf, false);
+
+ haveorigin = true;
+ }
+ // Or spawn at a specified origin.
+ else
+ {
+ print = Con_Printf;
+ haveorigin = false;
+ }
+
+ // Allow more than one key/value pair by cycling between expecting either one.
+ for(i = 2; i < Cmd_Argc(cmd); i++)
+ {
+ if(!expectval)
+ {
+ if(!(key = PRVM_ED_FindField(prog, Cmd_Argv(cmd, i))))
+ {
+ print("Key %s not found!\n", Cmd_Argv(cmd, i));
+ PRVM_ED_Free(prog, ed);
+ return;
+ }
+
+ /*
+ * This is mostly for dedicated server console, but if the
+ * player gave a custom origin, we can ignore the traceline.
+ */
+ if(!strcmp(Cmd_Argv(cmd, i), "origin"))
+ haveorigin = true;
+
+ expectval = true;
+ }
+ else
+ {
+ PRVM_ED_ParseEpair(prog, ed, key, Cmd_Argv(cmd, i), false);
+ expectval = false;
+ }
+ }
+
+ if(!haveorigin)
+ {
+ print("Missing origin\n");
+ PRVM_ED_Free(prog, ed);
+ return;
+ }
+
+ // Spawn it
+ PRVM_ED_CallPrespawnFunction(prog, ed);
+
+ if(!PRVM_ED_CallSpawnFunction(prog, ed, NULL, NULL))
+ {
+ print("Could not spawn a \"%s\". No such entity or it has no spawn function\n", Cmd_Argv(cmd, 1));
+ if(cmd->source == src_client)
+ Con_Printf("%s tried to spawn a \"%s\"\n", host_client->name, Cmd_Argv(cmd, 1));
+ // CallSpawnFunction already freed the edict for us.
+ return;
+ }
+
+ PRVM_ED_CallPostspawnFunction(prog, ed);
+
+ // Make it appear in the world
+ SV_LinkEdict(ed);
+
+ if(cmd->source == src_client)
+ Con_Printf("%s spawned a \"%s\"\n", host_client->name, Cmd_Argv(cmd, 1));
+}
+
+static void SV_Ent_Remove_f(cmd_state_t *cmd)
+{
+ prvm_prog_t *prog = SVVM_prog;
+ prvm_edict_t *ed;
+ int i, ednum;
+ void (*print)(const char *, ...) = (cmd->source == src_client ? SV_ClientPrintf : Con_Printf);
+
+ if(!Cmd_Argc(cmd))
+ return;
+
+ // Allow specifying edict by number
+ if(Cmd_Argc(cmd) > 1 && Cmd_Argv(cmd, 1))
+ {
+ ednum = atoi(Cmd_Argv(cmd, 1));
+ if(!ednum)
+ {
+ print("Cannot remove the world\n");
+ return;
+ }
+ }
+ // Or trace a line if it's a client who didn't specify one.
+ else if(cmd->source == src_client)
+ {
+ vec3_t org, temp, dest;
+ matrix4x4_t view;
+ trace_t trace;
+
+ SV_GetEntityMatrix(prog, host_client->edict, &view, true);
+
+ Matrix4x4_OriginFromMatrix(&view, org);
+ VectorSet(temp, 65536, 0, 0);
+ Matrix4x4_Transform(&view, temp, dest);
+
+ trace = SV_TraceLine(org, dest, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY, 0, 0, collision_extendmovelength.value);
+
+ if(trace.ent)
+ ednum = (int)PRVM_EDICT_TO_PROG(trace.ent);
+ if(!trace.ent || !ednum)
+ // Don't remove the world, but don't annoy players with a print if they miss
+ return;
+ }
+ else
+ {
+ // Only a dedicated server console should be able to reach this.
+ print("No edict given\n");
+ return;
+ }
+
+ ed = PRVM_EDICT_NUM(ednum);
+
+ if(ed)
+ {
+ // Skip players
+ for (i = 0; i < svs.maxclients; i++)
+ {
+ if(ed == svs.clients[i].edict)
+ return;
+ }
+
+ if(!ed->priv.required->free)
+ {
+ print("Removed a \"%s\"\n", PRVM_GetString(prog, PRVM_serveredictstring(ed, classname)));
+ PRVM_ED_ClearEdict(prog, ed);
+ PRVM_ED_Free(prog, ed);
+ }
+ }
+ else
+ {
+ // This should only be reachable if an invalid edict number was given
+ print("No such entity\n");
+ return;
+ }
+}
+
+static void SV_Ent_Remove_All_f(cmd_state_t *cmd)
+{
+ prvm_prog_t *prog = SVVM_prog;
+ int i, rmcount;
+ prvm_edict_t *ed;
+ void (*print)(const char *, ...) = (cmd->source == src_client ? SV_ClientPrintf : Con_Printf);
+
+ for (i = 0, rmcount = 0, ed = PRVM_EDICT_NUM(i); i < prog->num_edicts; i++, ed = PRVM_NEXT_EDICT(ed))
+ {
+ if(!ed->priv.required->free && !strcmp(PRVM_GetString(prog, PRVM_serveredictstring(ed, classname)), Cmd_Argv(cmd, 1)))
+ {
+ if(!i)
+ {
+ print("Cannot remove the world\n");
+ return;
+ }
+ PRVM_ED_ClearEdict(prog, ed);
+ PRVM_ED_Free(prog, ed);
+ rmcount++;
+ }
+ }
+
+ if(!rmcount)
+ print("No \"%s\" found\n", Cmd_Argv(cmd, 1));
+ else
+ print("Removed %i of \"%s\"\n", rmcount, Cmd_Argv(cmd, 1));
+}
+
void SV_InitOperatorCommands(void)
{
Cvar_RegisterVariable(&sv_cheats);
Cmd_AddCommand(CMD_USERINFO, "rate_burstsize", SV_Rate_BurstSize_f, "change your network connection speed");
Cmd_AddCommand(CMD_USERINFO, "pmodel", SV_PModel_f, "(Nehahra-only) change your player model choice");
Cmd_AddCommand(CMD_USERINFO, "playermodel", SV_Playermodel_f, "change your player model");
- Cmd_AddCommand(CMD_USERINFO, "playerskin", SV_Playerskin_f, "change your player skin number");
+ Cmd_AddCommand(CMD_USERINFO, "playerskin", SV_Playerskin_f, "change your player skin number");
+
+ Cmd_AddCommand(CMD_CHEAT | CMD_SERVER_FROM_CLIENT, "ent_create", SV_Ent_Create_f, "Creates an entity at the specified coordinate, of the specified classname. If executed from a server, origin has to be specified manually.");
+ Cmd_AddCommand(CMD_CHEAT | CMD_SERVER_FROM_CLIENT, "ent_remove_all", SV_Ent_Remove_All_f, "Removes all entities of the specified classname");
+ Cmd_AddCommand(CMD_CHEAT | CMD_SERVER_FROM_CLIENT, "ent_remove", SV_Ent_Remove_f, "Removes an entity by number, or the entity you're aiming at");
}