示例#1
0
/**
 * @brief Reads from a buffer according to format; version without syntactic sugar for variable arguments, to call it from other functions with variable arguments
 * @sa SV_ReadFormat
 * @param[in] buf The buffer we read the data from
 * @param[in] format The format string may not be nullptr
 * @param ap The variadic function argument list corresponding to the format string
 */
void NET_vReadFormat (dbuffer* buf, const char* format, va_list ap)
{
    while (*format) {
        const char typeID = *format++;

        switch (typeID) {
        case 'c':
            *va_arg(ap, int*) = NET_ReadChar(buf);
            break;
        case 'b':
            *va_arg(ap, int*) = NET_ReadByte(buf);
            break;
        case 's':
            *va_arg(ap, int*) = NET_ReadShort(buf);
            break;
        case 'l':
            *va_arg(ap, int*) = NET_ReadLong(buf);
            break;
        case 'p':
            NET_ReadPos(buf, *va_arg(ap, vec3_t*));
            break;
        case 'g':
            NET_ReadGPos(buf, *va_arg(ap, pos3_t*));
            break;
        case 'd':
            NET_ReadDir(buf, *va_arg(ap, vec3_t*));
            break;
        case 'a':
            *va_arg(ap, float*) = NET_ReadAngle(buf);
            break;
        case '!':
            format++;
            break;
        case '&': {
            char* str = va_arg(ap, char*);
            const size_t length = va_arg(ap, size_t);
            NET_ReadString(buf, str, length);
            break;
        }
        case '*':
        {
            const int n = NET_ReadShort(buf);

            *va_arg(ap, int*) = n;
            byte* p = va_arg(ap, byte*);

            for (int i = 0; i < n; i++)
                *p++ = NET_ReadByte(buf);
        }
        break;
        default:
            Com_Error(ERR_DROP, "ReadFormat: Unknown type!");
        }
    }
    /* Too many arguments for the given format; too few cause crash above */
#ifdef PARANOID
    if (!ap)
        Com_Error(ERR_DROP, "ReadFormat: Too many arguments!");
#endif
}
/**
 * @brief Announces that a player ends his turn
 * @param[in] self Pointer to the event structure that is currently executed
 * @param[in] msg The message buffer to read from
 * @sa CL_DoEndRound
 * @note event EV_ENDROUNDANNOUNCE
 * @todo Build into hud
 */
void CL_EndRoundAnnounce (const eventRegister_t* self, dbuffer* msg)
{
	/* get the needed values */
	const int playerNum = NET_ReadByte(msg);
	const int team = NET_ReadByte(msg);

	GAME_EndRoundAnnounce(playerNum, team);
}
示例#3
0
void NET_SkipFormat (dbuffer* buf, const char* format)
{
    while (*format) {
        const char typeID = *format++;

        switch (typeID) {
        case 'c':
            NET_ReadChar(buf);
            break;
        case 'b':
            NET_ReadByte(buf);
            break;
        case 's':
            NET_ReadShort(buf);
            break;
        case 'l':
            NET_ReadLong(buf);
            break;
        case 'p': {
            vec3_t v;
            NET_ReadPos(buf, v);
            break;
        }
        case 'g': {
            pos3_t p;
            NET_ReadGPos(buf, p);
            break;
        }
        case 'd': {
            vec3_t v;
            NET_ReadDir(buf, v);
            break;
        }
        case 'a':
            NET_ReadAngle(buf);
            break;
        case '!':
            format++;
            break;
        case '&':
            NET_ReadString(buf, nullptr, 0);
            break;
        case '*': {
            const int n = NET_ReadShort(buf);
            for (int i = 0; i < n; i++)
                NET_ReadByte(buf);
            break;
        }
        default:
            Com_Error(ERR_DROP, "ReadFormat: Unknown type!");
        }
    }
}
示例#4
0
void NET_ReadDir (dbuffer* buf, vec3_t dir)
{
    const int b = NET_ReadByte(buf);
    if (b >= lengthof(bytedirs))
        Com_Error(ERR_DROP, "NET_ReadDir: out of range");
    VectorCopy(bytedirs[b], dir);
}
示例#5
0
/**
 * @brief Activates the map render screen (ca_active)
 * @sa SCR_EndLoadingPlaque
 * @sa G_ClientBegin
 * @note EV_START
 */
