示例#1
0
/*
 * Sv_Begin_f
 */
static void Sv_Begin_f(void) {

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

	if (sv_client->state != SV_CLIENT_CONNECTED) { // catch duplicate spawns
		Com_Warn("Sv_Begin_f: Invalid Begin() from %s\n",
				Sv_NetaddrToString(sv_client));
		Sv_KickClient(sv_client, NULL);
		return;
	}

	if (sv.state == SV_ACTIVE_DEMO)
		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_Begin_f: Stale spawn count from %s\n",
				Sv_NetaddrToString(sv_client));
		Sv_New_f();
		return;
	}

	sv_client->state = SV_CLIENT_ACTIVE;

	// call the game begin function
	svs.game->ClientBegin(sv_player);

	Cbuf_InsertFromDefer();
}
示例#2
0
/*
 * @brief Handles the actual loading of .ogg music files.
 */
static _Bool S_LoadMusicFile(const char *name, void **buffer, SDL_RWops **rw, Mix_Music **music) {
	char path[MAX_QPATH];

	*music = NULL;

	StripExtension(name, path);
	g_snprintf(path, sizeof(path), "music/%s.ogg", name);

	int32_t len;
	if ((len = Fs_Load(path, buffer)) != -1) {

		if ((*rw = SDL_RWFromMem(*buffer, len))) {

			if ((*music = Mix_LoadMUS_RW(*rw))) {
				Com_Debug("Loaded %s\n", name);
			} else {
				Com_Warn("Failed to load %s: %s\n", name, Mix_GetError());
				SDL_FreeRW(*rw);
			}
		} else {
			Com_Warn("Failed to create SDL_RWops for %s\n", name);
			Fs_Free(*buffer);
		}
	} else {
		Com_Debug("Failed to load %s\n", name);
	}

	return *music != NULL;
}
示例#3
0
/**
 * @brief Inserts the specified media into the shared table.
 */
void S_RegisterMedia(s_media_t *media) {

	// check to see if we're already seeded
	if (media->seed != s_media_state.seed) {
		s_media_t *m;

		if ((m = g_hash_table_lookup(s_media_state.media, media->name))) {
			if (m != media) {
				Com_Debug(DEBUG_SOUND, "Replacing %s\n", media->name);
				S_FreeMedia_(NULL, m, m);
				g_hash_table_replace(s_media_state.media, media->name, media);
			} else {
				Com_Debug(DEBUG_SOUND, "Retaining %s\n", media->name);
			}
		} else {
			Com_Debug(DEBUG_SOUND, "Inserting %s\n", media->name);
			g_hash_table_insert(s_media_state.media, media->name, media);

			s_media_state.keys = g_list_insert_sorted(s_media_state.keys, media->name,
			                     S_RegisterMedia_Compare);
		}

		// re-seed the media to retain it
		media->seed = s_media_state.seed;
	}

	// finally re-register all dependencies
	GList *d = media->dependencies;
	while (d) {
		S_RegisterMedia((s_media_t *) d->data);
		d = d->next;
	}
}
示例#4
0
/*
 * @brief
 */
static void S_LoadSampleChunk(s_sample_t *sample) {
	char path[MAX_QPATH];
	void *buf;
	int32_t i, len;
	SDL_RWops *rw;

	if (sample->media.name[0] == '*') // place holder
		return;

	if (sample->media.name[0] == '#') { // global path
		g_strlcpy(path, (sample->media.name + 1), sizeof(path));
	} else { // or relative
		g_snprintf(path, sizeof(path), "sounds/%s", sample->media.name);
	}

	buf = NULL;
	rw = NULL;

	i = 0;
	while (SAMPLE_TYPES[i]) {

		StripExtension(path, path);
		g_strlcat(path, SAMPLE_TYPES[i++], sizeof(path));

		if ((len = Fs_Load(path, &buf)) == -1)
			continue;

		if (!(rw = SDL_RWFromMem(buf, len))) {
			Fs_Free(buf);
			continue;
		}

		if (!(sample->chunk = Mix_LoadWAV_RW(rw, false)))
			Com_Warn("%s\n", Mix_GetError());

		Fs_Free(buf);

		SDL_FreeRW(rw);

		if (sample->chunk) { // success
			break;
		}
	}

	if (sample->chunk) {
		Mix_VolumeChunk(sample->chunk, s_volume->value * MIX_MAX_VOLUME);
		Com_Debug("Loaded %s\n", path);
	} else {
		if (g_str_has_prefix(sample->media.name, "#players")) {
			Com_Debug("Failed to load player sample %s\n", sample->media.name);
		} else {
			Com_Warn("Failed to load %s\n", sample->media.name);
		}
	}
}
示例#5
0
/*
 * @brief Marks all nodes that can be reached by entites
 */
