void ClientReliableWrite_Angle(client_t *cl, float f) { if (cl->num_backbuf) { MSG_WriteAngle(&cl->backbuf, f); ClientReliable_FinishWrite(cl); } else MSG_WriteAngle(&cl->netchan.message, f); }
// 2000-05-02 NVS SVC by Maddes void NVS_WriteAngle (int dest, float f, sizebuf_t *sb) { int i; switch (dest) { case MSG_INIT: if (sv.nvs_msgsignon->conversion_tab[sv.nvs_msgserver->numwrites-sv.nvs_msgwrites]) { if (sb) // special signon { MSG_WriteAngle(sb, f); } else { MSG_WriteAngle (&sv.signon, f); } } break; case MSG_ONE: case MSG_ALL: case MSG_BROADCAST: for (i=0 ; i<svs.maxclients ; i++) { if (NVS_CheckClient(&svs.clients[i])) { if (dest == MSG_BROADCAST) // unreliable { MSG_WriteAngle (&svs.clients[i].datagram, f); } else if (dest == MSG_ONE && sb) // special reliable MSG_ONE { MSG_WriteAngle (sb, f); } else // reliable MSG_ONE, MSG_ALL { MSG_WriteAngle (&svs.clients[i].message, f); } } } break; default: Host_Error ("NVS_WriteAngle: bad destination"); break; } NVS_CheckCounter(); }
/* ================ SV_CreateBaseline Entity baselines are used to compress the update messages to the clients -- only the fields that differ from the baseline will be transmitted ================ */ void SV_CreateBaseline (void) { int i; edict_t *svent; int entnum; for (entnum = 0; entnum < sv.num_edicts ; entnum++) { svent = EDICT_NUM(entnum); if (svent->free) continue; // create baselines for all player slots, // and any other edict that has a visible model if (entnum > MAX_CLIENTS && !svent->v.modelindex) continue; // // create entity baseline // VectorCopy (svent->v.origin, svent->baseline.origin); VectorCopy (svent->v.angles, svent->baseline.angles); svent->baseline.frame = svent->v.frame; svent->baseline.skinnum = svent->v.skin; if (entnum > 0 && entnum <= MAX_CLIENTS) { svent->baseline.colormap = entnum; svent->baseline.modelindex = SV_ModelIndex("progs/player.mdl"); } else { svent->baseline.colormap = 0; svent->baseline.modelindex = SV_ModelIndex(PR_GetString(svent->v.model)); } CRITICAL_MESSAGE(sv_signon_lock, SV_SIGNON_LOCK, 0, { // // flush the signon message out to a seperate buffer if // nearly full // SV_FlushSignon (); // // add to the message // MSG_WriteByte (&sv.signon,svc_spawnbaseline); MSG_WriteShort (&sv.signon,entnum); MSG_WriteByte (&sv.signon, svent->baseline.modelindex); MSG_WriteByte (&sv.signon, svent->baseline.frame); MSG_WriteByte (&sv.signon, svent->baseline.colormap); MSG_WriteByte (&sv.signon, svent->baseline.skinnum); for (i=0 ; i<3 ; i++) { MSG_WriteCoord(&sv.signon, svent->baseline.origin[i]); MSG_WriteAngle(&sv.signon, svent->baseline.angles[i]); } });
/* =================== SV_ReadClientMove =================== */ void SV_ReadClientMove (usercmd_t *move) { int i; vec3_t angle; int bits; // read ping time host_client->ping_times[host_client->num_pings%NUM_PING_TIMES] = sv.time - MSG_ReadFloat (); host_client->num_pings++; // read current angles if (host_client->netconnection->proquake_connection == MOD_PROQUAKE) { for (i = 0; i<3; i++) angle[i] = MSG_ReadPreciseAngle(); } else { for (i = 0; i<3; i++) angle[i] = MSG_ReadAngle(); } // ProQuake - server-side fullpitch fix if (!pq_fullpitch.value) { if (angle[PITCH] > 80 || angle[PITCH] < -70) { angle[PITCH] = COM_Clamp(angle[PITCH], -70, 80); MSG_WriteByte (&host_client->message, svc_setangle); for (i=0 ; i < 3 ; i++) MSG_WriteAngle (&host_client->message, angle[i] ); } } VectorCopy (angle, host_client->edict->v.v_angle); // read movement move->forwardmove = MSG_ReadShort (); move->sidemove = MSG_ReadShort (); move->upmove = MSG_ReadShort (); // read buttons bits = MSG_ReadByte (); host_client->edict->v.button0 = bits & 1; host_client->edict->v.button2 = (bits & 2)>>1; i = MSG_ReadByte (); if (i) host_client->edict->v.impulse = i; #ifdef QUAKE2 // read light level host_client->edict->v.light_level = MSG_ReadByte (); #endif }
void Server_MakeStatic(ServerEntity_t *ent) { int i,bits=0; if(ent->alpha == ENTALPHA_ZERO) { ED_Free(ent); return; } if(SV_ModelIndex(ent->v.model) & 0xFF00) bits |= B_LARGEMODEL; if((int)(ent->v.frame) & 0xFF00) bits |= B_LARGEFRAME; if(ent->alpha != ENTALPHA_DEFAULT) bits |= B_ALPHA; if(bits) { MSG_WriteByte(&sv.signon, SVC_SPAWNSTATIC2); MSG_WriteByte(&sv.signon, bits); } else MSG_WriteByte(&sv.signon, svc_spawnstatic); if(bits & B_LARGEMODEL) MSG_WriteShort(&sv.signon, SV_ModelIndex(ent->v.model)); else MSG_WriteByte(&sv.signon, SV_ModelIndex(ent->v.model)); if(bits & B_LARGEFRAME) MSG_WriteShort(&sv.signon,ent->v.frame); else MSG_WriteByte(&sv.signon,ent->v.frame); MSG_WriteByte(&sv.signon,ent->Model.fScale); MSG_WriteByte(&sv.signon,ent->v.colormap); MSG_WriteByte(&sv.signon,ent->Model.iSkin); for (i=0 ; i<3 ; i++) { MSG_WriteCoord(&sv.signon, ent->v.origin[i]); MSG_WriteAngle(&sv.signon, ent->v.angles[i]); } if (bits & B_ALPHA) MSG_WriteByte (&sv.signon, ent->alpha); ED_Free (ent); }
/* ================ SV_CreateBaseline Entity baselines are used to compress the update messages to the clients -- only the fields that differ from the baseline will be transmitted ================ */ void SV_CreateBaseline (void) { int i, entnum, max_edicts; edict_t *svent; // because baselines for entnum >= 512 don't make sense // FIXME, translate baselines nums as well as packet entity nums? max_edicts = min (sv.num_edicts, 512); for (entnum = 0; entnum < max_edicts ; entnum++) { svent = EDICT_NUM(entnum); if (svent->free) continue; // create baselines for all player slots, and any other edict that has a visible model if (entnum > MAX_CLIENTS && !svent->v.modelindex) continue; // create entity baseline VectorCopy (svent->v.origin, svent->baseline.origin); VectorCopy (svent->v.angles, svent->baseline.angles); svent->baseline.frame = svent->v.frame; svent->baseline.skinnum = svent->v.skin; if (entnum > 0 && entnum <= MAX_CLIENTS) { svent->baseline.colormap = entnum; svent->baseline.modelindex = SV_ModelIndex("progs/player.mdl"); } else { svent->baseline.colormap = 0; svent->baseline.modelindex = SV_ModelIndex(PR_GetString(svent->v.model)); } // flush the signon message out to a separate buffer if // nearly full SV_FlushSignon (); // add to the message MSG_WriteByte (&sv.signon,svc_spawnbaseline); MSG_WriteShort (&sv.signon,entnum); MSG_WriteByte (&sv.signon, svent->baseline.modelindex); MSG_WriteByte (&sv.signon, svent->baseline.frame); MSG_WriteByte (&sv.signon, svent->baseline.colormap); MSG_WriteByte (&sv.signon, svent->baseline.skinnum); for (i = 0; i < 3; i++) { MSG_WriteCoord(&sv.signon, svent->baseline.origin[i]); MSG_WriteAngle(&sv.signon, svent->baseline.angles[i]); } } }
// All changes need to be in SV_SendEffect(), SV_ParseEffect(), // SV_SaveEffects(), SV_LoadEffects(), CL_ParseEffect() static void SV_SendEffect (sizebuf_t *sb, int idx) { qboolean DoTest; vec3_t TestO1, Diff; float Size, TestDistance; int i, count; if (sb == &sv.reliable_datagram && sv_ce_scale.value > 0) DoTest = true; else DoTest = false; VectorClear(TestO1); TestDistance = 0; switch (sv.Effects[idx].type) { case CE_RAIN: case CE_SNOW: DoTest = false; break; case CE_FOUNTAIN: DoTest = false; break; case CE_QUAKE: VectorCopy(sv.Effects[idx].ef.Quake.origin, TestO1); TestDistance = 700; break; case CE_WHITE_SMOKE: case CE_GREEN_SMOKE: case CE_GREY_SMOKE: case CE_RED_SMOKE: case CE_SLOW_WHITE_SMOKE: case CE_TELESMK1: case CE_TELESMK2: case CE_GHOST: case CE_REDCLOUD: case CE_FLAMESTREAM: case CE_ACID_MUZZFL: case CE_FLAMEWALL: case CE_FLAMEWALL2: case CE_ONFIRE: VectorCopy(sv.Effects[idx].ef.Smoke.origin, TestO1); TestDistance = 250; break; case CE_SM_WHITE_FLASH: case CE_YELLOWRED_FLASH: case CE_BLUESPARK: case CE_YELLOWSPARK: case CE_SM_CIRCLE_EXP: case CE_BG_CIRCLE_EXP: case CE_SM_EXPLOSION: case CE_LG_EXPLOSION: case CE_FLOOR_EXPLOSION: case CE_BLUE_EXPLOSION: case CE_REDSPARK: case CE_GREENSPARK: case CE_ICEHIT: case CE_MEDUSA_HIT: case CE_MEZZO_REFLECT: case CE_FLOOR_EXPLOSION2: case CE_XBOW_EXPLOSION: case CE_NEW_EXPLOSION: case CE_MAGIC_MISSILE_EXPLOSION: case CE_BONE_EXPLOSION: case CE_BLDRN_EXPL: case CE_ACID_HIT: case CE_LBALL_EXPL: case CE_FIREWALL_SMALL: case CE_FIREWALL_MEDIUM: case CE_FIREWALL_LARGE: case CE_ACID_SPLAT: case CE_ACID_EXPL: case CE_FBOOM: case CE_BRN_BOUNCE: case CE_LSHOCK: case CE_BOMB: case CE_FLOOR_EXPLOSION3: VectorCopy(sv.Effects[idx].ef.Smoke.origin, TestO1); TestDistance = 250; break; case CE_WHITE_FLASH: case CE_BLUE_FLASH: case CE_SM_BLUE_FLASH: case CE_RED_FLASH: VectorCopy(sv.Effects[idx].ef.Smoke.origin, TestO1); TestDistance = 250; break; case CE_RIDER_DEATH: DoTest = false; break; case CE_GRAVITYWELL: DoTest = false; break; case CE_TELEPORTERPUFFS: VectorCopy(sv.Effects[idx].ef.Teleporter.origin, TestO1); TestDistance = 350; break; case CE_TELEPORTERBODY: VectorCopy(sv.Effects[idx].ef.Teleporter.origin, TestO1); TestDistance = 350; break; case CE_BONESHARD: case CE_BONESHRAPNEL: VectorCopy(sv.Effects[idx].ef.Missile.origin, TestO1); TestDistance = 600; break; case CE_CHUNK: VectorCopy(sv.Effects[idx].ef.Chunk.origin, TestO1); TestDistance = 600; break; default: PR_RunError ("%s: bad type", __thisfunc__); break; } if (!DoTest) count = 1; else { count = svs.maxclients; TestDistance = (float)TestDistance * sv_ce_scale.value; TestDistance *= TestDistance; } for (i = 0 ; i < count ; i++) { if (DoTest) { if (svs.clients[i].active) { sb = &svs.clients[i].datagram; VectorSubtract(svs.clients[i].edict->v.origin, TestO1, Diff); Size = (Diff[0]*Diff[0]) + (Diff[1]*Diff[1]) + (Diff[2]*Diff[2]); if (Size > TestDistance) continue; if (sv_ce_max_size.value > 0 && sb->cursize > sv_ce_max_size.value) continue; } else continue; } MSG_WriteByte (sb, svc_start_effect); MSG_WriteByte (sb, idx); MSG_WriteByte (sb, sv.Effects[idx].type); switch (sv.Effects[idx].type) { case CE_RAIN: MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.min_org[0]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.min_org[1]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.min_org[2]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.max_org[0]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.max_org[1]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.max_org[2]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.e_size[0]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.e_size[1]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.e_size[2]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.dir[0]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.dir[1]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.dir[2]); MSG_WriteShort(sb, sv.Effects[idx].ef.Rain.color); MSG_WriteShort(sb, sv.Effects[idx].ef.Rain.count); MSG_WriteFloat(sb, sv.Effects[idx].ef.Rain.wait); break; case CE_SNOW: MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.min_org[0]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.min_org[1]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.min_org[2]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.max_org[0]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.max_org[1]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.max_org[2]); MSG_WriteByte(sb, sv.Effects[idx].ef.Rain.flags); MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.dir[0]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.dir[1]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.dir[2]); MSG_WriteByte(sb, sv.Effects[idx].ef.Rain.count); //MSG_WriteShort(sb, sv.Effects[idx].ef.Rain.veer); break; case CE_FOUNTAIN: MSG_WriteCoord(sb, sv.Effects[idx].ef.Fountain.pos[0]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Fountain.pos[1]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Fountain.pos[2]); MSG_WriteAngle(sb, sv.Effects[idx].ef.Fountain.angle[0]); MSG_WriteAngle(sb, sv.Effects[idx].ef.Fountain.angle[1]); MSG_WriteAngle(sb, sv.Effects[idx].ef.Fountain.angle[2]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Fountain.movedir[0]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Fountain.movedir[1]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Fountain.movedir[2]); MSG_WriteShort(sb, sv.Effects[idx].ef.Fountain.color); MSG_WriteByte(sb, sv.Effects[idx].ef.Fountain.cnt); break; case CE_QUAKE: MSG_WriteCoord(sb, sv.Effects[idx].ef.Quake.origin[0]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Quake.origin[1]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Quake.origin[2]); MSG_WriteFloat(sb, sv.Effects[idx].ef.Quake.radius); break; case CE_WHITE_SMOKE: case CE_GREEN_SMOKE: case CE_GREY_SMOKE: case CE_RED_SMOKE: case CE_SLOW_WHITE_SMOKE: case CE_TELESMK1: case CE_TELESMK2: case CE_GHOST: case CE_REDCLOUD: case CE_FLAMESTREAM: case CE_ACID_MUZZFL: case CE_FLAMEWALL: case CE_FLAMEWALL2: case CE_ONFIRE: MSG_WriteCoord(sb, sv.Effects[idx].ef.Smoke.origin[0]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Smoke.origin[1]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Smoke.origin[2]); MSG_WriteFloat(sb, sv.Effects[idx].ef.Smoke.velocity[0]); MSG_WriteFloat(sb, sv.Effects[idx].ef.Smoke.velocity[1]); MSG_WriteFloat(sb, sv.Effects[idx].ef.Smoke.velocity[2]); MSG_WriteFloat(sb, sv.Effects[idx].ef.Smoke.framelength); /* smoke frame is a mission pack thing only. */ if (sv_protocol > PROTOCOL_RAVEN_111) MSG_WriteFloat(sb, sv.Effects[idx].ef.Smoke.frame); break; case CE_SM_WHITE_FLASH: case CE_YELLOWRED_FLASH: case CE_BLUESPARK: case CE_YELLOWSPARK: case CE_SM_CIRCLE_EXP: case CE_BG_CIRCLE_EXP: case CE_SM_EXPLOSION: case CE_LG_EXPLOSION: case CE_FLOOR_EXPLOSION: case CE_FLOOR_EXPLOSION3: case CE_BLUE_EXPLOSION: case CE_REDSPARK: case CE_GREENSPARK: case CE_ICEHIT: case CE_MEDUSA_HIT: case CE_MEZZO_REFLECT: case CE_FLOOR_EXPLOSION2: case CE_XBOW_EXPLOSION: case CE_NEW_EXPLOSION: case CE_MAGIC_MISSILE_EXPLOSION: case CE_BONE_EXPLOSION: case CE_BLDRN_EXPL: case CE_ACID_HIT: case CE_ACID_SPLAT: case CE_ACID_EXPL: case CE_LBALL_EXPL: case CE_FIREWALL_SMALL: case CE_FIREWALL_MEDIUM: case CE_FIREWALL_LARGE: case CE_FBOOM: case CE_BOMB: case CE_BRN_BOUNCE: case CE_LSHOCK: MSG_WriteCoord(sb, sv.Effects[idx].ef.Smoke.origin[0]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Smoke.origin[1]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Smoke.origin[2]); break; case CE_WHITE_FLASH: case CE_BLUE_FLASH: case CE_SM_BLUE_FLASH: case CE_RED_FLASH: MSG_WriteCoord(sb, sv.Effects[idx].ef.Smoke.origin[0]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Smoke.origin[1]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Smoke.origin[2]); break; case CE_RIDER_DEATH: MSG_WriteCoord(sb, sv.Effects[idx].ef.RD.origin[0]); MSG_WriteCoord(sb, sv.Effects[idx].ef.RD.origin[1]); MSG_WriteCoord(sb, sv.Effects[idx].ef.RD.origin[2]); break; case CE_TELEPORTERPUFFS: MSG_WriteCoord(sb, sv.Effects[idx].ef.Teleporter.origin[0]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Teleporter.origin[1]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Teleporter.origin[2]); break; case CE_TELEPORTERBODY: MSG_WriteCoord(sb, sv.Effects[idx].ef.Teleporter.origin[0]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Teleporter.origin[1]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Teleporter.origin[2]); MSG_WriteFloat(sb, sv.Effects[idx].ef.Teleporter.velocity[0][0]); MSG_WriteFloat(sb, sv.Effects[idx].ef.Teleporter.velocity[0][1]); MSG_WriteFloat(sb, sv.Effects[idx].ef.Teleporter.velocity[0][2]); MSG_WriteFloat(sb, sv.Effects[idx].ef.Teleporter.skinnum); break; case CE_BONESHARD: case CE_BONESHRAPNEL: MSG_WriteCoord(sb, sv.Effects[idx].ef.Missile.origin[0]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Missile.origin[1]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Missile.origin[2]); MSG_WriteFloat(sb, sv.Effects[idx].ef.Missile.velocity[0]); MSG_WriteFloat(sb, sv.Effects[idx].ef.Missile.velocity[1]); MSG_WriteFloat(sb, sv.Effects[idx].ef.Missile.velocity[2]); MSG_WriteFloat(sb, sv.Effects[idx].ef.Missile.angle[0]); MSG_WriteFloat(sb, sv.Effects[idx].ef.Missile.angle[1]); MSG_WriteFloat(sb, sv.Effects[idx].ef.Missile.angle[2]); MSG_WriteFloat(sb, sv.Effects[idx].ef.Missile.avelocity[0]); MSG_WriteFloat(sb, sv.Effects[idx].ef.Missile.avelocity[1]); MSG_WriteFloat(sb, sv.Effects[idx].ef.Missile.avelocity[2]); break; case CE_GRAVITYWELL: MSG_WriteCoord(sb, sv.Effects[idx].ef.RD.origin[0]); MSG_WriteCoord(sb, sv.Effects[idx].ef.RD.origin[1]); MSG_WriteCoord(sb, sv.Effects[idx].ef.RD.origin[2]); MSG_WriteShort(sb, sv.Effects[idx].ef.RD.color); MSG_WriteFloat(sb, sv.Effects[idx].ef.RD.lifetime); break; case CE_CHUNK: MSG_WriteCoord(sb, sv.Effects[idx].ef.Chunk.origin[0]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Chunk.origin[1]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Chunk.origin[2]); MSG_WriteByte (sb, sv.Effects[idx].ef.Chunk.type); MSG_WriteCoord(sb, sv.Effects[idx].ef.Chunk.srcVel[0]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Chunk.srcVel[1]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Chunk.srcVel[2]); MSG_WriteByte (sb, sv.Effects[idx].ef.Chunk.numChunks); // Con_Printf ("Adding %d chunks on server...\n", sv.Effects[idx].Chunk.numChunks); break; default: PR_RunError ("%s: bad type", __thisfunc__); break; } } }
/* ==================== CL_Record_f record <demoname> <server> ==================== */ void CL_Record_f (void) { int c; char name[MAX_OSPATH]; sizebuf_t buf; char buf_data[MAX_MSGLEN]; int n, i, j; char *s; entity_t *ent; entity_state_t *es, blankes; player_info_t *player; extern char gamedirfile[]; int seq = 1; c = Cmd_Argc(); if (c != 2) { Con_Printf ("record <demoname>\n"); return; } if (cls.state != ca_active) { Con_Printf ("You must be connected to record.\n"); return; } if (cls.demorecording) CL_Stop_f(); sprintf (name, "%s/%s", com_gamedir, Cmd_Argv(1)); // // open the demo file // COM_DefaultExtension (name, ".qwd"); cls.demofile = fopen (name, "wb"); if (!cls.demofile) { Con_Printf ("ERROR: couldn't open.\n"); return; } Con_Printf ("recording to %s.\n", name); cls.demorecording = true; /*-------------------------------------------------*/ // serverdata // send the info about the new client to all connected clients memset(&buf, 0, sizeof(buf)); buf.data = buf_data; buf.maxsize = sizeof(buf_data); // send the serverdata MSG_WriteByte (&buf, svc_serverdata); MSG_WriteLong (&buf, PROTOCOL_VERSION); MSG_WriteLong (&buf, cl.servercount); MSG_WriteString (&buf, gamedirfile); if (cl.spectator) MSG_WriteByte (&buf, cl.playernum | 128); else MSG_WriteByte (&buf, cl.playernum); // send full levelname MSG_WriteString (&buf, cl.levelname); // send the movevars MSG_WriteFloat(&buf, movevars.gravity); MSG_WriteFloat(&buf, movevars.stopspeed); MSG_WriteFloat(&buf, movevars.maxspeed); MSG_WriteFloat(&buf, movevars.spectatormaxspeed); MSG_WriteFloat(&buf, movevars.accelerate); MSG_WriteFloat(&buf, movevars.airaccelerate); MSG_WriteFloat(&buf, movevars.wateraccelerate); MSG_WriteFloat(&buf, movevars.friction); MSG_WriteFloat(&buf, movevars.waterfriction); MSG_WriteFloat(&buf, movevars.entgravity); // send music MSG_WriteByte (&buf, svc_cdtrack); MSG_WriteByte (&buf, 0); // none in demos // send server info string MSG_WriteByte (&buf, svc_stufftext); MSG_WriteString (&buf, va("fullserverinfo \"%s\"\n", cl.serverinfo) ); // flush packet CL_WriteRecordDemoMessage (&buf, seq++); SZ_Clear (&buf); // soundlist MSG_WriteByte (&buf, svc_soundlist); MSG_WriteByte (&buf, 0); n = 0; s = cl.sound_name[n+1]; while (*s) { MSG_WriteString (&buf, s); if (buf.cursize > MAX_MSGLEN/2) { MSG_WriteByte (&buf, 0); MSG_WriteByte (&buf, n); CL_WriteRecordDemoMessage (&buf, seq++); SZ_Clear (&buf); MSG_WriteByte (&buf, svc_soundlist); MSG_WriteByte (&buf, n + 1); } n++; s = cl.sound_name[n+1]; } if (buf.cursize) { MSG_WriteByte (&buf, 0); MSG_WriteByte (&buf, 0); CL_WriteRecordDemoMessage (&buf, seq++); SZ_Clear (&buf); } // modellist MSG_WriteByte (&buf, svc_modellist); MSG_WriteByte (&buf, 0); n = 0; s = cl.model_name[n+1]; while (*s) { MSG_WriteString (&buf, s); if (buf.cursize > MAX_MSGLEN/2) { MSG_WriteByte (&buf, 0); MSG_WriteByte (&buf, n); CL_WriteRecordDemoMessage (&buf, seq++); SZ_Clear (&buf); MSG_WriteByte (&buf, svc_modellist); MSG_WriteByte (&buf, n + 1); } n++; s = cl.model_name[n+1]; } if (buf.cursize) { MSG_WriteByte (&buf, 0); MSG_WriteByte (&buf, 0); CL_WriteRecordDemoMessage (&buf, seq++); SZ_Clear (&buf); } // spawnstatic for (i = 0; i < cl.num_statics; i++) { ent = cl_static_entities + i; MSG_WriteByte (&buf, svc_spawnstatic); for (j = 1; j < MAX_MODELS; j++) if (ent->model == cl.model_precache[j]) break; if (j == MAX_MODELS) MSG_WriteByte (&buf, 0); else MSG_WriteByte (&buf, j); MSG_WriteByte (&buf, ent->frame); MSG_WriteByte (&buf, 0); MSG_WriteByte (&buf, ent->skinnum); for (j=0 ; j<3 ; j++) { MSG_WriteCoord (&buf, ent->origin[j]); MSG_WriteAngle (&buf, ent->angles[j]); } if (buf.cursize > MAX_MSGLEN/2) { CL_WriteRecordDemoMessage (&buf, seq++); SZ_Clear (&buf); } } // spawnstaticsound // static sounds are skipped in demos, life is hard // baselines memset(&blankes, 0, sizeof(blankes)); for (i = 0; i < MAX_EDICTS; i++) { es = cl_baselines + i; if (memcmp(es, &blankes, sizeof(blankes))) { MSG_WriteByte (&buf,svc_spawnbaseline); MSG_WriteShort (&buf, i); MSG_WriteByte (&buf, es->modelindex); MSG_WriteByte (&buf, es->frame); MSG_WriteByte (&buf, es->colormap); MSG_WriteByte (&buf, es->skinnum); for (j=0 ; j<3 ; j++) { MSG_WriteCoord(&buf, es->origin[j]); MSG_WriteAngle(&buf, es->angles[j]); } if (buf.cursize > MAX_MSGLEN/2) { CL_WriteRecordDemoMessage (&buf, seq++); SZ_Clear (&buf); } } } MSG_WriteByte (&buf, svc_stufftext); MSG_WriteString (&buf, va("cmd spawn %i 0\n", cl.servercount) ); if (buf.cursize) { CL_WriteRecordDemoMessage (&buf, seq++); SZ_Clear (&buf); } // send current status of all other players for (i = 0; i < MAX_CLIENTS; i++) { player = cl.players + i; MSG_WriteByte (&buf, svc_updatefrags); MSG_WriteByte (&buf, i); MSG_WriteShort (&buf, player->frags); MSG_WriteByte (&buf, svc_updateping); MSG_WriteByte (&buf, i); MSG_WriteShort (&buf, player->ping); MSG_WriteByte (&buf, svc_updatepl); MSG_WriteByte (&buf, i); MSG_WriteByte (&buf, player->pl); MSG_WriteByte (&buf, svc_updateentertime); MSG_WriteByte (&buf, i); MSG_WriteFloat (&buf, player->entertime); MSG_WriteByte (&buf, svc_updateuserinfo); MSG_WriteByte (&buf, i); MSG_WriteLong (&buf, player->userid); MSG_WriteString (&buf, player->userinfo); if (buf.cursize > MAX_MSGLEN/2) { CL_WriteRecordDemoMessage (&buf, seq++); SZ_Clear (&buf); } } // send all current light styles for (i=0 ; i<MAX_LIGHTSTYLES ; i++) { MSG_WriteByte (&buf, svc_lightstyle); MSG_WriteByte (&buf, (char)i); MSG_WriteString (&buf, cl_lightstyle[i].map); } for (i = 0; i < MAX_CL_STATS; i++) { MSG_WriteByte (&buf, svc_updatestatlong); MSG_WriteByte (&buf, i); MSG_WriteLong (&buf, cl.stats[i]); if (buf.cursize > MAX_MSGLEN/2) { CL_WriteRecordDemoMessage (&buf, seq++); SZ_Clear (&buf); } } #if 0 MSG_WriteByte (&buf, svc_updatestatlong); MSG_WriteByte (&buf, STAT_TOTALMONSTERS); MSG_WriteLong (&buf, cl.stats[STAT_TOTALMONSTERS]); MSG_WriteByte (&buf, svc_updatestatlong); MSG_WriteByte (&buf, STAT_SECRETS); MSG_WriteLong (&buf, cl.stats[STAT_SECRETS]); MSG_WriteByte (&buf, svc_updatestatlong); MSG_WriteByte (&buf, STAT_MONSTERS); MSG_WriteLong (&buf, cl.stats[STAT_MONSTERS]); #endif // get the client to check and download skins // when that is completed, a begin command will be issued MSG_WriteByte (&buf, svc_stufftext); MSG_WriteString (&buf, va("skins\n") ); CL_WriteRecordDemoMessage (&buf, seq++); CL_WriteSetDemoMessage(); // done }
/* ============== CL_SendMove ============== */ void CL_SendMove (usercmd_t *cmd) { int i; int bits; sizebuf_t buf; byte data[128]; buf.maxsize = 128; buf.cursize = 0; buf.data = data; cl.cmd = *cmd; // // send the movement message // MSG_WriteByte (&buf, clc_move); MSG_WriteFloat (&buf, cl.mtime[0]); // so server can get ping times for (i=0 ; i<3 ; i++) MSG_WriteAngle (&buf, cl.viewangles[i]); MSG_WriteShort (&buf, cmd->forwardmove); MSG_WriteShort (&buf, cmd->sidemove); MSG_WriteShort (&buf, cmd->upmove); // // send button bits // bits = 0; if ( in_attack.state & 3 ) bits |= 1; in_attack.state &= ~2; if (in_jump.state & 3) bits |= 2; in_jump.state &= ~2; MSG_WriteByte (&buf, bits); MSG_WriteByte (&buf, in_impulse); in_impulse = 0; // // deliver the message // if (cls.demoplayback) return; // // allways dump the first two message, because it may contain leftover inputs // from the last level // if (++cl.movemessages <= 2) return; if (NET_SendUnreliableMessage (cls.netcon, &buf) == -1) { Con_Printf ("CL_SendMove: lost server connection\n"); CL_Disconnect (); } }
// All changes need to be in SV_SendEffect(), SV_ParseEffect(), // SV_SaveEffects(), SV_LoadEffects(), CL_ParseEffect() void SV_SendEffect(sizebuf_t *sb, int index) { qboolean DoTest; vec3_t TestO; int TestDistance; int i; if (sv_ce_scale.value > 0) DoTest = true; else DoTest = false; VectorCopy(vec3_origin, TestO); switch(sv.Effects[index].type) { case CE_HWSHEEPINATOR: case CE_HWXBOWSHOOT: VectorCopy(sv.Effects[index].Xbow.origin[5], TestO); TestDistance = 900; break; case CE_SCARABCHAIN: VectorCopy(sv.Effects[index].Chain.origin, TestO); TestDistance = 900; break; case CE_TRIPMINE: VectorCopy(sv.Effects[index].Chain.origin, TestO); // DoTest = false; break; //ACHTUNG!!!!!!! setting DoTest to false here does not insure that effect will be sent to everyone! case CE_TRIPMINESTILL: TestDistance = 10000; DoTest = false; break; case CE_RAIN: TestDistance = 10000; DoTest = false; break; case CE_FOUNTAIN: TestDistance = 10000; DoTest = false; break; case CE_QUAKE: VectorCopy(sv.Effects[index].Quake.origin, TestO); TestDistance = 700; break; case CE_WHITE_SMOKE: case CE_GREEN_SMOKE: case CE_GREY_SMOKE: case CE_RED_SMOKE: case CE_SLOW_WHITE_SMOKE: case CE_TELESMK1: case CE_TELESMK2: case CE_GHOST: case CE_REDCLOUD: case CE_FLAMESTREAM: case CE_ACID_MUZZFL: case CE_FLAMEWALL: case CE_FLAMEWALL2: case CE_ONFIRE: case CE_RIPPLE: VectorCopy(sv.Effects[index].Smoke.origin, TestO); TestDistance = 250; break; case CE_SM_WHITE_FLASH: case CE_YELLOWRED_FLASH: case CE_BLUESPARK: case CE_YELLOWSPARK: case CE_SM_CIRCLE_EXP: case CE_BG_CIRCLE_EXP: case CE_SM_EXPLOSION: case CE_SM_EXPLOSION2: case CE_BG_EXPLOSION: case CE_FLOOR_EXPLOSION: case CE_BLUE_EXPLOSION: case CE_REDSPARK: case CE_GREENSPARK: case CE_ICEHIT: case CE_MEDUSA_HIT: case CE_MEZZO_REFLECT: case CE_FLOOR_EXPLOSION2: case CE_XBOW_EXPLOSION: case CE_NEW_EXPLOSION: case CE_MAGIC_MISSILE_EXPLOSION: case CE_BONE_EXPLOSION: case CE_BLDRN_EXPL: case CE_ACID_HIT: case CE_LBALL_EXPL: case CE_FIREWALL_SMALL: case CE_FIREWALL_MEDIUM: case CE_FIREWALL_LARGE: case CE_ACID_SPLAT: case CE_ACID_EXPL: case CE_FBOOM: case CE_BRN_BOUNCE: case CE_LSHOCK: case CE_BOMB: case CE_FLOOR_EXPLOSION3: VectorCopy(sv.Effects[index].Smoke.origin, TestO); TestDistance = 250; break; case CE_WHITE_FLASH: case CE_BLUE_FLASH: case CE_SM_BLUE_FLASH: case CE_HWSPLITFLASH: case CE_RED_FLASH: VectorCopy(sv.Effects[index].Smoke.origin, TestO); TestDistance = 250; break; case CE_RIDER_DEATH: DoTest = false; break; case CE_TELEPORTERPUFFS: VectorCopy(sv.Effects[index].Teleporter.origin, TestO); TestDistance = 350; break; case CE_TELEPORTERBODY: VectorCopy(sv.Effects[index].Teleporter.origin, TestO); TestDistance = 350; break; case CE_DEATHBUBBLES: if (sv.Effects[index].Bubble.owner < 0 || sv.Effects[index].Bubble.owner >= sv.num_edicts) { return; } VectorCopy(PROG_TO_EDICT(sv.Effects[index].Bubble.owner)->v.origin, TestO); TestDistance = 400; break; case CE_HWDRILLA: case CE_BONESHARD: case CE_BONESHRAPNEL: case CE_HWBONEBALL: case CE_HWRAVENSTAFF: case CE_HWRAVENPOWER: VectorCopy(sv.Effects[index].Missile.origin, TestO); TestDistance = 900; break; case CE_HWMISSILESTAR: case CE_HWEIDOLONSTAR: VectorCopy(sv.Effects[index].Missile.origin, TestO); TestDistance = 600; break; default: // Sys_Error ("SV_SendEffect: bad type"); PR_RunError ("SV_SendEffect: bad type"); break; } MSG_WriteByte (&sv.multicast, svc_start_effect); MSG_WriteByte (&sv.multicast, index); MSG_WriteByte (&sv.multicast, sv.Effects[index].type); switch(sv.Effects[index].type) { case CE_RAIN: MSG_WriteCoord(&sv.multicast, sv.Effects[index].Rain.min_org[0]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Rain.min_org[1]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Rain.min_org[2]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Rain.max_org[0]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Rain.max_org[1]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Rain.max_org[2]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Rain.e_size[0]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Rain.e_size[1]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Rain.e_size[2]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Rain.dir[0]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Rain.dir[1]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Rain.dir[2]); MSG_WriteShort(&sv.multicast, sv.Effects[index].Rain.color); MSG_WriteShort(&sv.multicast, sv.Effects[index].Rain.count); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Rain.wait); break; case CE_FOUNTAIN: MSG_WriteCoord(&sv.multicast, sv.Effects[index].Fountain.pos[0]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Fountain.pos[1]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Fountain.pos[2]); MSG_WriteAngle(&sv.multicast, sv.Effects[index].Fountain.angle[0]); MSG_WriteAngle(&sv.multicast, sv.Effects[index].Fountain.angle[1]); MSG_WriteAngle(&sv.multicast, sv.Effects[index].Fountain.angle[2]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Fountain.movedir[0]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Fountain.movedir[1]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Fountain.movedir[2]); MSG_WriteShort(&sv.multicast, sv.Effects[index].Fountain.color); MSG_WriteByte(&sv.multicast, sv.Effects[index].Fountain.cnt); break; case CE_QUAKE: MSG_WriteCoord(&sv.multicast, sv.Effects[index].Quake.origin[0]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Quake.origin[1]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Quake.origin[2]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Quake.radius); break; case CE_WHITE_SMOKE: case CE_GREEN_SMOKE: case CE_GREY_SMOKE: case CE_RED_SMOKE: case CE_SLOW_WHITE_SMOKE: case CE_TELESMK1: case CE_TELESMK2: case CE_GHOST: case CE_REDCLOUD: case CE_FLAMESTREAM: case CE_ACID_MUZZFL: case CE_FLAMEWALL: case CE_FLAMEWALL2: case CE_ONFIRE: case CE_RIPPLE: MSG_WriteCoord(&sv.multicast, sv.Effects[index].Smoke.origin[0]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Smoke.origin[1]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Smoke.origin[2]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Smoke.velocity[0]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Smoke.velocity[1]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Smoke.velocity[2]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Smoke.framelength); break; case CE_SM_WHITE_FLASH: case CE_YELLOWRED_FLASH: case CE_BLUESPARK: case CE_YELLOWSPARK: case CE_SM_CIRCLE_EXP: case CE_BG_CIRCLE_EXP: case CE_SM_EXPLOSION: case CE_SM_EXPLOSION2: case CE_BG_EXPLOSION: case CE_FLOOR_EXPLOSION: case CE_BLUE_EXPLOSION: case CE_REDSPARK: case CE_GREENSPARK: case CE_ICEHIT: case CE_MEDUSA_HIT: case CE_MEZZO_REFLECT: case CE_FLOOR_EXPLOSION2: case CE_XBOW_EXPLOSION: case CE_NEW_EXPLOSION: case CE_MAGIC_MISSILE_EXPLOSION: case CE_BONE_EXPLOSION: case CE_BLDRN_EXPL: case CE_ACID_HIT: case CE_ACID_SPLAT: case CE_ACID_EXPL: case CE_LBALL_EXPL: case CE_FIREWALL_SMALL: case CE_FIREWALL_MEDIUM: case CE_FIREWALL_LARGE: case CE_FBOOM: case CE_BOMB: case CE_BRN_BOUNCE: case CE_LSHOCK: MSG_WriteCoord(&sv.multicast, sv.Effects[index].Smoke.origin[0]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Smoke.origin[1]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Smoke.origin[2]); break; case CE_WHITE_FLASH: case CE_BLUE_FLASH: case CE_SM_BLUE_FLASH: case CE_HWSPLITFLASH: case CE_RED_FLASH: MSG_WriteCoord(&sv.multicast, sv.Effects[index].Smoke.origin[0]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Smoke.origin[1]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Smoke.origin[2]); break; case CE_RIDER_DEATH: MSG_WriteCoord(&sv.multicast, sv.Effects[index].RD.origin[0]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].RD.origin[1]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].RD.origin[2]); break; case CE_TELEPORTERPUFFS: MSG_WriteCoord(&sv.multicast, sv.Effects[index].Teleporter.origin[0]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Teleporter.origin[1]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Teleporter.origin[2]); break; case CE_TELEPORTERBODY: MSG_WriteCoord(&sv.multicast, sv.Effects[index].Teleporter.origin[0]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Teleporter.origin[1]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Teleporter.origin[2]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Teleporter.velocity[0][0]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Teleporter.velocity[0][1]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Teleporter.velocity[0][2]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Teleporter.skinnum); break; case CE_BONESHRAPNEL: case CE_HWBONEBALL: MSG_WriteCoord(&sv.multicast, sv.Effects[index].Missile.origin[0]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Missile.origin[1]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Missile.origin[2]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Missile.velocity[0]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Missile.velocity[1]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Missile.velocity[2]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Missile.angle[0]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Missile.angle[1]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Missile.angle[2]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Missile.avelocity[0]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Missile.avelocity[1]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Missile.avelocity[2]); break; case CE_BONESHARD: case CE_HWRAVENSTAFF: case CE_HWMISSILESTAR: case CE_HWEIDOLONSTAR: case CE_HWRAVENPOWER: MSG_WriteCoord(&sv.multicast, sv.Effects[index].Missile.origin[0]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Missile.origin[1]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Missile.origin[2]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Missile.velocity[0]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Missile.velocity[1]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Missile.velocity[2]); break; case CE_HWDRILLA: MSG_WriteCoord(&sv.multicast, sv.Effects[index].Missile.origin[0]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Missile.origin[1]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Missile.origin[2]); MSG_WriteAngle(&sv.multicast, sv.Effects[index].Missile.angle[0]); MSG_WriteAngle(&sv.multicast, sv.Effects[index].Missile.angle[1]); MSG_WriteShort(&sv.multicast, sv.Effects[index].Missile.speed); break; case CE_DEATHBUBBLES: MSG_WriteShort(&sv.multicast, sv.Effects[index].Bubble.owner); MSG_WriteByte(&sv.multicast, sv.Effects[index].Bubble.offset[0]); MSG_WriteByte(&sv.multicast, sv.Effects[index].Bubble.offset[1]); MSG_WriteByte(&sv.multicast, sv.Effects[index].Bubble.offset[2]); MSG_WriteByte(&sv.multicast, sv.Effects[index].Bubble.count); break; case CE_SCARABCHAIN: MSG_WriteCoord(&sv.multicast, sv.Effects[index].Chain.origin[0]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Chain.origin[1]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Chain.origin[2]); MSG_WriteShort(&sv.multicast, sv.Effects[index].Chain.owner+sv.Effects[index].Chain.material); MSG_WriteByte(&sv.multicast, sv.Effects[index].Chain.tag); break; case CE_TRIPMINESTILL: case CE_TRIPMINE: MSG_WriteCoord(&sv.multicast, sv.Effects[index].Chain.origin[0]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Chain.origin[1]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Chain.origin[2]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Chain.velocity[0]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Chain.velocity[1]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Chain.velocity[2]); break; case CE_HWSHEEPINATOR: MSG_WriteCoord(&sv.multicast, sv.Effects[index].Xbow.origin[5][0]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Xbow.origin[5][1]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Xbow.origin[5][2]); MSG_WriteAngle(&sv.multicast, sv.Effects[index].Xbow.angle[0]); MSG_WriteAngle(&sv.multicast, sv.Effects[index].Xbow.angle[1]); //now send the guys that have turned MSG_WriteByte(&sv.multicast, sv.Effects[index].Xbow.turnedbolts); MSG_WriteByte(&sv.multicast, sv.Effects[index].Xbow.activebolts); for (i=0;i<5;i++) { if ((1<<i)&sv.Effects[index].Xbow.turnedbolts) { MSG_WriteCoord(&sv.multicast, sv.Effects[index].Xbow.origin[i][0]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Xbow.origin[i][1]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Xbow.origin[i][2]); MSG_WriteAngle(&sv.multicast, sv.Effects[index].Xbow.vel[i][0]); MSG_WriteAngle(&sv.multicast, sv.Effects[index].Xbow.vel[i][1]); } } break; case CE_HWXBOWSHOOT: MSG_WriteCoord(&sv.multicast, sv.Effects[index].Xbow.origin[5][0]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Xbow.origin[5][1]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Xbow.origin[5][2]); MSG_WriteAngle(&sv.multicast, sv.Effects[index].Xbow.angle[0]); MSG_WriteAngle(&sv.multicast, sv.Effects[index].Xbow.angle[1]); // MSG_WriteFloat(&sv.multicast, sv.Effects[index].Xbow.angle[2]); MSG_WriteByte(&sv.multicast, sv.Effects[index].Xbow.bolts); MSG_WriteByte(&sv.multicast, sv.Effects[index].Xbow.randseed); //now send the guys that have turned MSG_WriteByte(&sv.multicast, sv.Effects[index].Xbow.turnedbolts); MSG_WriteByte(&sv.multicast, sv.Effects[index].Xbow.activebolts); for (i=0;i<5;i++) { if ((1<<i)&sv.Effects[index].Xbow.turnedbolts) { MSG_WriteCoord(&sv.multicast, sv.Effects[index].Xbow.origin[i][0]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Xbow.origin[i][1]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Xbow.origin[i][2]); MSG_WriteAngle(&sv.multicast, sv.Effects[index].Xbow.vel[i][0]); MSG_WriteAngle(&sv.multicast, sv.Effects[index].Xbow.vel[i][1]); } } break; default: // Sys_Error ("SV_SendEffect: bad type"); PR_RunError ("SV_SendEffect: bad type"); break; } if (sb) { SZ_Write (sb, sv.multicast.data, sv.multicast.cursize); SZ_Clear (&sv.multicast); } else { if (DoTest) { SV_Multicast (TestO, MULTICAST_PVS_R); } else { SV_Multicast (TestO, MULTICAST_ALL_R); } sv.Effects[index].client_list = clients_multicast; } }
void EXT_FUNC MSG_WriteAngle_api(sizebuf_t *sb, float f) { MSG_WriteAngle(sb, f); }
static qbool SV_MVD_Record (mvddest_t *dest) { sizebuf_t buf; byte buf_data[MAX_MSGLEN]; int n, i; char *s, info[MAX_INFO_STRING]; client_t *player; char *gamedir; if (!dest) return false; DestFlush(true); if (!sv.mvdrecording) { memset(&demo, 0, sizeof(demo)); for (i = 0; i < UPDATE_BACKUP; i++) { demo.recorder.frames[i] = demo_frames[i]; demo.recorder.frames[i].entities.entities = demo_entities[i]; } MVDBuffer_Init(&demo.dbuffer, demo.buffer, sizeof(demo.buffer)); MVDSetMsgBuf(NULL, &demo.frames[0].buf); demo.datagram.maxsize = sizeof(demo.datagram_data); demo.datagram.data = demo.datagram_data; sv.mvdrecording = true; } // else // SV_WriteRecordMVDMessage(&buf); demo.pingtime = demo.time = sv.time; dest->nextdest = demo.dest; demo.dest = dest; singledest = dest; /*-------------------------------------------------*/ // serverdata // send the info about the new client to all connected clients SZ_Init (&buf, buf_data, sizeof(buf_data)); // send the serverdata gamedir = Info_ValueForKey (svs.info, "*gamedir"); if (!gamedir[0]) gamedir = "qw"; MSG_WriteByte (&buf, svc_serverdata); MSG_WriteLong (&buf, PROTOCOL_VERSION); MSG_WriteLong (&buf, svs.spawncount); MSG_WriteString (&buf, gamedir); MSG_WriteFloat (&buf, sv.time); // send full levelname MSG_WriteString (&buf, sv.mapname); // send the movevars MSG_WriteFloat(&buf, sv.movevars.gravity); MSG_WriteFloat(&buf, sv.movevars.stopspeed); MSG_WriteFloat(&buf, sv.movevars.maxspeed); MSG_WriteFloat(&buf, sv.movevars.spectatormaxspeed); MSG_WriteFloat(&buf, sv.movevars.accelerate); MSG_WriteFloat(&buf, sv.movevars.airaccelerate); MSG_WriteFloat(&buf, sv.movevars.wateraccelerate); MSG_WriteFloat(&buf, sv.movevars.friction); MSG_WriteFloat(&buf, sv.movevars.waterfriction); MSG_WriteFloat(&buf, sv.movevars.entgravity); // send music MSG_WriteByte (&buf, svc_cdtrack); MSG_WriteByte (&buf, 0); // none in demos // send server info string MSG_WriteByte (&buf, svc_stufftext); MSG_WriteString (&buf, va("fullserverinfo \"%s\"\n", svs.info) ); // flush packet SV_WriteRecordMVDMessage (&buf); SZ_Clear (&buf); // soundlist MSG_WriteByte (&buf, svc_soundlist); MSG_WriteByte (&buf, 0); n = 0; s = sv.sound_name[n+1]; while (s) { MSG_WriteString (&buf, s); if (buf.cursize > MAX_MSGLEN/2) { MSG_WriteByte (&buf, 0); MSG_WriteByte (&buf, n); SV_WriteRecordMVDMessage (&buf); SZ_Clear (&buf); MSG_WriteByte (&buf, svc_soundlist); MSG_WriteByte (&buf, n + 1); } n++; s = sv.sound_name[n+1]; } if (buf.cursize) { MSG_WriteByte (&buf, 0); MSG_WriteByte (&buf, 0); SV_WriteRecordMVDMessage (&buf); SZ_Clear (&buf); } // modellist MSG_WriteByte (&buf, svc_modellist); MSG_WriteByte (&buf, 0); n = 0; s = sv.model_name[n+1]; while (s) { MSG_WriteString (&buf, s); if (buf.cursize > MAX_MSGLEN/2) { MSG_WriteByte (&buf, 0); MSG_WriteByte (&buf, n); SV_WriteRecordMVDMessage (&buf); SZ_Clear (&buf); MSG_WriteByte (&buf, svc_modellist); MSG_WriteByte (&buf, n + 1); } n++; s = sv.model_name[n+1]; } if (buf.cursize) { MSG_WriteByte (&buf, 0); MSG_WriteByte (&buf, 0); SV_WriteRecordMVDMessage (&buf); SZ_Clear (&buf); } // baselines { entity_state_t from; edict_t *ent; entity_state_t *state; memset(&from, 0, sizeof(from)); for (n = 0; n < sv.num_edicts; n++) { ent = EDICT_NUM(n); state = &ent->baseline; if (!state->number || !state->modelindex) { //ent doesn't have a baseline continue; } if (!ent) { MSG_WriteByte(&buf, svc_spawnbaseline); MSG_WriteShort (&buf, n); MSG_WriteByte (&buf, 0); MSG_WriteByte (&buf, 0); MSG_WriteByte (&buf, 0); MSG_WriteByte (&buf, 0); for (i=0 ; i<3 ; i++) { MSG_WriteCoord(&buf, 0); MSG_WriteAngle(&buf, 0); } } else { MSG_WriteByte(&buf, svc_spawnbaseline); MSG_WriteShort (&buf, n); MSG_WriteByte (&buf, state->modelindex&255); MSG_WriteByte (&buf, state->frame); MSG_WriteByte (&buf, (int)state->colormap); MSG_WriteByte (&buf, (int)state->skinnum); for (i=0 ; i<3 ; i++) { MSG_WriteCoord(&buf, state->s_origin[i]); MSG_WriteAngle(&buf, state->s_angles[i]); } } if (buf.cursize > MAX_MSGLEN/2) { SV_WriteRecordMVDMessage (&buf); SZ_Clear (&buf); } } } //prespawn for (n = 0; n < sv.num_signon_buffers; n++) { if (buf.cursize+sv.signon_buffer_size[n] > MAX_MSGLEN/2) { SV_WriteRecordMVDMessage (&buf); SZ_Clear (&buf); } SZ_Write (&buf, sv.signon_buffers[n], sv.signon_buffer_size[n]); } if (buf.cursize > MAX_MSGLEN/2) { SV_WriteRecordMVDMessage (&buf); SZ_Clear (&buf); } MSG_WriteByte (&buf, svc_stufftext); MSG_WriteString (&buf, va("cmd spawn %i\n",svs.spawncount) ); if (buf.cursize) { SV_WriteRecordMVDMessage (&buf); SZ_Clear (&buf); } // send current status of all other players for (i = 0; i < MAX_CLIENTS; i++) { player = svs.clients + i; MSG_WriteByte (&buf, svc_updatefrags); MSG_WriteByte (&buf, i); MSG_WriteShort (&buf, player->old_frags); MSG_WriteByte (&buf, svc_updateping); MSG_WriteByte (&buf, i); MSG_WriteShort (&buf, SV_CalcPing(player)); MSG_WriteByte (&buf, svc_updatepl); MSG_WriteByte (&buf, i); MSG_WriteByte (&buf, player->lossage); MSG_WriteByte (&buf, svc_updateentertime); MSG_WriteByte (&buf, i); MSG_WriteFloat (&buf, svs.realtime - player->connection_started); Q_strncpyz (info, player->userinfo, MAX_INFO_STRING); Info_RemovePrefixedKeys (info, '_'); // server passwords, etc MSG_WriteByte (&buf, svc_updateuserinfo); MSG_WriteByte (&buf, i); MSG_WriteLong (&buf, player->userid); MSG_WriteString (&buf, info); if (buf.cursize > MAX_MSGLEN/2) { SV_WriteRecordMVDMessage (&buf); SZ_Clear (&buf); } } // send all current light styles for (i=0 ; i<MAX_LIGHTSTYLES ; i++) { MSG_WriteByte (&buf, svc_lightstyle); MSG_WriteByte (&buf, (char)i); MSG_WriteString (&buf, sv.lightstyles[i]); } // get the client to check and download skins // when that is completed, a begin command will be issued MSG_WriteByte (&buf, svc_stufftext); MSG_WriteString (&buf, "skins\n"); SV_WriteRecordMVDMessage (&buf); SV_WriteSetMVDMessage(); singledest = NULL; // done return true; }
void SV_Begin_f (void) { unsigned pmodel = 0, emodel = 0; int i; if (host_client->state == cs_spawned) return; // don't begin again host_client->state = cs_spawned; // handle the case of a level changing while a client was connecting if ( atoi(Cmd_Argv(1)) != svs.spawncount ) { Con_Printf ("SV_Begin_f from different level\n"); SV_New_f (); return; } if (host_client->spectator) { SV_SpawnSpectator (); if (SpectatorConnect) { // copy spawn parms out of the client_t for (i=0 ; i< NUM_SPAWN_PARMS ; i++) (&pr_global_struct->parm1)[i] = host_client->spawn_parms[i]; // call the spawn function pr_global_struct->time = sv.time; pr_global_struct->self = EDICT_TO_PROG(sv_player); PR_ExecuteProgram (SpectatorConnect); } } else { // copy spawn parms out of the client_t for (i=0 ; i< NUM_SPAWN_PARMS ; i++) (&pr_global_struct->parm1)[i] = host_client->spawn_parms[i]; // call the spawn function pr_global_struct->time = sv.time; pr_global_struct->self = EDICT_TO_PROG(sv_player); PR_ExecuteProgram (pr_global_struct->ClientConnect); // actually spawn the player pr_global_struct->time = sv.time; pr_global_struct->self = EDICT_TO_PROG(sv_player); PR_ExecuteProgram (pr_global_struct->PutClientInServer); } // clear the net statistics, because connecting gives a bogus picture host_client->netchan.frame_latency = 0; host_client->netchan.frame_rate = 0; host_client->netchan.drop_count = 0; host_client->netchan.good_count = 0; //check he's not cheating pmodel = atoi(Info_ValueForKey (host_client->userinfo, "pmodel")); emodel = atoi(Info_ValueForKey (host_client->userinfo, "emodel")); if (pmodel != sv.model_player_checksum || emodel != sv.eyes_player_checksum) SV_BroadcastPrintf (PRINT_HIGH, "%s WARNING: non standard player/eyes model detected\n", host_client->name); // if we are paused, tell the client if (sv.paused) { ClientReliableWrite_Begin (host_client, svc_setpause, 2); ClientReliableWrite_Byte (host_client, sv.paused); SV_ClientPrintf(host_client, PRINT_HIGH, "Server is paused.\n"); } #if 0 // // send a fixangle over the reliable channel to make sure it gets there // Never send a roll angle, because savegames can catch the server // in a state where it is expecting the client to correct the angle // and it won't happen if the game was just loaded, so you wind up // with a permanent head tilt ent = EDICT_NUM( 1 + (host_client - svs.clients) ); MSG_WriteByte (&host_client->netchan.message, svc_setangle); for (i=0 ; i < 2 ; i++) MSG_WriteAngle (&host_client->netchan.message, ent->v.angles[i] ); MSG_WriteAngle (&host_client->netchan.message, 0 ); #endif }
void Game_WriteAngle(int mode,float f) { MSG_WriteAngle(Game_WriteDest(mode),f); }
/* ==================== CL_Record Called by CL_Record_f and CL_EasyRecord_f ==================== */ static void CL_Record (void) { sizebuf_t buf; byte buf_data[MAX_MSGLEN]; int n, i, j; char *s; entity_t *ent; entity_state_t *es, blankes; player_info_t *player; int seq = 1; #ifdef MVDPLAY if (cls.mvdplayback) { Com_Printf ("Can't record while playing MVD demo.\n"); return; } #endif cls.demorecording = true; /*-------------------------------------------------*/ // serverdata // send the info about the new client to all connected clients SZ_Init (&buf, buf_data, sizeof(buf_data)); // send the serverdata MSG_WriteByte (&buf, svc_serverdata); MSG_WriteLong (&buf, PROTOCOL_VERSION); MSG_WriteLong (&buf, cl.servercount); MSG_WriteString (&buf, cls.gamedirfile); if (cl.spectator) MSG_WriteByte (&buf, cl.playernum | 128); else MSG_WriteByte (&buf, cl.playernum); // send full levelname MSG_WriteString (&buf, cl.levelname); // send the movevars MSG_WriteFloat(&buf, movevars.gravity); MSG_WriteFloat(&buf, movevars.stopspeed); MSG_WriteFloat(&buf, cl.maxspeed); MSG_WriteFloat(&buf, movevars.spectatormaxspeed); MSG_WriteFloat(&buf, movevars.accelerate); MSG_WriteFloat(&buf, movevars.airaccelerate); MSG_WriteFloat(&buf, movevars.wateraccelerate); MSG_WriteFloat(&buf, movevars.friction); MSG_WriteFloat(&buf, movevars.waterfriction); MSG_WriteFloat(&buf, cl.entgravity); // send music MSG_WriteByte (&buf, svc_cdtrack); MSG_WriteByte (&buf, 0); // none in demos // send server info string MSG_WriteByte (&buf, svc_stufftext); MSG_WriteString (&buf, va("fullserverinfo \"%s\"\n", cl.serverinfo) ); // flush packet CL_WriteRecordDemoMessage (&buf, seq++); SZ_Clear (&buf); // soundlist MSG_WriteByte (&buf, svc_soundlist); MSG_WriteByte (&buf, 0); n = 0; s = cl.sound_name[n+1]; while (*s) { MSG_WriteString (&buf, s); if (buf.cursize > MAX_MSGLEN/2) { MSG_WriteByte (&buf, 0); MSG_WriteByte (&buf, n); CL_WriteRecordDemoMessage (&buf, seq++); SZ_Clear (&buf); MSG_WriteByte (&buf, svc_soundlist); MSG_WriteByte (&buf, n + 1); } n++; s = cl.sound_name[n+1]; } if (buf.cursize) { MSG_WriteByte (&buf, 0); MSG_WriteByte (&buf, 0); CL_WriteRecordDemoMessage (&buf, seq++); SZ_Clear (&buf); } #ifdef VWEP_TEST // vwep modellist if ((cl.z_ext & Z_EXT_VWEP) && cl.vw_model_name[0][0]) { // send VWep precaches // pray we don't overflow for (i = 0; i < MAX_VWEP_MODELS; i++) { s = cl.vw_model_name[i]; if (!*s) continue; MSG_WriteByte (&buf, svc_serverinfo); MSG_WriteString (&buf, "#vw"); MSG_WriteString (&buf, va("%i %s", i, TrimModelName(s))); } // send end-of-list messsage MSG_WriteByte (&buf, svc_serverinfo); MSG_WriteString (&buf, "#vw"); MSG_WriteString (&buf, ""); } // don't bother flushing, the vwep list is not that large (I hope) #endif // modellist MSG_WriteByte (&buf, svc_modellist); MSG_WriteByte (&buf, 0); n = 0; s = cl.model_name[n+1]; while (*s) { MSG_WriteString (&buf, s); if (buf.cursize > MAX_MSGLEN/2) { MSG_WriteByte (&buf, 0); MSG_WriteByte (&buf, n); CL_WriteRecordDemoMessage (&buf, seq++); SZ_Clear (&buf); MSG_WriteByte (&buf, svc_modellist); MSG_WriteByte (&buf, n + 1); } n++; s = cl.model_name[n+1]; } if (buf.cursize) { MSG_WriteByte (&buf, 0); MSG_WriteByte (&buf, 0); CL_WriteRecordDemoMessage (&buf, seq++); SZ_Clear (&buf); } // spawnstatic for (i = 0; i < cl.num_statics; i++) { ent = cl_static_entities + i; MSG_WriteByte (&buf, svc_spawnstatic); for (j = 1; j < MAX_MODELS; j++) if (ent->model == cl.model_precache[j]) break; if (j == MAX_MODELS) MSG_WriteByte (&buf, 0); else MSG_WriteByte (&buf, j); MSG_WriteByte (&buf, ent->frame); MSG_WriteByte (&buf, 0); MSG_WriteByte (&buf, ent->skinnum); for (j=0 ; j<3 ; j++) { MSG_WriteCoord (&buf, ent->origin[j]); MSG_WriteAngle (&buf, ent->angles[j]); } if (buf.cursize > MAX_MSGLEN/2) { CL_WriteRecordDemoMessage (&buf, seq++); SZ_Clear (&buf); } } // spawnstaticsound for (i = 0; i < cl.num_static_sounds; i++) { static_sound_t *ss = &cl.static_sounds[i]; MSG_WriteByte (&buf, svc_spawnstaticsound); for (j = 0; j < 3; j++) MSG_WriteCoord (&buf, ss->org[j]); MSG_WriteByte (&buf, ss->sound_num); MSG_WriteByte (&buf, ss->vol); MSG_WriteByte (&buf, ss->atten); if (buf.cursize > MAX_MSGLEN/2) { CL_WriteRecordDemoMessage (&buf, seq++); SZ_Clear (&buf); } } // baselines memset(&blankes, 0, sizeof(blankes)); for (i = 0; i < MAX_CL_EDICTS; i++) { es = &cl_entities[i].baseline; if (memcmp(es, &blankes, sizeof(blankes))) { MSG_WriteByte (&buf,svc_spawnbaseline); MSG_WriteShort (&buf, i); MSG_WriteByte (&buf, es->modelindex); MSG_WriteByte (&buf, es->frame); MSG_WriteByte (&buf, es->colormap); MSG_WriteByte (&buf, es->skinnum); for (j=0 ; j<3 ; j++) { MSG_WriteShort (&buf, es->s_origin[j]); MSG_WriteByte (&buf, es->s_angles[j]); } if (buf.cursize > MAX_MSGLEN/2) { CL_WriteRecordDemoMessage (&buf, seq++); SZ_Clear (&buf); } } } MSG_WriteByte (&buf, svc_stufftext); MSG_WriteString (&buf, va("cmd spawn %i 0\n", cl.servercount) ); if (buf.cursize) { CL_WriteRecordDemoMessage (&buf, seq++); SZ_Clear (&buf); } // send current status of all other players for (i = 0; i < MAX_CLIENTS; i++) { player = cl.players + i; MSG_WriteByte (&buf, svc_updatefrags); MSG_WriteByte (&buf, i); MSG_WriteShort (&buf, player->frags); MSG_WriteByte (&buf, svc_updateping); MSG_WriteByte (&buf, i); MSG_WriteShort (&buf, player->ping); MSG_WriteByte (&buf, svc_updatepl); MSG_WriteByte (&buf, i); MSG_WriteByte (&buf, player->pl); MSG_WriteByte (&buf, svc_updateentertime); MSG_WriteByte (&buf, i); MSG_WriteFloat (&buf, cls.realtime - player->entertime); MSG_WriteByte (&buf, svc_updateuserinfo); MSG_WriteByte (&buf, i); MSG_WriteLong (&buf, player->userid); MSG_WriteString (&buf, player->userinfo); if (buf.cursize > MAX_MSGLEN/2) { CL_WriteRecordDemoMessage (&buf, seq++); SZ_Clear (&buf); } } // send all current light styles for (i=0 ; i<MAX_LIGHTSTYLES ; i++) { if (!cl_lightstyle[i].length) continue; // don't send empty lightstyle strings MSG_WriteByte (&buf, svc_lightstyle); MSG_WriteByte (&buf, (char)i); MSG_WriteString (&buf, cl_lightstyle[i].map); } for (i = 0; i < MAX_CL_STATS; i++) { if (!cl.stats[i]) continue; // no need to send zero values if (cl.stats[i] >= 0 && cl.stats[i] <= 255) { MSG_WriteByte (&buf, svc_updatestat); MSG_WriteByte (&buf, i); MSG_WriteByte (&buf, cl.stats[i]); } else { MSG_WriteByte (&buf, svc_updatestatlong); MSG_WriteByte (&buf, i); MSG_WriteLong (&buf, cl.stats[i]); } if (buf.cursize > MAX_MSGLEN/2) { CL_WriteRecordDemoMessage (&buf, seq++); SZ_Clear (&buf); } } // get the client to check and download skins // when that is completed, a begin command will be issued MSG_WriteByte (&buf, svc_stufftext); MSG_WriteString (&buf, va("skins\n") ); CL_WriteRecordDemoMessage (&buf, seq++); CL_WriteSetDemoMessage(); // done }
static void VM_M_WriteAngle (prvm_prog_t *prog) { VM_SAFEPARMCOUNT(1, VM_M_WriteAngle); MSG_WriteAngle (VM_M_WriteDest(prog), PRVM_G_FLOAT(OFS_PARM0), sv.protocol); }
void ClientReliableWrite_Angle (float f) { assert (backbuf_write_started); MSG_WriteAngle (&backbuf, f); }
/* ================== SV_Begin_f ================== */ static void SV_Begin_f (void) { int i; host_client->state = cs_spawned; // handle the case of a level changing while a client was connecting if ( atoi(Cmd_Argv(1)) != svs.spawncount ) { Con_Printf ("%s from different level\n", __thisfunc__); SV_New_f (); return; } if (host_client->spectator) { SV_SpawnSpectator (); if (SpectatorConnect) { // copy spawn parms out of the client_t for (i = 0; i < NUM_SPAWN_PARMS; i++) (&pr_global_struct->parm1)[i] = host_client->spawn_parms[i]; // call the spawn function pr_global_struct->time = sv.time; pr_global_struct->self = EDICT_TO_PROG(sv_player); PR_ExecuteProgram (SpectatorConnect); } } else { // copy spawn parms out of the client_t for (i = 0; i < NUM_SPAWN_PARMS; i++) (&pr_global_struct->parm1)[i] = host_client->spawn_parms[i]; host_client->send_all_v = true; // call the spawn function pr_global_struct->time = sv.time; pr_global_struct->self = EDICT_TO_PROG(sv_player); PR_ExecuteProgram (pr_global_struct->ClientConnect); // actually spawn the player pr_global_struct->time = sv.time; pr_global_struct->self = EDICT_TO_PROG(sv_player); PR_ExecuteProgram (pr_global_struct->PutClientInServer); } // clear the net statistics, because connecting gives a bogus picture host_client->netchan.frame_latency = 0; host_client->netchan.frame_rate = 0; host_client->netchan.drop_count = 0; host_client->netchan.good_count = 0; #if 0 // // send a fixangle over the reliable channel to make sure it gets there // Never send a roll angle, because savegames can catch the server // in a state where it is expecting the client to correct the angle // and it won't happen if the game was just loaded, so you wind up // with a permanent head tilt ent = EDICT_NUM( 1 + (host_client - svs.clients) ); MSG_WriteByte (&host_client->netchan.message, svc_setangle); for (i = 0; i < 2; i++) MSG_WriteAngle (&host_client->netchan.message, ent->v.angles[i] ); MSG_WriteAngle (&host_client->netchan.message, 0 ); #endif }
static void Host_Spawn_f (void) { int i; client_t *client; edict_t *ent; float *sendangles; if (cmd_source == src_command) { Sys_Printf ("spawn is not valid from the console\n"); return; } if (host_client->spawned) { Sys_Printf ("Spawn not valid -- already spawned\n"); return; } // run the entrance script if (sv.loadgame) { // loaded games are fully inited already // if this is the last client to be connected, unpause sv.paused = false; } else { // set up the edict ent = host_client->edict; memset (&ent->v, 0, sv_pr_state.progs->entityfields * 4); SVfloat (ent, colormap) = NUM_FOR_EDICT (&sv_pr_state, ent); SVfloat (ent, team) = (host_client->colors & 15) + 1; SVstring (ent, netname) = PR_SetString (&sv_pr_state, host_client->name); // copy spawn parms out of the client_t for (i = 0; i < NUM_SPAWN_PARMS; i++) sv_globals.parms[i] = host_client->spawn_parms[i]; // call the spawn function *sv_globals.time = sv.time; *sv_globals.self = EDICT_TO_PROG (&sv_pr_state, sv_player); PR_ExecuteProgram (&sv_pr_state, sv_funcs.ClientConnect); if ((Sys_DoubleTime () - host_client->netconnection->connecttime) <= sv.time) Sys_Printf ("%s entered the game\n", host_client->name); PR_ExecuteProgram (&sv_pr_state, sv_funcs.PutClientInServer); } // send all current names, colors, and frag counts SZ_Clear (&host_client->message); // send time of update MSG_WriteByte (&host_client->message, svc_time); MSG_WriteFloat (&host_client->message, sv.time); for (i = 0, client = svs.clients; i < svs.maxclients; i++, client++) { MSG_WriteByte (&host_client->message, svc_updatename); MSG_WriteByte (&host_client->message, i); MSG_WriteString (&host_client->message, client->name); MSG_WriteByte (&host_client->message, svc_updatefrags); MSG_WriteByte (&host_client->message, i); MSG_WriteShort (&host_client->message, client->old_frags); MSG_WriteByte (&host_client->message, svc_updatecolors); MSG_WriteByte (&host_client->message, i); MSG_WriteByte (&host_client->message, client->colors); } // send all current light styles for (i = 0; i < MAX_LIGHTSTYLES; i++) { MSG_WriteByte (&host_client->message, svc_lightstyle); MSG_WriteByte (&host_client->message, (char) i); MSG_WriteString (&host_client->message, sv.lightstyles[i]); } // send some stats MSG_WriteByte (&host_client->message, svc_updatestat); MSG_WriteByte (&host_client->message, STAT_TOTALSECRETS); MSG_WriteLong (&host_client->message, *sv_globals.total_secrets); MSG_WriteByte (&host_client->message, svc_updatestat); MSG_WriteByte (&host_client->message, STAT_TOTALMONSTERS); MSG_WriteLong (&host_client->message, *sv_globals.total_monsters); MSG_WriteByte (&host_client->message, svc_updatestat); MSG_WriteByte (&host_client->message, STAT_SECRETS); MSG_WriteLong (&host_client->message, *sv_globals.found_secrets); MSG_WriteByte (&host_client->message, svc_updatestat); MSG_WriteByte (&host_client->message, STAT_MONSTERS); MSG_WriteLong (&host_client->message, *sv_globals.killed_monsters); // send a fixangle // Never send a roll angle, because savegames can catch the server // in a state where it is expecting the client to correct the angle // and it won't happen if the game was just loaded, so you wind up // with a permanent head tilt ent = EDICT_NUM (&sv_pr_state, 1 + (host_client - svs.clients)); MSG_WriteByte (&host_client->message, svc_setangle); sendangles = sv.loadgame ? SVvector (ent, v_angle): SVvector (ent, angles); MSG_WriteAngle (&host_client->message, sendangles[0]); MSG_WriteAngle (&host_client->message, sendangles[1]); MSG_WriteAngle (&host_client->message, 0); SV_WriteClientdataToMessage (sv_player, &host_client->message); MSG_WriteByte (&host_client->message, svc_signonnum); MSG_WriteByte (&host_client->message, 3); host_client->sendsignon = true; }