void CL_StartGame (const eventRegister_t* self, dbuffer* msg)
{
	const int isTeamPlay = NET_ReadByte(msg);

	/* init camera position and angles */
	OBJZERO(cl.cam);
	VectorSet(cl.cam.angles, 60.0, 60.0, 0.0);
	VectorSet(cl.cam.omega, 0.0, 0.0, 0.0);
	cl.cam.zoom = 1.25;
	CL_ViewCalcFieldOfViewX();

	Com_Printf("Starting the game...\n");

	/* make sure selActor is null (after reconnect or server change this is needed) */
	CL_ActorSelect(nullptr);

	/* center on first actor */
	cl_worldlevel->modified = true;
	if (cl.numTeamList) {
		const le_t* le = cl.teamList[0];
		CL_ViewCenterAtGridPosition(le->pos);
	}

	/* activate the renderer */
	CL_SetClientState(ca_active);

	GAME_StartBattlescape(isTeamPlay);
}
示例#6
0
void NET_ReadData (dbuffer* buf, void* data, int len)
{
	int i;

	for (i = 0; i < len; i++)
		((byte*) data)[i] = NET_ReadByte(buf);
}
示例#7
0
/**
 * @brief Moves actor.
 * @param[in] self Pointer to the event structure that is currently executed
 * @param[in] msg The netchannel message
 * @sa LET_PathMove
 * @note EV_ACTOR_MOVE
 */
void CL_ActorDoMove (const eventRegister_t* self, dbuffer* msg)
{
	const int number = NET_ReadShort(msg);

	/* get le */
	le_t* le = LE_Get(number);
	if (!le)
		LE_NotFoundError(number);

	if (!LE_IsActor(le))
		Com_Error(ERR_DROP, "Can't move, LE doesn't exist or is not an actor (entnum: %i, type: %i)\n",
			number, le->type);

	if (LE_IsDead(le))
		Com_Error(ERR_DROP, "Can't move, actor on team %i dead (entnum: %i)", le->team, number);

	/* lock this le for other events, the corresponding unlock is in LE_DoEndPathMove() */
	LE_Lock(le);
	if (le->isMoving()) {
		if (le->pathLength == le->pathPos) {
			LE_DoEndPathMove(le);
		} else {
			Com_Error(ERR_DROP, "Actor (entnum: %i) on team %i is still moving (%i steps left).  Times: %i, %i, %i",
					le->entnum, le->team, le->pathLength - le->pathPos, le->startTime, le->endTime, cl.time);
		}
	}

	int i = 0;
	/* the end of this event is marked with a 0 */
	while (NET_PeekLong(msg) != 0) {
		NET_ReadByte(msg);
		le->dvtab[i] = NET_ReadShort(msg); /** Don't adjust dv values here- the whole thing is needed to move the actor! */
		le->speed[i] = NET_ReadShort(msg);
		le->pathContents[i] = NET_ReadShort(msg);
		i++;
	}
	le->pathLength = i;

	if (le->pathLength > MAX_ROUTE)
		Com_Error(ERR_DROP, "Overflow in pathLength (entnum: %i)", number);

	/* skip the end of move marker */
	NET_ReadLong(msg);
	/* Also get the final position */
	NET_ReadGPos(msg, le->newPos);

	if (VectorCompare(le->newPos, le->pos))
		Com_Error(ERR_DROP, "start and end pos are the same (entnum: %i)", number);

	/* activate PathMove function */
	le->resetFloor();
	if (LE_IsInvisible(le))
		/* Hack: this relies on the visibility events interrupting the EV_ACTOR_MOVE event */
		LE_SetThink(le, LET_HiddenMove);
	else
		LE_SetThink(le, LET_StartPathMove);
	le->pathPos = 0;
	le->startTime = cl.time;
	le->endTime = cl.time;
}
示例#8
0
/**
 * @brief Decides if following events should be delayed. The delay is the amount of time the actor needs to walk
 * from the start to the end pos.
 */