_Bool FloodEntities(tree_t *tree) {
    int32_t i;
    vec3_t origin;
    const char *cl;
    _Bool inside;
    node_t *head_node;

    head_node = tree->head_node;
    Com_Debug("--- FloodEntities ---\n");
    inside = false;
    tree->outside_node.occupied = 0;
    cl = "";

    for (i = 1; i < num_entities; i++) {
        GetVectorForKey(&entities[i], "origin", origin);
        if (VectorCompare(origin, vec3_origin))
            continue;

        cl = ValueForKey(&entities[i], "classname");
        origin[2] += 1; // so objects on floor are ok

        // nudge playerstart around if needed so clipping hulls always
        // have a valid point
        if (!g_strcmp0(cl, "info_player_start")) {
            int32_t x, y;

            for (x = -16; x <= 16; x += 16) {
                for (y = -16; y <= 16; y += 16) {
                    origin[0] += x;
                    origin[1] += y;
                    if (PlaceOccupant(head_node, origin, &entities[i])) {
                        inside = true;
                        goto gotit;
                    }
                    origin[0] -= x;
                    origin[1] -= y;
                }
            }
gotit:
            ;
        } else {
            if (PlaceOccupant(head_node, origin, &entities[i]))
                inside = true;
        }
    }

    if (!inside) {
        Com_Debug("no entities in open -- no filling\n");
    } else if (tree->outside_node.occupied) {
        Com_Debug("entity %s reached from outside -- no filling\n", cl);
    }

    return inside && !tree->outside_node.occupied;
}
示例#6
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));
	}
}
示例#7
0
/*
 * @brief Plays the next track in the configured playlist.
 */
void S_NextTrack_f(void) {

	if (s_music_volume->value) {
		s_music_t *music = S_NextMusic();

		if (music) {
			S_PlayMusic(music);
		} else {
			Com_Debug("No music available\n");
		}
	} else {
		Com_Debug("Music is muted\n");
	}
}
示例#8
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));
	}
}
示例#9
0
/*
 * @brief Initializes the client console.
 */
void Cl_InitConsole(void) {

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

	cl_console.Append = Cl_Print;

	Con_AddConsole(&cl_console);

	file_t *file = Fs_OpenRead("history");
	if (file) {
		Con_ReadHistory(&cl_console, file);
		Fs_Close(file);
	} else {
		Com_Debug("Couldn't read history");
	}

	memset(&cl_chat_console, 0, sizeof(cl_chat_console));
	cl_chat_console.level = PRINT_CHAT | PRINT_TEAM_CHAT;
	
	cl_draw_chat = Cvar_Get("cl_draw_chat", "1", 0, "Draw recent chat messages");
	cl_draw_notify = Cvar_Get("cl_draw_notify", "1", 0, "Draw recent console activity");

	cl_notify_lines = Cvar_Get("cl_console_notify_lines", "3", CVAR_ARCHIVE, NULL);
	cl_notify_time = Cvar_Get("cl_notify_time", "3.0", CVAR_ARCHIVE, NULL);

	cl_chat_lines = Cvar_Get("cl_chat_lines", "3", CVAR_ARCHIVE, NULL);
	cl_chat_time = Cvar_Get("cl_chat_time", "10.0", CVAR_ARCHIVE, NULL);

	Cmd_Add("cl_toggle_console", Cl_ToggleConsole_f, CMD_SYSTEM | CMD_CLIENT, "Toggle the console");
	Cmd_Add("cl_message_mode", Cl_MessageMode_f, CMD_CLIENT, "Activate chat");
	Cmd_Add("cl_message_mode_2", Cl_MessageMode2_f, CMD_CLIENT, "Activate team chat");

	Com_Print("Client console initialized\n");
}
示例#10
0
/**
 * @brief Entry point for client-side prediction. For each server frame, run
 * the player movement code with the user commands we've sent to the server
 * but have not yet received acknowledgment for. Store the resulting move so
 * that it may be interpolated into by Cl_UpdateView.
 *
 * Most of the work is passed off to the client game, which is responsible for
 * the implementation Pm_Move.
 */
