//------------------------------------------------------------------------- /* Copyright (C) 2010 EDuke32 developers and contributors This file is part of EDuke32. EDuke32 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. 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 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ //------------------------------------------------------------------------- #include "duke3d.h" #include "game.h" #include "gamedef.h" #include "net.h" #include "premap.h" #include "enet/enet.h" #include "quicklz.h" #include "crc32.h" /* this should be lower than the MTU size by at least the size of the UDP and ENet headers or else fragmentation will occur */ #define SYNCPACKETSIZE 1344 ENetHost *g_netServer = NULL; ENetHost *g_netClient = NULL; ENetPeer *g_netClientPeer = NULL; int32_t g_netPort = 23513; int32_t g_netDisconnect = 0; char g_netPassword[32]; int32_t g_netSync = 0; int32_t g_netPlayersWaiting = 0; int32_t g_networkMode = NET_CLIENT; static char recbuf[180]; static int32_t g_chatPlayer = -1; // sprites of these statnums are synced to clients by the server int16_t g_netStatnums[10] = { STAT_PROJECTILE, STAT_PLAYER, STAT_STANDABLE, STAT_ACTIVATOR, STAT_TRANSPORT, STAT_EFFECTOR, STAT_ACTOR, STAT_ZOMBIEACTOR, STAT_MISC, MAXSTATUS }; int32_t lastupdate[MAXSPRITES]; int32_t lastsectupdate[MAXSECTORS]; int32_t lastwallupdate[MAXWALLS]; mapstate_t *g_multiMapState = NULL; static int32_t spritecrc[MAXSPRITES]; static int32_t sectcrc[MAXSECTORS]; static int32_t wallcrc[MAXWALLS]; void Net_Connect(const char *srvaddr) { ENetAddress address; ENetEvent event; char *addrstr = NULL; int32_t i; Net_Disconnect(); g_netClient = enet_host_create(NULL, 1, CHAN_MAX, 0, 0); if (g_netClient == NULL) { initprintf("An error occurred while trying to create an ENet client host.\n"); return; } addrstr = strtok((char *)srvaddr, ":"); enet_address_set_host(&address, addrstr); address.port = atoi((addrstr = strtok(NULL, ":")) == NULL ? "23513" : addrstr); g_netClientPeer = enet_host_connect(g_netClient, &address, CHAN_MAX, 0); if (g_netClientPeer == NULL) { initprintf("No available peers for initiating an ENet connection.\n"); return; } for (i=4; i>0; i--) { /* Wait up to 5 seconds for the connection attempt to succeed. */ if (enet_host_service(g_netClient, & event, 5000) > 0 && event.type == ENET_EVENT_TYPE_CONNECT) { initprintf("Connection to %s:%d succeeded.\n", (char *)srvaddr, address.port); return; } else { /* Either the 5 seconds are up or a disconnect event was */ /* received. Reset the peer in the event the 5 seconds */ /* had run out without any significant event. */ enet_peer_reset(g_netClientPeer); initprintf("Connection to %s:%d failed.\n",(char *)srvaddr,address.port); } initprintf(i ? "Retrying...\n" : "Giving up connection attempt.\n"); } Net_Disconnect(); } void Net_Disconnect(void) { if (g_netClient) { ENetEvent event; if (g_netClientPeer) enet_peer_disconnect_later(g_netClientPeer, 0); while (enet_host_service(g_netClient, & event, 3000) > 0) { switch (event.type) { case ENET_EVENT_TYPE_CONNECT: case ENET_EVENT_TYPE_NONE: case ENET_EVENT_TYPE_RECEIVE: if (event.packet) enet_packet_destroy(event.packet); break; case ENET_EVENT_TYPE_DISCONNECT: numplayers = playerswhenstarted = ud.multimode = 1; myconnectindex = screenpeek = 0; G_BackToMenu(); break; } } enet_peer_reset(g_netClientPeer); g_netClientPeer = NULL; enet_host_destroy(g_netClient); g_netClient = NULL; return; } if (g_netServer) { ENetPeer *currentPeer; ENetEvent event; for (currentPeer = g_netServer -> peers; currentPeer < & g_netServer -> peers [g_netServer -> peerCount]; ++ currentPeer) { enet_peer_disconnect_later(currentPeer, 0); } while (enet_host_service(g_netServer, & event, 3000) > 0) { switch (event.type) { case ENET_EVENT_TYPE_CONNECT: case ENET_EVENT_TYPE_NONE: case ENET_EVENT_TYPE_RECEIVE: case ENET_EVENT_TYPE_DISCONNECT: if (event.packet) enet_packet_destroy(event.packet); break; } } enet_host_destroy(g_netServer); g_netServer = NULL; } } static void Net_SendVersion(ENetPeer *client) { if (!g_netServer) return; buf[0] = PACKET_VERSION; buf[1] = BYTEVERSION; buf[2] = (uint8_t)atoi(s_buildDate); buf[3] = myconnectindex; enet_peer_send(client, CHAN_GAMESTATE, enet_packet_create(&buf[0], 4, ENET_PACKET_FLAG_RELIABLE)); } void Net_SendClientInfo(void) { int32_t i,l; for (l=0; (unsigned)laim_mode = ud.mouseaiming; buf[l++] = g_player[myconnectindex].ps->auto_aim = ud.config.AutoAim; buf[l++] = g_player[myconnectindex].ps->weaponswitch = ud.weaponswitch; buf[l++] = g_player[myconnectindex].ps->palookup = g_player[myconnectindex].pcolor = ud.color; buf[l++] = g_player[myconnectindex].pteam = ud.team; for (i=0; i<10; i++) { g_player[myconnectindex].wchoice[i] = g_player[0].wchoice[i]; buf[l++] = (uint8_t)g_player[0].wchoice[i]; } buf[l++] = myconnectindex; if (g_netClient) enet_peer_send(g_netClientPeer, CHAN_GAMESTATE, enet_packet_create(&buf[0], l, ENET_PACKET_FLAG_RELIABLE)); else if (g_netServer) enet_host_broadcast(g_netServer, CHAN_GAMESTATE, enet_packet_create(&buf[0], l, ENET_PACKET_FLAG_RELIABLE)); } void Net_SendUserMapName(void) { int32_t j; if (numplayers < 2) return; packbuf[0] = PACKET_USER_MAP; packbuf[1] = 0; Bcorrectfilename(boardfilename,0); j = Bstrlen(boardfilename); boardfilename[j++] = 0; Bstrcat(packbuf+1,boardfilename); packbuf[j++] = myconnectindex; if (g_netClient) enet_peer_send(g_netClientPeer, CHAN_GAMESTATE, enet_packet_create(packbuf, j, ENET_PACKET_FLAG_RELIABLE)); else if (g_netServer) enet_host_broadcast(g_netServer, CHAN_GAMESTATE, enet_packet_create(packbuf, j, ENET_PACKET_FLAG_RELIABLE)); } // FIXME: change all of the game starting support code to be fully server controlled void Net_NewGame(int32_t volume, int32_t level) { packbuf[0] = PACKET_NEW_GAME; packbuf[1] = ud.m_level_number = level; packbuf[2] = ud.m_volume_number = volume; packbuf[3] = ud.m_player_skill+1; packbuf[4] = ud.m_monsters_off; packbuf[5] = ud.m_respawn_monsters; packbuf[6] = ud.m_respawn_items; packbuf[7] = ud.m_respawn_inventory; packbuf[8] = ud.m_coop; packbuf[9] = ud.m_marker; packbuf[10] = ud.m_ffire; packbuf[11] = ud.m_noexits; packbuf[12] = myconnectindex; if (g_netClient) enet_peer_send(g_netClientPeer, CHAN_GAMESTATE, enet_packet_create(packbuf, 13, ENET_PACKET_FLAG_RELIABLE)); else if (g_netServer) enet_host_broadcast(g_netServer, CHAN_GAMESTATE, enet_packet_create(packbuf, 13, ENET_PACKET_FLAG_RELIABLE)); } // sends a simple crc32 of the current password, verified by the server before the connection can continue static void Net_SendChallenge(void) { int32_t l = 1; if (!g_netClientPeer) return; buf[0] = PACKET_AUTH; *(uint32_t *)&buf[1] = crc32once((uint8_t *)g_netPassword, Bstrlen(g_netPassword)); l += sizeof(int32_t); buf[l++] = myconnectindex; enet_peer_send(g_netClientPeer, CHAN_GAMESTATE, enet_packet_create(&buf[0], l, ENET_PACKET_FLAG_RELIABLE)); } static void P_RemovePlayer(int32_t i) { // server obviously can't leave the game, and index 0 shows up for disconnect events from // players that haven't gotten far enough into the connection process to get a player ID if (i == 0) return; g_player[i].playerquitflag = 0; Bsprintf(buf,"%s^00 is history!",g_player[i].user_name); G_AddUserQuote(buf); if (numplayers == 1) S_PlaySound(GENERIC_AMBIENCE17); if (g_player[myconnectindex].ps->gm & MODE_GAME) { if (screenpeek == i) screenpeek = myconnectindex; pub = NUMPAGES; pus = NUMPAGES; G_UpdateScreenArea(); P_QuickKill(g_player[i].ps); if (voting == i) { for (i=0; iftq = QUOTE_RESERVED2; g_player[myconnectindex].ps->fta = 180; } } // sync a connecting player up with the current game state void Net_SyncPlayer(ENetEvent *event) { int32_t i, j; g_netPlayersWaiting++; S_PlaySound(DUKE_GETWEAPON2); // open a new slot if necessary and save off the resulting slot # for future reference TRAVERSE_CONNECT(i) if (g_player[i].playerquitflag == 0) break; event->peer->data = (void *)((intptr_t)(i = (i == -1 ? playerswhenstarted++ : i))); g_player[i].netsynctime = totalclock; g_player[i].playerquitflag = 1; for (j=0; jpeer, CHAN_GAMESTATE, enet_packet_create(packbuf, 3, ENET_PACKET_FLAG_RELIABLE)); Net_SendClientInfo(); Net_SendUserMapName(); if (g_player[0].ps->gm & MODE_GAME) { if (g_multiMapState == NULL) g_multiMapState = (mapstate_t *)Bcalloc(1, sizeof(mapstate_t)); if (g_multiMapState) { char *buf = (char *)Bmalloc(sizeof(mapstate_t)<<1); sprite[g_player[i].ps->i].cstat = 32768; g_player[i].ps->runspeed = g_playerFriction; g_player[i].ps->last_extra = sprite[g_player[i].ps->i].extra = g_player[i].ps->max_player_health = g_maxPlayerHealth; G_SaveMapState(g_multiMapState); if ((j = qlz_compress((char *)g_multiMapState, buf, sizeof(mapstate_t), state_compress))) { size_t csize = qlz_size_compressed(buf); // all of these packets are SYNCPACKETSIZE do { enet_peer_send(event->peer, CHAN_SYNC, enet_packet_create((char *)(buf)+csize-j, SYNCPACKETSIZE, ENET_PACKET_FLAG_RELIABLE)); j -= SYNCPACKETSIZE; enet_host_service(g_netServer, NULL, 0); } while (j >= SYNCPACKETSIZE); // ...except for this one. A non-SYNCPACKETSIZE packet on CHAN_SYNC doubles as the signal that the transfer is done. enet_peer_send(event->peer, CHAN_SYNC, enet_packet_create((char *)(buf)+csize-j, j, ENET_PACKET_FLAG_RELIABLE)); enet_host_service(g_netServer, NULL, 0); } else initprintf("Error compressing map state for transfer!\n"); Bfree(buf); Bfree(g_multiMapState); g_multiMapState = NULL; } } } int32_t Net_UnpackSprite(int32_t i, uint8_t *pbuf) { int16_t sect = sprite[i].sectnum, statnum = sprite[i].statnum; int16_t opicnum, j = 0; #ifdef POLYMER int16_t lightid = -1; _prlight *mylight = NULL; #endif uint32_t flags = *(uint32_t *)&pbuf[j]; j += sizeof(uint32_t); opicnum = sprite[i].picnum; if (flags & NET_SPRITE_X) { sprite[i].x = *(int32_t *)&pbuf[j]; j += sizeof(int32_t); } if (flags & NET_SPRITE_Y) { sprite[i].y = *(int32_t *)&pbuf[j]; j += sizeof(int32_t); } if (flags & NET_SPRITE_Z) { sprite[i].z = *(int32_t *)&pbuf[j]; j += sizeof(int32_t); } if (flags & NET_SPRITE_SHADE) { sprite[i].shade = *(int8_t *)&pbuf[j]; j += sizeof(int8_t); } if (flags & NET_SPRITE_PAL) { sprite[i].pal = *(uint8_t *)&pbuf[j]; j += sizeof(uint8_t); } if (flags & NET_SPRITE_CLIPDIST) { sprite[i].clipdist = *(uint8_t *)&pbuf[j]; j += sizeof(uint8_t); } if (flags & NET_SPRITE_XREPEAT) { sprite[i].xrepeat = *(uint8_t *)&pbuf[j]; j += sizeof(uint8_t); } if (flags & NET_SPRITE_YREPEAT) { sprite[i].yrepeat = *(uint8_t *)&pbuf[j]; j += sizeof(uint8_t); } if (flags & NET_SPRITE_XOFFSET) { sprite[i].xoffset = *(int8_t *)&pbuf[j]; j += sizeof(int8_t); } if (flags & NET_SPRITE_YOFFSET) { sprite[i].yoffset = *(int8_t *)&pbuf[j]; j += sizeof(int8_t); } if (flags & NET_SPRITE_SECTNUM) { sect = *(int16_t *)&pbuf[j]; j += sizeof(int16_t); } if (flags & NET_SPRITE_STATNUM) { statnum = *(int16_t *)&pbuf[j]; j += sizeof(int16_t); } if (flags & NET_SPRITE_ANG) { sprite[i].ang = *(int16_t *)&pbuf[j]; j += sizeof(int16_t); } if (flags & NET_SPRITE_OWNER) { sprite[i].owner = *(int16_t *)&pbuf[j]; j += sizeof(int16_t); } if (flags & NET_SPRITE_XVEL) { sprite[i].xvel = *(int16_t *)&pbuf[j]; j += sizeof(int16_t); } if (flags & NET_SPRITE_YVEL) { sprite[i].yvel = *(int16_t *)&pbuf[j]; j += sizeof(int16_t); } if (flags & NET_SPRITE_ZVEL) { sprite[i].zvel = *(int16_t *)&pbuf[j]; j += sizeof(int16_t); } if (flags & NET_SPRITE_LOTAG) { sprite[i].lotag = *(int16_t *)&pbuf[j]; j += sizeof(int16_t); } if (flags & NET_SPRITE_HITAG) { sprite[i].hitag = *(int16_t *)&pbuf[j]; j += sizeof(int16_t); } if (flags & NET_SPRITE_EXTRA) { sprite[i].extra = *(int16_t *)&pbuf[j]; j += sizeof(int16_t); } if (flags & NET_SPRITE_CSTAT) { sprite[i].cstat = *(int16_t *)&pbuf[j]; j += sizeof(int16_t); } if (flags & NET_SPRITE_PICNUM) { sprite[i].picnum = *(int16_t *)&pbuf[j]; j += sizeof(int16_t); } if (sect == MAXSECTORS || statnum == MAXSTATUS) { // j += sizeof(netactor_t); if (sprite[i].sectnum != MAXSECTORS && sprite[i].statnum != MAXSTATUS) deletesprite(i); return j; } // doesn't exist on the client yet if (sprite[i].statnum == MAXSTATUS || sprite[i].sectnum == MAXSECTORS) { int16_t sprs[MAXSPRITES], z = 0; while ((sprs[z++] = insertsprite(sect, statnum)) != i); z--; while (z--) deletesprite(sprs[z]); } else { if (sect != sprite[i].sectnum) changespritesect(i, sect); if (statnum != sprite[i].statnum) changespritestat(i, statnum); } #ifdef POLYMER if (sprite[i].picnum == opicnum) { mylight = actor[i].lightptr; lightid = actor[i].lightId; } else if (getrendermode() == 4 && actor[i].lightptr != NULL) { polymer_deletelight(actor[i].lightId); actor[i].lightId = -1; actor[i].lightptr = NULL; } #endif /*initprintf("updating sprite %d (%d)\n",i,sprite[i].picnum);*/ flags = *(uint32_t *)&pbuf[j]; j += sizeof(uint32_t); if (flags & NET_ACTOR_T1) { actor[i].t_data[0] = *(int32_t *)&pbuf[j]; j += sizeof(int32_t); } if (flags & NET_ACTOR_T2) { actor[i].t_data[1] = *(int32_t *)&pbuf[j]; #if !defined SAMESIZE_ACTOR_T if (flags & NET_ACTOR_PTR1) actor[i].t_data[1] += (intptr_t)&script[0]; #endif j += sizeof(int32_t); } if (flags & NET_ACTOR_T3) { actor[i].t_data[2] = *(int32_t *)&pbuf[j]; j += sizeof(int32_t); } if (flags & NET_ACTOR_T4) { actor[i].t_data[3] = *(int32_t *)&pbuf[j]; j += sizeof(int32_t); } if (flags & NET_ACTOR_T5) { actor[i].t_data[4] = *(int32_t *)&pbuf[j]; #if !defined SAMESIZE_ACTOR_T if (flags & NET_ACTOR_PTR2) actor[i].t_data[4] += (intptr_t)&script[0]; #endif j += sizeof(int32_t); } if (flags & NET_ACTOR_T6) { actor[i].t_data[5] = *(int32_t *)&pbuf[j]; #if !defined SAMESIZE_ACTOR_T if (flags & NET_ACTOR_PTR3) actor[i].t_data[5] += (intptr_t)&script[0]; #endif j += sizeof(int32_t); } if (flags & NET_ACTOR_T7) { actor[i].t_data[6] = *(int32_t *)&pbuf[j]; j += sizeof(int32_t); } if (flags & NET_ACTOR_T8) { actor[i].t_data[7] = *(int32_t *)&pbuf[j]; j += sizeof(int32_t); } if (flags & NET_ACTOR_T9) { actor[i].t_data[8] = *(int32_t *)&pbuf[j]; j += sizeof(int32_t); } if (flags & NET_ACTOR_T10) { actor[i].t_data[9] = *(int32_t *)&pbuf[j]; j += sizeof(int32_t); } if (flags & NET_ACTOR_PICNUM) { actor[i].picnum = *(int16_t *)&pbuf[j]; j += sizeof(int16_t); } if (flags & NET_ACTOR_ANG) { actor[i].ang = *(int16_t *)&pbuf[j]; j += sizeof(int16_t); } if (flags & NET_ACTOR_EXTRA) { actor[i].extra = *(int16_t *)&pbuf[j]; j += sizeof(int16_t); } if (flags & NET_ACTOR_OWNER) { actor[i].owner = *(int16_t *)&pbuf[j]; j += sizeof(int16_t); } if (flags & NET_ACTOR_MOVFLAG) { actor[i].movflag = *(int16_t *)&pbuf[j]; j += sizeof(int16_t); } if (flags & NET_ACTOR_TEMPANG) { actor[i].tempang = *(int16_t *)&pbuf[j]; j += sizeof(int16_t); } if (flags & NET_ACTOR_TIMETOSLEEP) { actor[i].timetosleep = *(int16_t *)&pbuf[j]; j += sizeof(int16_t); } if (flags & NET_ACTOR_FLAGS) { actor[i].flags = *(int32_t *)&pbuf[j]; j += sizeof(int32_t); } #ifdef POLYMER actor[i].lightptr = mylight; actor[i].lightId = lightid; #endif actor[i].flags &= ~SPRITE_NULL; do { int16_t var_id = *(int16_t *)&pbuf[j]; j += sizeof(int16_t); if (var_id == MAXGAMEVARS) break; if (aGameVars[var_id].val.plValues) aGameVars[var_id].val.plValues[i] = *(int32_t *)&pbuf[j]; j += sizeof(int32_t); } while (1); return j; } int32_t Net_PackSprite(int32_t i, uint8_t *pbuf) { int32_t j = 0; uint32_t *flags; static spritetype netsprite[MAXSPRITES]; static netactor_t netactor[MAXSPRITES]; if (lastupdate[i] && !Bmemcmp(&sprite[i], &netsprite[i], sizeof(spritetype))) return 0; *(int16_t *)&pbuf[j] = i; j += sizeof(int16_t); flags = (uint32_t *)&pbuf[j]; *flags = 0; j += sizeof(uint32_t); if (sprite[i].sectnum == MAXSECTORS || sprite[i].statnum == MAXSTATUS) { *flags = NET_SPRITE_SECTNUM; *(int16_t *)&pbuf[j] = MAXSECTORS; j += sizeof(int16_t); Bmemcpy(&netsprite[i], &sprite[i], sizeof(spritetype)); return j; } if (!lastupdate[i] || sprite[i].x != netsprite[i].x) { *flags |= NET_SPRITE_X; *(int32_t *)&pbuf[j] = sprite[i].x; j += sizeof(int32_t); } if (!lastupdate[i] || sprite[i].y != netsprite[i].y) { *flags |= NET_SPRITE_Y; *(int32_t *)&pbuf[j] = sprite[i].y; j += sizeof(int32_t); } if (!lastupdate[i] || sprite[i].z != netsprite[i].z) { *flags |= NET_SPRITE_Z; *(int32_t *)&pbuf[j] = sprite[i].z; j += sizeof(int32_t); } if (!lastupdate[i] || sprite[i].shade != netsprite[i].shade) { *flags |= NET_SPRITE_SHADE; *(int8_t *)&pbuf[j] = sprite[i].shade; j += sizeof(int8_t); } if (!lastupdate[i] || sprite[i].pal != netsprite[i].pal) { *flags |= NET_SPRITE_PAL; *(uint8_t *)&pbuf[j] = sprite[i].pal; j += sizeof(uint8_t); } if (!lastupdate[i] || sprite[i].clipdist != netsprite[i].clipdist) { *flags |= NET_SPRITE_CLIPDIST; *(uint8_t *)&pbuf[j] = sprite[i].clipdist; j += sizeof(uint8_t); } if (!lastupdate[i] || sprite[i].xrepeat != netsprite[i].xrepeat) { *flags |= NET_SPRITE_XREPEAT; *(uint8_t *)&pbuf[j] = sprite[i].xrepeat; j += sizeof(uint8_t); } if (!lastupdate[i] || sprite[i].yrepeat != netsprite[i].yrepeat) { *flags |= NET_SPRITE_YREPEAT; *(uint8_t *)&pbuf[j] = sprite[i].yrepeat; j += sizeof(uint8_t); } if (!lastupdate[i] || sprite[i].xoffset != netsprite[i].xoffset) { *flags |= NET_SPRITE_XOFFSET; *(int8_t *)&pbuf[j] = sprite[i].xoffset; j += sizeof(int8_t); } if (!lastupdate[i] || sprite[i].yoffset != netsprite[i].yoffset) { *flags |= NET_SPRITE_YOFFSET; *(int8_t *)&pbuf[j] = sprite[i].yoffset; j += sizeof(int8_t); } if (!lastupdate[i] || sprite[i].sectnum != netsprite[i].sectnum || sprite[i].sectnum == MAXSECTORS) { *flags |= NET_SPRITE_SECTNUM; *(int16_t *)&pbuf[j] = sprite[i].sectnum; j += sizeof(int16_t); } if (!lastupdate[i] || sprite[i].statnum != netsprite[i].statnum || sprite[i].statnum == MAXSTATUS) { *flags |= NET_SPRITE_STATNUM; *(int16_t *)&pbuf[j] = sprite[i].statnum; j += sizeof(int16_t); } if (!lastupdate[i] || sprite[i].ang != netsprite[i].ang) { *flags |= NET_SPRITE_ANG; *(int16_t *)&pbuf[j] = sprite[i].ang; j += sizeof(int16_t); } if (!lastupdate[i] || sprite[i].owner != netsprite[i].owner) { *flags |= NET_SPRITE_OWNER; *(int16_t *)&pbuf[j] = sprite[i].owner; j += sizeof(int16_t); } if (!lastupdate[i] || sprite[i].xvel != netsprite[i].xvel) { *flags |= NET_SPRITE_XVEL; *(int16_t *)&pbuf[j] = sprite[i].xvel; j += sizeof(int16_t); } if (!lastupdate[i] || sprite[i].yvel != netsprite[i].yvel) { *flags |= NET_SPRITE_YVEL; *(int16_t *)&pbuf[j] = sprite[i].yvel; j += sizeof(int16_t); } if (!lastupdate[i] || sprite[i].zvel != netsprite[i].zvel) { *flags |= NET_SPRITE_ZVEL; *(int16_t *)&pbuf[j] = sprite[i].zvel; j += sizeof(int16_t); } if (!lastupdate[i] || sprite[i].lotag != netsprite[i].lotag) { *flags |= NET_SPRITE_LOTAG; *(int16_t *)&pbuf[j] = sprite[i].lotag; j += sizeof(int16_t); } if (!lastupdate[i] || sprite[i].hitag != netsprite[i].hitag) { *flags |= NET_SPRITE_HITAG; *(int16_t *)&pbuf[j] = sprite[i].hitag; j += sizeof(int16_t); } if (!lastupdate[i] || sprite[i].extra != netsprite[i].extra) { *flags |= NET_SPRITE_EXTRA; *(int16_t *)&pbuf[j] = sprite[i].extra; j += sizeof(int16_t); } if (!lastupdate[i] || sprite[i].cstat != netsprite[i].cstat) { *flags |= NET_SPRITE_CSTAT; *(int16_t *)&pbuf[j] = sprite[i].cstat; j += sizeof(int16_t); } if (!lastupdate[i] || sprite[i].picnum != netsprite[i].picnum) { *flags |= NET_SPRITE_PICNUM; *(int16_t *)&pbuf[j] = sprite[i].picnum; j += sizeof(int16_t); } if (lastupdate[i]) Bmemcpy(&netsprite[i], &sprite[i], sizeof(spritetype)); flags = (uint32_t *)&pbuf[j]; *flags = 0; j += sizeof(uint32_t); if (!lastupdate[i] || actor[i].t_data[0] != netactor[i].t_data[0]) { *flags |= NET_ACTOR_T1; *(int32_t *)&pbuf[j] = actor[i].t_data[0]; j += sizeof(int32_t); } if (!lastupdate[i] || actor[i].t_data[1] != netactor[i].t_data[1]) { *flags |= NET_ACTOR_T2; #if !defined SAMESIZE_ACTOR_T if (T2 >= (intptr_t)&script[0] && T2 < (intptr_t)(&script[g_scriptSize])) { *flags |= NET_ACTOR_PTR1; *(int32_t *)&pbuf[j] = (int32_t)(actor[i].t_data[1] - (intptr_t)&script[0]); } else #endif *(int32_t *)&pbuf[j] = actor[i].t_data[1]; j += sizeof(int32_t); } if (!lastupdate[i] || actor[i].t_data[2] != netactor[i].t_data[2]) { *flags |= NET_ACTOR_T3; *(int32_t *)&pbuf[j] = actor[i].t_data[2]; j += sizeof(int32_t); } if (!lastupdate[i] || actor[i].t_data[3] != netactor[i].t_data[3]) { *flags |= NET_ACTOR_T4; *(int32_t *)&pbuf[j] = actor[i].t_data[3]; j += sizeof(int32_t); } if (!lastupdate[i] || actor[i].t_data[4] != netactor[i].t_data[4]) { *flags |= NET_ACTOR_T5; #if !defined SAMESIZE_ACTOR_T if (T5 >= (intptr_t)&script[0] && T5 < (intptr_t)(&script[g_scriptSize])) { *flags |= NET_ACTOR_PTR2; *(int32_t *)&pbuf[j] = (int32_t)(actor[i].t_data[4] - (intptr_t)&script[0]); } else #endif *(int32_t *)&pbuf[j] = actor[i].t_data[4]; j += sizeof(int32_t); } if (!lastupdate[i] || actor[i].t_data[5] != netactor[i].t_data[5]) { *flags |= NET_ACTOR_T6; #if !defined SAMESIZE_ACTOR_T if (T6 >= (intptr_t)&script[0] && T6 < (intptr_t)(&script[g_scriptSize])) { *flags |= NET_ACTOR_PTR3; *(int32_t *)&pbuf[j] = (int32_t)(actor[i].t_data[5] - (intptr_t)&script[0]); } else #endif *(int32_t *)&pbuf[j] = actor[i].t_data[5]; j += sizeof(int32_t); } if (!lastupdate[i] || actor[i].t_data[6] != netactor[i].t_data[6]) { *flags |= NET_ACTOR_T7; *(int32_t *)&pbuf[j] = actor[i].t_data[6]; j += sizeof(int32_t); } if (!lastupdate[i] || actor[i].t_data[7] != netactor[i].t_data[7]) { *flags |= NET_ACTOR_T8; *(int32_t *)&pbuf[j] = actor[i].t_data[7]; j += sizeof(int32_t); } if (!lastupdate[i] || actor[i].t_data[8] != netactor[i].t_data[8]) { *flags |= NET_ACTOR_T9; *(int32_t *)&pbuf[j] = actor[i].t_data[8]; j += sizeof(int32_t); } if (!lastupdate[i] || actor[i].t_data[9] != netactor[i].t_data[9]) { *flags |= NET_ACTOR_T10; *(int32_t *)&pbuf[j] = actor[i].t_data[9]; j += sizeof(int32_t); } if (!lastupdate[i] || actor[i].picnum != netactor[i].picnum) { *flags |= NET_ACTOR_PICNUM; *(int16_t *)&pbuf[j] = actor[i].picnum; j += sizeof(int16_t); } if (!lastupdate[i] || actor[i].ang != netactor[i].ang) { *flags |= NET_ACTOR_ANG; *(int16_t *)&pbuf[j] = actor[i].ang; j += sizeof(int16_t); } if (!lastupdate[i] || actor[i].extra != netactor[i].extra) { *flags |= NET_ACTOR_EXTRA; *(int16_t *)&pbuf[j] = actor[i].extra; j += sizeof(int16_t); } if (!lastupdate[i] || actor[i].owner!= netactor[i].owner) { *flags |= NET_ACTOR_OWNER; *(int16_t *)&pbuf[j] = actor[i].owner; j += sizeof(int16_t); } if (!lastupdate[i] || actor[i].movflag != netactor[i].movflag) { *flags |= NET_ACTOR_MOVFLAG; *(int16_t *)&pbuf[j] = actor[i].movflag; j += sizeof(int16_t); } if (!lastupdate[i] || actor[i].tempang != netactor[i].tempang) { *flags |= NET_ACTOR_TEMPANG; *(int16_t *)&pbuf[j] = actor[i].tempang; j += sizeof(int16_t); } if (!lastupdate[i] || actor[i].timetosleep != netactor[i].timetosleep) { *flags |= NET_ACTOR_TIMETOSLEEP; *(int16_t *)&pbuf[j] = actor[i].timetosleep; j += sizeof(int16_t); } if (!lastupdate[i] || actor[i].flags != netactor[i].flags) { *flags |= NET_ACTOR_FLAGS; *(int32_t *)&pbuf[j] = actor[i].flags; j += sizeof(int32_t); } if (lastupdate[i]) Bmemcpy(&netactor[i], &actor[i], sizeof(netactor_t)); if (*flags == 0) return 0; { int16_t ii=g_gameVarCount-1; for (; ii>=0; ii--) { if ((aGameVars[ii].dwFlags & (GAMEVAR_PERACTOR|GAMEVAR_NOMULTI)) == GAMEVAR_PERACTOR && aGameVars[ii].val.plValues) { if (aGameVars[ii].val.plValues[i] != aGameVars[ii].lDefault) { *(int16_t *)&pbuf[j] = ii; j += sizeof(int16_t); *(int32_t *)&pbuf[j] = aGameVars[ii].val.plValues[i]; j += sizeof(int32_t); } } } *(int16_t *)&pbuf[j] = MAXGAMEVARS; j += sizeof(int16_t); } return j; } int32_t Net_UnpackSect(int32_t i, uint8_t *pbuf) { int32_t j = 0; uint32_t flags = *(uint32_t *)&pbuf[j]; j += sizeof(uint32_t); if (flags & NET_SECTOR_WALLPTR) { sector[i].wallptr = *(int16_t *)&pbuf[j]; j += sizeof(int16_t); } if (flags & NET_SECTOR_WALLNUM) { sector[i].wallnum = *(int16_t *)&pbuf[j]; j += sizeof(int16_t); } if (flags & NET_SECTOR_CEILINGZ) { sector[i].ceilingz = *(int32_t *)&pbuf[j]; j += sizeof(int32_t); } if (flags & NET_SECTOR_FLOORZ) { sector[i].floorz = *(int32_t *)&pbuf[j]; j += sizeof(int32_t); } if (flags & NET_SECTOR_CEILINGSTAT) { sector[i].ceilingstat = *(int16_t *)&pbuf[j]; j += sizeof(int16_t); } if (flags & NET_SECTOR_FLOORSTAT) { sector[i].floorstat = *(int16_t *)&pbuf[j]; j += sizeof(int16_t); } if (flags & NET_SECTOR_CEILINGPIC) { sector[i].ceilingpicnum = *(int16_t *)&pbuf[j]; j += sizeof(int16_t); } if (flags & NET_SECTOR_CEILINGSLOPE) { sector[i].ceilingheinum = *(int16_t *)&pbuf[j]; j += sizeof(int16_t); } if (flags & NET_SECTOR_CEILINGSHADE) { sector[i].ceilingshade = *(int8_t *)&pbuf[j]; j += sizeof(int8_t); } if (flags & NET_SECTOR_CEILINGPAL) { sector[i].ceilingpal = *(uint8_t *)&pbuf[j]; j += sizeof(uint8_t); } if (flags & NET_SECTOR_CEILINGXPAN) { sector[i].ceilingxpanning = *(uint8_t *)&pbuf[j]; j += sizeof(uint8_t); } if (flags & NET_SECTOR_CEILINGYPAN) { sector[i].ceilingypanning = *(uint8_t *)&pbuf[j]; j += sizeof(uint8_t); } if (flags & NET_SECTOR_FLOORPIC) { sector[i].floorpicnum = *(int16_t *)&pbuf[j]; j += sizeof(int16_t); } if (flags & NET_SECTOR_FLOORSLOPE) { sector[i].floorheinum = *(int16_t *)&pbuf[j]; j += sizeof(int16_t); } if (flags & NET_SECTOR_FLOORSHADE) { sector[i].floorshade = *(int8_t *)&pbuf[j]; j += sizeof(int8_t); } if (flags & NET_SECTOR_FLOORPAL) { sector[i].floorpal = *(uint8_t *)&pbuf[j]; j += sizeof(uint8_t); } if (flags & NET_SECTOR_FLOORXPAN) { sector[i].floorxpanning = *(uint8_t *)&pbuf[j]; j += sizeof(uint8_t); } if (flags & NET_SECTOR_FLOORYPAN) { sector[i].floorypanning = *(uint8_t *)&pbuf[j]; j += sizeof(uint8_t); } if (flags & NET_SECTOR_VISIBILITY) { sector[i].visibility = *(uint8_t *)&pbuf[j]; j += sizeof(uint8_t); } if (flags & NET_SECTOR_LOTAG) { sector[i].lotag = *(int16_t *)&pbuf[j]; j += sizeof(int16_t); } if (flags & NET_SECTOR_HITAG) { sector[i].hitag = *(int16_t *)&pbuf[j]; j += sizeof(int16_t); } if (flags & NET_SECTOR_EXTRA) { sector[i].extra = *(int16_t *)&pbuf[j]; j += sizeof(int16_t); } return j; } int32_t Net_PackSect(int32_t i, uint8_t *pbuf) { int32_t j = 0; uint32_t *flags; static sectortype netsect[MAXSECTORS]; if (lastsectupdate[i] && !Bmemcmp(§or[i], &netsect[i], sizeof(sectortype))) return 0; *(int16_t *)&pbuf[j] = i; j += sizeof(int16_t); flags = (uint32_t *)&pbuf[j]; *flags = 0; j += sizeof(uint32_t); if (!lastsectupdate[i] || sector[i].wallptr != netsect[i].wallptr) { *flags |= NET_SECTOR_WALLPTR; *(int16_t *)&pbuf[j] = sector[i].wallptr; j += sizeof(int16_t); } if (!lastsectupdate[i] || sector[i].wallnum != netsect[i].wallnum) { *flags |= NET_SECTOR_WALLNUM; *(int16_t *)&pbuf[j] = sector[i].wallnum; j += sizeof(int16_t); } if (!lastsectupdate[i] || sector[i].ceilingz != netsect[i].ceilingz) { *flags |= NET_SECTOR_CEILINGZ; *(int32_t *)&pbuf[j] = sector[i].ceilingz; j += sizeof(int32_t); } if (!lastsectupdate[i] || sector[i].floorz != netsect[i].floorz) { *flags |= NET_SECTOR_FLOORZ; *(int32_t *)&pbuf[j] = sector[i].floorz; j += sizeof(int32_t); } if (!lastsectupdate[i] || sector[i].ceilingstat != netsect[i].ceilingstat) { *flags |= NET_SECTOR_CEILINGSTAT; *(int16_t *)&pbuf[j] = sector[i].ceilingstat; j += sizeof(int16_t); } if (!lastsectupdate[i] || sector[i].floorstat != netsect[i].floorstat) { *flags |= NET_SECTOR_FLOORSTAT; *(int16_t *)&pbuf[j] = sector[i].floorstat; j += sizeof(int16_t); } if (!lastsectupdate[i] || sector[i].ceilingpicnum != netsect[i].ceilingpicnum) { *flags |= NET_SECTOR_CEILINGPIC; *(int16_t *)&pbuf[j] = sector[i].ceilingpicnum; j += sizeof(int16_t); } if (!lastsectupdate[i] || sector[i].ceilingheinum != netsect[i].ceilingheinum) { *flags |= NET_SECTOR_CEILINGSLOPE; *(int16_t *)&pbuf[j] = sector[i].ceilingheinum; j += sizeof(int16_t); } if (!lastsectupdate[i] || sector[i].ceilingshade != netsect[i].ceilingshade) { *flags |= NET_SECTOR_CEILINGSHADE; *(int8_t *)&pbuf[j] = sector[i].ceilingshade; j += sizeof(int8_t); } if (!lastsectupdate[i] || sector[i].ceilingpal != netsect[i].ceilingpal) { *flags |= NET_SECTOR_CEILINGPAL; *(uint8_t *)&pbuf[j] = sector[i].ceilingpal; j += sizeof(uint8_t); } if (!lastsectupdate[i] || sector[i].ceilingxpanning != netsect[i].ceilingxpanning) { *flags |= NET_SECTOR_CEILINGXPAN; *(uint8_t *)&pbuf[j] = sector[i].ceilingxpanning; j += sizeof(uint8_t); } if (!lastsectupdate[i] || sector[i].ceilingypanning != netsect[i].ceilingypanning) { *flags |= NET_SECTOR_CEILINGYPAN; *(uint8_t *)&pbuf[j] = sector[i].ceilingypanning; j += sizeof(uint8_t); } if (!lastsectupdate[i] || sector[i].floorpicnum != netsect[i].floorpicnum) { *flags |= NET_SECTOR_FLOORPIC; *(int16_t *)&pbuf[j] = sector[i].floorpicnum; j += sizeof(int16_t); } if (!lastsectupdate[i] || sector[i].floorheinum != netsect[i].floorheinum) { *flags |= NET_SECTOR_FLOORSLOPE; *(int16_t *)&pbuf[j] = sector[i].floorheinum; j += sizeof(int16_t); } if (!lastsectupdate[i] || sector[i].floorshade != netsect[i].floorshade) { *flags |= NET_SECTOR_FLOORSHADE; *(int8_t *)&pbuf[j] = sector[i].floorshade; j += sizeof(int8_t); } if (!lastsectupdate[i] || sector[i].floorpal != netsect[i].floorpal) { *flags |= NET_SECTOR_FLOORPAL; *(uint8_t *)&pbuf[j] = sector[i].floorpal; j += sizeof(uint8_t); } if (!lastsectupdate[i] || sector[i].floorxpanning != netsect[i].floorxpanning) { *flags |= NET_SECTOR_FLOORXPAN; *(uint8_t *)&pbuf[j] = sector[i].floorxpanning; j += sizeof(uint8_t); } if (!lastsectupdate[i] || sector[i].floorypanning != netsect[i].floorypanning) { *flags |= NET_SECTOR_FLOORYPAN; *(uint8_t *)&pbuf[j] = sector[i].floorypanning; j += sizeof(uint8_t); } if (!lastsectupdate[i] || sector[i].visibility != netsect[i].visibility) { *flags |= NET_SECTOR_VISIBILITY; *(uint8_t *)&pbuf[j] = sector[i].visibility; j += sizeof(uint8_t); } if (!lastsectupdate[i] || sector[i].lotag != netsect[i].lotag) { *flags |= NET_SECTOR_LOTAG; *(int16_t *)&pbuf[j] = sector[i].lotag; j += sizeof(int16_t); } if (!lastsectupdate[i] || sector[i].hitag != netsect[i].hitag) { *flags |= NET_SECTOR_HITAG; *(int16_t *)&pbuf[j] = sector[i].hitag; j += sizeof(int16_t); } if (!lastsectupdate[i] || sector[i].extra != netsect[i].extra) { *flags |= NET_SECTOR_EXTRA; *(int16_t *)&pbuf[j] = sector[i].extra; j += sizeof(int16_t); } if (lastsectupdate[i]) Bmemcpy(&netsect[i], §or[i], sizeof(sectortype)); return *flags ? j : 0; } int32_t Net_UnpackWall(int32_t i, uint8_t *pbuf) { int32_t j = 0; uint32_t flags = *(uint32_t *)&pbuf[j]; j += sizeof(uint32_t); if (flags & NET_WALL_X) { wall[i].x = *(int32_t *)&pbuf[j]; j += sizeof(int32_t); } if (flags & NET_WALL_Y) { wall[i].y = *(int32_t *)&pbuf[j]; j += sizeof(int32_t); } if (flags & NET_WALL_POINT2) { wall[i].point2 = *(int16_t *)&pbuf[j]; j += sizeof(int16_t); } if (flags & NET_WALL_NEXTWALL) { wall[i].nextwall = *(int16_t *)&pbuf[j]; j += sizeof(int16_t); } if (flags & NET_WALL_NEXTSECTOR) { wall[i].nextsector = *(int16_t *)&pbuf[j]; j += sizeof(int16_t); } if (flags & NET_WALL_CSTAT) { wall[i].cstat = *(int16_t *)&pbuf[j]; j += sizeof(int16_t); } if (flags & NET_WALL_PICNUM) { wall[i].picnum = *(int16_t *)&pbuf[j]; j += sizeof(int16_t); } if (flags & NET_WALL_OVERPICNUM) { wall[i].overpicnum = *(int16_t *)&pbuf[j]; j += sizeof(int16_t); } if (flags & NET_WALL_SHADE) { wall[i].shade = *(int8_t *)&pbuf[j]; j += sizeof(int8_t); } if (flags & NET_WALL_PAL) { wall[i].pal = *(uint8_t *)&pbuf[j]; j += sizeof(uint8_t); } if (flags & NET_WALL_XREPEAT) { wall[i].xrepeat = *(uint8_t *)&pbuf[j]; j += sizeof(uint8_t); } if (flags & NET_WALL_YREPEAT) { wall[i].yrepeat = *(uint8_t *)&pbuf[j]; j += sizeof(uint8_t); } if (flags & NET_WALL_XPANNING) { wall[i].xpanning = *(uint8_t *)&pbuf[j]; j += sizeof(uint8_t); } if (flags & NET_WALL_YPANNING) { wall[i].ypanning = *(uint8_t *)&pbuf[j]; j += sizeof(uint8_t); } if (flags & NET_WALL_LOTAG) { wall[i].lotag = *(int16_t *)&pbuf[j]; j += sizeof(int16_t); } if (flags & NET_WALL_HITAG) { wall[i].hitag = *(int16_t *)&pbuf[j]; j += sizeof(int16_t); } if (flags & NET_WALL_EXTRA) { wall[i].extra = *(int16_t *)&pbuf[j]; j += sizeof(int16_t); } return j; } int32_t Net_PackWall(int32_t i, uint8_t *pbuf) { int32_t j = 0; uint32_t *flags; static walltype netwall[MAXWALLS]; if (lastwallupdate[i] && !Bmemcmp(&wall[i], &netwall[i], sizeof(walltype))) return 0; *(int16_t *)&pbuf[j] = i; j += sizeof(int16_t); flags = (uint32_t *)&pbuf[j]; *flags = 0; j += sizeof(uint32_t); if (!lastwallupdate[i] || wall[i].x != netwall[i].x) { *flags |= NET_WALL_X; *(int32_t *)&pbuf[j] = wall[i].x; j += sizeof(int32_t); } if (!lastwallupdate[i] || wall[i].y != netwall[i].y) { *flags |= NET_WALL_Y; *(int32_t *)&pbuf[j] = wall[i].y; j += sizeof(int32_t); } if (!lastwallupdate[i] || wall[i].point2 != netwall[i].point2) { *flags |= NET_WALL_POINT2; *(int16_t *)&pbuf[j] = wall[i].point2; j += sizeof(int16_t); } if (!lastwallupdate[i] || wall[i].nextwall != netwall[i].nextwall) { *flags |= NET_WALL_NEXTWALL; *(int16_t *)&pbuf[j] = wall[i].nextwall; j += sizeof(int16_t); } if (!lastwallupdate[i] || wall[i].nextsector != netwall[i].nextsector) { *flags |= NET_WALL_NEXTSECTOR; *(int16_t *)&pbuf[j] = wall[i].nextsector; j += sizeof(int16_t); } if (!lastwallupdate[i] || wall[i].cstat != netwall[i].cstat) { *flags |= NET_WALL_CSTAT; *(int16_t *)&pbuf[j] = wall[i].cstat; j += sizeof(int16_t); } if (!lastwallupdate[i] || wall[i].picnum != netwall[i].picnum) { *flags |= NET_WALL_PICNUM; *(int16_t *)&pbuf[j] = wall[i].picnum; j += sizeof(int16_t); } if (!lastwallupdate[i] || wall[i].overpicnum != netwall[i].overpicnum) { *flags |= NET_WALL_OVERPICNUM; *(int16_t *)&pbuf[j] = wall[i].overpicnum; j += sizeof(int16_t); } if (!lastwallupdate[i] || wall[i].shade != netwall[i].shade) { *flags |= NET_WALL_SHADE; *(int8_t *)&pbuf[j] = wall[i].shade; j += sizeof(int8_t); } if (!lastwallupdate[i] || wall[i].pal != netwall[i].pal) { *flags |= NET_WALL_PAL; *(uint8_t *)&pbuf[j] = wall[i].pal; j += sizeof(uint8_t); } if (!lastwallupdate[i] || wall[i].xrepeat != netwall[i].xrepeat) { *flags |= NET_WALL_XREPEAT; *(uint8_t *)&pbuf[j] = wall[i].xrepeat; j += sizeof(uint8_t); } if (!lastwallupdate[i] || wall[i].yrepeat != netwall[i].yrepeat) { *flags |= NET_WALL_YREPEAT; *(uint8_t *)&pbuf[j] = wall[i].yrepeat; j += sizeof(uint8_t); } if (!lastwallupdate[i] || wall[i].xpanning != netwall[i].xpanning) { *flags |= NET_WALL_XPANNING; *(uint8_t *)&pbuf[j] = wall[i].xpanning; j += sizeof(uint8_t); } if (!lastwallupdate[i] || wall[i].ypanning != netwall[i].ypanning) { *flags |= NET_WALL_YPANNING; *(uint8_t *)&pbuf[j] = wall[i].ypanning; j += sizeof(uint8_t); } if (!lastwallupdate[i] || wall[i].lotag != netwall[i].lotag) { *flags |= NET_WALL_LOTAG; *(int16_t *)&pbuf[j] = wall[i].lotag; j += sizeof(int16_t); } if (!lastwallupdate[i] || wall[i].hitag != netwall[i].hitag) { *flags |= NET_WALL_HITAG; *(int16_t *)&pbuf[j] = wall[i].hitag; j += sizeof(int16_t); } if (!lastwallupdate[i] || wall[i].extra != netwall[i].extra) { *flags |= NET_WALL_EXTRA; *(int16_t *)&pbuf[j] = wall[i].extra; j += sizeof(int16_t); } if (lastwallupdate[i]) Bmemcpy(&netwall[i], &wall[i], sizeof(walltype)); return *flags ? j : 0; } void Net_ParseServerPacket(ENetEvent *event) { uint8_t *pbuf = event->packet->data; int32_t packbufleng = event->packet->dataLength; int32_t i, j, l; int32_t other = pbuf[--packbufleng]; input_t *nsyn; #if 0 initprintf("RECEIVED PACKET: type: %d : len %d\n", pbuf[0], packbufleng); #endif switch (pbuf[0]) { case PACKET_MASTER_TO_SLAVE: //[0] (receive master sync buffer) if (!(g_player[myconnectindex].ps->gm & MODE_GAME) || g_netSync) return; j = 0; packbufleng = qlz_size_decompressed((char *)&pbuf[1]); pbuf = (uint8_t *)Bcalloc(1, packbufleng+1); packbufleng = qlz_decompress((char *)&event->packet->data[1], (char *)(pbuf), state_decompress); ticrandomseed = *(int32_t *)&pbuf[j]; j += sizeof(int32_t); ud.pause_on = pbuf[j++]; TRAVERSE_CONNECT(i) { g_player[i].ps->dead_flag = *(int16_t *)&pbuf[j]; j += sizeof(int16_t); g_player[i].playerquitflag = pbuf[j++]; if (g_player[i].playerquitflag == 0) continue; /* if (i == myconnectindex && !g_player[i].ps->dead_flag) { j += offsetof(input_t, filler) + (sizeof(vec3_t) * 3) + // position and velocity (sizeof(int16_t) * 3); // ang and horiz goto process; } */ nsyn = (input_t *)&inputfifo[0][0]; if (i != myconnectindex || g_player[i].ps->dead_flag) Bmemcpy(&nsyn[i], &pbuf[j], offsetof(input_t, filler)); j += offsetof(input_t, filler); // Bmemcpy(&g_player[i].ps->opos.x, &g_player[i].ps->pos.x, sizeof(vec3_t)); // Bmemcpy(&g_player[i].ps->pos.x, &pbuf[j], sizeof(vec3_t) * 2); Bmemcpy(&sprite[g_player[i].ps->i], &pbuf[j], sizeof(vec3_t)); sprite[g_player[i].ps->i].z += PHEIGHT; j += sizeof(vec3_t) * 2; Bmemcpy(&g_player[i].ps->vel.x, &pbuf[j], sizeof(vec3_t)); j += sizeof(vec3_t); if (i != myconnectindex) { g_player[i].ps->oang = g_player[i].ps->ang; g_player[i].ps->ang = sprite[g_player[i].ps->i].ang = *(int16_t *)&pbuf[j]; j += sizeof(int16_t); Bmemcpy(&g_player[i].ps->ohoriz, &g_player[i].ps->horiz, sizeof(int16_t) * 2); Bmemcpy(&g_player[i].ps->horiz, &pbuf[j], sizeof(int16_t) * 2); j += sizeof(int16_t) * 2; } else j += sizeof(int16_t) * 3; //process: g_player[i].ps->gotweapon = *(uint16_t *)&pbuf[j]; j += sizeof(uint16_t); Bmemcpy(&g_player[i].ps->ammo_amount[0], &pbuf[j], sizeof(g_player[i].ps->ammo_amount)); j += sizeof(g_player[i].ps->ammo_amount); Bmemcpy(&g_player[i].ps->inv_amount[0], &pbuf[j], sizeof(g_player[i].ps->inv_amount)); j += sizeof(g_player[i].ps->inv_amount); Bmemcpy(g_player[i].frags, &pbuf[j], sizeof(g_player[i].frags)); j += sizeof(g_player[i].frags); sprite[g_player[i].ps->i].extra = (uint8_t)pbuf[j++]; sprite[g_player[i].ps->i].cstat = *(int16_t *)&pbuf[j]; j += sizeof(int16_t); g_player[i].ps->kickback_pic = (uint8_t)pbuf[j++]; actor[g_player[i].ps->i].owner = *(int16_t *)&pbuf[j]; j += sizeof(int16_t); actor[g_player[i].ps->i].picnum = *(int16_t *)&pbuf[j]; j += sizeof(int16_t); g_player[i].ps->curr_weapon = (uint8_t)pbuf[j++]; g_player[i].ps->last_weapon = (int8_t)pbuf[j++]; g_player[i].ps->wantweaponfire = (int8_t)pbuf[j++]; g_player[i].ps->weapon_pos = (int8_t)pbuf[j++]; g_player[i].ps->frag_ps = (uint8_t)pbuf[j++]; g_player[i].ps->frag = (uint8_t)pbuf[j++]; g_player[i].ps->fraggedself = (uint8_t)pbuf[j++]; g_player[i].ps->last_extra = (uint8_t)pbuf[j++]; g_player[i].ping = *(int16_t *)&pbuf[j]; j += sizeof(int16_t); g_player[i].ps->newowner = *(int16_t *)&pbuf[j]; j += sizeof(int16_t); if (g_player[i].ps->newowner == -1 && g_player[i].ps->cursectnum >= 0 && g_player[i].ps->cursectnum < numsectors) { updatesectorz(g_player[i].ps->pos.x, g_player[i].ps->pos.y, g_player[i].ps->pos.z, &g_player[i].ps->cursectnum); changespritesect(g_player[i].ps->i, g_player[i].ps->cursectnum); } sprite[g_player[i].ps->i].pal = (uint8_t)pbuf[j++]; l = i; i = g_player[l].ps->i; { #if defined SAMESIZE_ACTOR_T j++; Bmemcpy(&T5, &pbuf[j], sizeof(T5)); #else int16_t jj = j++; int32_t oa = (T5 >= (intptr_t)&script[0] && T5 < (intptr_t)&script[g_scriptSize]) ? T5-(intptr_t)&script[0] : T5; Bmemcpy(&T5, &pbuf[j], sizeof(T5)); j += sizeof(T5); if (oa != T5) T3 = T4 = 0; if (pbuf[jj] & 2) T5 += (intptr_t)&script[0]; #endif } do { int16_t var_id = *(int16_t *)&pbuf[j]; j += sizeof(int16_t); if (var_id == MAXGAMEVARS) break; aGameVars[var_id].val.plValues[i] = *(int32_t *)&pbuf[j]; j += sizeof(int32_t); } while (1); i = l; do { int16_t var_id = *(int16_t *)&pbuf[j]; j += sizeof(int16_t); if (var_id == MAXGAMEVARS) break; aGameVars[var_id].val.plValues[i] = *(int32_t *)&pbuf[j]; j += sizeof(int32_t); } while (1); } { // sprite/sector/wall updates tacked on to the end of the packet l = *(int16_t *)&pbuf[j]; j += sizeof(int16_t); // if (l) initprintf("unpacking %d sprites\n", l); while (l--) { int32_t spriteid = *(int16_t *)&pbuf[j]; j += sizeof(int16_t); /* initprintf("unpacking sprite %d at %d/%d\n", spriteid, j, packbufleng); initprintf("flags: %d\n", *(uint32_t *)&pbuf[j]); */ j += Net_UnpackSprite(spriteid, &pbuf[j]); } } Bfree(pbuf); break; case PACKET_MAP_STREAM: if (!(g_player[myconnectindex].ps->gm & MODE_GAME) || g_netSync) return; j = 0; packbufleng = qlz_size_decompressed((char *)&pbuf[1]); pbuf = (uint8_t *)Bmalloc(packbufleng); packbufleng = qlz_decompress((char *)&event->packet->data[1], (char *)(pbuf), state_decompress); l = *(uint16_t *)&pbuf[j]; j += sizeof(uint16_t); // if (l) initprintf("unpacking %d sprites\n", l); while (l--) { int32_t spriteid = *(int16_t *)&pbuf[j]; j += sizeof(int16_t); // initprintf("unpacking msprite %d at %d/%d\n", spriteid, j, packbufleng); j += Net_UnpackSprite(spriteid, &pbuf[j]); } l = *(uint16_t *)&pbuf[j]; j += sizeof(uint16_t); while (l--) { int16_t secid = *(int16_t *)&pbuf[j]; j += sizeof(int16_t); j += Net_UnpackSect(secid, &pbuf[j]); } l = *(uint16_t *)&pbuf[j]; j += sizeof(uint16_t); while (l--) { int16_t wallid = *(int16_t *)&pbuf[j]; j += sizeof(int16_t); j += Net_UnpackWall(wallid, &pbuf[j]); // we call dragpoint() to make sure the nextwall position gets updated too dragpoint(wallid, wall[wallid].x, wall[wallid].y); } Bfree(pbuf); break; case PACKET_MESSAGE: Bstrncpy(recbuf, (char *)pbuf+2, packbufleng-2); recbuf[packbufleng-2] = 0; G_AddUserQuote(recbuf); S_PlaySound(EXITMENUSOUND); pus = pub = NUMPAGES; break; case PACKET_NEW_GAME: if ((vote_map + vote_episode + voting) != -3) G_AddUserQuote("VOTE SUCCEEDED"); ud.m_level_number = ud.level_number = pbuf[1]; ud.m_volume_number = ud.volume_number = pbuf[2]; ud.m_player_skill = ud.player_skill = pbuf[3]; ud.m_monsters_off = ud.monsters_off = pbuf[4]; ud.m_respawn_monsters = ud.respawn_monsters = pbuf[5]; ud.m_respawn_items = ud.respawn_items = pbuf[6]; ud.m_respawn_inventory = ud.respawn_inventory = pbuf[7]; ud.m_coop = pbuf[8]; ud.m_marker = ud.marker = pbuf[9]; ud.m_ffire = ud.ffire = pbuf[10]; ud.m_noexits = ud.noexits = pbuf[11]; TRAVERSE_CONNECT(i) { P_ResetWeapons(i); P_ResetInventory(i); } G_NewGame(ud.volume_number,ud.level_number,ud.player_skill); ud.coop = ud.m_coop; if (G_EnterLevel(MODE_GAME)) { G_BackToMenu(); break; } if (g_netSync) { packbuf[0] = PACKET_PLAYER_READY; packbuf[1] = myconnectindex; if (g_netClientPeer) enet_peer_send(g_netClientPeer, CHAN_GAMESTATE, enet_packet_create(packbuf, 2, ENET_PACKET_FLAG_RELIABLE)); g_netSync = 0; } break; case PACKET_VERSION: if (pbuf[1] != BYTEVERSION || pbuf[2] != (uint8_t)atoi(s_buildDate)) { initprintf("Server protocol is version %d.%d, expecting %d.%d\n", pbuf[1], pbuf[2], BYTEVERSION, (uint8_t)atoi(s_buildDate)); initprintf("Server version mismatch! You cannot play Duke with different versions!\n"); g_netDisconnect = 1; return; } Net_SendChallenge(); break; case PACKET_NUM_PLAYERS: numplayers = pbuf[1]; playerswhenstarted = pbuf[2]; ud.multimode = pbuf[3]; if (pbuf[4]) // ID of new player { g_player[pbuf[4]].playerquitflag = 1; if (!g_player[pbuf[4]].ps) g_player[pbuf[4]].ps = (DukePlayer_t *) Bcalloc(1,sizeof(DukePlayer_t)); if (!g_player[pbuf[4]].sync) g_player[pbuf[4]].sync = (input_t *) Bcalloc(1,sizeof(input_t)); } if (pbuf[5] == NET_DEDICATED_SERVER) g_networkMode = NET_DEDICATED_CLIENT; for (i=0; igm & MODE_GAME) && !g_netSync) P_RemovePlayer(pbuf[1]); numplayers = pbuf[2]; ud.multimode = pbuf[3]; playerswhenstarted = pbuf[4]; break; case PACKET_PLAYER_SPAWN: if (!(g_player[myconnectindex].ps->gm & MODE_GAME) || g_netSync) break; P_ResetPlayer(pbuf[1]); Bmemcpy(&g_player[pbuf[1]].ps->pos.x, &pbuf[2], sizeof(vec3_t) * 2); Bmemcpy(&sprite[g_player[pbuf[1]].ps->i], &pbuf[2], sizeof(vec3_t)); break; case PACKET_PLAYER_PING: g_player[0].pingcnt++; return; case PACKET_FRAG: if (!(g_player[myconnectindex].ps->gm & MODE_GAME) || g_netSync) break; g_player[pbuf[1]].ps->frag_ps = pbuf[2]; actor[g_player[pbuf[1]].ps->i].picnum = pbuf[3]; ticrandomseed = *(int32_t *)&pbuf[4]; P_FragPlayer(pbuf[1]); break; case PACKET_CLIENT_INFO: for (i=1; pbuf[i]; i++) g_player[other].user_name[i-1] = pbuf[i]; g_player[other].user_name[i-1] = 0; i++; g_player[other].ps->aim_mode = pbuf[i++]; g_player[other].ps->auto_aim = pbuf[i++]; g_player[other].ps->weaponswitch = pbuf[i++]; g_player[other].ps->palookup = g_player[other].pcolor = pbuf[i++]; g_player[other].pteam = pbuf[i++]; j = i; for (; i-j<10; i++) g_player[other].wchoice[i-j] = pbuf[i]; g_player[other].playerquitflag = 1; break; case PACKET_RTS: if (rts_numlumps == 0) break; if (ud.config.SoundToggle == 0 || ud.lockout == 1 || ud.config.FXDevice < 0 || !(ud.config.VoiceToggle & 4)) break; FX_PlayAuto3D((char *)RTS_GetSound(pbuf[1]-1),RTS_SoundLength(pbuf[1]-1),0,0,0,255,-pbuf[1]); g_RTSPlaying = 7; break; case PACKET_USER_MAP: Bstrcpy(boardfilename,(char *)pbuf+1); boardfilename[packbufleng-1] = 0; Bcorrectfilename(boardfilename,0); if (boardfilename[0] != 0) { if ((i = kopen4loadfrommod(boardfilename,0)) < 0) { Bmemset(boardfilename,0,sizeof(boardfilename)); Net_SendUserMapName(); } else kclose(i); } if (ud.m_level_number == 7 && ud.m_volume_number == 0 && boardfilename[0] == 0) ud.m_level_number = 0; break; case PACKET_MAP_VOTE: if (voting == myconnectindex && g_player[(uint8_t)pbuf[1]].gotvote == 0) { g_player[(uint8_t)pbuf[1]].gotvote = 1; g_player[(uint8_t)pbuf[1]].vote = pbuf[2]; Bsprintf(tempbuf,"CONFIRMED VOTE FROM %s",g_player[(uint8_t)pbuf[1]].user_name); G_AddUserQuote(tempbuf); } break; case PACKET_MAP_VOTE_INITIATE: // call map vote voting = pbuf[1]; vote_episode = pbuf[2]; vote_map = pbuf[3]; Bsprintf(tempbuf,"%s^00 HAS CALLED A VOTE TO CHANGE MAP TO %s (E%dL%d)", g_player[(uint8_t)pbuf[1]].user_name, MapInfo[(uint8_t)(pbuf[2]*MAXLEVELS + pbuf[3])].name, pbuf[2]+1,pbuf[3]+1); G_AddUserQuote(tempbuf); Bsprintf(tempbuf,"PRESS F1 TO ACCEPT, F2 TO DECLINE"); G_AddUserQuote(tempbuf); for (i=MAXPLAYERS-1; i>=0; i--) { g_player[i].vote = 0; g_player[i].gotvote = 0; } g_player[voting].gotvote = g_player[voting].vote = 1; break; case PACKET_MAP_VOTE_CANCEL: // cancel map vote if (voting == pbuf[1]) { voting = -1; i = 0; for (j=MAXPLAYERS-1; j>=0; j--) i += g_player[j].gotvote; if (i != numplayers) Bsprintf(tempbuf,"%s^00 HAS CANCELED THE VOTE",g_player[(uint8_t)pbuf[1]].user_name); else Bsprintf(tempbuf,"VOTE FAILED"); for (i=MAXPLAYERS-1; i>=0; i--) { g_player[i].vote = 0; g_player[i].gotvote = 0; } G_AddUserQuote(tempbuf); } break; } } void Net_ParseClientPacket(ENetEvent *event) { uint8_t *pbuf = event->packet->data; int32_t packbufleng = event->packet->dataLength; int16_t i, j; int32_t other = pbuf[--packbufleng]; input_t *nsyn; #if 0 initprintf("RECEIVED PACKET: type: %d : len %d\n", pbuf[0], packbufleng); #endif switch (pbuf[0]) { case PACKET_SLAVE_TO_MASTER: //[1] (receive slave sync buffer) j = 0; packbufleng = qlz_size_decompressed((char *)&pbuf[1]); pbuf = (uint8_t *)Bcalloc(1, packbufleng+1); packbufleng = qlz_decompress((char *)&event->packet->data[1], (char *)(pbuf), state_decompress); nsyn = (input_t *)&inputfifo[0][0]; Bmemcpy(&nsyn[other], &pbuf[j], sizeof(input_t)); j += offsetof(input_t, filler); // anyone the server thinks is dead can go fuck themselves if (g_player[other].ps->dead_flag) { Bfree(pbuf); break; } else g_player[other].playerquitflag = 1; // Bmemcpy(&g_player[other].ps->opos.x, &g_player[other].ps->pos.x, sizeof(vec3_t)); // Bmemcpy(&g_player[other].ps->pos.x, &pbuf[j], sizeof(vec3_t) * 2); // updatesectorz(g_player[other].ps->pos.x, g_player[other].ps->pos.y, g_player[other].ps->pos.z, // &g_player[other].ps->cursectnum); // Bmemcpy(&sprite[g_player[other].ps->i], &pbuf[j], sizeof(vec3_t)); // sprite[g_player[other].ps->i].z += PHEIGHT; // changespritesect(g_player[other].ps->i, g_player[other].ps->cursectnum); // Bmemcpy(&g_player[other].ps->npos.x, &pbuf[j], sizeof(vec3_t)); j += sizeof(vec3_t) * 2; // Bmemcpy(&g_player[other].ps->vel.x, &pbuf[j], sizeof(vec3_t)); j += sizeof(vec3_t); g_player[other].ps->oang = g_player[other].ps->ang; Bmemcpy(&g_player[other].ps->ang, &pbuf[j], sizeof(int16_t)); Bmemcpy(&sprite[g_player[other].ps->i].ang, &pbuf[j], sizeof(int16_t)); j += sizeof(int16_t); Bmemcpy(&g_player[other].ps->ohoriz, &g_player[other].ps->horiz, sizeof(int16_t) * 2); Bmemcpy(&g_player[other].ps->horiz, &pbuf[j], sizeof(int16_t) * 2); j += sizeof(int16_t) * 2; Bfree(pbuf); break; case PACKET_PLAYER_READY: j = g_player[other].ps->i; Bmemcpy(g_player[other].ps, g_player[0].ps, sizeof(DukePlayer_t)); g_player[other].ps->i = j; changespritestat(j, STAT_PLAYER); g_player[other].ps->last_extra = sprite[g_player[other].ps->i].extra = g_player[other].ps->max_player_health; sprite[g_player[other].ps->i].cstat = 1+256; actor[g_player[other].ps->i].t_data[2] = actor[g_player[other].ps->i].t_data[3] = actor[g_player[other].ps->i].t_data[4] = 0; P_ResetPlayer(other); j = 0; packbuf[j++] = PACKET_PLAYER_SPAWN; packbuf[j++] = other; Bmemcpy(&packbuf[j], &g_player[other].ps->pos.x, sizeof(vec3_t) * 2); j += sizeof(vec3_t) * 2; packbuf[j++] = 0; enet_host_broadcast(g_netServer, CHAN_GAMESTATE , enet_packet_create(packbuf, j, ENET_PACKET_FLAG_RELIABLE)); // a player connecting is a good time to mark things as needing to be updated // we invalidate everything that has changed since we started sending the snapshot of the map to the new player { int32_t zz, i, nexti; for (zz = 0; (unsigned)zz < (sizeof(g_netStatnums)/sizeof(g_netStatnums[0])); zz++) TRAVERSE_SPRITE_STAT(headspritestat[g_netStatnums[zz]], i, nexti) { if (lastupdate[i] >= g_player[other].netsynctime) lastupdate[i] = 0; } } for (i=numwalls-1; i>=0; i--) if (lastwallupdate[i] >= g_player[other].netsynctime) lastwallupdate[i] = 0; for (i=numsectors-1; i>=0; i--) if (lastsectupdate[i] >= g_player[other].netsynctime) lastsectupdate[i] = 0; break; case PACKET_PLAYER_PING: if (g_player[myconnectindex].ps->gm & MODE_GAME) { packbuf[0] = PACKET_PLAYER_PING; packbuf[1] = myconnectindex; enet_peer_send(event->peer, CHAN_GAMESTATE, enet_packet_create(packbuf, 2, ENET_PACKET_FLAG_RELIABLE)); } g_player[other].pingcnt++; return; case PACKET_MESSAGE: Bstrncpy(recbuf, (char *)pbuf+2, packbufleng-2); recbuf[packbufleng-2] = 0; G_AddUserQuote(recbuf); S_PlaySound(EXITMENUSOUND); pus = pub = NUMPAGES; break; case PACKET_NEW_GAME: if ((vote_map + vote_episode + voting) != -3) G_AddUserQuote("VOTE SUCCEEDED"); ud.m_level_number = ud.level_number = pbuf[1]; ud.m_volume_number = ud.volume_number = pbuf[2]; ud.m_player_skill = ud.player_skill = pbuf[3]; ud.m_monsters_off = ud.monsters_off = pbuf[4]; ud.m_respawn_monsters = ud.respawn_monsters = pbuf[5]; ud.m_respawn_items = ud.respawn_items = pbuf[6]; ud.m_respawn_inventory = ud.respawn_inventory = pbuf[7]; ud.m_coop = pbuf[8]; ud.m_marker = ud.marker = pbuf[9]; ud.m_ffire = ud.ffire = pbuf[10]; ud.m_noexits = ud.noexits = pbuf[11]; TRAVERSE_CONNECT(i) { P_ResetWeapons(i); P_ResetInventory(i); } G_NewGame(ud.volume_number,ud.level_number,ud.player_skill); ud.coop = ud.m_coop; if (G_EnterLevel(MODE_GAME)) G_BackToMenu(); break; case PACKET_AUTH: { uint32_t crc = *(uint32_t *)&pbuf[1]; if (crc == crc32once((uint8_t *)g_netPassword, Bstrlen(g_netPassword))) Net_SyncPlayer(event); else { enet_peer_disconnect_later(event->peer, DISC_BAD_PASSWORD); initprintf("Bad password from client.\n"); } } break; case PACKET_CLIENT_INFO: for (i=1; pbuf[i]; i++) g_player[other].user_name[i-1] = pbuf[i]; g_player[other].user_name[i-1] = 0; i++; g_player[other].ps->aim_mode = pbuf[i++]; g_player[other].ps->auto_aim = pbuf[i++]; g_player[other].ps->weaponswitch = pbuf[i++]; g_player[other].ps->palookup = g_player[other].pcolor = pbuf[i++]; g_player[other].pteam = pbuf[i++]; for (j=i; i-j<10; i++) g_player[other].wchoice[i-j] = pbuf[i]; break; case PACKET_RTS: if (rts_numlumps == 0) break; if (ud.config.SoundToggle == 0 || ud.lockout == 1 || ud.config.FXDevice < 0 || !(ud.config.VoiceToggle & 4)) break; FX_PlayAuto3D((char *)RTS_GetSound(pbuf[1]-1),RTS_SoundLength(pbuf[1]-1),0,0,0,255,-pbuf[1]); g_RTSPlaying = 7; break; case PACKET_USER_MAP: Bstrcpy(boardfilename,(char *)pbuf+1); boardfilename[packbufleng-1] = 0; Bcorrectfilename(boardfilename,0); if (boardfilename[0] != 0) { if ((i = kopen4loadfrommod(boardfilename,0)) < 0) { Bmemset(boardfilename,0,sizeof(boardfilename)); Net_SendUserMapName(); } else kclose(i); } if (ud.m_level_number == 7 && ud.m_volume_number == 0 && boardfilename[0] == 0) ud.m_level_number = 0; break; case PACKET_MAP_VOTE: if (voting == myconnectindex && g_player[(uint8_t)pbuf[1]].gotvote == 0) { g_player[(uint8_t)pbuf[1]].gotvote = 1; g_player[(uint8_t)pbuf[1]].vote = pbuf[2]; Bsprintf(tempbuf,"CONFIRMED VOTE FROM %s",g_player[(uint8_t)pbuf[1]].user_name); G_AddUserQuote(tempbuf); } break; case PACKET_MAP_VOTE_INITIATE: voting = pbuf[1]; vote_episode = pbuf[2]; vote_map = pbuf[3]; Bsprintf(tempbuf,"%s^00 HAS CALLED A VOTE TO CHANGE MAP TO %s (E%dL%d)", g_player[(uint8_t)pbuf[1]].user_name, MapInfo[(uint8_t)(pbuf[2]*MAXLEVELS + pbuf[3])].name, pbuf[2]+1,pbuf[3]+1); G_AddUserQuote(tempbuf); Bsprintf(tempbuf,"PRESS F1 TO ACCEPT, F2 TO DECLINE"); G_AddUserQuote(tempbuf); for (i=MAXPLAYERS-1; i>=0; i--) { g_player[i].vote = 0; g_player[i].gotvote = 0; } g_player[voting].gotvote = g_player[voting].vote = 1; break; case PACKET_MAP_VOTE_CANCEL: if (voting == pbuf[1]) { voting = -1; i = 0; for (j=MAXPLAYERS-1; j>=0; j--) i += g_player[j].gotvote; if (i != numplayers) Bsprintf(tempbuf,"%s^00 HAS CANCELED THE VOTE",g_player[(uint8_t)pbuf[1]].user_name); else Bsprintf(tempbuf,"VOTE FAILED"); for (i=MAXPLAYERS-1; i>=0; i--) { g_player[i].vote = 0; g_player[i].gotvote = 0; } G_AddUserQuote(tempbuf); } break; case PACKET_REQUEST_GAMESTATE: if (g_netServer && g_player[0].ps->gm & MODE_GAME) { packbuf[0] = PACKET_NEW_GAME; packbuf[1] = ud.level_number; packbuf[2] = ud.volume_number; packbuf[3] = ud.player_skill+1; packbuf[4] = ud.monsters_off; packbuf[5] = ud.respawn_monsters; packbuf[6] = ud.respawn_items; packbuf[7] = ud.respawn_inventory; packbuf[8] = ud.coop; packbuf[9] = ud.marker; packbuf[10] = ud.ffire; packbuf[11] = ud.noexits; packbuf[12] = myconnectindex; enet_peer_send(event->peer, CHAN_GAMESTATE, enet_packet_create(packbuf, 13, ENET_PACKET_FLAG_RELIABLE)); g_netPlayersWaiting--; } break; } } void Net_GetPackets(void) { sampletimer(); MUSIC_Update(); S_Update(); G_HandleSpecialKeys(); if (g_netDisconnect) { Net_Disconnect(); g_netDisconnect = 0; if (g_gameQuit) G_GameExit(" "); return; } if (g_netServer) { ENetEvent event; // pull events from the wire into the packet queue without dispatching them, once per Net_GetPackets() call enet_host_service(g_netServer, NULL, 0); // dispatch any pending events from the local packet queue while (enet_host_check_events(g_netServer, &event) > 0) { switch (event.type) { case ENET_EVENT_TYPE_CONNECT: { char ipaddr[32]; enet_address_get_host_ip(&event.peer->address, ipaddr, sizeof(ipaddr)); initprintf("A new client connected from %s:%u.\n", ipaddr, event.peer -> address.port); } Net_SendVersion(event.peer); break; case ENET_EVENT_TYPE_RECEIVE: /* initprintf ("A packet of length %u containing %s was received from player %d on channel %u.\n", event.packet -> dataLength, event.packet -> data, event.peer -> data, event.channelID); */ Net_ParseClientPacket(&event); // broadcast takes care of enet_packet_destroy itself // we set the state to disconnected so enet_host_broadcast doesn't send the player back his own packets if ((event.channelID == CHAN_GAMESTATE && event.packet->data[0] > PACKET_BROADCAST) || event.channelID == CHAN_CHAT) { event.peer->state = ENET_PEER_STATE_DISCONNECTED; enet_host_broadcast(g_netServer, event.channelID, enet_packet_create(event.packet->data, event.packet->dataLength, event.packet->flags & ENET_PACKET_FLAG_RELIABLE)); event.peer->state = ENET_PEER_STATE_CONNECTED; } enet_packet_destroy(event.packet); g_player[(intptr_t)event.peer->data].ping = (event.peer->lastRoundTripTime + event.peer->roundTripTime)/2; break; case ENET_EVENT_TYPE_DISCONNECT: numplayers--; ud.multimode--; P_RemovePlayer((intptr_t)event.peer->data); packbuf[0] = PACKET_PLAYER_DISCONNECTED; packbuf[1] = (intptr_t)event.peer->data; packbuf[2] = numplayers; packbuf[3] = ud.multimode; packbuf[4] = playerswhenstarted; packbuf[5] = myconnectindex; enet_host_broadcast(g_netServer, CHAN_GAMESTATE, enet_packet_create(packbuf, 6, ENET_PACKET_FLAG_RELIABLE)); initprintf("%s disconnected.\n", g_player[(intptr_t)event.peer->data].user_name); event.peer->data = NULL; break; default: break; } } } else if (g_netClient) { ENetEvent event; size_t datasiz = 0; do { enet_host_service(g_netClient, NULL, 0); while (enet_host_check_events(g_netClient, &event) > 0) { switch (event.type) { case ENET_EVENT_TYPE_RECEIVE: /* initprintf("A packet of length %u was received from player %d on channel %u.\n", event.packet -> dataLength, event.peer -> data, event.channelID); */ // mapstate transfer from the server... all packets but the last are SYNCPACKETSIZE if (event.channelID == CHAN_SYNC) { static uint8_t *buf = NULL; if (buf == NULL) { g_netSync = 1; buf = (uint8_t *)Bcalloc(1, sizeof(mapstate_t)<<1); } g_multiMapState = (mapstate_t *)Brealloc(g_multiMapState, sizeof(mapstate_t)); rotatesprite(0,0,65536L,0,BETASCREEN,0,0,2+8+16+64,0,0,xdim-1,ydim-1); rotatesprite(160<<16,(104)<<16,60<<10,0,DUKENUKEM,0,0,2+8,0,0,xdim-1,ydim-1); rotatesprite(160<<16,(129)<<16,30<<11,0,THREEDEE,0,0,2+8,0,0,xdim-1,ydim-1); if (PLUTOPAK) // JBF 20030804 rotatesprite(160<<16,(151)<<16,30<<11,0,PLUTOPAKSPRITE+1,0,0,2+8,0,0,xdim-1,ydim-1); if (buf && event.packet->dataLength == SYNCPACKETSIZE) { char tbuf[64]; Bmemcpy((uint8_t *)(buf)+datasiz, event.packet->data, event.packet->dataLength); datasiz += SYNCPACKETSIZE; Bsprintf(tbuf, "RECEIVED %d BYTES\n", (int32_t)datasiz); gametext(160,190,tbuf,14,2); } // last packet of mapstate sequence else if (buf) { Bmemcpy((uint8_t *)(buf)+datasiz, event.packet->data, event.packet->dataLength); datasiz = 0; // g_netSync = 0; if (qlz_size_decompressed((const char *)buf) == sizeof(mapstate_t)) { qlz_decompress((const char *)buf, g_multiMapState, state_decompress); Bfree(buf); buf = NULL; packbuf[0] = PACKET_REQUEST_GAMESTATE; packbuf[1] = myconnectindex; enet_peer_send(g_netClientPeer, CHAN_GAMESTATE, enet_packet_create(&packbuf[0], 2, ENET_PACKET_FLAG_RELIABLE)); gametext(160,190,"TRANSFER COMPLETE",14,2); } else { initprintf("Invalid map state from server!\n"); Bfree(buf); buf = NULL; g_netDisconnect = 1; g_netSync = 0; gametext(160,190,"TRANSFER ERROR",14,2); } } else { initprintf("Error allocating buffer for map state!\n"); g_netDisconnect = 1; g_netSync = 0; gametext(160,190,"TRANSFER ERROR",14,2); } nextpage(); } else Net_ParseServerPacket(&event); enet_packet_destroy(event.packet); break; case ENET_EVENT_TYPE_DISCONNECT: g_netDisconnect = 1; numplayers = playerswhenstarted = ud.multimode = 1; myconnectindex = screenpeek = 0; G_BackToMenu(); switch (event.data) { case DISC_BAD_PASSWORD: initprintf("Bad password.\n"); return; case DISC_KICKED: initprintf("You have been kicked from the server.\n"); return; case DISC_BANNED: initprintf("You are banned from this server.\n"); return; default: initprintf("Disconnected.\n"); return; } default: break; } } } while (datasiz); } } void Net_ClientMove(void) { int32_t j; input_t *nsyn = (input_t *)&inputfifo[0][myconnectindex]; packbuf[0] = PACKET_SLAVE_TO_MASTER; j = 1; Bmemcpy(&packbuf[j], &nsyn[0], offsetof(input_t, filler)); j += offsetof(input_t, filler); Bmemcpy(&packbuf[j], &g_player[myconnectindex].ps->pos.x, sizeof(vec3_t) * 2); j += sizeof(vec3_t) * 2; Bmemcpy(&packbuf[j], &g_player[myconnectindex].ps->vel.x, sizeof(vec3_t)); j += sizeof(vec3_t); *(int16_t *)&packbuf[j] = g_player[myconnectindex].ps->ang; j += sizeof(int16_t); Bmemcpy(&packbuf[j], &g_player[myconnectindex].ps->horiz, sizeof(int16_t) * 2); j += sizeof(int16_t) * 2; { char buf[1024]; j = qlz_compress((char *)(packbuf)+1, (char *)buf, j, state_compress); Bmemcpy((char *)(packbuf)+1, (char *)buf, j); j++; } packbuf[j++] = myconnectindex; enet_peer_send(g_netClientPeer, CHAN_MOVE, enet_packet_create(packbuf, j, 0)); } void Net_UpdateClients(void) { input_t *osyn = (input_t *)&inputfifo[1][0]; input_t *nsyn = (input_t *)&inputfifo[0][0]; int16_t i, nexti, k = 0, l; int32_t j; if (!g_netServer || numplayers < 2) { ticrandomseed = randomseed; if (g_netServer) Bmemcpy(&osyn[0], &nsyn[0], sizeof(input_t)); return; } packbuf[0] = PACKET_MASTER_TO_SLAVE; j = 1; *(int32_t *)&packbuf[j] = ticrandomseed = randomseed; j += sizeof(int32_t); packbuf[j++] = ud.pause_on; TRAVERSE_CONNECT(i) { Bmemcpy(&osyn[i], &nsyn[i], offsetof(input_t, filler)); *(int16_t *)&packbuf[j] = g_player[i].ps->dead_flag; j += sizeof(int16_t); packbuf[j++] = g_player[i].playerquitflag; if (g_player[i].playerquitflag == 0) continue; Bmemcpy(&packbuf[j], &nsyn[i], offsetof(input_t, filler)); j += offsetof(input_t, filler); Bmemcpy(&packbuf[j], &g_player[i].ps->pos.x, sizeof(vec3_t) * 2); j += sizeof(vec3_t) * 2; Bmemcpy(&packbuf[j], &g_player[i].ps->vel.x, sizeof(vec3_t)); j += sizeof(vec3_t); *(int16_t *)&packbuf[j] = g_player[i].ps->ang; j += sizeof(int16_t); Bmemcpy(&packbuf[j], &g_player[i].ps->horiz, sizeof(int16_t) * 2); j += sizeof(int16_t) * 2; *(uint16_t *)&packbuf[j] = g_player[i].ps->gotweapon; j += sizeof(uint16_t); Bmemcpy(&packbuf[j], &g_player[i].ps->ammo_amount[0], sizeof(g_player[i].ps->ammo_amount)); j += sizeof(g_player[i].ps->ammo_amount); Bmemcpy(&packbuf[j], &g_player[i].ps->inv_amount[0], sizeof(g_player[i].ps->inv_amount)); j += sizeof(g_player[i].ps->inv_amount); Bmemcpy(&packbuf[j], g_player[i].frags, sizeof(g_player[i].frags)); j += sizeof(g_player[i].frags); packbuf[j++] = (uint8_t) sprite[g_player[i].ps->i].extra; *(int16_t *)&packbuf[j] = sprite[g_player[i].ps->i].cstat; j += sizeof(int16_t); packbuf[j++] = (uint8_t) g_player[i].ps->kickback_pic; *(int16_t *)&packbuf[j] = actor[g_player[i].ps->i].owner; j += sizeof(int16_t); *(int16_t *)&packbuf[j] = actor[g_player[i].ps->i].picnum; j += sizeof(int16_t); packbuf[j++] = (uint8_t) g_player[i].ps->curr_weapon; packbuf[j++] = (int8_t) g_player[i].ps->last_weapon; packbuf[j++] = (int8_t) g_player[i].ps->wantweaponfire; packbuf[j++] = (int8_t) g_player[i].ps->weapon_pos; packbuf[j++] = (uint8_t) g_player[i].ps->frag_ps; packbuf[j++] = g_player[i].ps->frag; packbuf[j++] = g_player[i].ps->fraggedself; packbuf[j++] = g_player[i].ps->last_extra; *(int16_t *)&packbuf[j] = g_player[i].ping; j += sizeof(int16_t); *(int16_t *)&packbuf[j] = g_player[i].ps->newowner; j += sizeof(int16_t); packbuf[j++] = sprite[g_player[i].ps->i].pal; l = i; i = g_player[l].ps->i; { int32_t jj; #if !defined SAMESIZE_ACTOR_T int32_t oa; #endif packbuf[(jj = j++)] = 0; #if !defined SAMESIZE_ACTOR_T if (T5 >= (intptr_t)&script[0] && T5 < (intptr_t)(&script[g_scriptSize])) { packbuf[jj] |= 2; T5 -= (intptr_t)&script[0]; } oa = T5; #endif Bmemcpy(&packbuf[j], &T5, sizeof(T5)); j += sizeof(T5); #if !defined SAMESIZE_ACTOR_T if (oa != T5) T3 = T4 = 0; if (packbuf[jj] & 2) T5 += (intptr_t)&script[0]; #endif } { int16_t ii=g_gameVarCount-1, kk = 0; for (; ii>=0 && j <= (SYNCPACKETSIZE-(SYNCPACKETSIZE>>3)); ii--) { if ((aGameVars[ii].dwFlags & (GAMEVAR_PERACTOR|GAMEVAR_NOMULTI)) == GAMEVAR_PERACTOR && aGameVars[ii].val.plValues) { if (aGameVars[ii].val.plValues[i] != aGameVars[ii].lDefault) { *(int16_t *)&packbuf[j] = ii; j += sizeof(int16_t); *(int32_t *)&packbuf[j] = aGameVars[ii].val.plValues[i]; j += sizeof(int32_t); kk++; if (j >= (SYNCPACKETSIZE-(SYNCPACKETSIZE>>3))) break; } } } *(int16_t *)&packbuf[j] = MAXGAMEVARS; j += sizeof(int16_t); } i = l; { int16_t ii=g_gameVarCount-1, kk = 0; for (; ii>=0 && j <= (SYNCPACKETSIZE-(SYNCPACKETSIZE>>3)); ii--) { if ((aGameVars[ii].dwFlags & (GAMEVAR_PERPLAYER|GAMEVAR_NOMULTI)) == GAMEVAR_PERPLAYER && aGameVars[ii].val.plValues) { if (aGameVars[ii].val.plValues[i] != aGameVars[ii].lDefault) { *(int16_t *)&packbuf[j] = ii; j += sizeof(int16_t); *(int32_t *)&packbuf[j] = aGameVars[ii].val.plValues[i]; j += sizeof(int32_t); kk++; if (j >= (SYNCPACKETSIZE-(SYNCPACKETSIZE>>3))) break; } } } *(int16_t *)&packbuf[j] = MAXGAMEVARS; j += sizeof(int16_t); } } k = 0; { int32_t zz, zj; packbuf[(zj = j)] = 0; j += sizeof(int16_t); for (zz = 0; (unsigned)zz < (sizeof(g_netStatnums)/sizeof(g_netStatnums[0])) && j <= (SYNCPACKETSIZE-(SYNCPACKETSIZE>>3)); zz++) TRAVERSE_SPRITE_STAT(headspritestat[g_netStatnums[zz]], i, nexti) { // only send newly spawned sprites if (!lastupdate[i] && sprite[i].statnum != MAXSTATUS) { int32_t ii; j += (ii = Net_PackSprite(i, (uint8_t *)&packbuf[j])); if (ii) k++; lastupdate[i] = totalclock; if (j >= (SYNCPACKETSIZE-(SYNCPACKETSIZE>>3))) break; } } *(int16_t *)&packbuf[zj] = k; j += sizeof(int16_t); } { char buf[PACKBUF_SIZE]; if (j >= PACKBUF_SIZE) { initprintf("Global packet buffer overflow! Size of packet: %i\n", j); } j = qlz_compress((char *)(packbuf)+1, (char *)buf, j, state_compress); Bmemcpy((char *)(packbuf)+1, (char *)buf, j); j++; } packbuf[j++] = myconnectindex; enet_host_broadcast(g_netServer, CHAN_MOVE, enet_packet_create(packbuf, j, 0)); } void Net_StreamLevel(void) { int16_t i, nexti; int32_t j = 0; int32_t zz, zj, k = 0, l; if (!g_netServer || numplayers < 2) return; packbuf[j++] = PACKET_MAP_STREAM; *(uint16_t *)&packbuf[(zj = j)] = 0; j += sizeof(uint16_t); for (zz = 0; (unsigned)zz < (sizeof(g_netStatnums)/sizeof(g_netStatnums[0])) && j <= (SYNCPACKETSIZE-(SYNCPACKETSIZE>>3)); zz++) TRAVERSE_SPRITE_STAT(headspritestat[g_netStatnums[zz]], i, nexti) { // only send STAT_MISC sprites at spawn time and let the client handle it from there if (totalclock > (lastupdate[i] + TICRATE) && sprite[i].statnum != STAT_MISC) { l = crc32once((uint8_t *)&sprite[i], sizeof(spritetype)); if (!lastupdate[i] || spritecrc[i] != l) { int32_t ii; /*initprintf("updating sprite %d (%d)\n",i,sprite[i].picnum);*/ spritecrc[i] = l; j += (ii = Net_PackSprite(i, (uint8_t *)&packbuf[j])); if (ii) k++; lastupdate[i] = totalclock; if (j >= (SYNCPACKETSIZE-(SYNCPACKETSIZE>>3))) break; } } } *(uint16_t *)&packbuf[zj] = k; k = 0; *(uint16_t *)&packbuf[(zj = j)] = 0; j += sizeof(uint16_t); for (i = numsectors-1; i >= 0 && j <= (SYNCPACKETSIZE-(SYNCPACKETSIZE>>3)); i--) { if (totalclock > (lastsectupdate[i] + TICRATE)) { l = crc32once((uint8_t *)§or[i], sizeof(sectortype)); if (sectcrc[i] != l) { sectcrc[i] = l; lastsectupdate[i] = totalclock; j += Net_PackSect(i, (uint8_t *)&packbuf[j]); k++; if (j >= (SYNCPACKETSIZE-(SYNCPACKETSIZE>>3))) break; } } } *(uint16_t *)&packbuf[zj] = k; k = 0; *(uint16_t *)&packbuf[(zj = j)] = 0; j += sizeof(uint16_t); for (i = numwalls-1; i >= 0 && j <= (SYNCPACKETSIZE-(SYNCPACKETSIZE>>3)); i--) { if (totalclock > (lastwallupdate[i] + TICRATE)) { l = crc32once((uint8_t *)&wall[i], sizeof(walltype)); if (wallcrc[i] != l) { wallcrc[i] = l; lastwallupdate[i] = totalclock; j += Net_PackWall(i, (uint8_t *)&packbuf[j]); k++; if (j >= (SYNCPACKETSIZE-(SYNCPACKETSIZE>>3))) break; } } } *(uint16_t *)&packbuf[zj] = k; { char buf[PACKBUF_SIZE]; if (j >= PACKBUF_SIZE) initprintf("Global packet buffer overflow! Size of packet: %i\n", j); j = qlz_compress((char *)(packbuf)+1, (char *)buf, j, state_compress); Bmemcpy((char *)(packbuf)+1, (char *)buf, j); j++; } packbuf[j++] = myconnectindex; enet_host_broadcast(g_netServer, CHAN_GAMESTATE, enet_packet_create(packbuf, j, ENET_PACKET_FLAG_RELIABLE)); } void faketimerhandler(void) { if (((uintptr_t)g_netServer|(uintptr_t)g_netClient) == (uintptr_t)NULL) return; enet_host_service(g_netServer ? g_netServer : g_netClient, NULL, 0); } void Net_EnterMessage(void) { int16_t hitstate, i, j, l; if (g_player[myconnectindex].ps->gm&MODE_SENDTOWHOM) { if (g_chatPlayer != -1 || ud.multimode < 3) { tempbuf[0] = PACKET_MESSAGE; tempbuf[2] = 0; recbuf[0] = 0; if (ud.multimode < 3) g_chatPlayer = 2; if (typebuf[0] == '/' && Btoupper(typebuf[1]) == 'M' && Btoupper(typebuf[2]) == 'E') { Bstrcat(recbuf,"* "); i = 3, j = Bstrlen(typebuf); Bstrcpy(tempbuf,typebuf); while (i < j) { typebuf[i-3] = tempbuf[i]; i++; } typebuf[i-3] = '\0'; Bstrcat(recbuf,g_player[myconnectindex].user_name); } else { Bstrcat(recbuf,g_player[myconnectindex].user_name); Bstrcat(recbuf,": "); } Bstrcat(recbuf,"^00"); Bstrcat(recbuf,typebuf); j = Bstrlen(recbuf); recbuf[j] = 0; Bstrcat(tempbuf+2,recbuf); if (g_chatPlayer >= ud.multimode) { tempbuf[1] = 255; tempbuf[j+2] = myconnectindex; j++; if (g_netServer) enet_host_broadcast(g_netServer, CHAN_CHAT, enet_packet_create(tempbuf, j+2, 0)); else if (g_netClient) enet_peer_send(g_netClientPeer, CHAN_CHAT, enet_packet_create(tempbuf, j+2, 0)); G_AddUserQuote(recbuf); quotebot += 8; l = G_GameTextLen(USERQUOTE_LEFTOFFSET,OSD_StripColors(tempbuf,recbuf)); while (l > (ud.config.ScreenWidth - USERQUOTE_RIGHTOFFSET)) { l -= (ud.config.ScreenWidth - USERQUOTE_RIGHTOFFSET); quotebot += 8; } quotebotgoal = quotebot; } g_chatPlayer = -1; g_player[myconnectindex].ps->gm &= ~(MODE_TYPE|MODE_SENDTOWHOM); } else if (g_chatPlayer == -1) { j = 50; gametext(320>>1,j,"SEND MESSAGE TO...",0,2+8+16); j += 8; TRAVERSE_CONNECT(i) { if (i == myconnectindex) { minitextshade((320>>1)-40+1,j+1,"A/ENTER - ALL",26,0,2+8+16); minitext((320>>1)-40,j,"A/ENTER - ALL",0,2+8+16); j += 7; } else { Bsprintf(buf," %d - %s",i+1,g_player[i].user_name); minitextshade((320>>1)-40-6+1,j+1,buf,26,0,2+8+16); minitext((320>>1)-40-6,j,buf,0,2+8+16); j += 7; } } minitextshade((320>>1)-40-4+1,j+1," ESC - Abort",26,0,2+8+16); minitext((320>>1)-40-4,j," ESC - Abort",0,2+8+16); j += 7; if (ud.screen_size > 0) j = 200-45; else j = 200-8; mpgametext(j,typebuf,0,2+8+16); if (KB_KeyWaiting()) { i = KB_GetCh(); if (i == 'A' || i == 'a' || i == 13) g_chatPlayer = ud.multimode; else if (i >= '1' || i <= (ud.multimode + '1')) g_chatPlayer = i - '1'; else { g_chatPlayer = ud.multimode; if (i == 27) { g_player[myconnectindex].ps->gm &= ~(MODE_TYPE|MODE_SENDTOWHOM); g_chatPlayer = -1; } else typebuf[0] = 0; } KB_ClearKeyDown(sc_1); KB_ClearKeyDown(sc_2); KB_ClearKeyDown(sc_3); KB_ClearKeyDown(sc_4); KB_ClearKeyDown(sc_5); KB_ClearKeyDown(sc_6); KB_ClearKeyDown(sc_7); KB_ClearKeyDown(sc_8); KB_ClearKeyDown(sc_A); KB_ClearKeyDown(sc_Escape); KB_ClearKeyDown(sc_Enter); } } } else { if (ud.screen_size > 1) j = 200-45; else j = 200-8; if (xdim >= 640 && ydim >= 480) j = scale(j,ydim,200); hitstate = Net_EnterText(320>>1,j,typebuf,120,1); if (hitstate == 1) { KB_ClearKeyDown(sc_Enter); if (Bstrlen(typebuf) == 0) { g_player[myconnectindex].ps->gm &= ~(MODE_TYPE|MODE_SENDTOWHOM); return; } if (ud.automsg) { if (SHIFTS_IS_PRESSED) g_chatPlayer = -1; else g_chatPlayer = ud.multimode; } g_player[myconnectindex].ps->gm |= MODE_SENDTOWHOM; } else if (hitstate == -1) g_player[myconnectindex].ps->gm &= ~(MODE_TYPE|MODE_SENDTOWHOM); else pub = NUMPAGES; } } void Net_WaitForServer(void) { int32_t server_ready = g_player[0].pingcnt; if (numplayers < 2 || g_netServer) return; P_SetGamePalette(g_player[myconnectindex].ps, TITLEPAL, 11); do { if (quitevent || keystatus[1]) G_GameExit(""); rotatesprite(0,0,65536L,0,BETASCREEN,0,0,2+8+16+64,0,0,xdim-1,ydim-1); rotatesprite(160<<16,(104)<<16,60<<10,0,DUKENUKEM,0,0,2+8,0,0,xdim-1,ydim-1); rotatesprite(160<<16,(129)<<16,30<<11,0,THREEDEE,0,0,2+8,0,0,xdim-1,ydim-1); if (PLUTOPAK) // JBF 20030804 rotatesprite(160<<16,(151)<<16,30<<11,0,PLUTOPAKSPRITE+1,0,0,2+8,0,0,xdim-1,ydim-1); gametext(160,170,"WAITING FOR SERVER",14,2); nextpage(); packbuf[0] = PACKET_PLAYER_PING; packbuf[1] = myconnectindex; if (g_netClientPeer) enet_peer_send(g_netClientPeer, CHAN_GAMESTATE, enet_packet_create(packbuf, 2, ENET_PACKET_FLAG_RELIABLE)); handleevents(); Net_GetPackets(); if (g_player[0].pingcnt > server_ready) { P_SetGamePalette(g_player[myconnectindex].ps, BASEPAL, 11); return; } } while (1); } void Net_ResetPrediction(void) { Bmemcpy(&my, &g_player[myconnectindex].ps, sizeof(vec3_t)); Bmemcpy(&omy, &g_player[myconnectindex].ps, sizeof(vec3_t)); Bmemset(&myvel, 0, sizeof(vec3_t)); myang = omyang = g_player[myconnectindex].ps->ang; myhoriz = omyhoriz = g_player[myconnectindex].ps->horiz; myhorizoff = omyhorizoff = g_player[myconnectindex].ps->horizoff; mycursectnum = g_player[myconnectindex].ps->cursectnum; myjumpingcounter = g_player[myconnectindex].ps->jumping_counter; myjumpingtoggle = g_player[myconnectindex].ps->jumping_toggle; myonground = g_player[myconnectindex].ps->on_ground; myhardlanding = g_player[myconnectindex].ps->hard_landing; myreturntocenter = g_player[myconnectindex].ps->return_to_center; }