Ejemplo n.º 1
0
/**
 * @brief Called during startup of mission to send team info
 */
void GAME_SpawnSoldiers (void)
{
	const cgame_export_t *list = GAME_GetCurrentType();
	qboolean spawnStatus;

	/* this callback is responsible to set up the cl.chrList */
	if (list && list->Spawn)
		spawnStatus = list->Spawn();
	else
		spawnStatus = GAME_Spawn();

	if (spawnStatus && cl.chrList.num > 0) {
		struct dbuffer *msg;

		/* send team info */
		msg = new_dbuffer();
		GAME_SendCurrentTeamSpawningInfo(msg, &cl.chrList);
		NET_WriteMsg(cls.netStream, msg);

		msg = new_dbuffer();
		NET_WriteByte(msg, clc_stringcmd);
		NET_WriteString(msg, "spawn\n");
		NET_WriteMsg(cls.netStream, msg);

		GAME_InitializeBattlescape(&cl.chrList);
	}
}
Ejemplo n.º 2
0
static void testDBuffer (void)
{
	int i;
	const int size = 10000000;
	dbuffer* buf = new_dbuffer();
	char data[128];
	size_t dataSize = sizeof(data);
	for (i = 0; i < size; i++)
		dbuffer_add(buf, "b", 1);
	CU_ASSERT_EQUAL(size, dbuffer_len(buf));

	CU_ASSERT_EQUAL(dataSize, dbuffer_get(buf, data, dataSize));
	CU_ASSERT_EQUAL(size, dbuffer_len(buf));

	CU_ASSERT_EQUAL(dataSize, dbuffer_extract(buf, data, dataSize));
	CU_ASSERT_EQUAL(size - dataSize, dbuffer_len(buf));

	free_dbuffer(buf);

	buf = new_dbuffer();
	dbuffer_add(buf, "b", 1);
	CU_ASSERT_EQUAL(1, dbuffer_len(buf));

	CU_ASSERT_EQUAL(1, dbuffer_get(buf, data, dataSize));
	CU_ASSERT_EQUAL(1, dbuffer_len(buf));

	CU_ASSERT_EQUAL(1, dbuffer_extract(buf, data, dataSize));
	CU_ASSERT_EQUAL(0, dbuffer_len(buf));

	buf = dbuffer_dup(buf);
	CU_ASSERT_EQUAL(0, dbuffer_len(buf));

	for (i = 0; i <= dataSize; i++)
		dbuffer_add(buf, "b", 1);
	CU_ASSERT_EQUAL(dataSize + 1, dbuffer_len(buf));

	CU_ASSERT_EQUAL(dataSize, dbuffer_extract(buf, data, dataSize));
	CU_ASSERT_EQUAL(1, dbuffer_len(buf));

	CU_ASSERT_EQUAL(1, dbuffer_remove(buf, 1));
	CU_ASSERT_EQUAL(0, dbuffer_len(buf));

	CU_ASSERT_EQUAL(0, dbuffer_remove(buf, 1));

	CU_ASSERT_EQUAL(0, dbuffer_get_at(buf, 1, data, dataSize));

	for (i = 0; i <= dataSize; i++)
		dbuffer_add(buf, "b", 1);
	CU_ASSERT_EQUAL(dataSize + 1, dbuffer_len(buf));

	CU_ASSERT_EQUAL(dataSize, dbuffer_get_at(buf, 1, data, dataSize));
	CU_ASSERT_EQUAL(dataSize + 1, dbuffer_len(buf));
}
Ejemplo n.º 3
0
/**
 * @brief Search the index in the config strings relative to a given start
 * @param name The value of the config string to search the index for
 * @param start The relative start point for the search
 * @param max The max. searched entries in the config string before giving up
 * @param create if @c true the value will get written into the config strings (appended)
 * @return @c 0 if not found
 */
static unsigned int SV_FindIndex (const char *name, int start, int max, qboolean create)
{
	int i;

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

	for (i = 1; i < max && SV_GetConfigString(start + i)[0] != '\0'; i++) {
		const char *configString = SV_GetConfigString(start + i);
		if (Q_streq(configString, name))
			return i;
	}

	if (!create)
		return 0;

	if (i == max)
		Com_Error(ERR_DROP, "*Index: overflow '%s' start: %i, max: %i", name, start, max);

	SV_SetConfigString(start + i, name);

	if (Com_ServerState() != ss_loading) {	/* send the update to everyone */
		struct dbuffer *msg = new_dbuffer();
		NET_WriteByte(msg, svc_configstring);
		NET_WriteShort(msg, start + i);
		NET_WriteString(msg, name);
		SV_Multicast(~0, msg);
	}

	return i;
}
Ejemplo n.º 4
0
/**
 * @brief Responds with teaminfo such as free team num
 * @sa CL_ParseTeamInfoMessage
 */