void Cl_PredictMovement(void) {

	if (!cls.cgame->UsePrediction()) {
		return;
	}

	const uint32_t last = cls.net_chan.outgoing_sequence;
	uint32_t ack = cls.net_chan.incoming_acknowledged;

	// if we are too far out of date, just freeze in place
	if (last - ack >= CMD_BACKUP) {
		Com_Debug(DEBUG_CLIENT, "Exceeded CMD_BACKUP\n");
		return;
	}

	GList *cmds = NULL;

	while (++ack <= last) {
		cmds = g_list_append(cmds, &cl.cmds[ack & CMD_MASK]);
	}

	cls.cgame->PredictMovement(cmds);

	g_list_free(cmds);
}
示例#11
0
/*
 * @brief Checks for client side prediction errors. Problems here can indicate
 * that Pm_Move or the protocol are not functioning correctly.
 */
void Cl_CheckPredictionError(void) {
	vec3_t delta;

	VectorClear(cl.predicted_state.error);

	if (!Cl_UsePrediction())
		return;

	// calculate the last user_cmd_t we sent that the server has processed
	const uint32_t frame = (cls.net_chan.incoming_acknowledged & CMD_MASK);

	// compare what the server returned with what we had predicted it to be
	VectorSubtract(cl.frame.ps.pm_state.origin, cl.predicted_state.origins[frame], delta);

	const vec_t error = VectorLength(delta);
	if (error > 1.0) {
		Com_Debug("%s\n", vtos(delta));

		if (error > 256.0) { // do not interpolate
			VectorClear(delta);
		}
	}

	VectorCopy(delta, cl.predicted_state.error);
}
示例#12
0
文件: cl_loc.c 项目: darkshade9/aq2w
/*
 * Cl_LoadLocations
 *
 * Parse a .loc file for the current level.
 */
void Cl_LoadLocations(void) {
	const char *c;
	char file_name[MAX_QPATH];
	FILE *f;
	int i;

	Cl_ClearLocations(); // clear any resident locations
	i = 0;

	// load the locations file
	c = Basename(cl.config_strings[CS_MODELS + 1]);
	snprintf(file_name, sizeof(file_name), "locations/%s", c);
	strcpy(file_name + strlen(file_name) - 3, "loc");

	if (Fs_OpenFile(file_name, &f, FILE_READ) == -1) {
		Com_Debug("Couldn't load %s\n", file_name);
		return;
	}

	while (i < MAX_LOCATIONS) {

		const int err = fscanf(f, "%f %f %f %[^\n]", &locations[i].loc[0],
				&locations[i].loc[1], &locations[i].loc[2], locations[i].desc);

		num_locations = i;
		if (err == EOF)
			break;
		i++;
	}

	Cl_LoadProgress(100);

	Com_Print("Loaded %i locations.\n", num_locations);
	Fs_CloseFile(f);
}
示例#13
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));
}
示例#14
0
/*
 * @brief Updates the interpolation fraction for the current client frame.
 * Because the client typically runs at a higher framerate than the server, we
 * use linear interpolation between the last 2 server frames. We aim to reach
 * the current server time just as a new packet arrives.
 */
static void Cl_UpdateLerp(const cl_frame_t *from) {

	if (time_demo->value) {
		cl.time = cl.frame.time;
		cl.lerp = 1.0;
		return;
	}

	if (cl.time > cl.frame.time) {
		// Com_Debug("High clamp: %dms\n", cl.time - cl.frame.time);
		cl.time = cl.frame.time;
		cl.lerp = 1.0;
	} else if (cl.time < from->time) {
		// Com_Debug("Low clamp: %dms\n", from->time - cl.time);
		cl.time = from->time;
		cl.lerp = 0.0;
	} else {
		const uint32_t delta = cl.time - from->time;
		const uint32_t interval = cl.frame.time - from->time;

		if (interval == 0) {
			Com_Debug("Bad clamp\n");
			cl.time = cl.frame.time;
			cl.lerp = 1.0;
			return;
		}

		cl.lerp = delta / (vec_t) interval;
	}
}
示例#15
0
/*
 * @brief Loads the music by the specified name.
 */
