/* net_svc_common.c (description) Copyright (C) 2001 Adam Olsen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to: Free Software Foundation, Inc. 59 Temple Place - Suite 330 Boston, MA 02111-1307, USA */ static const char rcsid[] = "$Id$"; #ifdef HAVE_CONFIG_H # include "config.h" #endif #ifndef _WIN32 # ifdef HAVE_UNISTD_H # include # endif #else # include #endif #ifdef HAVE_STRING_H # include #endif #ifdef HAVE_STRINGS_H # include #endif #include "QF/msg.h" #include "QF/net_packet.h" #include "QF/net_svc.h" #include "QF/net_ucmd.h" #include "QF/sound.h" #include "QF/sys.h" // N is netquake-only, Q is quakeworld-only, M is identical in both, // D is exists in both, but is different, X is used in neither static const char *net_svc_strings[] = { "svc_bad", "svc_nop", // M "svc_disconnect", // M "svc_qwupdatestat", // D "svc_version", // N [long] server version "svc_setview", // N [short] entity number "svc_qwsound", // D "svc_time", // N [float] server time "svc_qwprint", // D [string] null terminated string "svc_stufftext", // M [string] stuffed into client's // console buffer the string // should be \n terminated "svc_setangle", // M [vec3] set the view angle to this // absolute value "svc_serverdata", // D [long] version ... "svc_lightstyle", // M [byte] [string] "svc_updatename", // N [byte] [string] "svc_updatefrags", // M [byte] [short] "svc_clientdata", // N "svc_stopsound", // M "svc_updatecolors", // N [byte] [byte] "svc_particle", // N [vec3] "svc_damage", // M [byte] impact [byte] blood [vec3] // from "svc_spawnstatic", // M "svc_spawnbinary", // X "svc_spawnbaseline", // M "svc_qwtempentity", // D "svc_setpause", // M "svc_signonnum", // N "svc_centerprint", // M "svc_killedmonster", // M "svc_foundsecret", // M "svc_spawnstaticsound", // M "svc_qwintermission", // D "svc_finale", // M [string] music [string] text "svc_qwcdtrack", // D [byte] track [byte] looptrack "svc_sellscreen", // M "svc_smallkick", // D Quake svc_cutscene "svc_bigkick", // Q "svc_updateping", // Q "svc_updateentertime", // Q "svc_updatestatlong", // Q "svc_muzzleflash", // Q "svc_updateuserinfo", // Q "svc_download", // Q "svc_playerinfo", // Q "svc_nails", // Q "svc_chokecount", // Q "svc_modellist", // Q "svc_soundlist", // Q "svc_packetentities", // Q "svc_deltapacketentities", // Q "svc_maxspeed", // Q "svc_entgravity", // Q "svc_setinfo", // Q "svc_qwserverinfo", // Q "svc_updatepl", // Q }; const char * NET_SVC_GetString (svc_t type) { if (type >= 0 && type < (sizeof (net_svc_strings) / sizeof (const char *))) return net_svc_strings[type]; else return "Invalid SVC"; } // This is evil }:> net_svc_emit_t net_svc_common_emit_jumptable[] = { [svc_nop] = (net_svc_emit_t) NET_SVC_NOP_Emit, [svc_disconnect] = (net_svc_emit_t) NET_SVC_Disconnect_Emit, [svc_centerprint] = (net_svc_emit_t) NET_SVC_Centerprint_Emit, [svc_stufftext] = (net_svc_emit_t) NET_SVC_Stufftext_Emit, [svc_damage] = (net_svc_emit_t) NET_SVC_Damage_Emit, [svc_setangle] = (net_svc_emit_t) NET_SVC_SetAngle_Emit, [svc_lightstyle] = (net_svc_emit_t) NET_SVC_LightStyle_Emit, [svc_stopsound] = (net_svc_emit_t) NET_SVC_StopSound_Emit, [svc_updatefrags] = (net_svc_emit_t) NET_SVC_UpdateFrags_Emit, [svc_spawnbaseline] = (net_svc_emit_t) NET_SVC_SpawnBaseline_Emit, [svc_spawnstatic] = (net_svc_emit_t) NET_SVC_SpawnStatic_Emit, [svc_killedmonster] = (net_svc_emit_t) NET_SVC_KilledMonster_Emit, [svc_foundsecret] = (net_svc_emit_t) NET_SVC_FoundSecret_Emit, [svc_spawnstaticsound] = (net_svc_emit_t) NET_SVC_SpawnStaticSound_Emit, [svc_finale] = (net_svc_emit_t) NET_SVC_Finale_Emit, [svc_sellscreen] = (net_svc_emit_t) NET_SVC_SellScreen_Emit, [svc_setpause] = (net_svc_emit_t) NET_SVC_SetPause_Emit, }; int net_svc_common_emit_count = sizeof (net_svc_common_emit_jumptable) / sizeof (net_svc_emit_t); net_svc_parse_t net_svc_common_parse_jumptable[] = { [svc_nop] = (net_svc_parse_t) NET_SVC_NOP_Parse, [svc_disconnect] = (net_svc_parse_t) NET_SVC_Disconnect_Parse, [svc_centerprint] = (net_svc_parse_t) NET_SVC_Centerprint_Parse, [svc_stufftext] = (net_svc_parse_t) NET_SVC_Stufftext_Parse, [svc_damage] = (net_svc_parse_t) NET_SVC_Damage_Parse, [svc_setangle] = (net_svc_parse_t) NET_SVC_SetAngle_Parse, [svc_lightstyle] = (net_svc_parse_t) NET_SVC_LightStyle_Parse, [svc_stopsound] = (net_svc_parse_t) NET_SVC_StopSound_Parse, [svc_updatefrags] = (net_svc_parse_t) NET_SVC_UpdateFrags_Parse, [svc_spawnbaseline] = (net_svc_parse_t) NET_SVC_SpawnBaseline_Parse, [svc_spawnstatic] = (net_svc_parse_t) NET_SVC_SpawnStatic_Parse, [svc_killedmonster] = (net_svc_parse_t) NET_SVC_KilledMonster_Parse, [svc_foundsecret] = (net_svc_parse_t) NET_SVC_FoundSecret_Parse, [svc_spawnstaticsound] = (net_svc_parse_t) NET_SVC_SpawnStaticSound_Parse, [svc_finale] = (net_svc_parse_t) NET_SVC_Finale_Parse, [svc_sellscreen] = (net_svc_parse_t) NET_SVC_SellScreen_Parse, [svc_setpause] = (net_svc_parse_t) NET_SVC_SetPause_Parse, }; int net_svc_common_parse_count = sizeof (net_svc_common_parse_jumptable) / sizeof (net_svc_parse_t); net_svc_emit_t *net_svc_emit_jumptable; int net_svc_emit_count; net_svc_emit_t *net_svc_emit_jumptable; int net_svc_emit_count; net_svc_parse_t *net_svc_parse_jumptable; int net_svc_parse_count; net_status_t NET_SVC_Emit (svc_t type, void *block, sizebuf_t *buf) { int oldsize = buf->cursize; net_status_t retval; if (type < 0 || type >= net_svc_emit_count || !net_svc_emit_jumptable[type]) return NET_ERROR; MSG_WriteByte (buf, type); retval = net_svc_emit_jumptable[type] (block, buf); if (retval == NET_SHORT) buf->cursize = oldsize; // revert the buffer return retval; } net_status_t NET_SVC_Parse (svc_t *type, net_svc_any_t *block, msg_t *msg) { *type = MSG_ReadByte (msg); if (*type < 0 || *type >= net_svc_parse_count || !net_svc_parse_jumptable[*type]) return NET_ERROR; return net_svc_parse_jumptable[*type] (block, msg); } net_status_t NET_SVC_NOP_Emit (net_svc_nop_t *block, sizebuf_t *buf) { return buf->overflowed; } net_status_t NET_SVC_NOP_Parse (net_svc_nop_t *block, msg_t *msg) { return msg->badread; } net_status_t NET_SVC_Disconnect_Emit (net_svc_disconnect_t *block, sizebuf_t *buf) { return buf->overflowed; } net_status_t NET_SVC_Disconnect_Parse (net_svc_disconnect_t *block, msg_t *msg) { return msg->badread; } net_status_t NET_SVC_Centerprint_Emit (net_svc_centerprint_t *block, sizebuf_t *buf) { MSG_WriteString (buf, block->message); return buf->overflowed; } net_status_t NET_SVC_Centerprint_Parse (net_svc_centerprint_t *block, msg_t *msg) { block->message = MSG_ReadString (msg); return msg->badread; } net_status_t NET_SVC_Stufftext_Emit (net_svc_stufftext_t *block, sizebuf_t *buf) { MSG_WriteString (buf, block->commands); return buf->overflowed; } net_status_t NET_SVC_Stufftext_Parse (net_svc_stufftext_t *block, msg_t *msg) { block->commands = MSG_ReadString (msg); return msg->badread; } net_status_t NET_SVC_Damage_Emit (net_svc_damage_t *block, sizebuf_t *buf) { int i; MSG_WriteByte (buf, block->armor); MSG_WriteByte (buf, block->blood); for (i = 0; i < 3; i++) MSG_WriteCoord (buf, block->from[i]); return buf->overflowed; } net_status_t NET_SVC_Damage_Parse (net_svc_damage_t *block, msg_t *msg) { int i; block->armor = MSG_ReadByte (msg); block->blood = MSG_ReadByte (msg); for (i = 0; i < 3; i++) block->from[i] = MSG_ReadCoord (msg); return msg->badread; } net_status_t NET_SVC_SetAngle_Emit (net_svc_setangle_t *block, sizebuf_t *buf) { int i; for (i = 0; i < 3; i++) MSG_WriteAngle (buf, block->angles[i]); return buf->overflowed; } net_status_t NET_SVC_SetAngle_Parse (net_svc_setangle_t *block, msg_t *msg) { int i; for (i = 0; i < 3; i++) block->angles[i] = MSG_ReadAngle (msg); return msg->badread; } net_status_t NET_SVC_LightStyle_Emit (net_svc_lightstyle_t *block, sizebuf_t *buf) { MSG_WriteByte (buf, block->stylenum); MSG_WriteString (buf, block->map); return buf->overflowed; } net_status_t NET_SVC_LightStyle_Parse (net_svc_lightstyle_t *block, msg_t *msg) { block->stylenum = MSG_ReadByte (msg); block->map = MSG_ReadString (msg); return msg->badread; } net_status_t NET_SVC_StopSound_Emit (net_svc_stopsound_t *block, sizebuf_t *buf) { MSG_WriteShort (buf, (block->entity << 3) & (block->channel & 7)); return buf->overflowed; } net_status_t NET_SVC_StopSound_Parse (net_svc_stopsound_t *block, msg_t *msg) { int i = MSG_ReadShort (msg); block->entity = i >> 3; block->channel = i & 7; return msg->badread; } net_status_t NET_SVC_UpdateFrags_Emit (net_svc_updatefrags_t *block, sizebuf_t *buf) { MSG_WriteByte (buf, block->player); MSG_WriteShort (buf, block->frags); return buf->overflowed; } net_status_t NET_SVC_UpdateFrags_Parse (net_svc_updatefrags_t *block, msg_t *msg) { block->player = MSG_ReadByte (msg); block->frags = MSG_ReadShort (msg); return msg->badread; } net_status_t NET_SVC_SpawnBaseline_Emit (net_svc_spawnbaseline_t *block, sizebuf_t *buf) { int i; MSG_WriteShort (buf, block->num); MSG_WriteByte (buf, block->modelindex); MSG_WriteByte (buf, block->frame); MSG_WriteByte (buf, block->colormap); MSG_WriteByte (buf, block->skinnum); for (i = 0; i < 3; i++) { MSG_WriteCoord (buf, block->origin[i]); MSG_WriteAngle (buf, block->angles[i]); } return buf->overflowed; } net_status_t NET_SVC_SpawnBaseline_Parse (net_svc_spawnbaseline_t *block, msg_t *msg) { int i; block->num = MSG_ReadShort (msg); block->modelindex = MSG_ReadByte (msg); block->frame = MSG_ReadByte (msg); block->colormap = MSG_ReadByte (msg); block->skinnum = MSG_ReadByte (msg); // these are interlaced? bad drugs... for (i = 0; i < 3; i ++) { block->origin[i] = MSG_ReadCoord (msg); block->angles[i] = MSG_ReadAngle (msg); } return msg->badread; } net_status_t NET_SVC_SpawnStatic_Emit (net_svc_spawnstatic_t *block, sizebuf_t *buf) { int i; MSG_WriteByte (buf, block->modelindex); MSG_WriteByte (buf, block->frame); MSG_WriteByte (buf, block->colormap); MSG_WriteByte (buf, block->skinnum); for (i = 0; i < 3; i++) { MSG_WriteCoord (buf, block->origin[i]); MSG_WriteAngle (buf, block->angles[i]); } return buf->overflowed; } net_status_t NET_SVC_SpawnStatic_Parse (net_svc_spawnstatic_t *block, msg_t *msg) { int i; block->modelindex = MSG_ReadByte (msg); block->frame = MSG_ReadByte (msg); block->colormap = MSG_ReadByte (msg); block->skinnum = MSG_ReadByte (msg); // these are interlaced? bad drugs... for (i = 0; i < 3; i++) { block->origin[i] = MSG_ReadCoord (msg); block->angles[i] = MSG_ReadAngle (msg); } return msg->badread; } net_status_t NET_SVC_KilledMonster_Emit (net_svc_killedmonster_t *block, sizebuf_t *buf) { return buf->overflowed; } net_status_t NET_SVC_KilledMonster_Parse (net_svc_killedmonster_t *block, msg_t *msg) { return msg->badread; } net_status_t NET_SVC_FoundSecret_Emit (net_svc_foundsecret_t *block, sizebuf_t *buf) { return buf->overflowed; } net_status_t NET_SVC_FoundSecret_Parse (net_svc_foundsecret_t *block, msg_t *msg) { return msg->badread; } net_status_t NET_SVC_SpawnStaticSound_Emit (net_svc_spawnstaticsound_t *block, sizebuf_t *buf) { int i; for (i = 0; i < 3; i++) MSG_WriteCoord (buf, block->position[i]); MSG_WriteByte (buf, block->sound_num); MSG_WriteByte (buf, block->volume); MSG_WriteByte (buf, block->attenuation); return buf->overflowed; } net_status_t NET_SVC_SpawnStaticSound_Parse (net_svc_spawnstaticsound_t *block, msg_t *msg) { int i; for (i = 0; i < 3; i++) block->position[i] = MSG_ReadCoord (msg); block->sound_num = MSG_ReadByte (msg); block->volume = MSG_ReadByte (msg); block->attenuation = MSG_ReadByte (msg); return msg->badread; } net_status_t NET_SVC_Finale_Emit (net_svc_finale_t *block, sizebuf_t *buf) { MSG_WriteString (buf, block->message); return buf->overflowed; } net_status_t NET_SVC_Finale_Parse (net_svc_finale_t *block, msg_t *msg) { block->message = MSG_ReadString (msg); return msg->badread; } net_status_t NET_SVC_SellScreen_Emit (net_svc_sellscreen_t *block, sizebuf_t *buf) { return buf->overflowed; } net_status_t NET_SVC_SellScreen_Parse (net_svc_sellscreen_t *block, msg_t *msg) { return msg->badread; } net_status_t NET_SVC_SetPause_Emit (net_svc_setpause_t *block, sizebuf_t *buf) { MSG_WriteByte (buf, block->paused); return buf->overflowed; } net_status_t NET_SVC_SetPause_Parse (net_svc_setpause_t *block, msg_t *msg) { block->paused = MSG_ReadByte (msg); return msg->badread; }