int CL_ActorDoMoveTime (const eventRegister_t *self, dbuffer *msg, eventTiming_t *eventTiming)
{
	int time = 0;

	const int eventTime = eventTiming->nextTime;
	const int number = NET_ReadShort(msg);

	/* get le */
	const le_t *le = LE_Get(number);
	if (!le)
		LE_NotFoundError(number);

	pos3_t pos;
	VectorCopy(le->pos, pos);
	byte crouchingState = LE_IsCrouched(le) ? 1 : 0;

	/* the end of this event is marked with a 0 */
	while (NET_PeekLong(msg) != 0) {
		const dvec_t dvec = NET_ReadShort(msg);
		const byte dir = getDVdir(dvec);
		pos3_t oldPos;
		VectorCopy(pos, oldPos);
		PosAddDV(pos, crouchingState, dvec);
		time += LE_ActorGetStepTime(le, pos, oldPos, dir, NET_ReadShort(msg));
		NET_ReadShort(msg);
	}

	/* skip the end of move marker */
	NET_ReadLong(msg);

	/* Also skip the final position */
	NET_ReadByte(msg);
	NET_ReadByte(msg);
	NET_ReadByte(msg);

	assert(NET_PeekByte(msg) == EV_NULL);

	eventTiming->nextTime += time + 400;

	return eventTime;
}
示例#9
0
/**
 * @sa CL_ConnectionlessPacket
 * @sa CL_Frame
 * @sa CL_ParseServerMessage
 * @sa NET_ReadMsg
 * @sa SV_ReadPacket
 */
static void CL_ReadPackets (void)
{
	dbuffer* msg;
	while ((msg = NET_ReadMsg(cls.netStream))) {
		const svc_ops_t cmd = NET_ReadByte(msg);
		if (cmd == svc_oob)
			CL_ConnectionlessPacket(msg);
		else
			CL_ParseServerMessage(cmd, msg);
		delete msg;
	}
}
示例#10
0
/**
 * @brief Reads mission result data from server
 * @sa EV_RESULTS
 * @sa G_MatchSendResults
 * @sa GAME_CP_Results_f
 */
void CL_ParseResults (const eventRegister_t *self, struct dbuffer *msg)
{
	int winner;
	int i, j, num;
	int num_spawned[MAX_TEAMS];
	int num_alive[MAX_TEAMS];
	/* the first dimension contains the attacker team, the second the victim team */
	int num_kills[MAX_TEAMS][MAX_TEAMS];
	int num_stuns[MAX_TEAMS][MAX_TEAMS];
	qboolean nextmap;

	OBJZERO(num_spawned);
	OBJZERO(num_alive);
	OBJZERO(num_kills);
	OBJZERO(num_stuns);

	/* get number of teams */
	num = NET_ReadByte(msg);
	if (num > MAX_TEAMS)
		Com_Error(ERR_DROP, "Too many teams in result message");

	Com_DPrintf(DEBUG_CLIENT, "Receiving results with %i teams.\n", num);

	/* get winning team */
	winner = NET_ReadByte(msg);
	nextmap = NET_ReadByte(msg);

	if (cls.team > num)
		Com_Error(ERR_DROP, "Team number %d too high (only %d teams)", cls.team, num);

	/* get spawn and alive count */
	for (i = 0; i < num; i++) {
		num_spawned[i] = NET_ReadByte(msg);
		num_alive[i] = NET_ReadByte(msg);
	}

	/* get kills */
	for (i = 0; i < num; i++)
		for (j = 0; j < num; j++)
			num_kills[i][j] = NET_ReadByte(msg);

	/* get stuns */
	for (i = 0; i < num; i++)
		for (j = 0; j < num; j++)
			num_stuns[i][j] = NET_ReadByte(msg);

	GAME_HandleResults(msg, winner, num_spawned, num_alive, num_kills, num_stuns, nextmap);
}
示例#11
0
/**
 * @sa NET_ReadString
 */
int NET_ReadStringLine (dbuffer* buf, char* string, size_t length)
{
    unsigned int l = 0;
    do {
        int c = NET_ReadByte(buf);
        if (c == -1 || c == 0 || c == '\n')
            break;
        /* translate all format specs to avoid crash bugs */
        if (c == '%')
            c = '.';
        string[l] = c;
        l++;
    } while (l < length - 1);

    string[l] = 0;

    return l;
}
示例#12
0
/**
 * @sa CL_ReadPacket
 * @sa NET_ReadMsg
 * @sa SV_Start
 */