s_music_t *S_LoadMusic(const char *name) {
	char key[MAX_QPATH];
	s_music_t *music;

	StripExtension(name, key);

	if (!(music = (s_music_t *) S_FindMedia(key))) {

		void *buffer;
		SDL_RWops *rw;
		Mix_Music *mus;
		if (S_LoadMusicFile(key, &buffer, &rw, &mus)) {

			music = (s_music_t *) S_AllocMedia(key, sizeof(s_music_t));

			music->media.Retain = S_RetainMusic;
			music->media.Free = S_FreeMusic;

			music->buffer = buffer;
			music->rw = rw;
			music->music = mus;

			S_RegisterMedia((s_media_t *) music);
		} else {
			Com_Debug("S_LoadMusic: Couldn't load %s\n", key);
			music = NULL;
		}
	}

	if (music) {
		s_music_state.playlist = g_list_append(s_music_state.playlist, music);
	}

	return music;
}
示例#16
0
/*
 * @brief A connection-less packet has four leading 0xff bytes to distinguish
 * it from a game channel. Clients that are in the game can still send these,
 * and they will be handled here.
 */
static void Sv_ConnectionlessPacket(void) {

	Net_BeginReading(&net_message);
	Net_ReadLong(&net_message); // skip the -1 marker

	const char *s = Net_ReadStringLine(&net_message);

	Cmd_TokenizeString(s);

	const char *c = Cmd_Argv(0);
	const char *a = Net_NetaddrToString(&net_from);

	Com_Debug("Packet from %s: %s\n", a, c);

	if (!g_strcmp0(c, "ping"))
		Svc_Ping();
	else if (!g_strcmp0(c, "ack"))
		Svc_Ack();
	else if (!g_strcmp0(c, "status"))
		Svc_Status();
	else if (!g_strcmp0(c, "info"))
		Svc_Info();
	else if (!g_strcmp0(c, "get_challenge"))
		Svc_GetChallenge();
	else if (!g_strcmp0(c, "connect"))
		Svc_Connect();
	else if (!g_strcmp0(c, "rcon"))
		Svc_RemoteCommand();
	else
		Com_Print("Bad connectionless packet from %s:\n%s\n", a, s);
}
示例#17
0
/*
 * @brief
 */
static void Cl_KeyDown(cl_button_t *b) {
	SDL_Scancode k;

	const char *c = Cmd_Argv(1);
	if (c[0])
		k = atoi(c);
	else
		k = SDL_NUM_SCANCODES; // typed manually at the console for continuous down

	if (k == b->keys[0] || k == b->keys[1])
		return; // repeating key

	if (b->keys[0] == SDL_SCANCODE_UNKNOWN)
		b->keys[0] = k;
	else if (b->keys[1] == SDL_SCANCODE_UNKNOWN)
		b->keys[1] = k;
	else {
		Com_Debug("3 keys down for button\n");
		return;
	}

	if (b->state & 1)
		return; // still down

	// save the down time so that we can calculate fractional time later
	const char *t = Cmd_Argv(2);
	b->down_time = atoi(t);
	if (!b->down_time)
		b->down_time = cls.real_time;

	b->state |= 1;
}
示例#18
0
static void R_LoadHeightmap(const char *name, const SDL_Surface *surf) {
	char heightmap[MAX_QPATH];

	g_strlcpy(heightmap, name, sizeof(heightmap));
	char *c = strrchr(heightmap, '_');
	if (c) {
		*c = '\0';
	}

	SDL_Surface *hsurf;
	if (Img_LoadImage(va("%s_h", heightmap), &hsurf)) {

		if (hsurf->w == surf->w && hsurf->h == surf->h) {
			Com_Debug("Merging heightmap %s\n", heightmap);

			byte *in = hsurf->pixels;
			byte *out = surf->pixels;

			const size_t len = surf->w * surf->h;
			for (size_t i = 0; i < len; i++, in += 4, out += 4) {
				out[3] = (in[0] + in[1] + in[2]) / 3.0;
			}
		} else {
			Com_Warn("Incorrect heightmap resolution for %s\n", name);
		}

		SDL_FreeSurface(hsurf);
	}
}
示例#19
0
文件: sys.c 项目: darkshade9/aq2w
/*
 * Sys_FindFirst
 *
 * Returns the first full path name matched by the specified search path in
 * the Quake file system.  Wildcards are partially supported.
 */