static void SVC_TeamInfo (struct net_stream *s)
{
	client_t *cl;
	struct dbuffer *msg = new_dbuffer();
	char infoGlobal[MAX_INFO_STRING] = "";

	NET_WriteByte(msg, clc_oob);
	NET_WriteRawString(msg, "teaminfo\n");

	Info_SetValueForKey(infoGlobal, sizeof(infoGlobal), "sv_teamplay", Cvar_GetString("sv_teamplay"));
	Info_SetValueForKey(infoGlobal, sizeof(infoGlobal), "sv_maxteams", Cvar_GetString("sv_maxteams"));
	Info_SetValueForKey(infoGlobal, sizeof(infoGlobal), "sv_maxplayersperteam", Cvar_GetString("sv_maxplayersperteam"));
	NET_WriteString(msg, infoGlobal);

	cl = NULL;
	while ((cl = SV_GetNextClient(cl)) != NULL) {
		if (cl->state >= cs_connected) {
			char infoPlayer[MAX_INFO_STRING] = "";
			/* show players that already have a team with their teamnum */
			int teamId = svs.ge->ClientGetTeamNum(cl->player);
			if (!teamId)
				teamId = TEAM_NO_ACTIVE;
			Info_SetValueForKeyAsInteger(infoPlayer, sizeof(infoPlayer), "cl_team", teamId);
			Info_SetValueForKeyAsInteger(infoPlayer, sizeof(infoPlayer), "cl_ready", svs.ge->ClientIsReady(cl->player));
			Info_SetValueForKey(infoPlayer, sizeof(infoPlayer), "cl_name", cl->name);
			NET_WriteString(msg, infoPlayer);
		}
	}

	NET_WriteByte(msg, 0);

	NET_WriteMsg(s, msg);
}
Ejemplo n.º 5
0
/**
 * @brief Called when the player is totally leaving the server, either willingly
 * or unwillingly. This is NOT called if the entire server is quitting
 * or crashing.
 */
void SV_DropClient (client_t * drop, const char *message)
{
	/* add the disconnect */
	struct dbuffer *msg = new_dbuffer();
	NET_WriteByte(msg, svc_disconnect);
	NET_WriteString(msg, message);
	NET_WriteMsg(drop->stream, msg);
	SV_BroadcastPrintf(PRINT_CHAT, "%s was dropped from the server - reason: %s\n", drop->name, message);

	if (drop->state == cs_spawned || drop->state == cs_spawning) {
		/* call the prog function for removing a client */
		/* this will remove the body, among other things */
		TH_MutexLock(svs.serverMutex);
		svs.ge->ClientDisconnect(drop->player);
		TH_MutexUnlock(svs.serverMutex);
	}

	NET_StreamFinished(drop->stream);
	drop->stream = NULL;

	drop->player->inuse = qfalse;
	SV_SetClientState(drop, cs_free);
	drop->name[0] = 0;

	if (svs.abandon) {
		int count = 0;
		client_t *cl = NULL;
		while ((cl = SV_GetNextClient(cl)) != NULL)
			if (cl->state >= cs_connected)
				count++;
		if (count == 0)
			svs.killserver = qtrue;
	}
}
Ejemplo n.º 6
0
/**
 * @brief Merges two dbuffers
 * @param[in] old the source buffer
 * @param[in] old2 the second source buffer
 * @return the newly allocated buffer
 * Allocates a new dbuffer and initialises it to contain a copy of the
 * data in old ones
 */
struct dbuffer *dbuffer_merge (struct dbuffer *old, struct dbuffer *old2)
{
	/* element we're currently reading from */
	const struct dbuffer_element *e;
	struct dbuffer *buf = new_dbuffer();
	const char *p;

	e = old->head;
	p = old->start;
	while (e && (e->len > 0)) {
		dbuffer_add(buf, p, e->len);
		e = e->next;
		p = &e->data[0];
	}

	e = old2->head;
	p = old2->start;
	while (e && (e->len > 0)) {
		dbuffer_add(buf, p, e->len);
		e = e->next;
		p = &e->data[0];
	}