void SV_ReadPacket (struct net_stream *s)
{
	client_t *cl = (client_t *)NET_StreamGetData(s);
	struct dbuffer *msg;

	while ((msg = NET_ReadMsg(s))) {
		const int cmd = NET_ReadByte(msg);

		if (cmd == clc_oob)
			SV_ConnectionlessPacket(s, msg);
		else if (cl)
			SV_ExecuteClientMessage(cl, cmd, msg);
		else
			NET_StreamFree(s);

		free_dbuffer(msg);
	}
}
示例#13
0
/**
 * @sa CL_ReadPacket
 * @sa NET_ReadMsg
 * @sa SV_Start
 */
void SV_ReadPacket (struct net_stream *s)
{
	client_t *cl = static_cast<client_t *>(NET_StreamGetData(s));
	dbuffer *msg;

	while ((msg = NET_ReadMsg(s))) {
		const int cmd = NET_ReadByte(msg);

		if (cmd == clc_oob)
			SV_ConnectionlessPacket(s, msg);
		else if (cl)
			SV_ExecuteClientMessage(cl, cmd, msg);
		else {
			NET_StreamFree(s);
			s = NULL;
		}

		delete msg;
	}
}
示例#14
0
/**
 * @note Don't use this function in a way like
 * <code> char* s = NET_ReadString(sb);
 * char* t = NET_ReadString(sb);</code>
 * The second reading uses the same data buffer for the string - so
 * s is no longer the first - but the second string
 * @sa NET_ReadStringLine
 * @param[in,out] buf The input buffer to read the string data from
 * @param[out] string The output buffer to read the string into
 * @param[in] length The size of the output buffer
 */
int NET_ReadString (dbuffer* buf, char* string, size_t length)
{
    unsigned int l = 0;

    for (;;) {
        int c = NET_ReadByte(buf);
        if (c == -1 || c == 0)
            break;
        if (string && l < length - 1) {
            /* translate all format specs to avoid crash bugs */
            if (c == '%')
                c = '.';
            string[l] = c;
        }
        l++;
    }

    if (string)
        string[l] = '\0';

    return l;
}
示例#15
0
/**
 * @brief Performs end-of-turn processing.
 * @param[in] self Pointer to the event structure that is currently executed
 * @param[in] msg The netchannel message
 * @sa CL_EndRoundAnnounce
 */
void CL_DoEndRound (const eventRegister_t* self, dbuffer* msg)
{
	/* hud changes */
	if (cls.isOurRound())
		UI_ExecuteConfunc("endround");

	refdef.rendererFlags &= ~RDF_IRGOGGLES;

	/* change active player */
	Com_Printf("Team %i ended round\n", cl.actTeam);
	cl.actTeam = NET_ReadByte(msg);
	Com_Printf("Team %i's round started!\n", cl.actTeam);

	/* hud changes */
	if (cls.isOurRound()) {
		/* check whether a particle has to go */
		CL_ParticleCheckRounds();
		UI_ExecuteConfunc("startround");
		HUD_DisplayMessage(_("Your round started!"));
		S_StartLocalSample("misc/roundstart", SND_VOLUME_DEFAULT);
		CL_ActorConditionalMoveCalc(selActor);
	}
}
示例#16
0
/**
 * @brief Decides if following events should be delayed. The delay is the amount of time the actor needs to walk
 * from the start to the end pos.
 */