const char *Sys_FindFirst(const char *path) {
	struct dirent *d;
	char *p;

	if (fdir) {
		Com_Debug("Sys_FindFirst without Sys_FindClose");
		Sys_FindClose();
	}

	strcpy(findbase, path);

	if ((p = strrchr(findbase, '/')) != NULL) {
		*p = 0;
		strcpy(findpattern, p + 1);
	} else
		strcpy(findpattern, "*");

	if (strcmp(findpattern, "*.*") == 0)
		strcpy(findpattern, "*");

	if ((fdir = opendir(findbase)) == NULL)
		return NULL;

	while ((d = readdir(fdir)) != NULL) {
		if (!*findpattern || GlobMatch(findpattern, d->d_name)) {
			sprintf(findpath, "%s/%s", findbase, d->d_name);
			return findpath;
		}
	}
	return NULL;
}
示例#20
0
/*
 * @brief
 */
void Cl_ParseServers(void) {
	cl_server_info_t *server;

	byte *buffptr = net_message.data + 12;
	byte *buffend = buffptr + net_message.size - 12;

	// parse the list
	while (buffptr + 1 < buffend) {
		net_addr_t addr;
		byte ip[4];

		ip[0] = *buffptr++; // parse the address
		ip[1] = *buffptr++;
		ip[2] = *buffptr++;
		ip[3] = *buffptr++;

		uint16_t port = (*buffptr++) << 8; // and the port
		port += *buffptr++;

		char s[32];
		g_snprintf(s, sizeof(s), "%d.%d.%d.%d:%d", ip[0], ip[1], ip[2], ip[3], port);

		Com_Debug("Parsed %s\n", s);

		if (!Net_StringToNetaddr(s, &addr)) { // make sure it's valid
			Com_Warn("Invalid address: %s\n", s);
			break;
		}

		if (!addr.port) // 0's mean we're done
			break;

		server = Cl_ServerForNetaddr(&addr);

		if (!server)
			server = Cl_AddServer(&addr);

		server->source = SERVER_SOURCE_INTERNET;
	}

	net_message.read = net_message.size;

	// then ping them

	GList *e = cls.servers;

	while (e) {
		server = (cl_server_info_t *) e->data;

		if (server->source == SERVER_SOURCE_INTERNET) {
			server->ping_time = cls.real_time;
			server->ping = 0;

			Netchan_OutOfBandPrint(NS_UDP_CLIENT, &server->addr, "info %i", PROTOCOL_MAJOR);
		}

		e = e->next;
	}
}
示例#21
0
/**
 * @brief Adds an illumination with the given parameters.
 */
static void R_AddIllumination(const r_illumination_t *il) {

	if (r_illuminations.num_illuminations == LIGHTING_MAX_ILLUMINATIONS) {
		Com_Debug(DEBUG_RENDERER, "LIGHTING_MAX_ILLUMINATIONS\n");
		return;
	}

	r_illuminations.illuminations[r_illuminations.num_illuminations++] = *il;
}
示例#22
0
文件: sv_main.c 项目: darkshade9/aq2w
/*
 * Sv_Frame
 */
