/* * Sv_ReadPackets */ static void Sv_ReadPackets(void) { int i; sv_client_t *cl; byte qport; while (Net_GetPacket(NS_SERVER, &net_from, &net_message)) { // check for connectionless packet(0xffffffff) first if (*(int *) net_message.data == -1) { Sv_ConnectionlessPacket(); continue; } // read the qport out of the message so we can fix up // stupid address translating routers Msg_BeginReading(&net_message); Msg_ReadLong(&net_message); // sequence number Msg_ReadLong(&net_message); // sequence number qport = Msg_ReadByte(&net_message) & 0xff; // check for packets from connected clients for (i = 0, cl = svs.clients; i < sv_max_clients->integer; i++, cl++) { if (cl->state == SV_CLIENT_FREE) continue; if (!Net_CompareClientNetaddr(net_from, cl->netchan.remote_address)) continue; if (cl->netchan.qport != qport) continue; if (cl->netchan.remote_address.port != net_from.port) { Com_Warn("Sv_ReadPackets: Fixing up a translated port.\n"); cl->netchan.remote_address.port = net_from.port; } // this is a valid, sequenced packet, so process it if (Netchan_Process(&cl->netchan, &net_message)) { cl->last_message = svs.real_time; // nudge timeout Sv_ParseClientMessage(cl); } // we've processed the packet for the correct client, so break break; } } }
/* * Read a sound delta from the message buffer and play it. * Only used with psv_frame2 packets. */ void Cl_ReadSoundDelta2(deltatype_t type, boolean skip) { int sound = 0, soundFlags = 0; byte flags = 0; clmobj_t *cmo = NULL; thid_t mobjId = 0; sector_t *sector = NULL; polyobj_t *poly = NULL; mobj_t *emitter = NULL; float volume = 1; if(type == DT_SOUND) { // Delta ID is the sound ID. sound = Msg_ReadShort(); } else if(type == DT_MOBJ_SOUND) { if((cmo = Cl_FindMobj(mobjId = Msg_ReadShort())) != NULL) { if(cmo->flags & CLMF_HIDDEN) { // We can't play sounds from hidden mobjs, because we // aren't sure exactly where they are located. cmo = NULL; } else { emitter = &cmo->mo; } } } else if(type == DT_SECTOR_SOUND) { int index = (ushort) Msg_ReadShort(); if(index < numsectors) { sector = SECTOR_PTR(index); emitter = (mobj_t *) §or->soundorg; } } else /* DT_POLY_SOUND */ { int index = (ushort) Msg_ReadShort(); if(index < po_NumPolyobjs) { poly = PO_PTR(index); emitter = (mobj_t *) &poly->startSpot; } } flags = Msg_ReadByte(); if(type != DT_SOUND) { // The sound ID. sound = Msg_ReadShort(); } if(flags & SNDDF_VOLUME) { byte b = Msg_ReadByte(); if(b == 255) { // Full volume, no attenuation. soundFlags |= DDSF_NO_ATTENUATION; } else { volume = b / 127.0f; } } if(flags & SNDDF_REPEAT) { soundFlags |= DDSF_REPEAT; } // The delta has been read. Are we skipping? if(skip) return; // Now the entire delta has been read. // Should we start or stop a sound? if(volume > 0 && sound > 0) { // Do we need to queue this sound? if(type == DT_MOBJ_SOUND && !cmo) { // Create a new Hidden clmobj. cmo = Cl_CreateMobj(mobjId); cmo->flags |= CLMF_HIDDEN | CLMF_SOUND; cmo->sound = sound; cmo->volume = volume; /*#ifdef _DEBUG Con_Printf("Cl_ReadSoundDelta2(%i): Queueing: id=%i snd=%i vol=%.2f\n", type, mobjId, sound, volume); #endif */ // The sound will be started when the clmobj is unhidden. return; } // We will start a sound. if(type != DT_SOUND && !emitter) { // Not enough information. #ifdef _DEBUG Con_Printf("Cl_ReadSoundDelta2(%i): Insufficient data, snd=%i\n", type, sound); #endif return; } // Sounds originating from the viewmobj should really originate // from the real player mobj. if(cmo && cmo == playerstate[consoleplayer].cmo) { /*#ifdef _DEBUG Con_Printf("Cl_ReadSoundDelta2(%i): ViewMobj sound...\n", type); #endif */ emitter = players[consoleplayer].mo; } // First stop any sounds originating from the same emitter. // We allow only one sound per emitter. if(type != DT_SOUND && emitter) { S_StopSound(0, emitter); } S_LocalSoundAtVolume(sound | soundFlags, emitter, volume); /*#ifdef _DEBUG Con_Printf("Cl_ReadSoundDelta2(%i): Start snd=%i [%x] vol=%.2f", type, sound, flags, volume); if(cmo) Con_Printf(", mo=%i\n", cmo->mo.thinker.id); else if(sector) Con_Printf(", sector=%i\n", GET_SECTOR_IDX(sector)); else if(poly) Con_Printf(", poly=%i\n", GET_POLYOBJ_IDX(poly)); else Con_Printf("\n"); #endif */ } else if(sound >= 0) { // We must stop a sound. We'll only stop sounds from // specific sources. if(emitter) { S_StopSound(sound, emitter); /*#ifdef _DEBUG Con_Printf("Cl_ReadSoundDelta2(%i): Stop sound %i", type, sound); if(cmo) Con_Printf(", mo=%i\n", cmo->mo.thinker.id); else if(sector) Con_Printf(", sector=%i\n", GET_SECTOR_IDX(sector)); else if(poly) Con_Printf(", poly=%i\n", GET_POLYOBJ_IDX(poly)); else Con_Printf("\n"); #endif */ } } }
/* * Called when a psv_frame sound packet is received. */ void Cl_Sound(void) { int sound, volume = 127; float pos[3]; byte flags; int num; mobj_t *mo = NULL; flags = Msg_ReadByte(); // Sound ID. if(flags & SNDF_SHORT_SOUND_ID) { sound = Msg_ReadShort(); } else { sound = Msg_ReadByte(); } // Is the ID valid? if(sound < 1 || sound >= defs.count.sounds.num) { Con_Message("Cl_Sound: Out of bounds ID %i.\n", sound); return; // Bad sound ID! } #ifdef _DEBUG Con_Printf("Cl_Sound: %i\n", sound); #endif if(flags & SNDF_VOLUME) { volume = Msg_ReadByte(); if(volume > 127) { volume = 127; sound |= DDSF_NO_ATTENUATION; } } if(flags & SNDF_ID) { thid_t sourceId = Msg_ReadShort(); clmobj_t *cmo = Cl_FindMobj(sourceId); if(cmo) { S_LocalSoundAtVolume(sound, &cmo->mo, volume / 127.0f); } } else if(flags & SNDF_SECTOR) { num = Msg_ReadPackedShort(); if(num < 0 || num >= numsectors) { Con_Message("Cl_Sound: Invalid sector number %i.\n", num); return; } mo = (mobj_t *) &SECTOR_PTR(num)->soundorg; //S_StopSound(0, mo); S_LocalSoundAtVolume(sound, mo, volume / 127.0f); } else if(flags & SNDF_ORIGIN) { pos[VX] = Msg_ReadShort(); pos[VY] = Msg_ReadShort(); pos[VZ] = Msg_ReadShort(); S_LocalSoundAtVolumeFrom(sound, NULL, pos, volume / 127.0f); } else if(flags & SNDF_PLAYER) { S_LocalSoundAtVolume(sound, players[(flags & 0xf0) >> 4].mo, volume / 127.0f); }
/* * Sv_ParseClientMessage * * The current net_message is parsed for the given client. */ void Sv_ParseClientMessage(sv_client_t *cl) { user_cmd_t null_cmd, oldest_cmd, old_cmd, new_cmd; int net_drop; int strings_issued; int moves_issued; int last_frame; int c; char *s; sv_client = cl; sv_player = sv_client->edict; // allow a finite number of moves and strings moves_issued = strings_issued = 0; while (true) { if (net_message.read > net_message.size) { Com_Warn("Sv_ParseClientMessage: Bad read from %s\n", Sv_NetaddrToString(sv_client)); Sv_DropClient(cl); return; } c = Msg_ReadByte(&net_message); if (c == -1) break; switch (c) { case CL_CMD_USER_INFO: strncpy(cl->user_info, Msg_ReadString(&net_message), sizeof(cl->user_info) - 1); Sv_UserInfoChanged(cl); break; case CL_CMD_MOVE: if (++moves_issued > CMD_MAX_MOVES) { return; // someone is trying to cheat } last_frame = Msg_ReadLong(&net_message); if (last_frame != cl->last_frame) { cl->last_frame = last_frame; if (cl->last_frame > -1) { cl->frame_latency[cl->last_frame & (CLIENT_LATENCY_COUNTS - 1)] = svs.real_time - cl->frames[cl->last_frame & UPDATE_MASK].sent_time; } } memset(&null_cmd, 0, sizeof(null_cmd)); Msg_ReadDeltaUsercmd(&net_message, &null_cmd, &oldest_cmd); Msg_ReadDeltaUsercmd(&net_message, &oldest_cmd, &old_cmd); Msg_ReadDeltaUsercmd(&net_message, &old_cmd, &new_cmd); // don't start delta compression until the client is spawned // TODO: should this be a little higher up? if (cl->state != SV_CLIENT_ACTIVE) { cl->last_frame = -1; break; } // catch extremely high msec movements if (null_cmd.msec > CMD_MAX_MSEC || oldest_cmd.msec > CMD_MAX_MSEC || old_cmd.msec > CMD_MAX_MSEC || new_cmd.msec > CMD_MAX_MSEC) { Com_Warn("Sv_ParseClientMessage: Illegal msec from %s\n", Sv_NetaddrToString(cl)); Sv_KickClient(cl, "Illegal movement"); return; } net_drop = cl->netchan.dropped; if (net_drop < 20) { while (net_drop > 2) { Sv_ClientThink(cl, &cl->last_cmd); net_drop--; } if (net_drop > 1) Sv_ClientThink(cl, &oldest_cmd); if (net_drop > 0) Sv_ClientThink(cl, &old_cmd); } Sv_ClientThink(cl, &new_cmd); cl->last_cmd = new_cmd; break; case CL_CMD_STRING: s = Msg_ReadString(&net_message); // malicious users may try using too many string commands if (++strings_issued < CMD_MAX_STRINGS) Sv_UserStringCommand(s); else { Com_Warn( "Sv_ParseClientMessage: CMD_MAX_STRINGS exceeded for %s\n", Sv_NetaddrToString(cl)); Sv_KickClient(cl, "Too many commands."); return; } if (cl->state == SV_CLIENT_FREE) return; // disconnect command break; default: Com_Print("Sv_ParseClientMessage: unknown command %d\n", c); Sv_DropClient(cl); return; } } }