int CL_ActorDoMoveTime (const eventRegister_t* self, dbuffer* msg, eventTiming_t* eventTiming)
{
	int time = 0;

	const int eventTime = eventTiming->nextTime;
	const int number = NET_ReadShort(msg);
	/* get le */
	le_t* le = LE_Get(number);
	if (!le)
		LE_NotFoundError(number);

	pos3_t pos;
	VectorCopy(le->pos, pos);
	byte crouchingState = LE_IsCrouched(le) ? 1 : 0;

	leStep_t* newStep = Mem_AllocType(leStep_t);
	if (le->stepList == nullptr) {
		le->stepList = newStep;
		le->stepIndex = 0;
	} else {
		/* append to the list */
		leStep_t* step = le->stepList;
		while (step) {
			if (step->next == nullptr) {
				step->next = newStep;
				le->stepIndex++;
				break;
			}
			step = step->next;
		}
	}

	/* the end of this event is marked with a 0 */
	while (NET_PeekLong(msg) != 0) {
		newStep->steps = NET_ReadByte(msg);
		const dvec_t dvec = NET_ReadShort(msg);
		const byte dir = getDVdir(dvec);
		pos3_t oldPos;
		VectorCopy(pos, oldPos);
		PosAddDV(pos, crouchingState, dvec);
		const int stepTime = LE_ActorGetStepTime(le, pos, oldPos, dir, NET_ReadShort(msg));
		newStep->stepTimes[newStep->steps] = stepTime;
		time += stepTime;
		NET_ReadShort(msg);
	}
	++newStep->steps;

	if (newStep->steps > MAX_ROUTE)
		Com_Error(ERR_DROP, "route length overflow: %i", newStep->steps);

	/* skip the end of move marker */
	NET_ReadLong(msg);

	/* Also skip the final position */
	NET_ReadByte(msg);
	NET_ReadByte(msg);
	NET_ReadByte(msg);

	assert(NET_PeekByte(msg) == EV_NULL);

	eventTiming->nextTime += time + 400;
	newStep->lastMoveTime = eventTime;
	newStep->lastMoveDuration = time;
	return eventTime;
}
示例#17
0
文件: e_time.c 项目: chrisglass/ufoai
/**
 * @brief Calculates the time the event should get executed. If two events return the same time,
 * they are going to be executed in the order the were parsed.
 * @param[in] eType The event type
 * @param[in,out] msg The message buffer that can be modified to get the event time
 * @param[in] dt Delta time in msec since the last event was parsed
 */