void Sv_Frame(unsigned int msec) {
	unsigned int frame_millis;

	// if server is not active, do nothing
	if (!svs.initialized)
		return;

	// update time reference
	svs.real_time += msec;

	// keep the random time dependent
	rand();

	// check timeouts
	Sv_CheckTimeouts();

	// get packets from clients
	Sv_ReadPackets();

	frame_millis = 1000 / svs.frame_rate;

	// keep the game module's time in sync with reality
	if (!time_demo->value && svs.real_time < sv.time) {

		// if the server has fallen far behind the game, try to catch up
		if (sv.time - svs.real_time > frame_millis) {
			Com_Debug("Sv_Frame: Low clamp: %dms.\n",
					(sv.time - svs.real_time - frame_millis));
			svs.real_time = sv.time - frame_millis;
		} else { // wait until its time to run the next frame
			Net_Sleep(sv.time - svs.real_time);
			return;
		}
	}

	// update ping based on the last known frame from all clients
	Sv_UpdatePings();

	// give the clients some timeslices
	Sv_CheckCommandTimes();

	// let everything in the world think and move
	Sv_RunGameFrame();

	// send messages back to the clients that had packets read this frame
	Sv_SendClientMessages();

	// send a heartbeat to the master if needed
	Sv_HeartbeatMasters();

	// clear entity flags, etc for next frame
	Sv_ResetEntities();

#ifdef HAVE_CURSES
	Curses_Frame(msec);
#endif
}
示例#23
0
/*
 * @brief Merges the portal visibility for a leaf.
 */
static void ClusterMerge(uint32_t leaf_num) {
	leaf_t *leaf;
	byte portalvector[MAX_BSP_PORTALS / 8];
	byte uncompressed[MAX_BSP_LEAFS / 8];
	byte compressed[MAX_BSP_LEAFS / 8];
	uint32_t i, j;
	int32_t numvis;
	byte *dest;
	portal_t *p;
	int32_t pnum;

	if (map_vis.portal_bytes > sizeof(portalvector)) {
		Com_Error(ERR_FATAL, "VIS overflow. Try making more brushes CONTENTS_DETAIL.\n");
	}

	// OR together all the portal vis bits
	memset(portalvector, 0, map_vis.portal_bytes);
	leaf = &map_vis.leafs[leaf_num];
	for (i = 0; i < leaf->num_portals; i++) {
		p = leaf->portals[i];
		if (p->status != stat_done)
			Com_Error(ERR_FATAL, "Portal not done\n");
		for (j = 0; j < map_vis.portal_longs; j++)
			((long *) portalvector)[j] |= ((long *) p->vis)[j];
		pnum = p - map_vis.portals;
		portalvector[pnum >> 3] |= 1 << (pnum & 7);
	}

	// convert portal bits to leaf bits
	numvis = LeafVectorFromPortalVector(portalvector, uncompressed);

	if (uncompressed[leaf_num >> 3] & (1 << (leaf_num & 7))) {
		Com_Warn("Leaf portals saw into leaf\n");
	}

	uncompressed[leaf_num >> 3] |= (1 << (leaf_num & 7));
	numvis++; // count the leaf itself

	// save uncompressed for PHS calculation
	memcpy(map_vis.uncompressed + leaf_num * map_vis.leaf_bytes, uncompressed, map_vis.leaf_bytes);

	// compress the bit string
	Com_Debug("Cluster %4i : %4i visible\n", leaf_num, numvis);
	visibility_count += numvis;

	i = CompressVis(uncompressed, compressed);

	dest = map_vis.pointer;
	map_vis.pointer += i;

	if (map_vis.pointer > map_vis.end)
		Com_Error(ERR_FATAL, "VIS expansion overflow\n");

	d_vis->bit_offsets[leaf_num][DVIS_PVS] = dest - map_vis.base;

	memcpy(dest, compressed, i);
}
示例#24
0
/**
 * @brief
 */
static int32_t S_AllocChannel(void) {

	for (int32_t i = 0; i < MAX_CHANNELS; i++) {
		if (!s_env.channels[i].sample) {
			return i;
		}
	}

	Com_Debug(DEBUG_SOUND, "Failed\n");
	return -1;
}
示例#25
0
/*
 * @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();
	}
}
示例#26
0
/**
 * @brief Add a stain to the map.
 */
void R_AddStain(const r_stain_t *s) {

    if (!r_stainmap->value) {
        return;
    }

    if (r_view.num_stains == MAX_STAINS) {
        Com_Debug(DEBUG_RENDERER, "MAX_STAINS reached\n");
        return;
    }

    r_view.stains[r_view.num_stains++] = *s;
}
示例#27
0
/*
 * @brief Inserts the specified media into the shared table, re-registering all
 * of its dependencies as well.
 */