	return buf;
}
Ejemplo n.º 7
0
static void testEvents (void)
{
	int i;
	const event_t events[] = {EV_RESET, EV_START, EV_ENDROUND, EV_ENDROUNDANNOUNCE};
	for (i = 0; i < lengthof(events); i++) {
		struct dbuffer* buf = new_dbuffer();
		NET_WriteByte(buf, events[i]);
		CL_ParseEvent(buf);
	}
	CU_ASSERT_EQUAL(CL_ClearBattlescapeEvents(), lengthof(events));
}
Ejemplo n.º 8
0
static void testDBufferNetHandling (void)
{
	dbuffer* buf = new_dbuffer();
	NET_WriteByte(buf, 'b');
	CU_ASSERT_EQUAL(1, dbuffer_len(buf));
	NET_WriteShort(buf, 128);
	CU_ASSERT_EQUAL(3, dbuffer_len(buf));
	NET_WriteLong(buf, 128);
	CU_ASSERT_EQUAL(7, dbuffer_len(buf));
	free_dbuffer(buf);
}
Ejemplo n.º 9
0
/**
 * @sa SV_BroadcastCommand
 */
void SV_ClientCommand (client_t *client, const char *fmt, ...)
{
	va_list ap;
	char str[1024];
	struct dbuffer *msg = new_dbuffer();

	NET_WriteByte(msg, svc_stufftext);

	va_start(ap, fmt);
	NET_VPrintf(msg, fmt, ap, str, sizeof(str));
	va_end(ap);

	NET_WriteMsg(client->stream, msg);
}
Ejemplo n.º 10
0
static void testDBufferBigData (void)
{
	int i;
	int count = 100;
	byte *data;
	/* this entity string may not contain any inline models, we don't have the bsp tree loaded here */
	const int size = FS_LoadFile("game/entity.txt", &data);
	dbuffer* buf = new_dbuffer();

	for (i = 0; i < count; i++) {
		dbuffer_add(buf, (char *)data, size);
	}

	CU_ASSERT_EQUAL(size * count, dbuffer_len(buf));
	free_dbuffer(buf);
	FS_FreeFile(data);
}
Ejemplo n.º 11
0
/**
 * @brief Finishes the current round of the player in battlescape and starts the round for the next team.
 */
static void CL_NextRound_f (void)
{
	struct dbuffer *msg;
	/* can't end round if we are not in battlescape */
	if (!CL_BattlescapeRunning())
		return;

	/* can't end round if we're not active */
	if (cls.team != cl.actTeam) {
		HUD_DisplayMessage(_("This isn't your round"));
		return;
	}

	/* send endround */
	msg = new_dbuffer();
	NET_WriteByte(msg, clc_endround);
	NET_WriteMsg(cls.netStream, msg);
}
Ejemplo n.º 12
0
/**
 * @brief Allocate a dbuffer and prepend the given data to it
 * @param[in] old The source buffer
 * @param[in] data The data to insert at the beginning
 * @param[in] len The length of that data
 * @return the newly allocated buffer
 * Allocates a new dbuffer and initialises it to contain a copy of the
 * data in old
 */
struct dbuffer *dbuffer_prepend (struct dbuffer *old, const char *data, size_t len)
{
	/* element we're currently reading from */
	const struct dbuffer_element *e;
	struct dbuffer *buf = new_dbuffer();
	const char *p;

	dbuffer_add(buf, data, len);

	e = old->head;
	p = old->start;
	while (e && (e->len > 0)) {
		dbuffer_add(buf, p, e->len);
		e = e->next;
		p = &e->data[0];
	}

	return buf;
}
Ejemplo n.º 13
0
/**
 * @sa gi.AddEvent
 * @param[in] mask The player bitmask to send the events to. Use @c PM_ALL to send to every connected player.
 */
