コード例 #1
0
ファイル: cl_parse.c プロジェクト: jayschwa/quake2world
/*
 * @brief
 */
static void Cl_ParseSound(void) {
	vec3_t origin;
	vec_t *org;
	uint16_t index;
	uint16_t ent_num;
	int32_t atten;
	int32_t flags;

	flags = Net_ReadByte(&net_message);

	if ((index = Net_ReadByte(&net_message)) > MAX_SOUNDS)
		Com_Error(ERR_DROP, "Bad index (%d)\n", index);

	if (flags & S_ATTEN)
		atten = Net_ReadByte(&net_message);
	else
		atten = ATTEN_DEFAULT;

	if (flags & S_ENTNUM) { // entity relative
		ent_num = Net_ReadShort(&net_message);

		if (ent_num > MAX_EDICTS)
			Com_Error(ERR_DROP, "Bad entity number (%d)\n", ent_num);
	} else {
		ent_num = 0;
	}

	if (flags & S_ORIGIN) { // positioned in space
		Net_ReadPosition(&net_message, origin);

		org = origin;
	} else
		// use ent_num
		org = NULL;

	if (!cl.sound_precache[index])
		return;

	S_PlaySample(org, ent_num, cl.sound_precache[index], atten);
}
コード例 #2
0
ファイル: cl_parse.c プロジェクト: jayschwa/quake2world
/*
 * @brief A download message has been received from the server.
 */
static void Cl_ParseDownload(void) {
	int32_t size, percent;

	// read the data
	size = Net_ReadShort(&net_message);
	percent = Net_ReadByte(&net_message);
	if (size < 0) {
		Com_Debug("Server does not have this file\n");
		if (cls.download.file) {
			// if here, we tried to resume a file but the server said no
			Fs_Close(cls.download.file);
			cls.download.file = NULL;
		}
		Cl_RequestNextDownload();
		return;
	}

	// open the file if not opened yet
	if (!cls.download.file) {

		if (!(cls.download.file = Fs_OpenWrite(cls.download.tempname))) {
			net_message.read += size;
			Com_Warn("Failed to open %s\n", cls.download.tempname);
			Cl_RequestNextDownload();
			return;
		}
	}

	Fs_Write(cls.download.file, net_message.data + net_message.read, 1, size);

	net_message.read += size;

	if (percent != 100) {
		Net_WriteByte(&cls.net_chan.message, CL_CMD_STRING);
		Net_WriteString(&cls.net_chan.message, "nextdl");
	} else {
		Fs_Close(cls.download.file);
		cls.download.file = NULL;

		// add new archives to the search path
		if (Fs_Rename(cls.download.tempname, cls.download.name)) {
			if (strstr(cls.download.name, ".zip")) {
				Fs_AddToSearchPath(cls.download.name);
			}
		} else {
			Com_Error(ERR_DROP, "Failed to rename %s\n", cls.download.name);
		}

		// get another file if needed
		Cl_RequestNextDownload();
	}
}
コード例 #3
0
ファイル: sv_main.c プロジェクト: jayschwa/quake2world
/*
 * @brief
 */
static void Sv_ReadPackets(void) {
	int32_t i;
	sv_client_t * cl;
	byte qport;

	while (Net_ReceiveDatagram(NS_UDP_SERVER, &net_from, &net_message)) {

		// check for connectionless packet (0xffffffff) first
		if (*(uint32_t *) net_message.data == 0xffffffff) {
			Sv_ConnectionlessPacket();
			continue;
		}

		// read the qport out of the message so we can fix up
		// stupid address translating routers
		Net_BeginReading(&net_message);

		Net_ReadLong(&net_message); // sequence number
		Net_ReadLong(&net_message); // sequence number

		qport = Net_ReadByte(&net_message) & 0xff;

		// check for packets from connected clients
		for (i = 0, cl = svs.clients; i < sv_max_clients->integer; i++, cl++) {

			if (cl->state == SV_CLIENT_FREE)
				continue;

			if (!Net_CompareClientNetaddr(&net_from, &cl->net_chan.remote_address))
				continue;

			if (cl->net_chan.qport != qport)
				continue;

			if (cl->net_chan.remote_address.port != net_from.port) {
				Com_Warn("Fixing up a translated port\n");
				cl->net_chan.remote_address.port = net_from.port;
			}

			// this is a valid, sequenced packet, so process it
			if (Netchan_Process(&cl->net_chan, &net_message)) {
				cl->last_message = svs.real_time; // nudge timeout
				Sv_ParseClientMessage(cl);
			}

			// we've processed the packet for the correct client, so break
			break;
		}
	}
}
コード例 #4
0
/**
 * @brief Parses an incoming SVC_PRINT message.
 */