void R_RegisterMedia(r_media_t *media) {

	// check to see if we're already seeded
	if (media->seed != r_media_state.seed) {
		r_media_t *m;

		if ((m = g_hash_table_lookup(r_media_state.media, media->name))) {
			if (m != media) { // the old instance will eventually be freed
				Com_Debug("Replacing %s\n", media->name);
				R_FreeMedia_(NULL, m, m);
				g_hash_table_replace(r_media_state.media, media->name, media);
			} else {
				Com_Debug("Retaining %s\n", media->name);
			}
		} else {
			Com_Debug("Inserting %s\n", media->name);
			g_hash_table_insert(r_media_state.media, media->name, media);
		}

		r_media_state.keys = g_list_insert_sorted(r_media_state.keys, media->name,
				R_RegisterMedia_Compare);

		// re-seed the media to retain it
		media->seed = r_media_state.seed;
	}

	// call the implementation-specific register function
	if (media->Register) {
		media->Register(media);
	}

	// and finally re-register all dependencies
	GList *d = media->dependencies;
	while (d) {
		R_RegisterMedia((r_media_t *) d->data);
		d = d->next;
	}
}
示例#28
0
/*
 * @brief Inserts the specified media into the shared table.
 */
void S_RegisterMedia(s_media_t *media) {

	// check to see if we're already seeded
	if (media->seed != s_media_state.seed) {
		s_media_t *m;

		if ((m = g_hash_table_lookup(s_media_state.media, media->name))) {
			if (m != media) {
				Com_Error(ERR_DROP, "Name collision: %s\n", media->name);
			} else {
				Com_Debug("Retaining %s\n", media->name);
			}
		} else {
			Com_Debug("Inserting %s\n", media->name);
			g_hash_table_insert(s_media_state.media, media->name, media);
			s_media_state.keys = g_list_insert_sorted(s_media_state.keys, media->name,
					S_RegisterMedia_Compare);
		}

		// re-seed the media to retain it
		media->seed = s_media_state.seed;
	}
}
示例#29
0
/*
 * @brief Updates the game module's time and runs its frame function once per
 * server frame.
 */
static void Sv_RunGameFrame(void) {

	sv.frame_num++;
	sv.time = sv.frame_num * 1000 / svs.frame_rate;

	if (sv.time < svs.real_time) {
		Com_Debug("Sv_RunGameFrame: High clamp: %dms\n", svs.real_time - sv.time);
		svs.real_time = sv.time;
	}

	if (sv.state == SV_ACTIVE_GAME) {
		svs.game->Frame();
	}
}
示例#30
0
/**
 * @brief Checks for client side prediction errors. These will occur under normal gameplay
 * conditions if the client is pushed by another entity on the server (projectile, platform, etc.).
 */
void Cl_CheckPredictionError(void) {

	if (!cls.cgame->UsePrediction()) {
		return;
	}

	cl_predicted_state_t *pr = &cl.predicted_state;

	if (cl.delta_frame) {

		// calculate the last cl_cmd_t we sent that the server has processed
		const uint32_t cmd = cls.net_chan.incoming_acknowledged & CMD_MASK;

		// subtract what the server returned with what we had predicted it to be
		VectorSubtract(cl.frame.ps.pm_state.origin, pr->origins[cmd], pr->error);

		// if the error is too large, it was likely a teleport or respawn, so ignore it
		const vec_t len = VectorLength(pr->error);
		if (len > 64.0) {
			Com_Debug(DEBUG_CLIENT, "Clear %s\n", vtos(pr->error));
			VectorClear(pr->error);
		} else if (len > 0.1) {
			Com_Debug(DEBUG_CLIENT, "Error %s\n", vtos(pr->error));
		}

	} else {
		Com_Debug(DEBUG_CLIENT, "No delta\n");

		VectorCopy(cl.frame.ps.pm_state.origin, pr->view.origin);

		UnpackVector(cl.frame.ps.pm_state.view_offset, pr->view.offset);
		UnpackAngles(cl.frame.ps.pm_state.view_angles, pr->view.angles);

		VectorClear(pr->error);
	}
}