static void SV_AddEvent (unsigned int mask, int eType)
{
	pending_event_t *p = &sv->pendingEvent;
	Com_DPrintf(DEBUG_EVENTSYS, "Event type: %i (mask %i)\n", eType, mask);

	/* finish the last event */
	if (p->pending)
		SV_EndEvents();

	/* start the new event */
	p->pending = qtrue;
	p->playerMask = mask;
	p->type = eType;
	p->buf = new_dbuffer();

	/* write header */
	NET_WriteByte(p->buf, svc_event);
	NET_WriteByte(p->buf, eType);
}
Ejemplo n.º 14
0
static void SV_PingPlayers (void)
{
	client_t *cl;
	/* check for time wraparound */
	if (svs.lastPing > svs.realtime)
		svs.lastPing = svs.realtime;

	if (svs.realtime - svs.lastPing < PING_SECONDS * 1000)
		return;					/* not time to send yet */

	svs.lastPing = svs.realtime;
	cl = NULL;
	while ((cl = SV_GetNextClient(cl)) != NULL)
		if (cl->state != cs_free) {
			struct dbuffer *msg = new_dbuffer();
			NET_WriteByte(msg, svc_ping);
			NET_WriteMsg(cl->stream, msg);
		}
}
Ejemplo n.º 15
0
/**
 * @brief Sends text to all active clients
 */
void SV_BroadcastPrintf (int level, const char *fmt, ...)
{
	va_list argptr;
	struct dbuffer *msg;
	client_t *cl;
	char str[1024];

	msg = new_dbuffer();
	NET_WriteByte(msg, svc_print);
	NET_WriteByte(msg, level);

	va_start(argptr, fmt);
	NET_VPrintf(msg, fmt, argptr, str, sizeof(str));
	va_end(argptr);

	/* echo to console */
	if (sv_dedicated->integer) {
		char copy[1024];
		int i;
		const int length = sizeof(copy) - 1;

		va_start(argptr, fmt);
		Q_vsnprintf(copy, sizeof(copy), fmt, argptr);
		va_end(argptr);

		/* mask off high bits */
		for (i = 0; i < length && copy[i]; i++)
			copy[i] = copy[i] & 127;
		copy[i] = '\0';
		Com_Printf("%s", copy);
	}

	cl = NULL;
	while ((cl = SV_GetNextClient(cl)) != NULL) {
		if (level > cl->messagelevel)
			continue;
		if (cl->state < cs_connected)
			continue;
		NET_WriteConstMsg(cl->stream, msg);
	}

	free_dbuffer(msg);
}
Ejemplo n.º 16
0
/**
 * @brief Sends text across to be displayed if the level passes
 */
void SV_ClientPrintf (client_t * cl, int level, const char *fmt, ...)
{
	va_list argptr;
	struct dbuffer *msg;
	char str[1024];

	if (level > cl->messagelevel)
		return;

	msg = new_dbuffer();
	NET_WriteByte(msg, svc_print);
	NET_WriteByte(msg, level);

	va_start(argptr, fmt);
	NET_VPrintf(msg, fmt, argptr, str, sizeof(str));
	va_end(argptr);

	NET_WriteMsg(cl->stream, msg);
}
Ejemplo n.º 17
0
/**
 * @brief Responds with all the info that the server browser can see
 * @sa SV_StatusString
 */
static void SVC_Status (struct net_stream *s)
{
	client_t *cl;
	char player[1024];
	struct dbuffer *msg = new_dbuffer();
	NET_WriteByte(msg, clc_oob);
	NET_WriteRawString(msg, "print\n");

	NET_WriteRawString(msg, Cvar_Serverinfo());
	NET_WriteRawString(msg, "\n");

	cl = NULL;
	while ((cl = SV_GetNextClient(cl)) != NULL) {
		if (cl->state > cs_free) {
			Com_sprintf(player, sizeof(player), "%i \"%s\"\n", svs.ge->ClientGetTeamNum(cl->player), cl->name);
			NET_WriteRawString(msg, player);
		}
	}

	NET_WriteMsg(s, msg);
}
Ejemplo n.º 18
0
/**
 * @sa CL_ParseConfigString
 */
static void SV_Configstring (int index, const char *fmt, ...)
{
	char val[MAX_TOKEN_CHARS * MAX_TILESTRINGS];
	va_list argptr;

	if (index < 0 || index >= MAX_CONFIGSTRINGS)
		Com_Error(ERR_DROP, "configstring: bad index %i", index);

	va_start(argptr, fmt);
	Q_vsnprintf(val, sizeof(val), fmt, argptr);
	va_end(argptr);

	SV_SetConfigString(index, val);

	if (Com_ServerState() != ss_loading) { /* send the update to everyone */
		struct dbuffer *msg = new_dbuffer();
		NET_WriteByte(msg, svc_configstring);
		NET_WriteShort(msg, index);
		NET_WriteString(msg, val);

		/* send to all clients */
		SV_Multicast(~0, msg);
	}
}
Ejemplo n.º 19
0
/**
 * @brief If origin is NULL, the origin is determined from the entity origin or the midpoint of the entity box for bmodels.
 */
