/** * @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 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; }
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!"); } } }
/** * @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; }
/** * @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; }
static int SV_ReadLong (void) { return NET_ReadLong(sv->messageBuffer); }
/** * @sa NET_WritePos */ void NET_ReadPos (dbuffer* buf, vec3_t pos) { pos[0] = NET_ReadLong(buf) / POSSCALE; pos[1] = NET_ReadLong(buf) / POSSCALE; pos[2] = NET_ReadLong(buf) / POSSCALE; }
float NET_ReadCoord (dbuffer* buf) { return (float) NET_ReadLong(buf) * (1.0 / 32); }