Esempio n. 1
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));
}
Esempio n. 2
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));
	}
}
Esempio n. 3
0
/*
 * Sv_Baselines_f
 */
static void Sv_Baselines_f(void) {
	unsigned int start;
	entity_state_t nullstate;
	entity_state_t *base;

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

	if (sv_client->state != SV_CLIENT_CONNECTED) {
		Com_Warn("Sv_Baselines_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_Baselines_f: Stale spawn count from %s\n",
				Sv_NetaddrToString(sv_client));
		Sv_New_f();
		return;
	}

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

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

	// write a packet full of data
	while (sv_client->netchan.message.size < MAX_MSG_SIZE / 2 && start
			< MAX_EDICTS) {
		base = &sv.baselines[start];
		if (base->model1 || base->sound || base->effects) {
			Msg_WriteByte(&sv_client->netchan.message, SV_CMD_ENTITY_BASELINE);
			Msg_WriteDeltaEntity(&nullstate, base, &sv_client->netchan.message,
					true, true);
		}
		start++;
	}

	// send next command
	if (start == MAX_EDICTS) {
		Msg_WriteByte(&sv_client->netchan.message, SV_CMD_CBUF_TEXT);
		Msg_WriteString(&sv_client->netchan.message,
				va("precache %i\n", svs.spawn_count));
	} else {
		Msg_WriteByte(&sv_client->netchan.message, SV_CMD_CBUF_TEXT);
		Msg_WriteString(&sv_client->netchan.message,
				va("baselines %i %i\n", svs.spawn_count, start));
	}
}
Esempio n. 4
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;
}
Esempio n. 5
0
/*
 * @brief Sends the shutdown message message to all connected clients. The message
 * is sent immediately, because the server could completely terminate after
 * returning from this function.
 */
static void Sv_ShutdownMessage(const char *msg, _Bool reconnect) {
	sv_client_t * cl;
	int32_t i;

	if (!svs.initialized)
		return;

	Sb_Clear(&net_message);

	if (msg) { // send message
		Msg_WriteByte(&net_message, SV_CMD_PRINT);
		Msg_WriteByte(&net_message, PRINT_HIGH);
		Msg_WriteString(&net_message, msg);
	}

	if (reconnect) // send reconnect
		Msg_WriteByte(&net_message, SV_CMD_RECONNECT);
	else
		// or just disconnect
		Msg_WriteByte(&net_message, SV_CMD_DISCONNECT);

	for (i = 0, cl = svs.clients; i < sv_max_clients->integer; i++, cl++)
		if (cl->state >= SV_CLIENT_CONNECTED)
			Netchan_Transmit(&cl->netchan, net_message.size, net_message.data);
}
Esempio n. 6
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
}