Beispiel #1
0
/*
 * @brief Searches sv.config_strings from the specified start, searching for the
 * desired name. If not found, the name can be optionally created and sent to
 * all connected clients. This allows the game to lazily load assets.
 */
static uint16_t Sv_FindIndex(const char *name, uint16_t start, uint16_t max, _Bool create) {
	uint16_t i;

	if (!name || !name[0])
		return 0;

	for (i = 0; i < max && sv.config_strings[start + i][0]; i++)
		if (!g_strcmp0(sv.config_strings[start + i], name))
			return i;

	if (!create)
		return 0;

	if (i == max) {
		Com_Warn("Max index for %s reached\n", name);
		return 0;
	}

	g_strlcpy(sv.config_strings[start + i], name, sizeof(sv.config_strings[i]));

	if (sv.state != SV_LOADING) { // send the update to everyone
		Sb_Clear(&sv.multicast);
		Msg_WriteChar(&sv.multicast, SV_CMD_CONFIG_STRING);
		Msg_WriteShort(&sv.multicast, start + i);
		Msg_WriteString(&sv.multicast, name);
		Sv_Multicast(vec3_origin, MULTICAST_ALL_R);
	}

	return i;
}
Beispiel #2
0
/*
 * Sv_New_f
 *
 * Sends the first message from the server to a connected client.
 * This will be sent on the initial connection and upon each server load.
 */
static void Sv_New_f(void) {
	int player_num;

	Com_Debug("New() from %s\n", Sv_NetaddrToString(sv_client));

	if (sv_client->state != SV_CLIENT_CONNECTED) {
		Com_Warn("Sv_New_f: %s already spawned\n",
				Sv_NetaddrToString(sv_client));
		return;
	}

	// demo servers will send the demo file's server info packet
	if (sv.state == SV_ACTIVE_DEMO) {
		return;
	}

	// send the server data
	Msg_WriteByte(&sv_client->netchan.message, SV_CMD_SERVER_DATA);
	Msg_WriteLong(&sv_client->netchan.message, PROTOCOL);
	Msg_WriteLong(&sv_client->netchan.message, svs.spawn_count);
	Msg_WriteLong(&sv_client->netchan.message, svs.frame_rate);
	Msg_WriteByte(&sv_client->netchan.message, 0);
	Msg_WriteString(&sv_client->netchan.message, Cvar_GetString("game"));

	player_num = sv_client - svs.clients;
	Msg_WriteShort(&sv_client->netchan.message, player_num);

	// send full level name
	Msg_WriteString(&sv_client->netchan.message, sv.config_strings[CS_NAME]);

	// begin fetching config_strings
	Msg_WriteByte(&sv_client->netchan.message, SV_CMD_CBUF_TEXT);
	Msg_WriteString(&sv_client->netchan.message,
			va("config_strings %i 0\n", svs.spawn_count));
}
Beispiel #3
0
/*
 * Sv_NextDownload_f
 */
static void Sv_NextDownload_f(void) {
	int r, size, percent;
	byte buf[MAX_MSG_SIZE];
	size_buf_t msg;

	if (!sv_client->download)
		return;

	r = sv_client->download_size - sv_client->download_count;

	if (r > 1024) // cap the download chunk at 1024 bytes
		r = 1024;

	Sb_Init(&msg, buf, MAX_MSG_SIZE);

	Msg_WriteByte(&msg, SV_CMD_DOWNLOAD);
	Msg_WriteShort(&msg, r);

	sv_client->download_count += r;
	size = sv_client->download_size;
	if (!size)
		size = 1;

	percent = sv_client->download_count * 100 / size;
	Msg_WriteByte(&msg, percent);

	Sb_Write(&msg, sv_client->download + sv_client->download_count - r, r);
	Sb_Write(&sv_client->netchan.message, msg.data, msg.size);

	if (sv_client->download_count != sv_client->download_size)
		return;

	Fs_FreeFile(sv_client->download);
	sv_client->download = NULL;
}
Beispiel #4
0
/*
 * Sv_ConfigStrings_f
 */
static void Sv_ConfigStrings_f(void) {
	unsigned int start;

	Com_Debug("ConfigStrings() from %s\n", Sv_NetaddrToString(sv_client));

	if (sv_client->state != SV_CLIENT_CONNECTED) {
		Com_Warn("Sv_ConfigStrings_f: %s already spawned\n",
				Sv_NetaddrToString(sv_client));
		return;
	}

	// handle the case of a level changing while a client was connecting
	if (strtoul(Cmd_Argv(1), NULL, 0) != svs.spawn_count) {
		Com_Debug("Sv_ConfigStrings_f: Stale spawn count from %s\n",
				Sv_NetaddrToString(sv_client));
		Sv_New_f();
		return;
	}

	start = strtoul(Cmd_Argv(2), NULL, 0);

	if (start >= MAX_CONFIG_STRINGS) { // catch bad offsets
		Com_Warn("Sv_ConfigStrings_f: Bad config_string offset from %s\n",
				Sv_NetaddrToString(sv_client));
		Sv_KickClient(sv_client, NULL);
		return;
	}

	// write a packet full of data
	while (sv_client->netchan.message.size < MAX_MSG_SIZE / 2 && start
			< MAX_CONFIG_STRINGS) {
		if (sv.config_strings[start][0]) {
			Msg_WriteByte(&sv_client->netchan.message, SV_CMD_CONFIG_STRING);
			Msg_WriteShort(&sv_client->netchan.message, start);
			Msg_WriteString(&sv_client->netchan.message,
					sv.config_strings[start]);
		}
		start++;
	}

	// send next command
	if (start == MAX_CONFIG_STRINGS) {
		Msg_WriteByte(&sv_client->netchan.message, SV_CMD_CBUF_TEXT);
		Msg_WriteString(&sv_client->netchan.message,
				va("baselines %i 0\n", svs.spawn_count));
	} else {
		Msg_WriteByte(&sv_client->netchan.message, SV_CMD_CBUF_TEXT);
		Msg_WriteString(&sv_client->netchan.message,
				va("config_strings %i %i\n", svs.spawn_count, start));
	}
}
Beispiel #5
0
/*
 * Cl_WriteDemoHeader
 *
 * Writes server_data, config_strings, and baselines once a non-delta
 * compressed frame arrives from the server.
 */
