/* * ======================= * SV_SendClientDatagram * ======================= */ static bool SV_SendClientDatagram(client_t client) { byte[] buf = new byte[quakedef.MAX_DATAGRAM]; common.sizebuf_t msg = new common.sizebuf_t(); msg.data = buf; msg.maxsize = buf.Length; msg.cursize = 0; common.MSG_WriteByte(msg, net.svc_time); common.MSG_WriteFloat(msg, sv.time); // add the client specific data to the datagram SV_WriteClientdataToMessage(client.edict, msg); SV_WriteEntitiesToClient(client.edict, msg); // copy the server datagram if there is space if (msg.cursize + sv.datagram.cursize < msg.maxsize) { common.SZ_Write(msg, sv.datagram.data, sv.datagram.cursize); } // send the datagram if (net.NET_SendUnreliableMessage(client.netconnection, msg) == -1) { return(false); } return(true); }
/* * ======================= * SV_SendNop * * Send a nop message without trashing or sending the accumulated client * message buffer * ======================= */ static void SV_SendNop(client_t client) { common.sizebuf_t msg = new common.sizebuf_t(); byte[] buf = new byte[4]; msg.data = buf; msg.maxsize = buf.Length; msg.cursize = 0; common.MSG_WriteChar(msg, net.svc_nop); net.NET_SendUnreliableMessage(client.netconnection, msg); client.last_message = host.realtime; }
/* * ================ * SV_SendReconnect * * Tell all the clients that the server is changing levels * ================ */ static void SV_SendReconnect() { byte[] data = new byte[128]; common.sizebuf_t msg = new common.sizebuf_t(); msg.data = data; msg.cursize = 0; msg.maxsize = data.Length; common.MSG_WriteChar(msg, net.svc_stufftext); common.MSG_WriteString(msg, "reconnect\n"); net.NET_SendToAll(msg, 5); if (client.cls.state != client.cactive_t.ca_dedicated) { quake.cmd.Cmd_ExecuteString("reconnect\n\0".ToCharArray(), quake.cmd.cmd_source_t.src_command); } }
static int Loop_SendMessage(qsocket_t sock, common.sizebuf_t data) { byte[] buffer; int ofs; int bufferLength; if (sock.driverdata == null) { return(-1); } bufferLength = ((qsocket_t)sock.driverdata).receiveMessageLength; if ((bufferLength + data.cursize + 4) > NET_MAXMESSAGE) { sys_linux.Sys_Error("Loop_SendMessage: overflow\n"); } buffer = ((qsocket_t)sock.driverdata).receiveMessage; ofs = bufferLength; // message type buffer[ofs++] = 1; // length buffer[ofs++] = (byte)(data.cursize & 0xff); buffer[ofs++] = (byte)(data.cursize >> 8); // align ofs++; // message Buffer.BlockCopy(data.data, 0, buffer, ofs, data.cursize); ((qsocket_t)sock.driverdata).receiveMessageLength = IntAlign(bufferLength + data.cursize + 4); sock.canSend = false; return(1); }
static int Loop_SendUnreliableMessage(qsocket_t sock, common.sizebuf_t data) { byte[] buffer; int ofs; int bufferLength; if (sock.driverdata == null) { return(-1); } bufferLength = ((qsocket_t)sock.driverdata).receiveMessageLength; if ((bufferLength + data.cursize + sizeof(byte) + sizeof(short)) > NET_MAXMESSAGE) { return(0); } buffer = ((qsocket_t)sock.driverdata).receiveMessage; ofs = bufferLength; // message type buffer[ofs++] = 2; // length buffer[ofs++] = (byte)(data.cursize & 0xff); buffer[ofs++] = (byte)(data.cursize >> 8); // align ofs++; // message Buffer.BlockCopy(data.data, 0, buffer, ofs, data.cursize); ((qsocket_t)sock.driverdata).receiveMessageLength = IntAlign(bufferLength + data.cursize + 4); return(1); }
static void CL_KeepaliveMessage() { double time; int ret; common.sizebuf_t old = new common.sizebuf_t(); byte[] olddata = new byte[8192]; if (server.sv.active) return; // no need if server is local if (client.cls.demoplayback) return; // read messages from server, should just be nops common.sizebuf_t.Copy(net.net_message, old); Buffer.BlockCopy(net.net_message.data, 0, olddata, 0, net.net_message.cursize); do { ret = CL_GetMessage (); switch (ret) { default: host.Host_Error("CL_KeepaliveMessage: CL_GetMessage failed"); break; case 0: break; // nothing waiting case 1: host.Host_Error("CL_KeepaliveMessage: received a message"); break; case 2: if (common.MSG_ReadByte() != net.svc_nop) host.Host_Error ("CL_KeepaliveMessage: datagram wasn't a nop"); break; } } while (ret != 0); common.sizebuf_t.Copy(old, net.net_message); Buffer.BlockCopy(olddata, 0, net.net_message.data, 0, net.net_message.cursize); // check time time = sys_linux.Sys_FloatTime (); if (time - lastmsg < 5) return; lastmsg = time; // write out a nop console.Con_Printf ("--> client to server keepalive\n"); common.MSG_WriteByte (cls.message, net.clc_nop); net.NET_SendMessage (cls.netcon, cls.message); common.SZ_Clear (cls.message); }
/* ================ SV_SendReconnect Tell all the clients that the server is changing levels ================ */ static void SV_SendReconnect() { byte[] data = new byte[128]; common.sizebuf_t msg = new common.sizebuf_t(); msg.data = data; msg.cursize = 0; msg.maxsize = data.Length; common.MSG_WriteChar (msg, net.svc_stufftext); common.MSG_WriteString (msg, "reconnect\n"); net.NET_SendToAll (msg, 5); if (client.cls.state != client.cactive_t.ca_dedicated) quake.cmd.Cmd_ExecuteString("reconnect\n\0".ToCharArray(), quake.cmd.cmd_source_t.src_command); }
/* ======================= SV_SendNop Send a nop message without trashing or sending the accumulated client message buffer ======================= */ static void SV_SendNop(client_t client) { common.sizebuf_t msg = new common.sizebuf_t(); byte[] buf = new byte[4]; msg.data = buf; msg.maxsize = buf.Length; msg.cursize = 0; common.MSG_WriteChar (msg, net.svc_nop); net.NET_SendUnreliableMessage (client.netconnection, msg); client.last_message = host.realtime; }
/* ======================= SV_SendClientDatagram ======================= */ static bool SV_SendClientDatagram(client_t client) { byte[] buf = new byte[quakedef.MAX_DATAGRAM]; common.sizebuf_t msg = new common.sizebuf_t(); msg.data = buf; msg.maxsize = buf.Length; msg.cursize = 0; common.MSG_WriteByte (msg, net.svc_time); common.MSG_WriteFloat (msg, sv.time); // add the client specific data to the datagram SV_WriteClientdataToMessage(client.edict, msg); SV_WriteEntitiesToClient(client.edict, msg); // copy the server datagram if there is space if (msg.cursize + sv.datagram.cursize < msg.maxsize) common.SZ_Write(msg, sv.datagram.data, sv.datagram.cursize); // send the datagram if (net.NET_SendUnreliableMessage (client.netconnection, msg) == -1) { return false; } return true; }
/* * ================== * SV_WriteClientdataToMessage * * ================== */ public static void SV_WriteClientdataToMessage(prog.edict_t ent, common.sizebuf_t msg) { int bits; int i; prog.edict_t other; int items; // // send a damage message // if (ent.v.dmg_take != 0 || ent.v.dmg_save != 0) { other = prog.PROG_TO_EDICT(ent.v.dmg_inflictor); common.MSG_WriteByte(msg, net.svc_damage); common.MSG_WriteByte(msg, (int)ent.v.dmg_save); common.MSG_WriteByte(msg, (int)ent.v.dmg_take); for (i = 0; i < 3; i++) { common.MSG_WriteCoord(msg, other.v.origin[i] + 0.5 * (other.v.mins[i] + other.v.maxs[i])); } ent.v.dmg_take = 0; ent.v.dmg_save = 0; } // // send the current viewpos offset from the view entity // SV_SetIdealPitch(); // how much to look up / down ideally // a fixangle might get lost in a dropped packet. Oh well. if (ent.v.fixangle != 0) { common.MSG_WriteByte(msg, net.svc_setangle); for (i = 0; i < 3; i++) { common.MSG_WriteAngle(msg, ent.v.angles[i]); } ent.v.fixangle = 0; } bits = 0; if (ent.v.view_ofs[2] != net.DEFAULT_VIEWHEIGHT) { bits |= net.SU_VIEWHEIGHT; } if (ent.v.idealpitch != 0) { bits |= net.SU_IDEALPITCH; } // stuff the sigil bits into the high bits of items for sbar, or else // mix in items2 //val = GetEdictFieldValue(ent, "items2"); /*if (val) * items = (int)ent->v.items | ((int)val->_float << 23); * else*/ items = (int)ent.v.items | ((int)prog.pr_global_struct[0].serverflags << 28); bits |= net.SU_ITEMS; if (((int)ent.v.flags & FL_ONGROUND) != 0) { bits |= net.SU_ONGROUND; } if (ent.v.waterlevel >= 2) { bits |= net.SU_INWATER; } for (i = 0; i < 3; i++) { if (ent.v.punchangle[i] != 0) { bits |= (net.SU_PUNCH1 << i); } if (ent.v.velocity[i] != 0) { bits |= (net.SU_VELOCITY1 << i); } } if (ent.v.weaponframe != 0) { bits |= net.SU_WEAPONFRAME; } if (ent.v.armorvalue != 0) { bits |= net.SU_ARMOR; } // if (ent.v.weapon != 0) bits |= net.SU_WEAPON; // send the data common.MSG_WriteByte(msg, net.svc_clientdata); common.MSG_WriteShort(msg, bits); if ((bits & net.SU_VIEWHEIGHT) != 0) { common.MSG_WriteChar(msg, (int)ent.v.view_ofs[2]); } if ((bits & net.SU_IDEALPITCH) != 0) { common.MSG_WriteChar(msg, (int)ent.v.idealpitch); } for (i = 0; i < 3; i++) { if ((bits & (net.SU_PUNCH1 << i)) != 0) { common.MSG_WriteChar(msg, (int)ent.v.punchangle[i]); } if ((bits & (net.SU_VELOCITY1 << i)) != 0) { common.MSG_WriteChar(msg, (int)ent.v.velocity[i] / 16); } } // [always sent] if (bits & SU_ITEMS) common.MSG_WriteLong(msg, items); if ((bits & net.SU_WEAPONFRAME) != 0) { common.MSG_WriteByte(msg, (int)ent.v.weaponframe); } if ((bits & net.SU_ARMOR) != 0) { common.MSG_WriteByte(msg, (int)ent.v.armorvalue); } if ((bits & net.SU_WEAPON) != 0) { common.MSG_WriteByte(msg, SV_ModelIndex(prog.pr_string(ent.v.weaponmodel))); } common.MSG_WriteShort(msg, (int)ent.v.health); common.MSG_WriteByte(msg, (int)ent.v.currentammo); common.MSG_WriteByte(msg, (int)ent.v.ammo_shells); common.MSG_WriteByte(msg, (int)ent.v.ammo_nails); common.MSG_WriteByte(msg, (int)ent.v.ammo_rockets); common.MSG_WriteByte(msg, (int)ent.v.ammo_cells); if (common.standard_quake) { common.MSG_WriteByte(msg, (int)ent.v.weapon); } else { for (i = 0; i < 32; i++) { if ((((int)ent.v.weapon) & (1 << i)) != 0) { common.MSG_WriteByte(msg, i); break; } } } }
/* * ============= * SV_WriteEntitiesToClient * * ============= */ static void SV_WriteEntitiesToClient(prog.edict_t clent, common.sizebuf_t msg) { int e, i; int bits; double[] org = new double[3]; double miss; prog.edict_t ent; // send over all entities (excpet the client) that touch the pvs for (e = 1; e < sv.num_edicts; e++) { ent = sv.edicts[e]; // ignore if not touching a PV leaf if (ent != clent) // clent is ALLWAYS sent { // ignore ents without visible models if (ent.v.modelindex == 0 || prog.pr_string(ent.v.model) == null) { continue; } } if (msg.maxsize - msg.cursize < 16) { console.Con_Printf("packet overflow\n"); return; } // send an update bits = 0; for (i = 0; i < 3; i++) { miss = ent.v.origin[i] - ent.baseline.origin[i]; if (miss < -0.1 || miss > 0.1) { bits |= net.U_ORIGIN1 << i; } } if (ent.v.angles[0] != ent.baseline.angles[0]) { bits |= net.U_ANGLE1; } if (ent.v.angles[1] != ent.baseline.angles[1]) { bits |= net.U_ANGLE2; } if (ent.v.angles[2] != ent.baseline.angles[2]) { bits |= net.U_ANGLE3; } if (ent.v.movetype == MOVETYPE_STEP) { bits |= net.U_NOLERP; // don't mess up the step animation } if (ent.baseline.colormap != ent.v.colormap) { bits |= net.U_COLORMAP; } if (ent.baseline.skin != ent.v.skin) { bits |= net.U_SKIN; } if (ent.baseline.frame != ent.v.frame) { bits |= net.U_FRAME; } if (ent.baseline.effects != ent.v.effects) { bits |= net.U_EFFECTS; } if (ent.baseline.modelindex != ent.v.modelindex) { bits |= net.U_MODEL; } if (e >= 256) { bits |= net.U_LONGENTITY; } if (bits >= 256) { bits |= net.U_MOREBITS; } // // write the message // common.MSG_WriteByte(msg, bits | net.U_SIGNAL); if ((bits & net.U_MOREBITS) != 0) { common.MSG_WriteByte(msg, bits >> 8); } if ((bits & net.U_LONGENTITY) != 0) { common.MSG_WriteShort(msg, e); } else { common.MSG_WriteByte(msg, e); } if ((bits & net.U_MODEL) != 0) { common.MSG_WriteByte(msg, (int)ent.v.modelindex); } if ((bits & net.U_FRAME) != 0) { common.MSG_WriteByte(msg, (int)ent.v.frame); } if ((bits & net.U_COLORMAP) != 0) { common.MSG_WriteByte(msg, (int)ent.v.colormap); } if ((bits & net.U_SKIN) != 0) { common.MSG_WriteByte(msg, (int)ent.v.skin); } if ((bits & net.U_EFFECTS) != 0) { common.MSG_WriteByte(msg, (int)ent.v.effects); } if ((bits & net.U_ORIGIN1) != 0) { common.MSG_WriteCoord(msg, ent.v.origin[0]); } if ((bits & net.U_ANGLE1) != 0) { common.MSG_WriteAngle(msg, ent.v.angles[0]); } if ((bits & net.U_ORIGIN2) != 0) { common.MSG_WriteCoord(msg, ent.v.origin[1]); } if ((bits & net.U_ANGLE2) != 0) { common.MSG_WriteAngle(msg, ent.v.angles[1]); } if ((bits & net.U_ORIGIN3) != 0) { common.MSG_WriteCoord(msg, ent.v.origin[2]); } if ((bits & net.U_ANGLE3) != 0) { common.MSG_WriteAngle(msg, ent.v.angles[2]); } } }
/* ======================= SV_SendNop Send a nop message without trashing or sending the accumulated client message buffer ======================= */ static void SV_SendNop(client_t client) { common.sizebuf_t msg = new common.sizebuf_t(); Uint8Array buf = new Uint8Array(4); msg.data = buf; msg.maxsize = buf.Length; msg.cursize = 0; common.MSG_WriteChar (msg, net.svc_nop); if (net.NET_SendUnreliableMessage(client.netconnection, msg) == -1) host.SV_DropClient(true); // if the message couldn't send, kick off client.last_message = host.realtime; }
static void CL_KeepaliveMessage() { double time; int ret; common.sizebuf_t old = new common.sizebuf_t(); byte[] olddata = new byte[8192]; if (server.sv.active) { return; // no need if server is local } if (client.cls.demoplayback) { return; } // read messages from server, should just be nops common.sizebuf_t.Copy(net.net_message, old); Buffer.BlockCopy(net.net_message.data, 0, olddata, 0, net.net_message.cursize); do { ret = CL_GetMessage(); switch (ret) { default: host.Host_Error("CL_KeepaliveMessage: CL_GetMessage failed"); break; case 0: break; // nothing waiting case 1: host.Host_Error("CL_KeepaliveMessage: received a message"); break; case 2: if (common.MSG_ReadByte() != net.svc_nop) { host.Host_Error("CL_KeepaliveMessage: datagram wasn't a nop"); } break; } } while (ret != 0); common.sizebuf_t.Copy(old, net.net_message); Buffer.BlockCopy(olddata, 0, net.net_message.data, 0, net.net_message.cursize); // check time time = sys_linux.Sys_FloatTime(); if (time - lastmsg < 5) { return; } lastmsg = time; // write out a nop console.Con_Printf("--> client to server keepalive\n"); common.MSG_WriteByte(cls.message, net.clc_nop); net.NET_SendMessage(cls.netcon, cls.message); common.SZ_Clear(cls.message); }