diff --git a/polymer/eduke32/source/actors.c b/polymer/eduke32/source/actors.c index 05f927ad0..a8c91a69c 100644 --- a/polymer/eduke32/source/actors.c +++ b/polymer/eduke32/source/actors.c @@ -532,7 +532,7 @@ void A_DeleteSprite(int32_t s) void A_AddToDeleteQueue(int32_t i) { - if (g_netClientPeer || g_spriteDeleteQueueSize == 0) + if (g_spriteDeleteQueueSize == 0) { A_DeleteSprite(i); return; diff --git a/polymer/eduke32/source/demo.c b/polymer/eduke32/source/demo.c index ca4a90ffd..c04aa3da0 100644 --- a/polymer/eduke32/source/demo.c +++ b/polymer/eduke32/source/demo.c @@ -926,7 +926,7 @@ nextdemo_nomenu: } else if (g_player[myconnectindex].ps->gm&MODE_TYPE) { - Net_EnterMessage(); + Net_SendMessage(); if ((g_player[myconnectindex].ps->gm&MODE_TYPE) != MODE_TYPE) g_player[myconnectindex].ps->gm = MODE_MENU; diff --git a/polymer/eduke32/source/game.c b/polymer/eduke32/source/game.c index c1043ed72..81d69b5a6 100644 --- a/polymer/eduke32/source/game.c +++ b/polymer/eduke32/source/game.c @@ -3026,7 +3026,7 @@ void G_DisplayRest(int32_t smoothratio) if (!Demo_IsProfiling()) { if (g_player[myconnectindex].ps->gm&MODE_TYPE) - Net_EnterMessage(); + Net_SendMessage(); else M_DisplayMenus(); } @@ -7299,9 +7299,9 @@ FOUNDCHEAT: i = Bstrlen(CheatStrings[k])-1; ud.m_player_skill = ud.player_skill = cheatbuf[i] - '1'; } - if (numplayers > 1 && g_netServer) + /*if (numplayers > 1 && g_netServer) Net_NewGame(ud.m_volume_number,ud.m_level_number); - else g_player[myconnectindex].ps->gm |= MODE_RESTART; + else*/ g_player[myconnectindex].ps->gm |= MODE_RESTART; end_cheat(); return; @@ -7480,22 +7480,10 @@ void G_HandleLocalKeys(void) { if (KB_UnBoundKeyPressed(sc_F1) || KB_UnBoundKeyPressed(sc_F2) || ud.autovote) { - tempbuf[0] = PACKET_MAP_VOTE; - tempbuf[1] = myconnectindex; - tempbuf[2] = (KB_UnBoundKeyPressed(sc_F1) || ud.autovote ? ud.autovote-1 : 0); - tempbuf[3] = myconnectindex; - - if (g_netClient) - enet_peer_send(g_netClientPeer, CHAN_GAMESTATE, enet_packet_create(tempbuf, 4, ENET_PACKET_FLAG_RELIABLE)); - else if (g_netServer) - enet_host_broadcast(g_netServer, CHAN_GAMESTATE, enet_packet_create(tempbuf, 4, ENET_PACKET_FLAG_RELIABLE)); - - G_AddUserQuote("Vote Cast"); - g_player[myconnectindex].gotvote = 1; + Net_SendMapVote(KB_UnBoundKeyPressed(sc_F1) || ud.autovote ? ud.autovote-1 : 0); KB_ClearKeyDown(sc_F1); KB_ClearKeyDown(sc_F2); - voting = -1; } } @@ -10875,19 +10863,20 @@ int32_t G_DoMoveThings(void) // Net_CorrectPrediction(); if (g_netServer) - Net_UpdateClients(); + Net_SendServerUpdates(); if ((everyothertime&1) == 0) { G_AnimateWalls(); A_MoveCyclers(); - if (g_netServer) - Net_StreamLevel(); +// Map updates are disabled for now +// if (g_netServer && (everyothertime % 10) == 0) +// Net_SendMapUpdate(); } if (g_netClient) //Slave - Net_ClientMove(); + Net_SendClientUpdate(); return 0; } diff --git a/polymer/eduke32/source/gameexec.c b/polymer/eduke32/source/gameexec.c index a352ab502..f46c542c2 100644 --- a/polymer/eduke32/source/gameexec.c +++ b/polymer/eduke32/source/gameexec.c @@ -1969,9 +1969,9 @@ nullquote: ud.m_volume_number = ud.volume_number = volnume; ud.m_level_number = ud.level_number = levnume; - if (numplayers > 1 && g_netServer) - Net_NewGame(volnume,levnume); - else + //if (numplayers > 1 && g_netServer) + // Net_NewGame(volnume,levnume); + //else { g_player[myconnectindex].ps->gm |= MODE_EOL; ud.display_bonus_screen = 0; diff --git a/polymer/eduke32/source/menus.c b/polymer/eduke32/source/menus.c index 2887e3ff8..e3c684ddf 100644 --- a/polymer/eduke32/source/menus.c +++ b/polymer/eduke32/source/menus.c @@ -804,22 +804,6 @@ void M_DisplayMenus(void) Net_GetPackets(); - if (g_netSync) - { - P_SetGamePalette(g_player[myconnectindex].ps, TITLEPAL, 8+2+1); - rotatesprite_fs(0,0,65536L,0,BETASCREEN,0,0,2+8+16+64); - - rotatesprite_fs(160<<16,(104)<<16,60<<10,0,DUKENUKEM,0,0,2+8); - rotatesprite_fs(160<<16,(129)<<16,30<<11,0,THREEDEE,0,0,2+8); - if (PLUTOPAK) // JBF 20030804 - rotatesprite_fs(160<<16,(151)<<16,30<<11,0,PLUTOPAKSPRITE+1,0,0,2+8); - - gametext(160,190,"Transferring gamestate",14,2); - nextpage(); - - return; - } - { if (buttonstat != 0 && !onbar) { @@ -5227,100 +5211,23 @@ VOLUME_ALL_40x: case 603: { - int32_t plrvotes = 0, j = 0; - x = M_Probe(186,124,0,0); if (voting != myconnectindex) + { g_player[myconnectindex].ps->gm &= ~MODE_MENU; - - if (x == -1) - { - if (voting == myconnectindex) - { - for (i=0; ii || (plrvotes > (numplayers>>1)) || (g_netServer)) - { - if (plrvotes > (numplayers>>1) || !g_player[myconnectindex].ps->i || (g_netServer)) - { - if (ud.m_player_skill == 3) ud.m_respawn_monsters = 1; - else ud.m_respawn_monsters = 0; - - if ((GametypeFlags[ud.m_coop] & GAMETYPE_ITEMRESPAWN)) ud.m_respawn_items = 1; - else ud.m_respawn_items = 0; - - ud.m_respawn_inventory = 1; - - for (TRAVERSE_CONNECT(margin)) - { - P_ResetWeapons(margin); - P_ResetInventory(margin); - - } - - Net_NewGame(ud.m_volume_number,ud.m_level_number); - - if (voting == myconnectindex && !(g_netServer)) - G_AddUserQuote("Vote Succeeded"); - - G_NewGame(ud.m_volume_number,ud.m_level_number,ud.m_player_skill+1); - if (G_EnterLevel(MODE_GAME)) G_BackToMenu(); - - return; - } - else if (j == numplayers) - { - for (i=0; igm &= ~MODE_MENU; - } - } - else - { + } + else + { mgametext(160,90,"Waiting for votes",0,2); - } - break; + } + + break; } case 600: margin = (320>>1) - 120; @@ -5436,35 +5343,14 @@ VOLUME_ALL_40x: // master does whatever it wants if (g_netServer) { - M_ChangeMenu(603); + Net_FillNewGame(&pendingnewgame, 1); + Net_StartNewGame(); + Net_SendNewGame(1, NULL); break; } if (voting == -1) { - if (g_player[myconnectindex].ps->i) - { - for (i=0; iactor[0],&actor[0],sizeof(netactor_t)*MAXSPRITES); for (i=MAXSPRITES-1; i>=0; i--) - for (j=0;j<10;j++) + for (j=0; j<10; j++) save->actor[i].t_data[j] = actor[i].t_data[j]; @@ -128,16 +128,16 @@ void Net_SaveMapState(netmapstate_t *save) Bmemcpy(&save->g_mirrorWall[0],&g_mirrorWall[0],sizeof(g_mirrorWall)); Bmemcpy(&save->g_mirrorSector[0],&g_mirrorSector[0],sizeof(g_mirrorSector)); Bmemcpy(&save->g_mirrorCount,&g_mirrorCount,sizeof(g_mirrorCount)); -/* Bmemcpy(&save->animategoal[0],&animategoal[0],sizeof(animategoal)); - Bmemcpy(&save->animatevel[0],&animatevel[0],sizeof(animatevel)); - Bmemcpy(&save->g_animateCount,&g_animateCount,sizeof(g_animateCount)); - Bmemcpy(&save->animatesect[0],&animatesect[0],sizeof(animatesect)); + /* Bmemcpy(&save->animategoal[0],&animategoal[0],sizeof(animategoal)); + Bmemcpy(&save->animatevel[0],&animatevel[0],sizeof(animatevel)); + Bmemcpy(&save->g_animateCount,&g_animateCount,sizeof(g_animateCount)); + Bmemcpy(&save->animatesect[0],&animatesect[0],sizeof(animatesect)); - G_Util_PtrToIdx(animateptr, g_animateCount, sector, P2I_FWD); - Bmemcpy(&save->animateptr[0],&animateptr[0],sizeof(animateptr)); - G_Util_PtrToIdx(animateptr, g_animateCount, sector, P2I_BACK); -*/ + G_Util_PtrToIdx(animateptr, g_animateCount, sector, P2I_FWD); + Bmemcpy(&save->animateptr[0],&animateptr[0],sizeof(animateptr)); + G_Util_PtrToIdx(animateptr, g_animateCount, sector, P2I_BACK); + */ Bmemcpy(&save->g_numPlayerSprites,&g_numPlayerSprites,sizeof(g_numPlayerSprites)); Bmemcpy(&save->g_earthquakeTime,&g_earthquakeTime,sizeof(g_earthquakeTime)); @@ -145,25 +145,25 @@ void Net_SaveMapState(netmapstate_t *save) Bmemcpy(&save->randomseed,&randomseed,sizeof(randomseed)); Bmemcpy(&save->g_globalRandom,&g_globalRandom,sizeof(g_globalRandom)); -/* - for (i=g_gameVarCount-1; i>=0; i--) - { - if (aGameVars[i].dwFlags & GAMEVAR_NORESET) continue; - if (aGameVars[i].dwFlags & GAMEVAR_PERPLAYER) - { - if (!save->vars[i]) - save->vars[i] = Bcalloc(MAXPLAYERS,sizeof(intptr_t)); - Bmemcpy(&save->vars[i][0],&aGameVars[i].val.plValues[0],sizeof(intptr_t) * MAXPLAYERS); - } - else if (aGameVars[i].dwFlags & GAMEVAR_PERACTOR) - { - if (!save->vars[i]) - save->vars[i] = Bcalloc(MAXSPRITES,sizeof(intptr_t)); - Bmemcpy(&save->vars[i][0],&aGameVars[i].val.plValues[0],sizeof(intptr_t) * MAXSPRITES); - } - else save->vars[i] = (intptr_t *)aGameVars[i].val.lValue; - } -*/ + /* + for (i=g_gameVarCount-1; i>=0; i--) + { + if (aGameVars[i].dwFlags & GAMEVAR_NORESET) continue; + if (aGameVars[i].dwFlags & GAMEVAR_PERPLAYER) + { + if (!save->vars[i]) + save->vars[i] = Bcalloc(MAXPLAYERS,sizeof(intptr_t)); + Bmemcpy(&save->vars[i][0],&aGameVars[i].val.plValues[0],sizeof(intptr_t) * MAXPLAYERS); + } + else if (aGameVars[i].dwFlags & GAMEVAR_PERACTOR) + { + if (!save->vars[i]) + save->vars[i] = Bcalloc(MAXSPRITES,sizeof(intptr_t)); + Bmemcpy(&save->vars[i][0],&aGameVars[i].val.plValues[0],sizeof(intptr_t) * MAXSPRITES); + } + else save->vars[i] = (intptr_t *)aGameVars[i].val.lValue; + } + */ // ototalclock = totalclock; @@ -175,76 +175,79 @@ extern void Gv_RefreshPointers(void); void Net_RestoreMapState(netmapstate_t *save) { - if (save != NULL) + int32_t i; + // int32_t x; // used in commented code below + intptr_t j; + char phealth[MAXPLAYERS]; + + if (save == NULL) { - int32_t i; - // int32_t x; // used in commented code below - intptr_t j; - char phealth[MAXPLAYERS]; + return; + } - initprintf("restoring revision %d\n", save->revision); - Bassert(save->crc == crc32once((uint8_t *)save, offsetof(netmapstate_t, crc))); + initprintf("restoring revision %d\n", save->revision); + Bassert(save->crc == crc32once((uint8_t *)save, offsetof(netmapstate_t, crc))); - for (i=0; ii].extra; + for (i=0; ii].extra; - pub = NUMPAGES; - pus = NUMPAGES; - G_UpdateScreenArea(); + pub = NUMPAGES; + pus = NUMPAGES; + G_UpdateScreenArea(); - Bmemcpy(&numwalls,&save->numwalls,sizeof(numwalls)); - Bmemcpy(&wall[0],&save->wall[0],sizeof(walltype)*MAXWALLS); - Bmemcpy(&numsectors,&save->numsectors,sizeof(numsectors)); - Bmemcpy(§or[0],&save->sector[0],sizeof(sectortype)*MAXSECTORS); - Bmemcpy(&sprite[0],&save->sprite[0],sizeof(spritetype)*MAXSPRITES); - Bmemcpy(&spriteext[0],&save->spriteext[0],sizeof(spriteext_t)*MAXSPRITES); + Bmemcpy(&numwalls,&save->numwalls,sizeof(numwalls)); + Bmemcpy(&wall[0],&save->wall[0],sizeof(walltype)*MAXWALLS); + Bmemcpy(&numsectors,&save->numsectors,sizeof(numsectors)); + Bmemcpy(§or[0],&save->sector[0],sizeof(sectortype)*MAXSECTORS); - Bmemcpy(&headspritesect[0],&save->headspritesect[0],sizeof(headspritesect)); - Bmemcpy(&prevspritesect[0],&save->prevspritesect[0],sizeof(prevspritesect)); - Bmemcpy(&nextspritesect[0],&save->nextspritesect[0],sizeof(nextspritesect)); - Bmemcpy(&headspritestat[0],&save->headspritestat[0],sizeof(headspritestat)); - Bmemcpy(&prevspritestat[0],&save->prevspritestat[0],sizeof(prevspritestat)); - Bmemcpy(&nextspritestat[0],&save->nextspritestat[0],sizeof(nextspritestat)); + Bmemcpy(&sprite[0],&save->sprite[0],sizeof(spritetype)*MAXSPRITES); + Bmemcpy(&spriteext[0],&save->spriteext[0],sizeof(spriteext_t)*MAXSPRITES); - Bmemcpy(&actor[0],&save->actor[0],sizeof(netactor_t)*MAXSPRITES); + Bmemcpy(&headspritesect[0],&save->headspritesect[0],sizeof(headspritesect)); + Bmemcpy(&prevspritesect[0],&save->prevspritesect[0],sizeof(prevspritesect)); + Bmemcpy(&nextspritesect[0],&save->nextspritesect[0],sizeof(nextspritesect)); + Bmemcpy(&headspritestat[0],&save->headspritestat[0],sizeof(headspritestat)); + Bmemcpy(&prevspritestat[0],&save->prevspritestat[0],sizeof(prevspritestat)); + Bmemcpy(&nextspritestat[0],&save->nextspritestat[0],sizeof(nextspritestat)); + + Bmemcpy(&actor[0],&save->actor[0],sizeof(netactor_t)*MAXSPRITES); - for (i=MAXSPRITES-1; i>=0; i--) - for (j=0;j<10;j++) - actor[i].t_data[j] = save->actor[i].t_data[j]; + for (i=MAXSPRITES-1; i>=0; i--) + for (j=0; j<10; j++) + actor[i].t_data[j] = save->actor[i].t_data[j]; + Bmemcpy(&g_numCyclers,&save->g_numCyclers,sizeof(g_numCyclers)); + Bmemcpy(&cyclers[0][0],&save->cyclers[0][0],sizeof(cyclers)); + Bmemcpy(&g_playerSpawnPoints[0],&save->g_playerSpawnPoints[0],sizeof(g_playerSpawnPoints)); + Bmemcpy(&g_numAnimWalls,&save->g_numAnimWalls,sizeof(g_numAnimWalls)); + Bmemcpy(&SpriteDeletionQueue[0],&save->SpriteDeletionQueue[0],sizeof(SpriteDeletionQueue)); + Bmemcpy(&g_spriteDeleteQueuePos,&save->g_spriteDeleteQueuePos,sizeof(g_spriteDeleteQueuePos)); + Bmemcpy(&animwall[0],&save->animwall[0],sizeof(animwall)); + Bmemcpy(&msx[0],&save->msx[0],sizeof(msx)); + Bmemcpy(&msy[0],&save->msy[0],sizeof(msy)); + Bmemcpy(&g_mirrorWall[0],&save->g_mirrorWall[0],sizeof(g_mirrorWall)); + Bmemcpy(&g_mirrorSector[0],&save->g_mirrorSector[0],sizeof(g_mirrorSector)); + Bmemcpy(&g_mirrorCount,&save->g_mirrorCount,sizeof(g_mirrorCount)); + /* - Bmemcpy(&g_numCyclers,&save->g_numCyclers,sizeof(g_numCyclers)); - Bmemcpy(&cyclers[0][0],&save->cyclers[0][0],sizeof(cyclers)); - Bmemcpy(&g_playerSpawnPoints[0],&save->g_playerSpawnPoints[0],sizeof(g_playerSpawnPoints)); - Bmemcpy(&g_numAnimWalls,&save->g_numAnimWalls,sizeof(g_numAnimWalls)); - Bmemcpy(&SpriteDeletionQueue[0],&save->SpriteDeletionQueue[0],sizeof(SpriteDeletionQueue)); - Bmemcpy(&g_spriteDeleteQueuePos,&save->g_spriteDeleteQueuePos,sizeof(g_spriteDeleteQueuePos)); - Bmemcpy(&animwall[0],&save->animwall[0],sizeof(animwall)); - Bmemcpy(&msx[0],&save->msx[0],sizeof(msx)); - Bmemcpy(&msy[0],&save->msy[0],sizeof(msy)); - Bmemcpy(&g_mirrorWall[0],&save->g_mirrorWall[0],sizeof(g_mirrorWall)); - Bmemcpy(&g_mirrorSector[0],&save->g_mirrorSector[0],sizeof(g_mirrorSector)); - Bmemcpy(&g_mirrorCount,&save->g_mirrorCount,sizeof(g_mirrorCount)); - /* + Bmemcpy(&animategoal[0],&save->animategoal[0],sizeof(animategoal)); + Bmemcpy(&animatevel[0],&save->animatevel[0],sizeof(animatevel)); + Bmemcpy(&g_animateCount,&save->g_animateCount,sizeof(g_animateCount)); + Bmemcpy(&animatesect[0],&save->animatesect[0],sizeof(animatesect)); - Bmemcpy(&animategoal[0],&save->animategoal[0],sizeof(animategoal)); - Bmemcpy(&animatevel[0],&save->animatevel[0],sizeof(animatevel)); - Bmemcpy(&g_animateCount,&save->g_animateCount,sizeof(g_animateCount)); - Bmemcpy(&animatesect[0],&save->animatesect[0],sizeof(animatesect)); + Bmemcpy(&animateptr[0],&save->animateptr[0],sizeof(animateptr)); + G_Util_PtrToIdx(animateptr, g_animateCount, sector, P2I_BACK); + */ - Bmemcpy(&animateptr[0],&save->animateptr[0],sizeof(animateptr)); - G_Util_PtrToIdx(animateptr, g_animateCount, sector, P2I_BACK); -*/ - - Bmemcpy(&g_numPlayerSprites,&save->g_numPlayerSprites,sizeof(g_numPlayerSprites)); - Bmemcpy(&g_earthquakeTime,&save->g_earthquakeTime,sizeof(g_earthquakeTime)); + Bmemcpy(&g_numPlayerSprites,&save->g_numPlayerSprites,sizeof(g_numPlayerSprites)); + Bmemcpy(&g_earthquakeTime,&save->g_earthquakeTime,sizeof(g_earthquakeTime)); // Bmemcpy(&lockclock,&save->lockclock,sizeof(lockclock)); - Bmemcpy(&randomseed,&save->randomseed,sizeof(randomseed)); - Bmemcpy(&g_globalRandom,&save->g_globalRandom,sizeof(g_globalRandom)); + Bmemcpy(&randomseed,&save->randomseed,sizeof(randomseed)); + Bmemcpy(&g_globalRandom,&save->g_globalRandom,sizeof(g_globalRandom)); -/* + /* for (i=g_gameVarCount-1; i>=0; i--) { if (aGameVars[i].dwFlags & GAMEVAR_NORESET) continue; @@ -260,23 +263,23 @@ void Net_RestoreMapState(netmapstate_t *save) } else aGameVars[i].val.lValue = (intptr_t)save->vars[i]; } -*/ + */ - Gv_RefreshPointers(); + Gv_RefreshPointers(); - for (i=0; ii].extra = phealth[i]; + for (i=0; ii].extra = phealth[i]; - if (g_player[myconnectindex].ps->over_shoulder_on != 0) - { - g_cameraDistance = 0; - g_cameraClock = 0; - g_player[myconnectindex].ps->over_shoulder_on = 1; - } + if (g_player[myconnectindex].ps->over_shoulder_on != 0) + { + g_cameraDistance = 0; + g_cameraClock = 0; + g_player[myconnectindex].ps->over_shoulder_on = 1; + } - screenpeek = myconnectindex; + screenpeek = myconnectindex; -/* + /* if (ud.lockout == 0) { for (x=g_numAnimWalls-1; x>=0; x--) @@ -297,18 +300,185 @@ void Net_RestoreMapState(netmapstate_t *save) break; } } -*/ + */ - G_ResetInterpolations(); + G_ResetInterpolations(); // Net_ResetPrediction(); // G_ClearFIFO(); // G_ResetTimers(); - initprintf("Net_RestoreMapState(): restored revision %u\n",save->revision); + initprintf("Net_RestoreMapState(): restored revision %u\n",save->revision); +} + +static void P_RemovePlayer(int32_t p) +{ + // 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 (p == 0) return; + + g_player[p].playerquitflag = 0; + + Bsprintf(buf,"%s^00 is history!",g_player[p].user_name); + G_AddUserQuote(buf); + + if (numplayers == 1) + S_PlaySound(GENERIC_AMBIENCE17); + + if (g_player[myconnectindex].ps->gm & MODE_GAME) + { + if (screenpeek == p) + screenpeek = myconnectindex; + + pub = NUMPAGES; + pus = NUMPAGES; + G_UpdateScreenArea(); + + P_QuickKill(g_player[p].ps); + + if (voting == p) + { + for (p=0; pftq = 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 + for (TRAVERSE_CONNECT(i)) + { + if (g_player[i].playerquitflag == 0) + { + break; + } + } + + if (i == -1) + { + i = playerswhenstarted++; + } + + event->peer->data = (void *)(intptr_t)i; + + g_player[i].netsynctime = totalclock; + g_player[i].playerquitflag = 1; + g_player[i].revision = g_netMapRevision; + + for (j=0; jpeer); + Net_SendClientInfo(); + Net_SendUserMapName(); + Net_SendClientSync(event, i); +} + +static void display_betascreen(void) +{ + rotatesprite_fs(0,0,65536,0,BETASCREEN,0,0,2+8+16+64); + + rotatesprite_fs(160<<16,(104)<<16,60<<10,0,DUKENUKEM,0,0,2+8); + rotatesprite_fs(160<<16,(129)<<16,30<<11,0,THREEDEE,0,0,2+8); + if (PLUTOPAK) // JBF 20030804 + rotatesprite_fs(160<<16,(151)<<16,30<<11,0,PLUTOPAKSPRITE+1,0,0,2+8); +} + +void faketimerhandler(void) +{ + if (g_netServer==NULL && g_netClient==NULL) + return; + + enet_host_service(g_netServer ? g_netServer : g_netClient, NULL, 0); +} + +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, 8+2+1); + + do + { + if (quitevent || keystatus[1]) G_GameExit(""); + + display_betascreen(); + + 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)); + + G_HandleAsync(); + + if (g_player[0].pingcnt > server_ready) + { + P_SetGamePalette(g_player[myconnectindex].ps, BASEPAL, 8+2+1); + 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; +} + +//////////////////////////////////////////////////////////////////////////////// +// Connect/Disconnect void Net_Connect(const char *srvaddr) { @@ -426,920 +596,35 @@ void Net_Disconnect(void) } enet_host_destroy(g_netServer); g_netServer = NULL; - Bfree(streamoutput); } } -static void Net_SendVersion(ENetPeer *client) +void Net_ReceiveDisconnect(ENetEvent *event) { - if (!g_netServer) return; + g_netDisconnect = 1; + numplayers = playerswhenstarted = ud.multimode = 1; + myconnectindex = screenpeek = 0; + G_BackToMenu(); - buf[0] = PACKET_VERSION; - buf[1] = BYTEVERSION; - // XXX: s_buildDate is outdated and useless; uint8 is not enough :/ - 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++) + switch (event->data) { - 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) + case DISC_BAD_PASSWORD: + initprintf("Bad password.\n"); return; - - packbuf[0] = PACKET_USER_MAP; - - Bcorrectfilename(boardfilename,0); - - // user map name is sent with a NUL at the end - j = Bstrlen(boardfilename)+1; - Bmemcpy(&packbuf[1], boardfilename, j); - j++; - - 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 p) -{ - // 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 (p == 0) return; - - g_player[p].playerquitflag = 0; - - Bsprintf(buf,"%s^00 is history!",g_player[p].user_name); - G_AddUserQuote(buf); - - if (numplayers == 1) - S_PlaySound(GENERIC_AMBIENCE17); - - if (g_player[myconnectindex].ps->gm & MODE_GAME) - { - if (screenpeek == p) - screenpeek = myconnectindex; - - pub = NUMPAGES; - pus = NUMPAGES; - G_UpdateScreenArea(); - - P_QuickKill(g_player[p].ps); - - if (voting == p) - { - for (p=0; pftq = 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 - for (TRAVERSE_CONNECT(i)) - if (g_player[i].playerquitflag == 0) - break; - if (i == -1) - i = playerswhenstarted++; - event->peer->data = (void *)(intptr_t)i; - - g_player[i].netsynctime = totalclock; - g_player[i].playerquitflag = 1; - g_player[i].revision = g_netMapRevision; - - 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) - { - alloc_multimapstate(i); - - { - char *buf = (char *)Bmalloc(sizeof(netmapstate_t)+512); - - 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; - - Net_SaveMapState(g_multiMapState[i]); - if ((j = qlz_compress((char *)g_multiMapState[i], buf, sizeof(netmapstate_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(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(buf+csize-j, j, ENET_PACKET_FLAG_RELIABLE)); - enet_host_service(g_netServer, NULL, 0); - - initprintf("Compressed %u bytes to %u\n", (uint32_t)sizeof(netmapstate_t), (uint32_t)qlz_size_compressed(buf)); - } - else - initprintf("Error compressing map state for transfer!\n"); - - Bfree(buf); - } - } -} - -static int32_t NewGameCommon(uint8_t *pbuf) -{ - int32_t i; - - 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]; - - for (TRAVERSE_CONNECT(i)) - { - P_ResetWeapons(i); - P_ResetInventory(i); - g_player[i].revision = 0; - } - - G_NewGame(ud.volume_number,ud.level_number,ud.player_skill); - ud.coop = ud.m_coop; - - g_netMapRevision = 0; - - if (G_EnterLevel(MODE_GAME)) - { - G_BackToMenu(); - return 1; - } - - return 0; -} - -static void ParsePacketCommon(uint8_t *pbuf, int32_t packbufleng, int32_t serverpacketp) -{ - int32_t i, j; - int32_t other = pbuf[packbufleng]; - - switch (pbuf[0]) - { - 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_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]; - - if (serverpacketp) - 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_ParseServerPacket(ENetEvent *event) -{ - uint8_t *pbuf = event->packet->data; - int32_t packbufleng = event->packet->dataLength; - int32_t i, j, l; - input_t *nsyn; - - --packbufleng; // int32_t other = pbuf[--packbufleng]; - -#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+512); - 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++]; - - for (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; - - { - int32_t oa; - - j++; - oa = T5; - - T5 = *(int32_t *)&pbuf[j]; - j += sizeof(int32_t); - - if (oa != T5) T3 = T4 = 0; - } - - do - { - uint16_t var_id = *(uint16_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 - { - uint16_t var_id = *(uint16_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); - } - - Bfree(pbuf); - - break; - - case PACKET_MAP_STREAM: - if (!(g_player[myconnectindex].ps->gm & MODE_GAME) || g_netSync) - return; - - if (*(uint32_t *)&pbuf[1] != g_multiMapState[0]->revision) - { - initprintf("base revision mismatch, expected %d and found %d\n", g_player[myconnectindex].revision, *(uint32_t *)&pbuf[1]); - return; - } - - if (!streamoutput) - streamoutput = (netmapstate_t *)Bcalloc(1, sizeof(netmapstate_t)); - - { - usize_t osize = 0; - int ret; - - packbufleng = qlz_size_decompressed((char *)&pbuf[5]); - pbuf = (uint8_t *)Bmalloc(packbufleng<<1); - packbufleng = qlz_decompress((char *)&event->packet->data[5], (char *)(pbuf), state_decompress); - - initprintf("packbufleng: %d\n", packbufleng); - - ret = xd3_decode_memory((const uint8_t *)pbuf, packbufleng, - (const uint8_t *)g_multiMapState[0], sizeof(netmapstate_t), - (uint8_t *)streamoutput, &osize, sizeof(netmapstate_t), XD3_COMPLEVEL_1|XD3_NOCOMPRESS); - - if (ret) - { - initprintf("xdelta3 returned %d\n", ret); - Bfree(pbuf); - break; - } - - if (sizeof(netmapstate_t) != osize) - initprintf("decompressed data size mismatch!\n"); - else - { - Net_RestoreMapState(streamoutput); - g_player[myconnectindex].revision = streamoutput->revision; - Bmemcpy(g_multiMapState[0], streamoutput, sizeof(netmapstate_t)); - } - - Bfree(pbuf); - } - - break; - - case PACKET_NEW_GAME: - if (NewGameCommon(pbuf)) - break; - - if (g_netSync) - { - Net_RestoreMapState(g_multiMapState[0]); - - 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; - - g_player[myconnectindex].ps->gm = MODE_GAME; - ready2send = 1; - } - 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++; + 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; - - 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; - default: - ParsePacketCommon(pbuf, packbufleng, 1); - break; - } -} - -void Net_ParseClientPacket(ENetEvent *event) -{ - uint8_t *pbuf = event->packet->data; - int32_t packbufleng = event->packet->dataLength; - int16_t 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) - { - const int32_t playeridx = (int32_t)(intptr_t)event->peer->data; - uint32_t rev; - - j = 0; - - packbufleng = qlz_size_decompressed((char *)&pbuf[1]); - pbuf = (uint8_t *)Bcalloc(1, packbufleng+512); - packbufleng = qlz_decompress((const char *)&event->packet->data[1], (char *)(pbuf), state_decompress); - - nsyn = (input_t *)&inputfifo[0][0]; - - alloc_multimapstate(playeridx); - - rev = *(uint32_t *)&pbuf[j]; - - if (g_player[playeridx].revision != rev) - { - g_player[playeridx].ready = 1; - g_player[playeridx].revision = rev; - if (rev != g_pendingMapState[playeridx]->revision) - initprintf("wtf? expected confirmation of revision %d from player %d, got revision %d\n", - g_pendingMapState[playeridx]->revision, playeridx, rev); - else - { - Bmemcpy(g_multiMapState[playeridx], g_pendingMapState[playeridx], sizeof(netmapstate_t)); - initprintf("player %d now at base revision %d\n", playeridx, g_player[playeridx].revision); - } - } - - j += sizeof(uint32_t); - - // XXX: g_multiMapRevisions[...] is NULL when started like - // (peer 1)$ eduke32 -server - // (peer 2)$ eduke32 -connect localhost - // (peer 1 starts some map) -// Bmemcpy(g_multiMapState[playeridx], g_multiMapRevisions[g_player[other].revision&(NET_REVISIONS-1)], sizeof(netmapstate_t)); - - 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); - - g_player[other].ready = 1; - - 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)); - - 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++; + initprintf("Disconnected.\n"); return; - - case PACKET_NEW_GAME: - NewGameCommon(pbuf); - return; - - 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_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; - - default: - ParsePacketCommon(pbuf, packbufleng, 0); - break; } } -static void display_betascreen(void) -{ - rotatesprite_fs(0,0,65536,0,BETASCREEN,0,0,2+8+16+64); - - rotatesprite_fs(160<<16,(104)<<16,60<<10,0,DUKENUKEM,0,0,2+8); - rotatesprite_fs(160<<16,(129)<<16,30<<11,0,THREEDEE,0,0,2+8); - if (PLUTOPAK) // JBF 20030804 - rotatesprite_fs(160<<16,(151)<<16,30<<11,0,PLUTOPAKSPRITE+1,0,0,2+8); -} +//////////////////////////////////////////////////////////////////////////////// +// Packet Handlers void Net_GetPackets(void) { @@ -1362,335 +647,928 @@ void Net_GetPackets(void) 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) - { - const intptr_t playeridx = (intptr_t)event.peer->data; - - 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) - { - const ENetPacket *pak = event.packet; - - event.peer->state = ENET_PEER_STATE_DISCONNECTED; - enet_host_broadcast(g_netServer, event.channelID, - enet_packet_create(pak->data, pak->dataLength, pak->flags&ENET_PACKET_FLAG_RELIABLE)); - event.peer->state = ENET_PEER_STATE_CONNECTED; - } - - enet_packet_destroy(event.packet); - g_player[playeridx].ping = (event.peer->lastRoundTripTime + event.peer->roundTripTime)/2; - break; - - case ENET_EVENT_TYPE_DISCONNECT: - numplayers--; - ud.multimode--; - - P_RemovePlayer(playeridx); - - packbuf[0] = PACKET_PLAYER_DISCONNECTED; - packbuf[1] = playeridx; - 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[playeridx].user_name); - event.peer->data = NULL; - break; - - default: - break; - } - } + Net_HandleClientPackets(); } else if (g_netClient) { - ENetEvent event; - size_t datasiz = 0; + Net_HandleServerPackets(); + } +} - do +void Net_HandleClientPackets(void) +{ + 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) + { + const intptr_t playeridx = (intptr_t)event.peer->data; + + switch (event.type) { - enet_host_service(g_netClient, NULL, 0); + case ENET_EVENT_TYPE_CONNECT: + { + char ipaddr[32]; - while (enet_host_check_events(g_netClient, &event) > 0) + 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) { - switch (event.type) - { - case ENET_EVENT_TYPE_RECEIVE: + const ENetPacket *pak = event.packet; - /* - initprintf("A packet of length %u was received from player %d on channel %u.\n", - event.packet -> dataLength, - event.peer -> data, - event.channelID); - */ + event.peer->state = ENET_PEER_STATE_DISCONNECTED; + enet_host_broadcast(g_netServer, event.channelID, + enet_packet_create(pak->data, pak->dataLength, pak->flags&ENET_PACKET_FLAG_RELIABLE)); + event.peer->state = ENET_PEER_STATE_CONNECTED; + } - // mapstate transfer from the server... all packets but the last are SYNCPACKETSIZE - if (event.channelID == CHAN_SYNC) - { - static uint8_t *buf = NULL; + enet_packet_destroy(event.packet); + g_player[playeridx].ping = (event.peer->lastRoundTripTime + event.peer->roundTripTime)/2; + break; - if (buf == NULL) - { - g_netSync = 1; - buf = (uint8_t *)Bcalloc(1, sizeof(netmapstate_t)+512); - if (buf == NULL) // TODO: G_GameExit should send a "bye" packet? - G_GameExit("OUT OF MEMORY in Net_GetPackets:sync"); - } + case ENET_EVENT_TYPE_DISCONNECT: + numplayers--; + ud.multimode--; - alloc_multimapstate(0); + P_RemovePlayer(playeridx); - display_betascreen(); + packbuf[0] = PACKET_PLAYER_DISCONNECTED; + packbuf[1] = playeridx; + packbuf[2] = numplayers; + packbuf[3] = ud.multimode; + packbuf[4] = playerswhenstarted; + packbuf[5] = myconnectindex; - Bassert(datasiz+event.packet->dataLength <= sizeof(netmapstate_t)+512); + enet_host_broadcast(g_netServer, CHAN_GAMESTATE, + enet_packet_create(packbuf, 6, ENET_PACKET_FLAG_RELIABLE)); - if (event.packet->dataLength == SYNCPACKETSIZE) - { - char tbuf[64]; + initprintf("%s disconnected.\n", g_player[playeridx].user_name); + event.peer->data = NULL; + break; - Bmemcpy(buf+datasiz, event.packet->data, SYNCPACKETSIZE); - datasiz += SYNCPACKETSIZE; + default: + break; + } + } +} - Bsprintf(tbuf, "Received %d bytes\n", (int32_t)datasiz); - gametext(160,190,tbuf,14,2); - } - else - { - // last packet of mapstate sequence +void Net_HandleServerPackets(void) +{ + ENetEvent event; - Bmemcpy(buf+datasiz, event.packet->data, event.packet->dataLength); - datasiz = 0; + enet_host_service(g_netClient, NULL, 0); - if (qlz_size_decompressed((const char *)buf) == sizeof(netmapstate_t)) - { - qlz_decompress((const char *)buf, g_multiMapState[0], state_decompress); - - 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! Decompressed to %u bytes, expected %u.\n", - (uint32_t)qlz_size_decompressed((char *)buf), (uint32_t)sizeof(netmapstate_t)); - - g_netDisconnect = 1; - g_netSync = 0; - - gametext(160,190,"Transfer Error",14,2); - } - - Bfree(buf); - buf = NULL; - } - - 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 (enet_host_check_events(g_netClient, &event) > 0) + { + if (event.type == ENET_EVENT_TYPE_DISCONNECT) + { + Net_ReceiveDisconnect(&event); + } + else if (event.type == ENET_EVENT_TYPE_RECEIVE) + { + if (event.channelID == CHAN_SYNC) + { + Net_ReceiveClientSync(&event); + } + else + { + Net_ParseServerPacket(&event); } } - while (datasiz); + + enet_packet_destroy(event.packet); } } -void Net_ClientMove(void) +void Net_ParseClientPacket(ENetEvent *event) { - int32_t siz = 1; - input_t *nsyn = (input_t *)&inputfifo[0][myconnectindex]; - - packbuf[0] = PACKET_SLAVE_TO_MASTER; - - *(uint32_t *)&packbuf[siz] = g_player[myconnectindex].revision; - siz += sizeof(uint32_t); - - Bmemcpy(&packbuf[siz], &nsyn[0], offsetof(input_t, filler)); - siz += offsetof(input_t, filler); - - Bmemcpy(&packbuf[siz], &g_player[myconnectindex].ps->pos.x, sizeof(vec3_t) * 2); - siz += sizeof(vec3_t) * 2; - - Bmemcpy(&packbuf[siz], &g_player[myconnectindex].ps->vel.x, sizeof(vec3_t)); - siz += sizeof(vec3_t); - - *(int16_t *)&packbuf[siz] = g_player[myconnectindex].ps->ang; - siz += sizeof(int16_t); - - Bmemcpy(&packbuf[siz], &g_player[myconnectindex].ps->horiz, sizeof(int16_t) * 2); - siz += sizeof(int16_t) * 2; + uint8_t *pbuf = event->packet->data; + int32_t packbufleng = event->packet->dataLength; + int16_t j; + int32_t other = pbuf[--packbufleng]; +#if 0 + initprintf("Received Packet: type: %d : len %d\n", pbuf[0], packbufleng); +#endif + switch (pbuf[0]) { - char buf[1024]; + case PACKET_SLAVE_TO_MASTER: //[1] (receive slave sync buffer) + Net_ReceiveClientUpdate(event); + break; - Bassert((signed)sizeof(buf) >= siz+400); - siz = qlz_compress(packbuf+1, buf, siz, state_compress); - Bmemcpy(packbuf+1, buf, siz); - siz++; + case PACKET_PLAYER_READY: + + if (other == 0) + { + break; + } + + 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)); + 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++; + break; + + case PACKET_AUTH: + Net_RecieveChallenge(pbuf, packbufleng, event); + break; + + case PACKET_REQUEST_GAMESTATE: + + if (g_netServer && g_player[0].ps->gm & MODE_GAME) + { + Net_SendNewGame(0, event->peer); + } + + break; + + default: + Net_ParsePacketCommon(pbuf, packbufleng, 0); + break; } - - packbuf[siz++] = myconnectindex; - - enet_peer_send(g_netClientPeer, CHAN_MOVE, enet_packet_create(packbuf, siz, 0)); - } -char g_netCompressBuf[PACKBUF_SIZE+400]; - -void Net_UpdateClients(void) +void Net_ParseServerPacket(ENetEvent *event) { - input_t *osyn = (input_t *)&inputfifo[1][0]; - input_t *nsyn = (input_t *)&inputfifo[0][0]; - int16_t i, l; - int32_t siz = 1; + uint8_t *pbuf = event->packet->data; + int32_t packbufleng = event->packet->dataLength; + int32_t i, j, l; + input_t *nsyn; - if (!g_netServer || numplayers < 2) + --packbufleng; // int32_t other = pbuf[--packbufleng]; + +#if 0 + initprintf("Received Packet: type: %d : len %d\n", pbuf[0], packbufleng); +#endif + switch (pbuf[0]) + { + case PACKET_MASTER_TO_SLAVE: + + if (!(g_player[myconnectindex].ps->gm & MODE_GAME)) + { + return; + } + + Net_ReceiveServerUpdate(event); + break; + + case PACKET_MAP_STREAM: + + if (!(g_player[myconnectindex].ps->gm & MODE_GAME)) + return; + + if (*(uint32_t *)&pbuf[1] != g_multiMapState[0]->revision) + { + initprintf("base revision mismatch, expected %d and found %d\n", g_player[myconnectindex].revision, *(uint32_t *)&pbuf[1]); + return; + } + + Net_ReceiveMapUpdate(pbuf, packbufleng); + + break; + + case PACKET_NEW_GAME: + Net_ReceiveNewGame(event); + break; + + case PACKET_VERSION: + Net_RecieveVersion(pbuf, packbufleng); + break; + + case PACKET_NUM_PLAYERS: + Net_RecieveNewPlayer(event->packet->data, event->packet->dataLength); + break; + + case PACKET_PLAYER_INDEX: + Net_RecievePlayerIndex(event->packet->data, event->packet->dataLength); + break; + + case PACKET_PLAYER_DISCONNECTED: + if ((g_player[myconnectindex].ps->gm & MODE_GAME)) + 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)) 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)) 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; + + default: + Net_ParsePacketCommon(pbuf, packbufleng, 1); + break; + } +} + +void Net_ParsePacketCommon(uint8_t *pbuf, int32_t packbufleng, int32_t serverpacketp) +{ + int32_t i, j; + + switch (pbuf[0]) + { + case PACKET_MESSAGE: + Net_ReceiveMessage(pbuf, packbufleng); + break; + + case PACKET_CLIENT_INFO: + Net_ReceiveClientInfo(pbuf, packbufleng, serverpacketp); + 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: + Net_ReceiveUserMapName(pbuf, packbufleng); + break; + + case PACKET_MAP_VOTE: + Net_RecieveMapVote(pbuf); + break; + + case PACKET_MAP_VOTE_INITIATE: // call map vote + Net_RecieveMapVoteInitiate(pbuf); + break; + + case PACKET_MAP_VOTE_CANCEL: // cancel map vote + Net_RecieveMapVoteCancel(pbuf); + break; + } +} + +//////////////////////////////////////////////////////////////////////////////// +// Version Packets + +void Net_SendVersion(ENetPeer *client) +{ + if (!g_netServer) { - ticrandomseed = randomseed; - if (g_netServer) - Bmemcpy(&osyn[0], &nsyn[0], sizeof(input_t)); return; } - packbuf[0] = PACKET_MASTER_TO_SLAVE; + buf[0] = PACKET_VERSION; + buf[1] = BYTEVERSION; + // XXX: s_buildDate is outdated and useless; uint8 is not enough :/ + buf[2] = (uint8_t)atoi(s_buildDate); + buf[3] = myconnectindex; - *(int32_t *)&packbuf[siz] = ticrandomseed = randomseed; - siz += sizeof(int32_t); - packbuf[siz++] = ud.pause_on; + enet_peer_send(client, CHAN_GAMESTATE, enet_packet_create(&buf[0], 4, ENET_PACKET_FLAG_RELIABLE)); +} + +void Net_RecieveVersion(uint8_t *pbuf, int32_t packbufleng) +{ + 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(); +} + +//////////////////////////////////////////////////////////////////////////////// +// Challenge Packets + +// sends a simple crc32 of the current password, verified by the server before the connection can continue +void Net_SendChallenge(ENetPeer *client) +{ + 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)); +} + +void Net_RecieveChallenge(uint8_t *pbuf, int32_t packbufleng, ENetEvent *event) +{ + 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"); + } +} + +//////////////////////////////////////////////////////////////////////////////// +// Num Players Packets + +void Net_SendNewPlayer(int32_t newplayerindex) +{ + packbuf[0] = PACKET_NUM_PLAYERS; + packbuf[1] = numplayers; + packbuf[2] = playerswhenstarted; + packbuf[3] = ud.multimode; + packbuf[4] = newplayerindex; + packbuf[5] = g_networkMode; + packbuf[6] = myconnectindex; + enet_host_broadcast(g_netServer, CHAN_GAMESTATE, enet_packet_create(packbuf, 7, ENET_PACKET_FLAG_RELIABLE)); +} + +void Net_RecieveNewPlayer(uint8_t *pbuf, int32_t packbufleng) +{ + int32_t i; + + 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; iaim_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_ReceiveClientInfo(uint8_t *pbuf, int32_t packbufleng, int32_t fromserver) +{ + uint32_t i, j; + int32_t other = pbuf[packbufleng]; + + 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]; + } + + if (fromserver) + { + g_player[other].playerquitflag = 1; + } +} + +//////////////////////////////////////////////////////////////////////////////// +// Map Name Packets + +void Net_SendUserMapName(void) +{ + int32_t j; + + if (numplayers < 2) + return; + + packbuf[0] = PACKET_USER_MAP; + + Bcorrectfilename(boardfilename,0); + + // user map name is sent with a NUL at the end + j = Bstrlen(boardfilename)+1; + Bmemcpy(&packbuf[1], boardfilename, j); + j++; + + 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)); + } +} + +void Net_ReceiveUserMapName(uint8_t *pbuf, int32_t packbufleng) +{ + int32_t i; + + 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; +} + +//////////////////////////////////////////////////////////////////////////////// +// Client Sync Packets + +void Net_SendClientSync(ENetEvent *event, int32_t player) +{ + int32_t j; + int32_t i = player; + + if ((g_player[0].ps->gm & MODE_GAME) == 0) + { + return; + } + + alloc_multimapstate(i); + + 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; + + Net_SaveMapState(g_multiMapState[i]); + if ((j = qlz_compress((char *)g_multiMapState[i], tempnetbuf, sizeof(netmapstate_t), state_compress))) + { + enet_peer_send(event->peer, CHAN_SYNC, enet_packet_create(tempnetbuf, j, ENET_PACKET_FLAG_RELIABLE)); + enet_host_service(g_netServer, NULL, 0); + + initprintf("Compressed %u bytes to %u\n", (uint32_t)sizeof(netmapstate_t), (uint32_t)qlz_size_compressed(tempnetbuf)); + } + else + { + initprintf("Error compressing map state for transfer!\n"); + } +} + +void Net_ReceiveClientSync(ENetEvent *event) +{ + const char *pbuf = (const char *) event->packet->data; + if (qlz_size_decompressed(pbuf) == sizeof(netmapstate_t)) + { + alloc_multimapstate(0); + qlz_decompress((const char *)pbuf, g_multiMapState[0], state_decompress); + + 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! Decompressed to %u bytes, expected %u.\n", + (uint32_t)qlz_size_decompressed((char *)buf), (uint32_t)sizeof(netmapstate_t)); + + g_netDisconnect = 1; + + gametext(160,190,"Transfer Error",14,2); + } +} + +//////////////////////////////////////////////////////////////////////////////// +// Map Update Packets + +char g_netCompressBuf[PACKBUF_SIZE+400]; + +void Net_SendMapUpdate(void) +{ + int32_t pi; + int32_t siz = 0; + netmapstate_t *currentstate; + usize_t osize = sizeof(netmapstate_t); + + if (!g_netServer || numplayers < 2) + return; + + currentstate = g_multiMapRevisions[g_netMapRevision % NET_REVISIONS]; + + if (currentstate == NULL) + { + currentstate = (netmapstate_t *) Bcalloc(1, sizeof(netmapstate_t)); + g_multiMapRevisions[g_netMapRevision % NET_REVISIONS] = currentstate; + } + + Net_SaveMapState(currentstate); + + for (pi=0; pi<(signed)g_netServer->peerCount; pi++) + { + ENetPeer *const currentPeer = &g_netServer->peers[pi]; + const intptr_t playeridx = (intptr_t)currentPeer->data; + + if (currentPeer->state != ENET_PEER_STATE_CONNECTED || !g_player[playeridx].playerquitflag) + { + continue; + } + + if (g_player[playeridx].revision == g_netMapRevision) + { + continue; + } + + packbuf[0] = PACKET_MAP_STREAM; + *(uint32_t *)&packbuf[1] = g_player[playeridx].revision; // base revision for this update + + xd3_encode_memory((const uint8_t *) currentstate, sizeof(netmapstate_t), + (const uint8_t *) g_multiMapState[playeridx], sizeof(netmapstate_t), + (uint8_t *)tempnetbuf, &osize, sizeof(netmapstate_t), XD3_COMPLEVEL_1|XD3_NOCOMPRESS); + + Bmemcpy(g_pendingMapState[playeridx], currentstate, sizeof(netmapstate_t)); + + siz = qlz_compress((char *)tempnetbuf, packbuf+1+sizeof(uint32_t), osize, state_compress); + + siz++; // Because of the packet tag + siz += sizeof(uint32_t); // Because of the revision + + packbuf[siz++] = myconnectindex; + + initprintf("final packet size: %d\n", siz); + + enet_peer_send(currentPeer, CHAN_GAMESTATE, enet_packet_create(packbuf, siz, ENET_PACKET_FLAG_RELIABLE)); + } + + g_netMapRevision++; +} + +void Net_ReceiveMapUpdate(uint8_t *pbuf, int32_t packbufleng) +{ + int ret; + usize_t osize = 0; + netmapstate_t *receivedstate; + + packbufleng = qlz_size_decompressed((char *)&pbuf[5]); + pbuf = (uint8_t *)Bmalloc(packbufleng<<1); + packbufleng = qlz_decompress((char *)&pbuf[4], (char *)(pbuf), state_decompress); + + initprintf("packbufleng: %d\n", packbufleng); + + ret = xd3_decode_memory((const uint8_t *)pbuf, packbufleng, + (const uint8_t *)g_multiMapState[0], sizeof(netmapstate_t), + (uint8_t *)tempnetbuf, &osize, sizeof(netmapstate_t), XD3_COMPLEVEL_1|XD3_NOCOMPRESS); + + if (ret) + { + initprintf("xdelta3 returned %d\n", ret); + Bfree(pbuf); + return; + } + + if (sizeof(netmapstate_t) != osize) + { + initprintf("decompressed data size mismatch!\n"); + } + else + { + receivedstate = (netmapstate_t *) tempnetbuf; + Net_RestoreMapState(receivedstate); + g_player[myconnectindex].revision = receivedstate->revision; + Bmemcpy(g_multiMapState[0], receivedstate, sizeof(netmapstate_t)); + } + + Bfree(pbuf); +} + +//////////////////////////////////////////////////////////////////////////////// +// Player Updates + +void Net_FillPlayerUpdate(playerupdate_t *update, int32_t player) +{ + update->playerindex = player; + + update->pos = g_player[player].ps->pos; + update->opos = g_player[player].ps->opos; + update->vel = g_player[player].ps->vel; + update->ang = g_player[player].ps->ang; + update->horiz = g_player[player].ps->horiz; + update->horizoff = g_player[player].ps->horizoff; + update->ping = g_player[player].ping; + update->deadflag = g_player[player].ps->dead_flag; + update->playerquitflag = g_player[player].playerquitflag; +} + +void Net_ExtractPlayerUpdate(playerupdate_t *update) +{ + const int32_t playerindex = update->playerindex; + + if (playerindex != myconnectindex) + { + g_player[playerindex].ps->pos = update->pos; + g_player[playerindex].ps->opos = update->opos; + g_player[playerindex].ps->vel = update->vel; + g_player[playerindex].ps->ang = update->ang; + g_player[playerindex].ps->horiz = update->horiz; + g_player[playerindex].ps->horizoff = update->horizoff; + } + + g_player[playerindex].ping = update->ping; + g_player[playerindex].ps->dead_flag = update->deadflag; + g_player[playerindex].playerquitflag = update->playerquitflag; + + //updatesectorz(g_player[other].ps->pos.x, g_player[other].ps->pos.y, g_player[other].ps->pos.z, &g_player[other].ps->cursectnum); + //changespritesect(g_player[other].ps->i, g_player[other].ps->cursectnum); +} + +//////////////////////////////////////////////////////////////////////////////// +// Server Update Packets + +#pragma pack(push,1) +typedef struct +{ + uint8_t header; + uint8_t numplayers; + input_t nsyn; + int32_t seed; + int16_t pause_on; +} serverupdate_t; +#pragma pack(pop) + +#pragma pack(push,1) +typedef struct +{ + uint8_t extra; + int16_t cstat; + uint16_t owner; + uint16_t picnum; + uint16_t gotweapon; + uint8_t kickback_pic; + uint8_t frags[MAXPLAYERS]; + int16_t inv_amount[GET_MAX]; + int16_t ammo_amount[MAX_WEAPONS]; + + uint8_t curr_weapon; + uint8_t last_weapon; + uint8_t wantweaponfire; + uint8_t weapon_pos; + uint8_t frag_ps; + uint8_t frag; + uint8_t fraggedself; + uint8_t last_extra; + uint8_t pal; + uint16_t ping; + uint16_t newowner; + + playerupdate_t player; +} serverplayerupdate_t; +#pragma pack(pop) + +void Net_SendServerUpdates(void) +{ + int16_t i; + char *updatebuf; + serverupdate_t serverupdate; + serverplayerupdate_t playerupdate; + input_t *osyn = (input_t *)&inputfifo[1][0]; + input_t *nsyn = (input_t *)&inputfifo[0][0]; + + ticrandomseed = randomseed; + + if (g_netServer) + { + Bmemcpy(&osyn[0], &nsyn[0], sizeof(input_t)); + } + + if (!g_netServer || numplayers < 2) + { + return; + } + + if ((ticrandomseed % 5) == 0) + { + return; + } + + serverupdate.header = PACKET_MASTER_TO_SLAVE; + serverupdate.seed = ticrandomseed; + serverupdate.nsyn = *nsyn; + serverupdate.pause_on = ud.pause_on; + + serverupdate.numplayers = 0; + updatebuf = tempnetbuf + sizeof(serverupdate_t); for (TRAVERSE_CONNECT(i)) { - Bmemcpy(&osyn[i], &nsyn[i], offsetof(input_t, filler)); + if (g_player[i].playerquitflag == 0) + { + continue; + } - *(int16_t *)&packbuf[siz] = g_player[i].ps->dead_flag; - siz += sizeof(int16_t); + Net_FillPlayerUpdate(&playerupdate.player, i); - packbuf[siz++] = g_player[i].playerquitflag; + playerupdate.gotweapon = g_player[i].ps->gotweapon; + playerupdate.extra = sprite[g_player[i].ps->i].extra; + playerupdate.cstat = sprite[g_player[i].ps->i].cstat; + playerupdate.owner = actor[g_player[i].ps->i].owner; + playerupdate.picnum = actor[g_player[i].ps->i].picnum; + playerupdate.kickback_pic = g_player[i].ps->kickback_pic; + Bmemcpy(playerupdate.frags, g_player[i].frags, sizeof(playerupdate.frags)); + Bmemcpy(playerupdate.inv_amount, g_player[i].ps->inv_amount, sizeof(playerupdate.inv_amount)); + Bmemcpy(playerupdate.ammo_amount, g_player[i].ps->ammo_amount, sizeof(playerupdate.ammo_amount)); - if (g_player[i].playerquitflag == 0) continue; + playerupdate.curr_weapon = g_player[i].ps->curr_weapon; + playerupdate.last_weapon = g_player[i].ps->last_weapon; + playerupdate.wantweaponfire = g_player[i].ps->wantweaponfire; + playerupdate.weapon_pos = g_player[i].ps->weapon_pos; + playerupdate.frag_ps = g_player[i].ps->frag_ps; + playerupdate.frag = g_player[i].ps->frag; + playerupdate.fraggedself = g_player[i].ps->fraggedself; + playerupdate.last_extra = g_player[i].ps->last_extra; + playerupdate.ping = g_player[i].ping; + playerupdate.newowner = g_player[i].ps->newowner; + playerupdate.pal = sprite[g_player[i].ps->i].pal; - Bmemcpy(&packbuf[siz], &nsyn[i], offsetof(input_t, filler)); - siz += offsetof(input_t, filler); + Bmemcpy(updatebuf, &playerupdate, sizeof(serverplayerupdate_t)); + updatebuf += sizeof(serverplayerupdate_t); + serverupdate.numplayers++; + } - Bmemcpy(&packbuf[siz], &g_player[i].ps->pos.x, sizeof(vec3_t) * 2); - siz += sizeof(vec3_t) * 2; + if (serverupdate.numplayers == 0) + { + return; + } - Bmemcpy(&packbuf[siz], &g_player[i].ps->vel.x, sizeof(vec3_t)); - siz += sizeof(vec3_t); + Bmemcpy(tempnetbuf, &serverupdate, sizeof(serverupdate_t)); - *(int16_t *)&packbuf[siz] = g_player[i].ps->ang; - siz += sizeof(int16_t); + enet_host_broadcast(g_netServer, CHAN_MOVE, enet_packet_create(tempnetbuf, sizeof(serverupdate_t) + (serverupdate.numplayers * sizeof(serverplayerupdate_t)), 0)); - Bmemcpy(&packbuf[siz], &g_player[i].ps->horiz, sizeof(int16_t) * 2); - siz += sizeof(int16_t) * 2; + /* - *(uint16_t *)&packbuf[siz] = g_player[i].ps->gotweapon; - siz += sizeof(uint16_t); - - Bmemcpy(&packbuf[siz], &g_player[i].ps->ammo_amount[0], sizeof(g_player[i].ps->ammo_amount)); - siz += sizeof(g_player[i].ps->ammo_amount); - - Bmemcpy(&packbuf[siz], &g_player[i].ps->inv_amount[0], sizeof(g_player[i].ps->inv_amount)); - siz += sizeof(g_player[i].ps->inv_amount); - - Bmemcpy(&packbuf[siz], g_player[i].frags, sizeof(g_player[i].frags)); - siz += sizeof(g_player[i].frags); - - packbuf[siz++] = (uint8_t) sprite[g_player[i].ps->i].extra; - - *(int16_t *)&packbuf[siz] = sprite[g_player[i].ps->i].cstat; - siz += sizeof(int16_t); - - packbuf[siz++] = (uint8_t) g_player[i].ps->kickback_pic; - - *(int16_t *)&packbuf[siz] = actor[g_player[i].ps->i].owner; - siz += sizeof(int16_t); - - *(int16_t *)&packbuf[siz] = actor[g_player[i].ps->i].picnum; - siz += sizeof(int16_t); - - packbuf[siz++] = (uint8_t) g_player[i].ps->curr_weapon; - packbuf[siz++] = (int8_t) g_player[i].ps->last_weapon; - packbuf[siz++] = (int8_t) g_player[i].ps->wantweaponfire; - packbuf[siz++] = (int8_t) g_player[i].ps->weapon_pos; - packbuf[siz++] = (uint8_t) g_player[i].ps->frag_ps; - - packbuf[siz++] = g_player[i].ps->frag; - packbuf[siz++] = g_player[i].ps->fraggedself; - packbuf[siz++] = g_player[i].ps->last_extra; - - *(int16_t *)&packbuf[siz] = g_player[i].ping; - siz += sizeof(int16_t); - - *(int16_t *)&packbuf[siz] = g_player[i].ps->newowner; - siz += sizeof(int16_t); - - packbuf[siz++] = sprite[g_player[i].ps->i].pal; + for (TRAVERSE_CONNECT(i)) + { l = i; i = g_player[l].ps->i; @@ -1706,7 +1584,7 @@ void Net_UpdateClients(void) { int16_t ii=g_gameVarCount-1; - for (; ii>=0 && siz <= (SYNCPACKETSIZE-(SYNCPACKETSIZE>>3)); ii--) + for (; ii>=0 && siz <= (SYNCPACKETSIZE-(SYNCPACKETSIZE>>3)); ii--) // SYNCPACKETSIZE-(SYNCPACKETSIZE>>3) == 1176 { if ((aGameVars[ii].dwFlags & (GAMEVAR_PERACTOR|GAMEVAR_NOMULTI)) == GAMEVAR_PERACTOR && aGameVars[ii].val.plValues && aGameVars[ii].val.plValues[i] != aGameVars[ii].lDefault) @@ -1749,17 +1627,18 @@ void Net_UpdateClients(void) } { -#if 1 + #if 1 // We're screwed anyway if this fails: Bassert(siz <= PACKBUF_SIZE); -#else + #else if (siz >= PACKBUF_SIZE) { initprintf("Global packet buffer overflow! Size of packet: %i\n", siz); return; } -#endif - siz = qlz_compress(packbuf+1, g_netCompressBuf, siz, state_compress); + #endif + + siz = qlz_compress(packbuf+1, compressbuf, siz, state_compress); if (siz >= PACKBUF_SIZE-1) { @@ -1767,95 +1646,173 @@ void Net_UpdateClients(void) return; } - Bmemcpy(packbuf+1, g_netCompressBuf, siz); + Bmemcpy(packbuf+1, compressbuf, siz); siz++; } packbuf[siz++] = myconnectindex; enet_host_broadcast(g_netServer, CHAN_MOVE, enet_packet_create(packbuf, siz, 0)); + */ } -void Net_StreamLevel(void) +void Net_ReceiveServerUpdate(ENetEvent *event) { - int32_t pi; - int32_t siz = 0; - usize_t osize = sizeof(netmapstate_t); + int32_t i; + char *updatebuf; + int8_t numupdates; + serverupdate_t serverupdate; + serverplayerupdate_t playerupdate; - if (!g_netServer || numplayers < 2) - return; - - if (!streamoutput) - streamoutput = (netmapstate_t *)Bcalloc(1, sizeof(netmapstate_t)); - - for (pi=0; pi<(signed)g_netServer->peerCount; pi++) + if (((event->packet->dataLength - sizeof(serverupdate_t)) % sizeof(serverplayerupdate_t)) != 0) { - ENetPeer *const currentPeer = &g_netServer->peers[pi]; - const intptr_t playeridx = (intptr_t)currentPeer->data; - - if (currentPeer->state != ENET_PEER_STATE_CONNECTED || !g_player[playeridx].playerquitflag || !g_player[playeridx].ready) - continue; - - g_player[playeridx].ready = 0; - - packbuf[0] = PACKET_MAP_STREAM; - *(uint32_t *)&packbuf[1] = g_player[playeridx].revision; // base revision for this update - - if (g_multiMapRevisions[g_netMapRevision&(NET_REVISIONS-1)] == NULL) - g_multiMapRevisions[g_netMapRevision&(NET_REVISIONS-1)] = (netmapstate_t *)Bcalloc(1, sizeof(netmapstate_t)); - - Net_SaveMapState(g_multiMapRevisions[g_netMapRevision&(NET_REVISIONS-1)]); - - xd3_encode_memory((const uint8_t *)g_multiMapRevisions[g_netMapRevision&(NET_REVISIONS-1)], sizeof(netmapstate_t), - (const uint8_t *)g_multiMapState[playeridx], sizeof(netmapstate_t), - (uint8_t *)streamoutput, &osize, sizeof(netmapstate_t), XD3_COMPLEVEL_1|XD3_NOCOMPRESS); - - Bmemcpy(g_pendingMapState[playeridx], g_multiMapRevisions[g_netMapRevision&(NET_REVISIONS-1)], sizeof(netmapstate_t)); - - initprintf("upd %u->%u: ", g_player[playeridx].revision, g_netMapRevision); - - { - if (osize >= PACKBUF_SIZE) - { - // XXX: this currently happens when e.g. switching levels - initprintf("Packet buffer overflow! GAMESTATE payload size " - "after diff before compress: %u\n", osize); - return; - } - - siz = qlz_compress((char *)streamoutput, g_netCompressBuf, osize, state_compress); - - if (siz >= PACKBUF_SIZE-1) - { - initprintf("Global packet buffer overflow! GAMESTATE payload size " - "after diff and compress: %d\n", siz); - return; - } - - Bmemcpy(packbuf+1+sizeof(uint32_t), g_netCompressBuf, siz); - siz++; - siz += sizeof(uint32_t); - } - - packbuf[siz++] = myconnectindex; - - initprintf("final packet size: %d\n", siz); - - enet_peer_send(currentPeer, CHAN_GAMESTATE, enet_packet_create(packbuf, siz, ENET_PACKET_FLAG_RELIABLE)); + return; } - g_netMapRevision++; + updatebuf = (char *) event->packet->data; + Bmemcpy(&serverupdate, updatebuf, sizeof(serverupdate_t)); + updatebuf += sizeof(serverupdate_t); + inputfifo[0][0] = serverupdate.nsyn; + ud.pause_on = serverupdate.pause_on; + + ticrandomseed = serverupdate.seed; + + for (i = 0; i < serverupdate.numplayers; ++i) + { + Bmemcpy(&playerupdate, updatebuf, sizeof(serverplayerupdate_t)); + updatebuf += sizeof(serverplayerupdate_t); + + Net_ExtractPlayerUpdate(&playerupdate.player); + + g_player[i].ps->gotweapon = playerupdate.gotweapon; + sprite[g_player[i].ps->i].extra = playerupdate.extra; + sprite[g_player[i].ps->i].cstat = playerupdate.cstat; + //actor[g_player[i].ps->i].owner = playerupdate.owner; // This makes baby jesus cry + actor[g_player[i].ps->i].picnum = playerupdate.picnum; + g_player[i].ps->kickback_pic = playerupdate.kickback_pic; + Bmemcpy(g_player[i].frags, playerupdate.frags, sizeof(playerupdate.frags)); + Bmemcpy(g_player[i].ps->inv_amount, playerupdate.inv_amount, sizeof(playerupdate.inv_amount)); + Bmemcpy(g_player[i].ps->ammo_amount, playerupdate.ammo_amount, sizeof(playerupdate.ammo_amount)); + + g_player[i].ps->curr_weapon = playerupdate.curr_weapon; + g_player[i].ps->last_weapon = playerupdate.last_weapon; + g_player[i].ps->wantweaponfire = playerupdate.wantweaponfire; + g_player[i].ps->weapon_pos = playerupdate.weapon_pos; + g_player[i].ps->frag_ps = playerupdate.frag_ps; + g_player[i].ps->frag = playerupdate.frag; + g_player[i].ps->fraggedself = playerupdate.fraggedself; + g_player[i].ps->last_extra = playerupdate.last_extra; + g_player[i].ping = playerupdate.ping; + sprite[g_player[i].ps->i].pal = playerupdate.pal; + g_player[i].ps->newowner = playerupdate.newowner; + + /* + 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); + } + */ + } + + /* + for (TRAVERSE_CONNECT(i)) + { + l = i; + + i = g_player[l].ps->i; + + { + int32_t oa; + + j++; + oa = T5; + + T5 = *(int32_t *)&pbuf[j]; + j += sizeof(int32_t); + + if (oa != T5) T3 = T4 = 0; + } + + do + { + uint16_t var_id = *(uint16_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 + { + uint16_t var_id = *(uint16_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); + } + */ } -void faketimerhandler(void) +//////////////////////////////////////////////////////////////////////////////// +// Client Update Packets + +#pragma pack(push,1) +typedef struct { - if (g_netServer==NULL && g_netClient==NULL) - return; + uint8_t header; + uint32_t revision; + input_t nsyn; + playerupdate_t player; +} clientupdate_t; +#pragma pack(pop) - enet_host_service(g_netServer ? g_netServer : g_netClient, NULL, 0); +void Net_SendClientUpdate(void) +{ + clientupdate_t update; + update.header = PACKET_SLAVE_TO_MASTER; + update.revision = g_player[myconnectindex].revision; + update.nsyn = inputfifo[0][myconnectindex]; + + Net_FillPlayerUpdate(&update.player, myconnectindex); + + enet_peer_send(g_netClientPeer, CHAN_MOVE, enet_packet_create(&update, sizeof(clientupdate_t), 0)); } -void Net_EnterMessage(void) +void Net_ReceiveClientUpdate(ENetEvent *event) +{ + int32_t playeridx; + clientupdate_t update; + + if (event->packet->dataLength != sizeof(clientupdate_t)) + { + return; + } + + Bmemcpy(&update, (char *) event->packet->data, sizeof(clientupdate_t)); + + playeridx = (int32_t)(intptr_t) event->peer->data; + + g_player[playeridx].revision = update.revision; + inputfifo[0][playeridx] = update.nsyn; + + Net_ExtractPlayerUpdate(&update.player); +} + +//////////////////////////////////////////////////////////////////////////////// +// Message Packets + +void Net_SendMessage(void) { int16_t hitstate, i, j, l; @@ -2007,54 +1964,351 @@ void Net_EnterMessage(void) } } -void Net_WaitForServer(void) +void Net_ReceiveMessage(uint8_t *pbuf, int32_t packbufleng) { - int32_t server_ready = g_player[0].pingcnt; + Bstrncpy(recbuf, (char *)pbuf+2, packbufleng-2); + recbuf[packbufleng-2] = 0; - if (numplayers < 2 || g_netServer) return; + G_AddUserQuote(recbuf); + S_PlaySound(EXITMENUSOUND); - P_SetGamePalette(g_player[myconnectindex].ps, TITLEPAL, 8+2+1); + pus = pub = NUMPAGES; +} - do +//////////////////////////////////////////////////////////////////////////////// +// New Game Packets + +void Net_StartNewGame() +{ + int32_t i; + + for (TRAVERSE_CONNECT(i)) { - if (quitevent || keystatus[1]) G_GameExit(""); + P_ResetWeapons(i); + P_ResetInventory(i); + g_player[i].revision = 0; + } - display_betascreen(); + Net_ExtractNewGame(&pendingnewgame, 0); + G_NewGame(ud.volume_number,ud.level_number,ud.player_skill); + ud.coop = ud.m_coop; - gametext(160,170,"Waiting for server",14,2); - nextpage(); + g_netMapRevision = 0; - packbuf[0] = PACKET_PLAYER_PING; - packbuf[1] = myconnectindex; + if (G_EnterLevel(MODE_GAME)) + { + G_BackToMenu(); + } +} - if (g_netClientPeer) - enet_peer_send(g_netClientPeer, CHAN_GAMESTATE, enet_packet_create(packbuf, 2, ENET_PACKET_FLAG_RELIABLE)); +void Net_SendNewGame(int32_t frommenu, ENetPeer *peer) +{ + newgame_t newgame; - G_HandleAsync(); + newgame.header = PACKET_NEW_GAME; + Net_FillNewGame(&newgame, frommenu); - if (g_player[0].pingcnt > server_ready) + if (peer) + { + enet_peer_send(peer, CHAN_GAMESTATE, enet_packet_create(&newgame, sizeof(newgame_t), ENET_PACKET_FLAG_RELIABLE)); + } + else + { + enet_host_broadcast(g_netServer, CHAN_GAMESTATE, enet_packet_create(&newgame, sizeof(newgame_t), ENET_PACKET_FLAG_RELIABLE)); + } + + g_netPlayersWaiting--; +} + +void Net_ReceiveNewGame(ENetEvent *event) +{ + if ((vote_map + vote_episode + voting) != -3) + G_AddUserQuote("Vote Succeeded"); + + Bmemcpy(&pendingnewgame, event->packet->data, sizeof(newgame_t)); + Net_StartNewGame(); + + 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_player[myconnectindex].ps->gm = MODE_GAME; + ready2send = 1; +} + +void Net_FillNewGame(newgame_t *newgame, int32_t frommenu) +{ + if (frommenu) + { + newgame->level_number = ud.m_level_number; + newgame->volume_number = ud.m_volume_number; + newgame->player_skill = ud.m_player_skill; + newgame->monsters_off = ud.m_monsters_off; + newgame->respawn_monsters = ud.m_respawn_monsters; + newgame->respawn_items = ud.m_respawn_items; + newgame->respawn_inventory = ud.m_respawn_inventory; + newgame->ffire = ud.m_ffire; + newgame->noexits = ud.m_noexits; + newgame->coop = ud.m_coop; + } + else + { + newgame->level_number = ud.level_number; + newgame->volume_number = ud.volume_number; + newgame->player_skill = ud.player_skill; + newgame->monsters_off = ud.monsters_off; + newgame->respawn_monsters = ud.respawn_monsters; + newgame->respawn_items = ud.respawn_items; + newgame->respawn_inventory = ud.respawn_inventory; + newgame->ffire = ud.ffire; + newgame->noexits = ud.noexits; + newgame->coop = ud.coop; + } +} + +void Net_ExtractNewGame(newgame_t *newgame, int32_t menuonly) +{ + ud.m_level_number = newgame->level_number; + ud.m_volume_number = newgame->volume_number; + ud.m_player_skill = newgame->player_skill; + ud.m_monsters_off = newgame->monsters_off; + ud.m_respawn_monsters = newgame->respawn_monsters; + ud.m_respawn_items = newgame->respawn_items; + ud.m_respawn_inventory = newgame->respawn_inventory; + ud.m_ffire = newgame->ffire; + ud.m_noexits = newgame->noexits; + ud.m_coop = newgame->coop; + + if (!menuonly) + { + ud.level_number = newgame->level_number; + ud.volume_number = newgame->volume_number; + ud.player_skill = newgame->player_skill; + ud.monsters_off = newgame->monsters_off; + ud.respawn_monsters = newgame->respawn_monsters; + ud.respawn_monsters = newgame->respawn_items; + ud.respawn_inventory = newgame->respawn_inventory; + ud.ffire = newgame->ffire; + ud.noexits = newgame->noexits; + ud.coop = newgame->coop; + } +} + +//////////////////////////////////////////////////////////////////////////////// +// Map Vote Packets + +void Net_SendMapVoteInitiate(void) +{ + int32_t i; + newgame_t newgame; + + if (!g_netClient) + { + return; + } + + voting = myconnectindex; + + newgame.header = PACKET_MAP_VOTE_INITIATE; + newgame.connection = myconnectindex; + Net_FillNewGame(&newgame, 1); + + enet_peer_send(g_netClientPeer, CHAN_GAMESTATE, enet_packet_create(&newgame, sizeof(newgame_t), ENET_PACKET_FLAG_RELIABLE)); +} + +void Net_RecieveMapVoteInitiate(uint8_t *pbuf) +{ + int32_t i; + + Bmemcpy(&pendingnewgame, pbuf, sizeof(newgame_t)); + Net_ExtractNewGame(&pendingnewgame, 1); + + voting = pendingnewgame.connection; + vote_episode = pendingnewgame.volume_number; + vote_map = pendingnewgame.level_number; + + Bsprintf(tempbuf,"%s^00 has called a vote to change map to %s (E%dL%d)", + g_player[voting].user_name, + MapInfo[(uint8_t)(vote_episode*MAXLEVELS + vote_map)].name, + vote_episode+1,vote_map+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; +} + +void Net_SendMapVote(int32_t votefor) +{ + voting = -1; + g_player[myconnectindex].gotvote = 1; + g_player[myconnectindex].vote = votefor; + + tempbuf[0] = PACKET_MAP_VOTE; + tempbuf[1] = myconnectindex; + tempbuf[2] = votefor; + tempbuf[3] = myconnectindex; + + if (g_netClient) + { + enet_peer_send(g_netClientPeer, CHAN_GAMESTATE, enet_packet_create(tempbuf, 4, ENET_PACKET_FLAG_RELIABLE)); + } + else if (g_netServer) + { + enet_host_broadcast(g_netServer, CHAN_GAMESTATE, enet_packet_create(tempbuf, 4, ENET_PACKET_FLAG_RELIABLE)); + } + + Net_CheckForEnoughVotes(); +} + +void Net_RecieveMapVote(uint8_t *pbuf) +{ + if (voting == myconnectindex && g_player[(uint8_t)pbuf[1]].gotvote == 0) + { + Bsprintf(tempbuf,"Confirmed vote from %s",g_player[(uint8_t)pbuf[1]].user_name); + G_AddUserQuote(tempbuf); + } + + if (!g_netServer) + { + return; + } + + g_player[(uint8_t)pbuf[1]].gotvote = 1; + g_player[(uint8_t)pbuf[1]].vote = pbuf[2]; + Net_CheckForEnoughVotes(); +} + +void Net_CheckForEnoughVotes() +{ + int32_t i; + int32_t requiredvotes; + int32_t numfor, numagainst; + + // Only the server can decide map changes + if (!g_netServer || numplayers <= 1) + { + return; + } + + // If there are just two players, both of them deserve a vote + if (numplayers == 2) + { + requiredvotes = 2; + } + else + { + // If more than two players, we need at least 50% of the players to vote + // Which means that if there's an odd number of players, we'll need slightly more than 50% of the vote. + requiredvotes = numplayers / 2; + if (numplayers % 2 == 1) { - P_SetGamePalette(g_player[myconnectindex].ps, BASEPAL, 8+2+1); - return; + requiredvotes++; } } - while (1); + + numfor = numagainst = 0; + for (i=0; i= requiredvotes) + { + Net_StartNewGame(); + Net_SendNewGame(1, NULL); + } + else if (numagainst >= requiredvotes || (numfor + numagainst) == numplayers) + { + Net_SendMapVoteCancel(1); + } } -void Net_ResetPrediction(void) +// If failed is true, that means the vote lost. Otherwise it was cancelled by the client who initiated it. +void Net_SendMapVoteCancel(int32_t failed) { - Bmemcpy(&my, &g_player[myconnectindex].ps, sizeof(vec3_t)); - Bmemcpy(&omy, &g_player[myconnectindex].ps, sizeof(vec3_t)); - Bmemset(&myvel, 0, sizeof(vec3_t)); + int32_t i; - 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; + // Only the server or the client that initiated the vote can cancel the vote + if (g_netClient && voting != myconnectindex) + { + return; + } + + tempbuf[0] = PACKET_MAP_VOTE_CANCEL; + tempbuf[1] = myconnectindex; + + // If we're forwarding a cancelled message, change the connection index to the one who cancelled it. + if (g_netServer && !failed) + { + tempbuf[1] = voting; + } + + voting = -1; + + if (g_netClient) + { + enet_peer_send(g_netClientPeer, CHAN_GAMESTATE, enet_packet_create(tempbuf, 2, ENET_PACKET_FLAG_RELIABLE)); + } + else if (g_netServer) + { + enet_host_broadcast(g_netServer, CHAN_GAMESTATE, enet_packet_create(tempbuf, 2, ENET_PACKET_FLAG_RELIABLE)); + } +} + +void Net_RecieveMapVoteCancel(uint8_t *pbuf) +{ + int32_t i, numvotes; + + // Ignore if we're not voting + if (voting == -1) + { + return; + } + + // Ignore cancellations from clients that did not initiate the map vote + if (voting != pbuf[1] && voting != myconnectindex) + { + return; + } + + if (voting == myconnectindex || voting != pbuf[1]) + { + Bsprintf(tempbuf,"Vote Failed"); + } + else if (voting == pbuf[1]) + { + Bsprintf(tempbuf,"%s^00 has canceled the vote",g_player[voting].user_name); + } + + G_AddUserQuote(tempbuf); + + if (g_netServer) + { + Net_SendMapVoteCancel(0); + } + + voting = -1; } diff --git a/polymer/eduke32/source/net.h b/polymer/eduke32/source/net.h index 66f266aa3..8651560c0 100644 --- a/polymer/eduke32/source/net.h +++ b/polymer/eduke32/source/net.h @@ -92,7 +92,6 @@ typedef struct { uint32_t revision; int32_t animategoal[MAXANIMATES], animatevel[MAXANIMATES], g_animateCount; int32_t animateptr[MAXANIMATES]; -// int32_t lockclock; int32_t msx[2048], msy[2048]; int32_t randomseed, g_globalRandom; @@ -138,30 +137,118 @@ extern int32_t g_netDisconnect; extern int32_t g_netPlayersWaiting; extern int32_t g_netPort; extern int32_t g_networkMode; -extern int32_t g_netSync; extern int32_t lastsectupdate[MAXSECTORS]; extern int32_t lastupdate[MAXSPRITES]; extern int32_t lastwallupdate[MAXWALLS]; extern int16_t g_netStatnums[10]; +#pragma pack(push,1) +typedef struct { + vec3_t pos; + vec3_t opos; + vec3_t vel; + int16_t ang; + int16_t horiz; + int16_t horizoff; + int16_t ping; + int16_t playerindex; + int16_t deadflag; + int16_t playerquitflag; +} playerupdate_t; +#pragma pack(pop) -int32_t Net_PackSprite(int32_t i,uint8_t *pbuf); -int32_t Net_UnpackSprite(int32_t i,uint8_t *pbuf); -void Net_ClientMove(void); +#pragma pack(push,1) +typedef struct { + int8_t header; + int8_t connection; + int8_t level_number; + int8_t volume_number; + int8_t player_skill; + int8_t monsters_off; + int8_t respawn_monsters; + int8_t respawn_items; + int8_t respawn_inventory; + int8_t marker; + int8_t ffire; + int8_t noexits; + int8_t coop; +} newgame_t; +#pragma pack(pop) + +newgame_t pendingnewgame; + +// Connect/Disconnect void Net_Connect(const char *srvaddr); void Net_Disconnect(void); -void Net_EnterMessage(void); +void Net_ReceiveDisconnect(ENetEvent *event); + +// Packet Handlers void Net_GetPackets(void); -void Net_NewGame(int32_t volume,int32_t level); +void Net_HandleServerPackets(void); +void Net_HandleClientPackets(void); void Net_ParseClientPacket(ENetEvent *event); void Net_ParseServerPacket(ENetEvent *event); +void Net_ParsePacketCommon(uint8_t *pbuf, int32_t packbufleng, int32_t serverpacketp); + +void Net_SendVersion(ENetPeer *client); +void Net_RecieveVersion(uint8_t *pbuf, int32_t packbufleng); + +void Net_SendChallenge(); +void Net_RecieveChallenge(uint8_t *pbuf, int32_t packbufleng, ENetEvent *event); + +void Net_SendNewPlayer(int32_t newplayerindex); +void Net_RecieveNewPlayer(uint8_t *pbuf, int32_t packbufleng); + +void Net_SendPlayerIndex(int32_t index, ENetPeer *peer); +void Net_RecievePlayerIndex(uint8_t *pbuf, int32_t packbufleng); + +void Net_SendClientInfo(void); +void Net_ReceiveClientInfo(uint8_t *pbuf, int32_t packbufleng, int32_t fromserver); + +void Net_SendUserMapName(void); +void Net_ReceiveUserMapName(uint8_t *pbuf, int32_t packbufleng); + +void Net_SendClientSync(ENetEvent *event, int32_t player); +void Net_ReceiveClientSync(ENetEvent *event); + +void Net_SendMapUpdate(void); +void Net_ReceiveMapUpdate(uint8_t *pbuf, int32_t packbufleng); + +void Net_FillPlayerUpdate(playerupdate_t *update, int32_t player); +void Net_ExtractPlayerUpdate(playerupdate_t *update); + +void Net_SendServerUpdates(void); +void Net_ReceiveServerUpdate(ENetEvent *event); + +void Net_SendClientUpdate(void); +void Net_ReceiveClientUpdate(ENetEvent *event); + +void Net_SendMessage(void); +void Net_ReceiveMessage(uint8_t *pbuf, int32_t packbufleng); + +void Net_StartNewGame(); +void Net_SendNewGame(int32_t frommenu, ENetPeer *peer); +void Net_ReceiveNewGame(ENetEvent *event); + +void Net_FillNewGame(newgame_t* newgame, int32_t frommenu); +void Net_ExtractNewGame(newgame_t* newgame, int32_t menuonly); + +void Net_SendMapVoteInitiate(void); +void Net_RecieveMapVoteInitiate(uint8_t *pbuf); + +void Net_SendMapVote(int32_t votefor); +void Net_RecieveMapVote(uint8_t *pbuf); +void Net_CheckForEnoughVotes(); + +void Net_SendMapVoteCancel(int32_t failed); +void Net_RecieveMapVoteCancel(uint8_t *pbuf); + +////////// + void Net_ResetPrediction(void); void Net_RestoreMapState(netmapstate_t *save); -void Net_SendClientInfo(void); -void Net_SendUserMapName(void); -void Net_StreamLevel(void); void Net_SyncPlayer(ENetEvent *event); -void Net_UpdateClients(void); void Net_WaitForServer(void); void faketimerhandler(void); -#endif + +#endif // __netplay_h__ diff --git a/polymer/eduke32/source/osdcmds.c b/polymer/eduke32/source/osdcmds.c index 2e5e4ffc7..11214d33f 100644 --- a/polymer/eduke32/source/osdcmds.c +++ b/polymer/eduke32/source/osdcmds.c @@ -98,6 +98,7 @@ static int32_t osdcmd_changelevel(const osdfuncparm_t *parm) if (numplayers > 1) { + /* if (g_netServer) Net_NewGame(volume,level); else if (voting == -1) @@ -132,6 +133,7 @@ static int32_t osdcmd_changelevel(const osdfuncparm_t *parm) g_player[myconnectindex].ps->gm |= MODE_MENU; M_ChangeMenu(603); } + */ return OSDCMD_OK; } if (g_player[myconnectindex].ps->gm & MODE_GAME) @@ -227,6 +229,7 @@ static int32_t osdcmd_map(const osdfuncparm_t *parm) if (numplayers > 1) { + /* if (g_netServer) { Net_SendUserMapName(); @@ -267,6 +270,7 @@ static int32_t osdcmd_map(const osdfuncparm_t *parm) g_player[myconnectindex].ps->gm |= MODE_MENU; M_ChangeMenu(603); } + */ return OSDCMD_OK; }