/* * =============== * CL_Netchan_Transmit * ================ */ void CL_Netchan_Transmit(netchan_t *chan, msg_t *msg) { MSG_WriteByte(msg, clc_EOF); CL_Netchan_Encode(msg); Netchan_Transmit(chan, msg->cursize, msg->data); }
/* * ================= * Netchan_SV_Process * ================= */ bool SV_Netchan_Process(client_t *client, msg_t *msg) { int ret; ret = Netchan_Process(&client->netchan, msg); if (!ret) { return(false); } SV_Netchan_Decode(client, msg); return(true); }
/* * ================= * CL_Netchan_Process * ================= */ bool CL_Netchan_Process(netchan_t *chan, msg_t *msg) { int ret; ret = Netchan_Process(chan, msg); if (!ret) { return(false); } CL_Netchan_Decode(msg); newsize += msg->cursize; return(true); }
/* * ================== * SV_UpdateServerCommandsToClient * * (re)send all server commands the client hasn't acknowledged yet * ================== */ void SV_UpdateServerCommandsToClient(client_t *client, msg_t *msg) { int i; // write any unacknowledged serverCommands for (i = client->reliableAcknowledge + 1; i <= client->reliableSequence; i++) { MSG_WriteByte(msg, svc_serverCommand); MSG_WriteLong(msg, i); MSG_WriteString(msg, client->reliableCommands[i & (MAX_RELIABLE_COMMANDS - 1)]); } client->reliableSent = client->reliableSequence; }
/* * ============== * CL_Netchan_Encode * * // first 12 bytes of the data are always: * long serverId; * long messageAcknowledge; * long reliableAcknowledge; * * ============== */ static void CL_Netchan_Encode(msg_t *msg) { int serverId, messageAcknowledge, reliableAcknowledge; int i, index, srdc, sbit, soob; byte key, *string; if (msg->cursize <= CL_ENCODE_START) { return; } srdc = msg->readcount; sbit = msg->bit; soob = msg->oob; msg->bit = 0; msg->readcount = 0; msg->oob = (bool)0; serverId = MSG_ReadLong(msg); messageAcknowledge = MSG_ReadLong(msg); reliableAcknowledge = MSG_ReadLong(msg); msg->oob = (bool)soob; msg->bit = sbit; msg->readcount = srdc; string = (byte *)clc.serverCommands[reliableAcknowledge & (MAX_RELIABLE_COMMANDS - 1)]; index = 0; // key = clc.challenge ^ serverId ^ messageAcknowledge; for (i = CL_ENCODE_START; i < msg->cursize; i++) { // modify the key with the last received now acknowledged server command if (!string[index]) { index = 0; } if (string[index] > 127 || string[index] == '%') { key ^= '.' << (i & 1); } else { key ^= string[index] << (i & 1); } index++; // encode the data with this key *(msg->data + i) = (*(msg->data + i)) ^ key; } }
/* * ============== * SV_Netchan_Encode * * // first four bytes of the data are always: * long reliableAcknowledge; * * ============== */ static void SV_Netchan_Encode(client_t *client, msg_t *msg) { long reliableAcknowledge, i, index; byte key, *string; int srdc, sbit, soob; if (msg->cursize < SV_ENCODE_START) { return; } srdc = msg->readcount; sbit = msg->bit; soob = msg->oob; msg->bit = 0; msg->readcount = 0; msg->oob = (bool)0; reliableAcknowledge = MSG_ReadLong(msg); msg->oob = (bool)soob; msg->bit = sbit; msg->readcount = srdc; string = (byte *)client->lastClientCommandString; index = 0; // xor the client challenge with the netchan sequence number key = client->challenge ^ client->netchan.outgoingSequence; for (i = SV_ENCODE_START; i < msg->cursize; i++) { // modify the key with the last received and with this message acknowledged client command if (!string[index]) { index = 0; } if (string[index] > 127 || string[index] == '%') { key ^= '.' << (i & 1); } else { key ^= string[index] << (i & 1); } index++; // encode the data with this key *(msg->data + i) = *(msg->data + i) ^ key; } }
/* * ============== * SV_Netchan_Decode * * // first 12 bytes of the data are always: * long serverId; * long messageAcknowledge; * long reliableAcknowledge; * * ============== */ static void SV_Netchan_Decode(client_t *client, msg_t *msg) { int serverId, messageAcknowledge, reliableAcknowledge; int i, index, srdc, sbit, soob; byte key, *string; srdc = msg->readcount; sbit = msg->bit; soob = msg->oob; msg->oob = (bool)0; serverId = MSG_ReadLong(msg); messageAcknowledge = MSG_ReadLong(msg); reliableAcknowledge = MSG_ReadLong(msg); msg->oob = (bool)soob; msg->bit = sbit; msg->readcount = srdc; string = (byte *)client->reliableCommands[reliableAcknowledge & (MAX_RELIABLE_COMMANDS - 1)]; index = 0; // key = client->challenge ^ serverId ^ messageAcknowledge; for (i = msg->readcount + SV_DECODE_START; i < msg->cursize; i++) { // modify the key with the last sent and acknowledged server command if (!string[index]) { index = 0; } if (string[index] > 127 || string[index] == '%') { key ^= '.' << (i & 1); } else { key ^= string[index] << (i & 1); } index++; // decode the data with this key *(msg->data + i) = *(msg->data + i) ^ key; } }
/* * ============== * CL_Netchan_Decode * * // first four bytes of the data are always: * long reliableAcknowledge; * * ============== */ static void CL_Netchan_Decode(msg_t *msg) { long reliableAcknowledge, i, index; byte key, *string; int srdc, sbit, soob; srdc = msg->readcount; sbit = msg->bit; soob = msg->oob; msg->oob = (bool)0; reliableAcknowledge = MSG_ReadLong(msg); msg->oob = (bool)soob; msg->bit = sbit; msg->readcount = srdc; string = (byte *)clc.reliableCommands[reliableAcknowledge & (MAX_RELIABLE_COMMANDS - 1)]; index = 0; // xor the client challenge with the netchan sequence number (need something that changes every message) key = clc.challenge ^ LittleLong(*(unsigned *)msg->data); for (i = msg->readcount + CL_DECODE_START; i < msg->cursize; i++) { // modify the key with the last sent and with this message acknowledged client command if (!string[index]) { index = 0; } if (string[index] > 127 || string[index] == '%') { key ^= '.' << (i & 1); } else { key ^= string[index] << (i & 1); } index++; // decode the data with this key *(msg->data + i) = *(msg->data + i) ^ key; } }
/* * =============== * SV_Netchan_Transmit * TTimo * https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=462 * if there are some unsent fragments (which may happen if the snapshots * and the gamestate are fragmenting, and collide on send for instance) * then buffer them and make sure they get sent in correct order * ================ */ void SV_Netchan_Transmit(client_t *client, msg_t *msg) //int length, const byte *data ) { { MSG_WriteByte(msg, svc_EOF); if (client->netchan.unsentFragments) { netchan_buffer_t *netbuf; Com_DPrintf("#462 SV_Netchan_Transmit: unsent fragments, stacked\n"); netbuf = (netchan_buffer_t *)Z_Malloc(sizeof(netchan_buffer_t)); // store the msg, we can't store it encoded, as the encoding depends on stuff we still have to finish sending MSG_Copy(&netbuf->msg, netbuf->msgBuffer, sizeof(netbuf->msgBuffer), msg); netbuf->next = NULL; // insert it in the queue, the message will be encoded and sent later *client->netchan_end_queue = netbuf; client->netchan_end_queue = &(*client->netchan_end_queue)->next; // emit the next fragment of the current message for now Netchan_TransmitNextFragment(&client->netchan); } else { SV_Netchan_Encode(client, msg); Netchan_Transmit(&client->netchan, msg->cursize, msg->data); } }
void Huff_Decompress(msg_t *mbuf, int offset) { int ch, cch, i, j, size; byte seq[65536];
bool Sys_GetPacket(netadr_t *net_from, msg_t *net_message);
/* * ============================================================================= * * Delta encode a client frame onto the network channel * * A normal server packet will look like: * * 4 sequence number (high bit set if an oversize fragment) * <optional reliable commands> * 1 svc_snapshot * 4 last client reliable command * 4 serverTime * 1 lastframe for delta compression * 1 snapFlags * 1 areaBytes * <areabytes> * <playerstate> * <packetentities> * * ============================================================================= */ /* * ============= * SV_EmitPacketEntities * * Writes a delta update of an entityState_t list to the message. * ============= */ static void SV_EmitPacketEntities(clientSnapshot_t *from, clientSnapshot_t *to, msg_t *msg) { entityState_t *oldent, *newent; int oldindex, newindex; int oldnum, newnum; int from_num_entities; // generate the delta update if (!from) { from_num_entities = 0; } else { from_num_entities = from->num_entities; } newent = NULL; oldent = NULL; newindex = 0; oldindex = 0; while (newindex < to->num_entities || oldindex < from_num_entities) { if (newindex >= to->num_entities) { newnum = 9999; } else { newent = &svs.snapshotEntities[(to->first_entity + newindex) % svs.numSnapshotEntities]; newnum = newent->number; } if (oldindex >= from_num_entities) { oldnum = 9999; } else { oldent = &svs.snapshotEntities[(from->first_entity + oldindex) % svs.numSnapshotEntities]; oldnum = oldent->number; } if (newnum == oldnum) { // delta update from old position // because the force parm is false, this will not result // in any bytes being emited if the entity has not changed at all MSG_WriteDeltaEntity(msg, oldent, newent, false); oldindex++; newindex++; continue; } if (newnum < oldnum) { // this is a new entity, send it from the baseline MSG_WriteDeltaEntity(msg, &sv.svEntities[newnum].baseline, newent, true); newindex++; continue; } if (newnum > oldnum) { // the old entity isn't present in the new message MSG_WriteDeltaEntity(msg, oldent, NULL, true); oldindex++; continue; } } MSG_WriteBits(msg, (MAX_GENTITIES - 1), GENTITYNUM_BITS); // end of packetentities }
/* * ================== * SV_WriteSnapshotToClient * ================== */ static void SV_WriteSnapshotToClient(client_t *client, msg_t *msg) { clientSnapshot_t *frame, *oldframe; int lastframe; int i; int snapFlags; // this is the snapshot we are creating frame = &client->frames[client->netchan.outgoingSequence & PACKET_MASK]; // try to use a previous frame as the source for delta compressing the snapshot if (client->deltaMessage <= 0 || client->state != CS_ACTIVE) { // client is asking for a retransmit oldframe = NULL; lastframe = 0; } else if (client->netchan.outgoingSequence - client->deltaMessage >= (PACKET_BACKUP - 3)) { // client hasn't gotten a good message through in a long time Com_DPrintf("%s: Delta request from out of date packet.\n", client->name); oldframe = NULL; lastframe = 0; } else { // we have a valid snapshot to delta from oldframe = &client->frames[client->deltaMessage & PACKET_MASK]; lastframe = client->netchan.outgoingSequence - client->deltaMessage; // the snapshot's entities may still have rolled off the buffer, though if (oldframe->first_entity <= svs.nextSnapshotEntities - svs.numSnapshotEntities) { Com_DPrintf("%s: Delta request from out of date entities.\n", client->name); oldframe = NULL; lastframe = 0; } } MSG_WriteByte(msg, svc_snapshot); // NOTE, MRE: now sent at the start of every message from server to client // let the client know which reliable clientCommands we have received //MSG_WriteLong( msg, client->lastClientCommand ); // send over the current server time so the client can drift // its view of time to try to match MSG_WriteLong(msg, svs.time); // what we are delta'ing from MSG_WriteByte(msg, lastframe); snapFlags = svs.snapFlagServerBit; if (client->rateDelayed) { snapFlags |= SNAPFLAG_RATE_DELAYED; } if (client->state != CS_ACTIVE) { snapFlags |= SNAPFLAG_NOT_ACTIVE; } MSG_WriteByte(msg, snapFlags); // send over the areabits MSG_WriteByte(msg, frame->areabytes); MSG_WriteData(msg, frame->areabits, frame->areabytes); // delta encode the playerstate if (oldframe) { MSG_WriteDeltaPlayerstate(msg, &oldframe->ps, &frame->ps); } else { MSG_WriteDeltaPlayerstate(msg, NULL, &frame->ps); } // delta encode the entities SV_EmitPacketEntities(oldframe, frame, msg); // padding for rate debugging if (sv_padPackets->integer) { for (i = 0; i < sv_padPackets->integer; i++) { MSG_WriteByte(msg, svc_nop); } } }