void SV_StartSound (int mask, const vec3_t origin, const edict_t *entity, const char *sound)
{
	vec3_t origin_v;
	struct dbuffer *msg;

	/* use the entity origin unless it is a bmodel or explicitly specified */
	if (!origin) {
		origin = origin_v;
		if (entity->solid == SOLID_BSP) {
			VectorCenterFromMinsMaxs(entity->mins, entity->maxs, origin_v);
			VectorAdd(entity->origin, origin_v, origin_v);
		} else {
			VectorCopy(entity->origin, origin_v);
		}
	}

	msg = new_dbuffer();

	NET_WriteByte(msg, svc_sound);
	NET_WriteString(msg, sound);
	NET_WritePos(msg, origin);

	SV_Multicast(mask, msg);
}
Ejemplo n.º 20
0
/**
 * @brief Used by SV_Shutdown to send a final message to all
 * connected clients before the server goes down.
 * @sa SV_Shutdown
 */
static void SV_FinalMessage (const char *message, qboolean reconnect)
{
	client_t *cl;
	struct dbuffer *msg = new_dbuffer();

	if (reconnect)
		NET_WriteByte(msg, svc_reconnect);
	else
		NET_WriteByte(msg, svc_disconnect);
	NET_WriteString(msg, message);

	cl = NULL;
	while ((cl = SV_GetNextClient(cl)) != NULL)
		if (cl->state >= cs_connected) {
			NET_WriteConstMsg(cl->stream, msg);
			NET_StreamFinished(cl->stream);
			cl->stream = NULL;
		}

	/* make sure, that this is send */
	NET_Wait(0);

	free_dbuffer(msg);
}
Ejemplo n.º 21
0
/**
 * @brief Sends the first message from the server to a connected client.
 * This will be sent on the initial connection and upon each server load.
 * Client reads via CL_ParseServerData in cl_parse.c
 * @sa CL_Reconnect_f
 * @sa CL_ConnectionlessPacket
 */
static void SV_New_f (client_t *cl)
{
	Com_DPrintf(DEBUG_SERVER, "New() from %s\n", cl->name);

	if (cl->state != cs_connected) {
		if (cl->state == cs_spawning) {
			/* client typed 'reconnect/new' while connecting. */
			Com_Printf("SV_New_f: client typed 'reconnect/new' while connecting\n");
			SV_ClientCommand(cl, "\ndisconnect\nreconnect\n");
			SV_DropClient(cl, "");
		} else
			Com_DPrintf(DEBUG_SERVER, "WARNING: Illegal 'new' from %s, client state %d. This shouldn't happen...\n", cl->name, cl->state);
		return;
	}

	/* client state to prevent multiple new from causing high cpu / overflows. */
	SV_SetClientState(cl, cs_spawning);

	/* serverdata needs to go over for all types of servers
	 * to make sure the protocol is right, and to set the gamedir */

	/* send the serverdata */
	{
		const int playernum = cl - SV_GetClient(0);
		struct dbuffer *msg = new_dbuffer();
		NET_WriteByte(msg, svc_serverdata);
		NET_WriteLong(msg, PROTOCOL_VERSION);

		NET_WriteShort(msg, playernum);

		/* send full levelname */
		NET_WriteString(msg, SV_GetConfigString(CS_NAME));

		NET_WriteMsg(cl->stream, msg);
	}

	/* game server */
	if (Com_ServerState() == ss_game) {
		int i;
		for (i = 0; i < MAX_CONFIGSTRINGS; i++) {
			const char *configString;
			/* CS_TILES and CS_POSITIONS can stretch over multiple configstrings,
			 * so don't send the middle parts again. */
			if (i > CS_TILES && i < CS_POSITIONS)
				continue;
			if (i > CS_POSITIONS && i < CS_MODELS)
				continue;

			configString = SV_GetConfigString(i);
			if (configString[0] != '\0') {
				struct dbuffer *msg = new_dbuffer();
				Com_DPrintf(DEBUG_SERVER, "sending configstring %d: %s\n", i, configString);
				NET_WriteByte(msg, svc_configstring);
				NET_WriteShort(msg, i);
				NET_WriteString(msg, configString);
				/* enqueue and free msg */
				NET_WriteMsg(cl->stream, msg);
			}
		}
	}

	SV_ClientCommand(cl, "precache\n");
}