static void Cl_ParsePrint(void) {

	const byte level = Net_ReadByte(&net_message);
	const char *string = Net_ReadString(&net_message);

	// the server shouldn't have sent us anything below our level anyway
	if (level >= message_level->integer) {

		// check to see if we should ignore the message
		if (*cl_ignore->string) {

			char patterns[MAX_STRING_CHARS];
			g_strlcpy(patterns, cl_ignore->string, sizeof(patterns));

			const char *p = patterns;
			while (true) {
				const char *pattern = ParseToken(&p);
				if (pattern == NULL) {
					break;
				}

				if (GlobMatch(pattern, string)) {
					return;
				}
			}
		}

		char *sample = NULL;
		switch (level) {
			case PRINT_CHAT:
			case PRINT_TEAM_CHAT:
				if (level == PRINT_CHAT && *cl_chat_sound->string) {
					sample = cl_chat_sound->string;
				} else if (level == PRINT_TEAM_CHAT && *cl_team_chat_sound->string) {
					sample = cl_team_chat_sound->string;
				}
				break;
			default:
				break;
		}

		if (sample) {
			S_AddSample(&(const s_play_sample_t) {
				.sample = S_LoadSample(sample)
			});
		}

		Con_Append(level, string);
	}
コード例 #5
0
ファイル: cl_parse.c プロジェクト: jayschwa/quake2world
/*
 * @brief
 */
static void Cl_ParseServerData(void) {
	char *str;
	int32_t i;

	// wipe the cl_client_t struct
	Cl_ClearState();

	cls.state = CL_CONNECTED;
	cls.key_state.dest = KEY_CONSOLE;

	// parse protocol version number
	i = Net_ReadLong(&net_message);

	// ensure protocol matches
	if (i != PROTOCOL) {
		Com_Error(ERR_DROP, "Server is using unknown protocol %d\n", i);
	}

	// retrieve spawn count and packet rate
	cl.server_count = Net_ReadLong(&net_message);
	cl.server_hz = Net_ReadLong(&net_message);

	// determine if we're viewing a demo
	cl.demo_server = Net_ReadByte(&net_message);

	// game directory
	str = Net_ReadString(&net_message);
	if (g_strcmp0(Cvar_GetString("game"), str)) {

		Fs_SetGame(str);

		// reload the client game
		Cl_InitCgame();
	}

	// parse player entity number
	cl.entity_num = Net_ReadShort(&net_message);

	// get the full level name
	str = Net_ReadString(&net_message);
	Com_Print("\n");
	Com_Print("%c%s\n", 2, str);
}
コード例 #6
0
/**
 * @brief
 */
static void Cl_ParseServerData(void) {

	// wipe the cl_client_t struct
	Cl_ClearState();

	Cl_SetKeyDest(KEY_CONSOLE);

	// parse protocol version number
	const uint16_t major = Net_ReadShort(&net_message);
	const uint16_t minor = Net_ReadShort(&net_message);

	// ensure protocol major matches
	if (major != PROTOCOL_MAJOR) {
		Com_Error(ERROR_DROP, "Server is using protocol major %d\n", major);
	}

	// determine if we're viewing a demo
	cl.demo_server = Net_ReadByte(&net_message);

	// game directory
	char *str = Net_ReadString(&net_message);
	if (g_strcmp0(Cvar_GetString("game"), str)) {

		Fs_SetGame(str);

		// reload the client game
		Cl_InitCgame();
	}

	// ensure protocol minor matches
	if (minor != cls.cgame->protocol) {
		Com_Error(ERROR_DROP, "Server is using protocol minor %d\n", minor);
	}

	// parse client slot number, which is our entity number + 1
	cl.client_num = Net_ReadShort(&net_message);

	// get the full level name
	str = Net_ReadString(&net_message);
	Com_Print("\n");
	Com_Print("^2%s^7\n", str);
}
コード例 #7
0
ファイル: cl_parse.c プロジェクト: jayschwa/quake2world
/*
 * @brief
 */
void Cl_ParseServerMessage(void) {
	int32_t cmd, old_cmd;
	char *s;
	int32_t i;

	if (cl_show_net_messages->integer == 1)
		Com_Print("%u ", (uint32_t) net_message.size);
	else if (cl_show_net_messages->integer >= 2)
		Com_Print("------------------\n");

	cl.byte_counter += net_message.size;
	cmd = 0;

	// parse the message
	while (true) {
		if (net_message.read > net_message.size) {
			Com_Error(ERR_DROP, "Bad server message\n");
		}

		old_cmd = cmd;
		cmd = Net_ReadByte(&net_message);

		if (cmd == -1) {
			Cl_ShowNet("END OF MESSAGE");
			break;
		}

		if (cl_show_net_messages->integer >= 2 && sv_cmd_names[cmd])
			Cl_ShowNet(sv_cmd_names[cmd]);

		switch (cmd) {

			case SV_CMD_BASELINE:
				Cl_ParseBaseline();
				break;

			case SV_CMD_CBUF_TEXT:
				s = Net_ReadString(&net_message);
				Cbuf_AddText(s);
				break;

			case SV_CMD_CONFIG_STRING:
				Cl_ParseConfigString();
				break;

			case SV_CMD_DISCONNECT:
				Com_Error(ERR_DROP, "Server disconnected\n");
				break;

			case SV_CMD_DOWNLOAD:
				Cl_ParseDownload();
				break;

			case SV_CMD_FRAME:
				Cl_ParseFrame();
				break;

			case SV_CMD_PRINT:
				i = Net_ReadByte(&net_message);
				s = Net_ReadString(&net_message);
				if (i == PRINT_CHAT) {
					if (Cl_IgnoreChatMessage(s)) // filter /ignore'd chatters
						break;
					if (*cl_chat_sound->string) // trigger chat sound
						S_StartLocalSample(cl_chat_sound->string);
				} else if (i == PRINT_TEAMCHAT) {
					if (Cl_IgnoreChatMessage(s)) // filter /ignore'd chatters
						break;
					if (*cl_team_chat_sound->string) // trigger chat sound
						S_StartLocalSample(cl_team_chat_sound->string);
				}
				Com_Print("%s", s);
				break;

			case SV_CMD_RECONNECT:
				Com_Print("Server disconnected, reconnecting...\n");
				// stop download
				if (cls.download.file) {
					if (cls.download.http) // clean up http downloads
						Cl_HttpDownload_Complete();
					else
						// or just stop legacy ones
						Fs_Close(cls.download.file);
					cls.download.name[0] = '\0';
					cls.download.file = NULL;
				}
				cls.state = CL_CONNECTING;
				cls.connect_time = 0; // fire immediately
				break;

			case SV_CMD_SERVER_DATA:
				Cl_ParseServerData();
				break;

			case SV_CMD_SOUND:
				Cl_ParseSound();
				break;

			default:
				// delegate to the client game module before failing
				if (!cls.cgame->ParseMessage(cmd)) {
					Com_Error(ERR_DROP, "Illegible server message:\n"
							" %d: last command was %s\n", cmd, sv_cmd_names[old_cmd]);
				}
				break;
		}
	}

	Cl_AddNetGraph();

	Cl_WriteDemoMessage();
}
コード例 #8
0
ファイル: net_chan.c プロジェクト: jayschwa/quake2world
/*
 * @brief Called when the current net_message is from remote_address
 * modifies net_message so that it points to the packet payload
 */
_Bool Netchan_Process(net_chan_t *chan, mem_buf_t *msg) {
	uint32_t sequence, sequence_ack;
	uint32_t reliable_ack, reliable_message;

	// get sequence numbers
	Net_BeginReading(msg);

	sequence = Net_ReadLong(msg);
	sequence_ack = Net_ReadLong(msg);

	// read the qport if we are a server
	if (chan->source == NS_UDP_SERVER)
		Net_ReadByte(msg);

	reliable_message = sequence >> 31;
	reliable_ack = sequence_ack >> 31;

	sequence &= ~(1 << 31);
	sequence_ack &= ~(1 << 31);

	if (net_showpackets->value) {
		if (reliable_message)
			Com_Print("Recv %u bytes: s=%i reliable=%i ack=%i rack=%i\n", (uint32_t) msg->size,
					sequence, chan->incoming_reliable_sequence ^ 1, sequence_ack, reliable_ack);
		else
			Com_Print("Recv %u bytes : s=%i ack=%i rack=%i\n", (uint32_t) msg->size, sequence,
					sequence_ack, reliable_ack);
	}

	// discard stale or duplicated packets
	if (sequence <= chan->incoming_sequence) {
		if (net_showdrop->value)
			Com_Print("%s:Out of order packet %i at %i\n",
					Net_NetaddrToString(&chan->remote_address), sequence, chan->incoming_sequence);
		return false;
	}

	// dropped packets don't keep the message from being used
	chan->dropped = sequence - (chan->incoming_sequence + 1);
	if (chan->dropped > 0) {
		if (net_showdrop->value)
			Com_Print("%s:Dropped %i packets at %i\n", Net_NetaddrToString(&chan->remote_address),
					chan->dropped, sequence);
	}

	// if the current outgoing reliable message has been acknowledged
	// clear the buffer to make way for the next
	if (reliable_ack == chan->reliable_sequence)
		chan->reliable_size = 0; // it has been received

	// if this message contains a reliable message, bump incoming_reliable_sequence
	chan->incoming_sequence = sequence;
	chan->incoming_acknowledged = sequence_ack;
	chan->incoming_reliable_acknowledged = reliable_ack;
	if (reliable_message) {
		chan->incoming_reliable_sequence ^= 1;
	}

	// the message can now be read from the current message pointer
	chan->last_received = quake2world.time;

	return true;
}