int CL_GetEventTime (const event_t eType, struct dbuffer *msg, const int dt)
{
	const eventRegister_t *eventData = CL_GetEvent(eType);

#ifdef OLDEVENTTIME
	/* the time the event should be executed. This value is used to sort the
	 * event chain to determine which event must be executed at first. This
	 * value also ensures, that the events are executed in the correct
	 * order. E.g. @c impactTime is used to delay some events in case the
	 * projectile needs some time to reach its target. */
	int eventTime;

	if (eType == EV_RESET) {
		parsedDeath = qfalse;
		nextTime = 0;
		shootTime = 0;
		impactTime = 0;
	} else if (eType == EV_ACTOR_DIE)
		parsedDeath = qtrue;

	/* get event time */
	if (nextTime < cl.time)
		nextTime = cl.time;
	if (impactTime < cl.time)
		impactTime = cl.time;

	if (eType == EV_ACTOR_DIE || eType == EV_MODEL_EXPLODE)
		eventTime = impactTime;
	else if (eType == EV_ACTOR_SHOOT || eType == EV_ACTOR_SHOOT_HIDDEN)
		eventTime = shootTime;
	else if (eType == EV_RESULTS)
		eventTime = nextTime + 1400;
	else
		eventTime = nextTime;

	if (eType == EV_ENT_APPEAR || eType == EV_INV_ADD || eType == EV_PARTICLE_APPEAR || eType == EV_PARTICLE_SPAWN) {
		if (parsedDeath) { /* drop items after death (caused by impact) */
			eventTime = impactTime + 400;
			/* EV_INV_ADD messages are the last events sent after a death */
			if (eType == EV_INV_ADD)
				parsedDeath = qfalse;
		} else if (impactTime > cl.time) { /* item thrown on the ground */
			eventTime = impactTime + 75;
		}
	}

	/* calculate time interval before the next event */
	switch (eType) {
	case EV_ACTOR_APPEAR:
		if (cl.actTeam != cls.team)
			nextTime += 600;
		break;
	case EV_INV_RELOAD:
		/* let the reload sound play */
		nextTime += 600;
		break;
	case EV_ACTOR_START_SHOOT:
		nextTime += 300;
		shootTime = nextTime;
		break;
	case EV_ACTOR_SHOOT_HIDDEN:
		{
			int first;
			int objIdx;
			const objDef_t *obj;
			weaponFireDefIndex_t weapFdsIdx;
			fireDefIndex_t fireDefIndex;

			NET_ReadFormat(msg, eventData->formatString, &first, &objIdx, &weapFdsIdx, &fireDefIndex);

			obj = INVSH_GetItemByIDX(objIdx);
			if (first) {
				nextTime += 500;
				impactTime = shootTime = nextTime;
			} else {
				const fireDef_t *fd = FIRESH_GetFiredef(obj, weapFdsIdx, fireDefIndex);
				/* impact right away - we don't see it at all
				 * bouncing is not needed here, too (we still don't see it) */
				impactTime = shootTime;
				nextTime = shootTime + 1400;
				if (fd->delayBetweenShots > 0.0)
					shootTime += 1000 / fd->delayBetweenShots;
			}
			parsedDeath = qfalse;
		}
		break;
	case EV_ACTOR_MOVE:
		{
			le_t *le;
			int number, i;
			int time = 0;
			int pathLength;
			byte crouchingState;
			pos3_t pos, oldPos;

			number = NET_ReadShort(msg);
			/* get le */
			le = LE_Get(number);
			if (!le)
				LE_NotFoundError(number);

			pathLength = NET_ReadByte(msg);

			/* Also skip the final position */
			NET_ReadByte(msg);
			NET_ReadByte(msg);
			NET_ReadByte(msg);

			VectorCopy(le->pos, pos);
			crouchingState = LE_IsCrouched(le) ? 1 : 0;

			for (i = 0; i < pathLength; i++) {
				const dvec_t dvec = NET_ReadShort(msg);
				const byte dir = getDVdir(dvec);
				VectorCopy(pos, oldPos);
				PosAddDV(pos, crouchingState, dvec);
				time += LE_ActorGetStepTime(le, pos, oldPos, dir, NET_ReadShort(msg));
				NET_ReadShort(msg);
			}
			nextTime += time + 400;
		}
		break;
	case EV_ACTOR_SHOOT:
		{
			const fireDef_t	*fd;
			int flags, dummy;
			int objIdx, surfaceFlags;
			objDef_t *obj;
			int weap_fds_idx, fd_idx;
			shoot_types_t shootType;
			vec3_t muzzle, impact;

			/* read data */
			NET_ReadFormat(msg, eventData->formatString, &dummy, &dummy, &dummy, &objIdx, &weap_fds_idx, &fd_idx, &shootType, &flags, &surfaceFlags, &muzzle, &impact, &dummy);

			obj = INVSH_GetItemByIDX(objIdx);
			fd = FIRESH_GetFiredef(obj, weap_fds_idx, fd_idx);

			if (!(flags & SF_BOUNCED)) {
				/* shooting */
				if (fd->speed > 0.0 && !CL_OutsideMap(impact, UNIT_SIZE * 10)) {
					impactTime = shootTime + 1000 * VectorDist(muzzle, impact) / fd->speed;
				} else {
					impactTime = shootTime;
				}
				if (cl.actTeam != cls.team)
					nextTime = impactTime + 1400;
				else
					nextTime = impactTime + 400;
				if (fd->delayBetweenShots > 0.0)
					shootTime += 1000 / fd->delayBetweenShots;
			} else {
				/* only a bounced shot */
				eventTime = impactTime;
				if (fd->speed > 0.0) {
					impactTime += 1000 * VectorDist(muzzle, impact) / fd->speed;
					nextTime = impactTime;
				}
			}
			parsedDeath = qfalse;
		}
		break;
	case EV_ACTOR_THROW:
		nextTime += NET_ReadShort(msg);
		impactTime = shootTime = nextTime;
		parsedDeath = qfalse;
		break;
	default:
		break;
	}

	Com_DPrintf(DEBUG_EVENTSYS, "%s => eventTime: %i, nextTime: %i, impactTime: %i, shootTime: %i\n",
			eventData->name, eventTime, nextTime, impactTime, shootTime);

	return eventTime;
#else
	if (!eventData->timeCallback)
		return cl.time;

	return eventData->timeCallback(eventData, msg, dt);
#endif
}
示例#18
0
static int SV_ReadByte (void)
{
	return NET_ReadByte(sv->messageBuffer);
}
示例#19
0
/**
 * @sa NET_WriteGPos
 * @sa NET_ReadByte
 * @note pos3_t are byte values
 */
void NET_ReadGPos (dbuffer* buf, pos3_t pos)
{
    pos[0] = NET_ReadByte(buf);
    pos[1] = NET_ReadByte(buf);
    pos[2] = NET_ReadByte(buf);
}