static void reportShipSelected (GETMELEE_STATE *gms, COUNT index) { size_t playerI; for (playerI = 0; playerI < NUM_PLAYERS; playerI++) { NetConnection *conn = netConnections[playerI]; if (conn == NULL) continue; if (!NetConnection_isConnected (conn)) continue; Netplay_Notify_shipSelected (conn, index); } (void) gms; }
int flushPacketQueue(NetConnection *conn) { int flushResult; PacketQueue *queue = &conn->queue; assert(NetConnection_isConnected(conn)); flushResult = flushPacketQueueLinks(conn, &queue->firstUrgent); if (queue->firstUrgent == NULL) queue->endUrgent = &queue->firstUrgent; if (flushResult == -1) { // errno is set return -1; } flushResult = flushPacketQueueLinks(conn, &queue->first); if (queue->first == NULL) queue->end = &queue->first; if (flushResult == -1) { // errno is set return -1; } // If a turn change had been requested by the other side while it was // our turn, we first sent everything we still had to send in our turn. // Now that is done, it is the time to actually give up the turn. if (conn->stateFlags.pendingTurnChange) { assert(conn->stateFlags.myTurn); conn->stateFlags.myTurn = false; conn->stateFlags.pendingTurnChange = false; // Send the confirmation to the other side: if (sendEndTurnDirect(conn) == -1) { // errno is set return -1; } } return 0; }
void queuePacket(NetConnection *conn, Packet *packet, bool urgent) { PacketQueue *queue; PacketQueueLink *link; assert(NetConnection_isConnected(conn)); assert(!urgent || !packetTypeData[packetType(packet)].inTurn); // Urgent packets should never stall the connection. queue = &conn->queue; link = PacketQueueLink_alloc(); link->packet = packet; link->next = NULL; if (urgent) { *queue->endUrgent = link; queue->endUrgent = &link->next; } else { *queue->end = link; queue->end = &link->next; } queue->size++; // XXX: perhaps check that this queue isn't getting too large? #ifdef NETPLAY_DEBUG if (packetType(packet) != PACKET_BATTLEINPUT && packetType(packet) != PACKET_CHECKSUM) { // Reporting BattleInput or Checksum would get so spammy that it // would slow down the battle. log_add(log_Debug, "NETPLAY: [%d] ==> Queueing packet of type %s.\n", NetConnection_getPlayerNr(conn), packetTypeData[packetType(packet)].name); } #endif }
// Post: the NetState for all players is NetState_interBattle static BOOLEAN GetMeleeStarShips (COUNT playerMask, HSTARSHIP *ships) { COUNT playerI; BOOLEAN ok; GETMELEE_STATE gmstate; TimeCount now; COUNT i; #ifdef NETPLAY for (playerI = 0; playerI < NUM_PLAYERS; playerI++) { NetConnection *conn; if ((playerMask & (1 << playerI)) == 0) continue; // XXX: This does not have to be done per connection. conn = netConnections[playerI]; if (conn != NULL) { BattleStateData *battleStateData; battleStateData = (BattleStateData *) NetConnection_getStateData (conn); battleStateData->getMeleeState = &gmstate; } } #endif ok = true; now = GetTimeCounter (); gmstate.InputFunc = DoGetMelee; gmstate.Initialized = FALSE; for (i = 0; i < NUM_PLAYERS; ++i) { // We have to use TFB_Random() results in specific order playerI = GetPlayerOrder (i); gmstate.player[playerI].selecting = (playerMask & (1 << playerI)) != 0; gmstate.player[playerI].ships_left = battle_counter[playerI]; // We determine in advance which ship would be chosen if the player // wants a random ship, to keep it simple to keep network parties // synchronised. gmstate.player[playerI].randomIndex = (COUNT)TFB_Random () % gmstate.player[playerI].ships_left; gmstate.player[playerI].done = FALSE; if (!gmstate.player[playerI].selecting) continue; gmstate.player[playerI].timeIn = now; gmstate.player[playerI].row = 0; gmstate.player[playerI].col = NUM_PICKMELEE_COLUMNS; #ifdef NETPLAY gmstate.player[playerI].remoteSelected = FALSE; #endif gmstate.player[playerI].flashContext = Flash_createHighlight (ScreenContext, NULL); Flash_setMergeFactors (gmstate.player[playerI].flashContext, 2, 3, 2); Flash_setFrameTime (gmstate.player[playerI].flashContext, ONE_SECOND / 16); #ifdef NETPLAY if (PlayerControl[playerI] & NETWORK_CONTROL) Flash_setSpeed (gmstate.player[playerI].flashContext, ONE_SECOND / 2, 0, ONE_SECOND / 2, 0); else #endif { Flash_setSpeed (gmstate.player[playerI].flashContext, 0, ONE_SECOND / 16, 0, ONE_SECOND / 16); } PickMelee_ChangedSelection (&gmstate, playerI); Flash_start (gmstate.player[playerI].flashContext); } #ifdef NETPLAY { // NB. gmstate.player[].randomIndex and gmstate.player[].done must // be initialised before negotiateReadyConnections is completed, to // ensure that they are initialised when the SelectShip packet // arrives. bool allOk = negotiateReadyConnections (true, NetState_selectShip); if (!allOk) { // Some network connection has been reset. ok = false; } } #endif SetDefaultMenuRepeatDelay (); SetContext (OffScreenContext); DoInput (&gmstate, FALSE); WaitForSoundEnd (0); for (playerI = 0; playerI < NUM_PLAYERS; playerI++) { if (!gmstate.player[playerI].selecting) continue; if (gmstate.player[playerI].done) { // Flash rectangle is already terminated. ships[playerI] = gmstate.player[playerI].hBattleShip; } else { Flash_terminate (gmstate.player[playerI].flashContext); gmstate.player[playerI].flashContext = NULL; ok = false; } } #ifdef NETPLAY if (ok) { if (!negotiateReadyConnections (true, NetState_interBattle)) ok = false; } else setStateConnections (NetState_interBattle); #endif if (!ok) { // Aborting. GLOBAL (CurrentActivity) &= ~IN_BATTLE; } #ifdef NETPLAY for (playerI = 0; playerI < NUM_PLAYERS; playerI++) { NetConnection *conn; if ((playerMask & (1 << playerI)) == 0) continue; // XXX: This does not have to be done per connection. conn = netConnections[playerI]; if (conn != NULL && NetConnection_isConnected (conn)) { BattleStateData *battleStateData; battleStateData = (BattleStateData *) NetConnection_getStateData (conn); battleStateData->getMeleeState = NULL; } } #endif return ok; }