Esempio n. 1
0
/*
===============
HTTP_StartDownload

Actually starts a download by adding it to the curl multi
handle.
===============
*/
void HTTP_StartDownload (dlhandle_t *dl)
{
	cvar_t				*hostname;
	char				escapedFilePath[2048];

	hostname = gi.cvar ("hostname", NULL, 0);
	if (!hostname)
		TDM_Error ("HTTP_StartDownload: Couldn't get hostname cvar");

	dl->tempBuffer = NULL;
	dl->speed = 0;
	dl->fileSize = 0;
	dl->position = 0;

	if (!dl->curl)
		dl->curl = curl_easy_init ();

	HTTP_EscapePath (dl->filePath, escapedFilePath);

	Com_sprintf (dl->URL, sizeof(dl->URL), "http://%s%s%s", otdm_api_ip, g_http_path->string, escapedFilePath);

	curl_easy_setopt (dl->curl, CURLOPT_HTTPHEADER, http_header_slist);	
	curl_easy_setopt (dl->curl, CURLOPT_ENCODING, "");
	curl_easy_setopt (dl->curl, CURLOPT_DEBUGFUNCTION, CURL_Debug);
	curl_easy_setopt (dl->curl, CURLOPT_VERBOSE, 1);
	curl_easy_setopt (dl->curl, CURLOPT_NOPROGRESS, 0);
	curl_easy_setopt (dl->curl, CURLOPT_WRITEDATA, dl);
	if (g_http_bind->string[0])
		curl_easy_setopt (dl->curl, CURLOPT_INTERFACE, g_http_bind->string);
	else
		curl_easy_setopt (dl->curl, CURLOPT_INTERFACE, NULL);

	curl_easy_setopt (dl->curl, CURLOPT_WRITEFUNCTION, HTTP_Recv);

	if (g_http_proxy->string[0])
		curl_easy_setopt (dl->curl, CURLOPT_PROXY, g_http_proxy->string);
	else
		curl_easy_setopt (dl->curl, CURLOPT_PROXY, NULL);
	curl_easy_setopt (dl->curl, CURLOPT_FOLLOWLOCATION, 1);
	curl_easy_setopt (dl->curl, CURLOPT_MAXREDIRS, 5);
	curl_easy_setopt (dl->curl, CURLOPT_WRITEHEADER, dl);
	curl_easy_setopt (dl->curl, CURLOPT_HEADERFUNCTION, HTTP_Header);
	curl_easy_setopt (dl->curl, CURLOPT_PROGRESSDATA, dl);
	curl_easy_setopt (dl->curl, CURLOPT_USERAGENT, "OpenTDM (" OPENTDM_VERSION ")");
	curl_easy_setopt (dl->curl, CURLOPT_REFERER, hostname->string);
	curl_easy_setopt (dl->curl, CURLOPT_URL, dl->URL);

	if (curl_multi_add_handle (multi, dl->curl) != CURLM_OK)
	{
		gi.dprintf ("HTTP_StartDownload: curl_multi_add_handle: error\n");
		return;
	}

	handleCount++;
}
Esempio n. 2
0
/*
==============
TDM_AddPlayerToMatchinfo
==============
A new player joined mid-match (invite / etc), update teamplayerinfo to reflect this.
*/
void TDM_AddPlayerToMatchinfo (edict_t *ent)
{
	int				i;
	teamplayer_t	*new_teamplayers;

	if (!current_matchinfo.teamplayers)
		TDM_Error ("TDM_AddPlayerToMatchinfo: no teamplayers");

	//allocate a new teamplayers array
	new_teamplayers = gi.TagMalloc (sizeof(teamplayer_t) * (current_matchinfo.num_teamplayers + 1), TAG_GAME);
	memcpy (new_teamplayers, current_matchinfo.teamplayers, sizeof(teamplayer_t) * current_matchinfo.num_teamplayers);

	//setup this client
	TDM_SetupTeamInfoForPlayer (ent, new_teamplayers + current_matchinfo.num_teamplayers);

	//fix up pointers on existing clients and other things that reference teamplayers. NASTY!
	for (i = 0; i < current_matchinfo.num_teamplayers; i++)
	{
		if (current_matchinfo.captains[TEAM_A] == current_matchinfo.teamplayers + i)
			current_matchinfo.captains[TEAM_A] = new_teamplayers + i;
		else if (current_matchinfo.captains[TEAM_B] == current_matchinfo.teamplayers + i)
			current_matchinfo.captains[TEAM_B] = new_teamplayers + i;

		if (level.tdm_timeout_caller == current_matchinfo.teamplayers + i)
			level.tdm_timeout_caller = new_teamplayers + i;

		//might not have a current client (disconnected)
		if (current_matchinfo.teamplayers[i].client)
			current_matchinfo.teamplayers[i].client->client->resp.teamplayerinfo = new_teamplayers + i;
	}

	//remove old memory
	gi.TagFree (current_matchinfo.teamplayers);

	//move everything to new
	current_matchinfo.teamplayers = new_teamplayers;
	current_matchinfo.num_teamplayers++;
}
Esempio n. 3
0
void ParseEntityString (qboolean respawn)
{
	edict_t		*ent;
	int			inhibit;
	const char	*com_token;
	const char	*entities;
	int			i;

	entities = level.entity_string;

	ent = NULL;
	inhibit = 0;
	i = 0;

	//mark all the spawned_entities as inuse so G_Spawn doesn't try to pick them during
	//trigger spawning etc
	for (i = 0; i < num_spawned_entities; i++)
		spawned_entities[i]->inuse = true;

	i = 0;

// parse ents
	while (1)
	{
		// parse the opening brace	
		com_token = COM_Parse (&entities);
		if (!entities)
			break;
		if (com_token[0] != '{')
			gi.error ("ED_LoadFromFile: found %s when expecting {",com_token);

		if (respawn)
		{
			ent = spawned_entities[i];
			if (ent != world)
			{
				//double check we aren't overwriting stuff that we shouldn't be
				if (ent->enttype == ENT_DOOR_TRIGGER || ent->enttype == ENT_PLAT_TRIGGER)
					TDM_Error ("ParseEntityString: Trying to reuse an already spawned ent!");
				G_FreeEdict (ent);
				G_InitEdict (ent);
			}
			i++;
		}
		else
		{
			if (!ent)
				ent = g_edicts;
			else
				ent = G_Spawn ();
		}
		entities = ED_ParseEdict (entities, ent);

		// yet another map hack
		if (!Q_stricmp(level.mapname, "command") && !Q_stricmp(ent->classname, "trigger_once") && !Q_stricmp(ent->model, "*27"))
			ent->spawnflags &= ~SPAWNFLAG_NOT_HARD;

		// remove things (except the world) from different skill levels or deathmatch
		if (ent != g_edicts)
		{
			if ( ent->spawnflags & SPAWNFLAG_NOT_DEATHMATCH )
			{
				G_FreeEdict (ent);	
				inhibit++;

				//have to keep num_spawned in sync for respawn
				if (!respawn)
					spawned_entities[num_spawned_entities++] = ent;
				continue;
			}

			ent->spawnflags &= ~(SPAWNFLAG_NOT_EASY|SPAWNFLAG_NOT_MEDIUM|SPAWNFLAG_NOT_HARD|SPAWNFLAG_NOT_COOP|SPAWNFLAG_NOT_DEATHMATCH);
		}
		else if (respawn)
			continue;

		ED_CallSpawn (ent);

		if (!respawn)
		{
			if (num_spawned_entities == MAX_EDICTS * 4)
				TDM_Error ("Exceeded MAX_EDICTS * 4 entities during entity string parse");
			spawned_entities[num_spawned_entities++] = ent;
		}
		else
		{
			//an elevator or something respawned on top of a player? don't do it for match start, since
			//players will be respawning anyway.
			if (tdm_match_status < MM_PLAYING && (ent->solid == SOLID_BBOX || ent->solid == SOLID_BSP))
			{
				edict_t	*touch[MAX_EDICTS];
				int		count;
				int		j;

				//r1: fix 00000196, can't killbox during map spawn due to risk of killing half-spawned
				//map entities. do a pseudo-killbox that only whacks players instead.

				count = gi.BoxEdicts (ent->absmin, ent->absmax, touch, MAX_EDICTS, AREA_SOLID);
				for (j = 0; j < count; j++)
				{
					if (touch[j] == ent)
						continue;

					//no point killing anything that won't clip (eg corpses)
					if (touch[j]->solid == SOLID_NOT || touch[j]->enttype == ENT_BODYQUE)
						continue;

					if (!touch[j]->client)
						continue;

					if (touch[j]->inuse)
						T_Damage (touch[j], ent, ent, vec3_origin, ent->s.origin, vec3_origin, 100000, 0, DAMAGE_NO_PROTECTION, MOD_TELEFRAG);
				}
			}
		}
	}

	//gi.dprintf ("%i entities inhibited\n", inhibit);

#ifdef DEBUG
	i = 1;
	ent = EDICT_NUM(i);
	while (i < globals.num_edicts) {
		if (ent->inuse != 0 || ent->inuse != 1)
			Com_DPrintf("Invalid entity %d\n", i);
		i++, ent++;
	}
#endif

	G_FindTeams ();
}
Esempio n. 4
0
/*
==============
TDM_GetPlayerIdView
==============
Find the best player for the id view and return a configstring index that contains their info.
*/
int TDM_GetPlayerIdView (edict_t *ent)
{
	edict_t		*ignore;
	edict_t		*target;
	vec3_t		forward;
	trace_t		tr;
	vec3_t		start;
	vec3_t		mins = {-4,-4,-4};
	vec3_t		maxs = {4,4,4};
	qboolean	ignoreConfigStringUpdate;
	int			i;
	int			powerarmor;
	qboolean	show_health_info;

	ignoreConfigStringUpdate = false;

	if (ent->client->chase_target)
	{
		target = ent->client->chase_target->client->resp.last_id_client;
	}
	else
	{
		int	tracemask;

		VectorCopy (ent->s.origin, start);
		start[2] += ent->viewheight;

		AngleVectors (ent->client->v_angle, forward, NULL, NULL);

		VectorScale (forward, 4096, forward);
		VectorAdd (ent->s.origin, forward, forward);

		ignore = ent;

		target = NULL;

		tracemask = CONTENTS_SOLID|CONTENTS_MONSTER|MASK_WATER;

		//find best player through tracing
		for (i = 0; i < 10; i++)
		{
			tr = gi.trace (start, mins, maxs, forward, ignore, tracemask);

			//hit transparent water
			if (tr.ent == world && tr.surface && (tr.surface->flags & (SURF_TRANS33|SURF_TRANS66)))
			{
				tracemask &= ~MASK_WATER;
				VectorCopy (tr.endpos, start);
				continue;
			}

			if (tr.ent == world || tr.fraction == 1.0f)
				break;

			//we hit something that's a player and it's alive and on our team!
			//note, we trace twice so we hit water planes
			if (tr.ent && tr.ent->client && tr.ent->health > 0 && visible (tr.ent, ent, CONTENTS_SOLID | MASK_WATER))
			{
				target = tr.ent;
				break;
			}
			else
			{
				VectorCopy (tr.endpos, start);
				ignore = tr.ent;
			}
		}

		//if trace was unsuccessful, try guessing based on angles
		if (!target)
		{
			edict_t		*who, *best;
			vec3_t		dir;
			float		distance, bdistance = 0.0f;
			float		bd = 0.0f, d;

			AngleVectors (ent->client->v_angle, forward, NULL, NULL);
			best = NULL;

			for (who = g_edicts + 1; who <= g_edicts + game.maxclients; who++)
			{
				if (!who->inuse)
					continue;

				if (who->health <= 0)
					continue;

				if (who == ent)
					continue;

				VectorSubtract (who->s.origin, ent->s.origin, dir);
				distance = VectorLength (dir);

				VectorNormalize (dir);
				d = DotProduct (forward, dir);

				//note, we trace twice so we hit water planes
				if (d > bd && visible (ent, who, CONTENTS_SOLID | MASK_WATER) && visible (who, ent, CONTENTS_SOLID | MASK_WATER))
				{
					bdistance = distance;
					bd = d;
					best = who;
				}
			}

			if (best)
			{
				if (!best->client->pers.team)
					TDM_Error ("TDM_GetPlayerIdView: Got a spectator via DotProduct with %d health (%s)", best->health, best->client->pers.netname);
				//allow variable slop based on proximity
				if ((bdistance < 150 && bd > 0.50f) || (bdistance < 250 && bd > 0.90f) || (bdistance < 600 && bd > 0.96f) || bd > 0.98f)
					target = best;
			}
		}
		else if (!target->client->pers.team)
			TDM_Error ("TDM_GetPlayerIdView: Got a spectator via trace with %d health (%s)", target->health, target->client->pers.netname);
	}

	if (!target)
		return 0;

	show_health_info = false;

	if (ent->client->pers.team == target->client->pers.team)
	{
		//same team, show health info
		show_health_info = true;
	}
	else if (ent->client->pers.team == TEAM_SPEC)
	{
		/*if (!ent->client->chase_target)
		{
			//free floating camera, DON'T show health info
			show_health_info = false;
		}
		else */
		if (ent->client->chase_target && ent->client->chase_target->client->pers.team == target->client->pers.team)
		{
			//viewing someone on the same team as our chase target, show health info
			show_health_info = true;
		}
	}

	//check for power armor
	if (target->client->inventory[ITEM_ITEM_POWER_SCREEN] > 0 || target->client->inventory[ITEM_ITEM_POWER_SHIELD] > 0)
		powerarmor = target->client->inventory[ITEM_AMMO_CELLS];
	else
		powerarmor = -1;

	//don't spam configstring if they haven't changed since last time
	if (ent->client->resp.last_id_client == target &&
		ent->client->resp.last_id_health == target->health &&
		ent->client->resp.last_id_armor == TDM_GetArmorValue (target) &&
		ent->client->resp.last_id_powerarmor == powerarmor)
		ignoreConfigStringUpdate = true;

	ent->client->resp.last_id_client = target;
	ent->client->resp.last_id_health = target->health;
	ent->client->resp.last_id_armor = TDM_GetArmorValue (target);
	ent->client->resp.last_id_powerarmor = powerarmor;

	if (!ignoreConfigStringUpdate)
	{
		char	*string;

		if (show_health_info)
		{
			char	buff[16];

			//show power armor if they have it
			if (powerarmor != -1)
				sprintf (buff, " P:%d", powerarmor);
			else
				buff[0] = '\0';

			if (ent->client->pers.config.id_highlight)
				string = TDM_SetColorText (va ("%16s H:%d A:%d%s",
						target->client->pers.netname,
						target->health,
						TDM_GetArmorValue (target),
						buff));
			else
				string = va ("%16s H:%d A:%d%s",
						target->client->pers.netname,
						target->health,
						TDM_GetArmorValue (target),
						buff);
		}
		else
		{
			if (ent->client->pers.config.id_highlight)
				string = TDM_SetColorText (va ("%16s", target->client->pers.netname));
			else
				string = va ("%16s", target->client->pers.netname);
		}

		gi.WriteByte (SVC_CONFIGSTRING);
		gi.WriteShort (CS_TDM_ID_VIEW);
		gi.WriteString (string);
		gi.unicast (ent, false);
	}

	return target - g_edicts;
}
Esempio n. 5
0
/*
===============
CL_FinishHTTPDownload

A download finished, find out what it was, whether there were any errors and
if so, how severe. If none, rename file and other such stuff.
===============
*/
static void HTTP_FinishDownload (void)
{
	int			msgs_in_queue;
	CURLMsg		*msg;
	CURLcode	result;
	dlhandle_t	*dl;
	CURL		*curl;
	long		responseCode;
	double		timeTaken;
	double		fileSize;
	unsigned	i;

	do
	{
		msg = curl_multi_info_read (multi, &msgs_in_queue);

		if (!msg)
		{
			gi.dprintf ("HTTP_FinishDownload: Odd, no message for us...\n");
			return;
		}

		if (msg->msg != CURLMSG_DONE)
		{
			gi.dprintf ("HTTP_FinishDownload: Got some weird message...\n");
			continue;
		}

		curl = msg->easy_handle;

		for (i = 0; i < MAX_DOWNLOADS; i++)
		{
			if (downloads[i].curl == curl)
				break;
		}

		if (i == MAX_DOWNLOADS)
			TDM_Error ("HTTP_FinishDownload: Handle not found!");

		dl = &downloads[i];

		result = msg->data.result;

		switch (result)
		{
			//for some reason curl returns CURLE_OK for a 404...
			case CURLE_HTTP_RETURNED_ERROR:
			case CURLE_OK:
			
				curl_easy_getinfo (curl, CURLINFO_RESPONSE_CODE, &responseCode);
				if (responseCode == 404)
				{
					TDM_HandleDownload (dl->tdm_handle, NULL, 0, responseCode);
					gi.dprintf ("HTTP: %s: 404 File Not Found\n", dl->URL);
					curl_multi_remove_handle (multi, dl->curl);
					dl->inuse = false;
					continue;
				}
				else if (responseCode == 200)
				{
					TDM_HandleDownload (dl->tdm_handle, dl->tempBuffer, dl->position, responseCode);
					gi.TagFree (dl->tempBuffer);
				}
				else
				{
					TDM_HandleDownload (dl->tdm_handle, NULL, 0, responseCode);
					if (dl->tempBuffer)
						gi.TagFree (dl->tempBuffer);
				}
				break;

			//fatal error
			default:
				TDM_HandleDownload (dl->tdm_handle, NULL, 0, 0);
				gi.dprintf ("HTTP Error: %s: %s\n", dl->URL, curl_easy_strerror (result));
				curl_multi_remove_handle (multi, dl->curl);
				dl->inuse = false;
				continue;
		}

		//show some stats
		curl_easy_getinfo (curl, CURLINFO_TOTAL_TIME, &timeTaken);
		curl_easy_getinfo (curl, CURLINFO_SIZE_DOWNLOAD, &fileSize);

		//FIXME:
		//technically i shouldn't need to do this as curl will auto reuse the
		//existing handle when you change the URL. however, the handleCount goes
		//all weird when reusing a download slot in this way. if you can figure
		//out why, please let me know.
		curl_multi_remove_handle (multi, dl->curl);

		dl->inuse = false;

		gi.dprintf ("HTTP: Finished %s: %.f bytes, %.2fkB/sec\n", dl->URL, fileSize, (fileSize / 1024.0) / timeTaken);
	} while (msgs_in_queue > 0);
}