static void Cl_WriteDemoHeader(void) {
	byte buffer[MAX_MSG_SIZE];
	size_buf_t msg;
	int i;
	int len;
	entity_state_t null_state;

	// write out messages to hold the startup information
	Sb_Init(&msg, buffer, sizeof(buffer));

	// write the server data
	Msg_WriteByte(&msg, SV_CMD_SERVER_DATA);
	Msg_WriteLong(&msg, PROTOCOL);
	Msg_WriteLong(&msg, cl.server_count);
	Msg_WriteLong(&msg, cl.server_frame_rate);
	Msg_WriteByte(&msg, 1); // demo_server byte
	Msg_WriteString(&msg, Cvar_GetString("game"));
	Msg_WriteShort(&msg, cl.player_num);
	Msg_WriteString(&msg, cl.config_strings[CS_NAME]);

	// and config_strings
	for (i = 0; i < MAX_CONFIG_STRINGS; i++) {
		if (*cl.config_strings[i] != '\0') {
			if (msg.size + strlen(cl.config_strings[i]) + 32 > msg.max_size) { // write it out
				len = LittleLong(msg.size);
				Fs_Write(&len, 4, 1, cls.demo_file);
				Fs_Write(msg.data, msg.size, 1, cls.demo_file);
				msg.size = 0;
			}

			Msg_WriteByte(&msg, SV_CMD_CONFIG_STRING);
			Msg_WriteShort(&msg, i);
			Msg_WriteString(&msg, cl.config_strings[i]);
		}
	}

	// and baselines
	for (i = 0; i < MAX_EDICTS; i++) {
		entity_state_t *ent = &cl.entities[i].baseline;
		if (!ent->number)
			continue;

		if (msg.size + 64 > msg.max_size) { // write it out
			len = LittleLong(msg.size);
			Fs_Write(&len, 4, 1, cls.demo_file);
			Fs_Write(msg.data, msg.size, 1, cls.demo_file);
			msg.size = 0;
		}

		memset(&null_state, 0, sizeof(null_state));

		Msg_WriteByte(&msg, SV_CMD_ENTITY_BASELINE);
		Msg_WriteDeltaEntity(&null_state, &cl.entities[i].baseline, &msg, true,
				true);
	}

	Msg_WriteByte(&msg, SV_CMD_CBUF_TEXT);
	Msg_WriteString(&msg, "precache 0\n");

	// write it to the demo file

	len = LittleLong(msg.size);
	Fs_Write(&len, 4, 1, cls.demo_file);
	Fs_Write(msg.data, msg.size, 1, cls.demo_file);

	Com_Print("Recording to %s.\n", cls.demo_path);
	// the rest of the demo file will be individual frames
}
Beispiel #6
0
/*
 * Sv_Download_f
 */
static void Sv_Download_f(void) {
	const char *name;
	void *buf;
	unsigned int i = 0, offset = 0;

	name = Cmd_Argv(1);

	if (Cmd_Argc() > 2)
		offset = strtoul(Cmd_Argv(2), NULL, 0); // downloaded offset

	// catch illegal offset or file_names
	if (*name == '.' || *name == '/' || *name == '\\' || strstr(
			name, "..")) {
		Com_Warn("Sv_Download_f: Malicious download (%s:%d) from %s\n", name,
				offset, Sv_NetaddrToString(sv_client));
		Sv_KickClient(sv_client, NULL);
		return;
	}

	while (downloadable[i]) { // ensure download name is allowed
		if (GlobMatch(downloadable[i], name))
			break;
		i++;
	}

	if (!downloadable[i]) { // it wasn't
		Com_Warn("Sv_Download_f: Illegal download (%s) from %s\n", name,
				Sv_NetaddrToString(sv_client));
		Sv_KickClient(sv_client, NULL);
		return;
	}

	if (!sv_udp_download->value) { // lastly, ensure server wishes to allow
		Msg_WriteByte(&sv_client->netchan.message, SV_CMD_DOWNLOAD);
		Msg_WriteShort(&sv_client->netchan.message, -1);
		Msg_WriteByte(&sv_client->netchan.message, 0);
		return;
	}

	if (sv_client->download) // free last download
		Fs_FreeFile(sv_client->download);

	sv_client->download_size = Fs_LoadFile(name, &buf);
	sv_client->download = (byte *) buf;
	sv_client->download_count = offset;

	if (offset > sv_client->download_size)
		sv_client->download_count = sv_client->download_size;

	if (!sv_client->download) { // legal file name, but missing file
		Com_Warn("Sv_Download_f: Couldn't download %s to %s\n", name,
				Sv_NetaddrToString(sv_client));
		Msg_WriteByte(&sv_client->netchan.message, SV_CMD_DOWNLOAD);
		Msg_WriteShort(&sv_client->netchan.message, -1);
		Msg_WriteByte(&sv_client->netchan.message, 0);
		return;
	}

	Sv_NextDownload_f();
	Com_Debug("Downloading %s to %s\n", name, sv_client->name);
}