/** Receive droid and transporter loading information * * \sa sendDroidEmbark(),sendDroidDisEmbark(),recvDroidDisEmbark() */ BOOL recvDroidEmbark(NETQUEUE queue) { DROID* psDroid; DROID* psTransporterDroid; BOOL bDroidRemoved; NETbeginDecode(queue, GAME_DROIDEMBARK); { uint8_t player; uint32_t droidID; uint32_t transporterID; NETuint8_t(&player); NETuint32_t(&droidID); NETuint32_t(&transporterID); // we have to find the droid on our (local) list first. if (!IdToDroid(droidID, player, &psDroid)) { NETend(); // Possible it already died? (sync error?) debug(LOG_WARNING, "player's %d droid %d wasn't found?", player,droidID); return false; } if (!IdToDroid(transporterID, player, &psTransporterDroid)) { NETend(); // Possible it already died? (sync error?) debug(LOG_WARNING, "player's %d transport droid %d wasn't found?", player,transporterID); return false; } if (psDroid == NULL) { // how can this happen? return true; } // Take it out of the world without destroying it (just removes it from the droid list) bDroidRemoved = droidRemove(psDroid, apsDroidLists); // Init the order for when disembark psDroid->order = DORDER_NONE; setDroidTarget(psDroid, NULL); psDroid->psTarStats = NULL; if (bDroidRemoved) { // and now we need to add it to their transporter group! grpJoin(psTransporterDroid->psGroup, psDroid); } else { // possible sync error? debug(LOG_WARNING, "Eh? Where did unit %d go? Couldn't load droid onto transporter.", droidID); } } NETend(); return true; }
// recv BOOL recvDroidSecondary(NETQUEUE queue) { DROID* psDroid; SECONDARY_ORDER sec = DSO_ATTACK_RANGE; SECONDARY_STATE state = DSS_NONE; NETbeginDecode(queue, GAME_SECONDARY); { uint8_t player; uint32_t droid; NETuint8_t(&player); NETuint32_t(&droid); NETenum(&sec); NETenum(&state); // If we can not find the droid should we not ask for it? if (!IdToDroid(droid, player, &psDroid)) { NETend(); return false; } } NETend(); // Set the droids secondary order turnOffMultiMsg(true); secondarySetState(psDroid, sec, state); turnOffMultiMsg(false); return true; }
// accept and process incoming ping messages. bool recvPing(NETQUEUE queue) { bool isNew = false; uint8_t sender, us = selectedPlayer; uint8_t challenge[sizeof(pingChallenge)]; EcKey::Sig challengeResponse; NETbeginDecode(queue, NET_PING); NETuint8_t(&sender); NETbool(&isNew); if (isNew) { NETbin(challenge, sizeof(pingChallenge)); } else { NETbytes(&challengeResponse); } NETend(); if (sender >= MAX_PLAYERS) { debug(LOG_ERROR, "Bad NET_PING packet, sender is %d", (int)sender); return false; } // If this is a new ping, respond to it if (isNew) { challengeResponse = getMultiStats(us).identity.sign(&challenge, sizeof(pingChallenge)); NETbeginEncode(NETnetQueue(sender), NET_PING); // We are responding to a new ping isNew = false; NETuint8_t(&us); NETbool(&isNew); NETbytes(&challengeResponse); NETend(); } // They are responding to one of our pings else { if (!getMultiStats(sender).identity.empty() && !getMultiStats(sender).identity.verify(challengeResponse, pingChallenge, sizeof(pingChallenge))) { // Either bad signature, or we sent more than one ping packet and this response is to an older one than the latest. debug(LOG_NEVER, "Bad and/or old NET_PING packet, alleged sender is %d", (int)sender); return false; } // Work out how long it took them to respond ingame.PingTimes[sender] = (realTime - PingSend[sender]) / 2; // Note that we have received it PingSend[sender] = 0; } return true; }
// //////////////////////////////////////////////////////////////////////////// // Network File packet processor. bool recvMapFileRequested(NETQUEUE queue) { //char mapStr[256],mapName[256],fixedname[256]; uint32_t player; PHYSFS_sint64 fileSize_64; PHYSFS_file *pFileHandle; if(!NetPlay.isHost) // only host should act { ASSERT(false, "Host only routine detected for client!"); return false; } // Check to see who wants the file NETbeginDecode(queue, NET_FILE_REQUESTED); NETuint32_t(&player); NETend(); if (!NetPlay.players[player].wzFile.isSending) { NetPlay.players[player].needFile = true; NetPlay.players[player].wzFile.isCancelled = false; NetPlay.players[player].wzFile.isSending = true; LEVEL_DATASET *mapData = levFindDataSet(game.map, &game.hash); addConsoleMessage("Map was requested: SENDING MAP!",DEFAULT_JUSTIFY, SYSTEM_MESSAGE); char *mapStr = mapData->realFileName; debug(LOG_NET, "Map was requested. Looking for %s", mapStr); // Checking to see if file is available... pFileHandle = PHYSFS_openRead(mapStr); if (pFileHandle == NULL) { debug(LOG_ERROR, "Failed to open %s for reading: %s", mapStr, PHYSFS_getLastError()); debug(LOG_FATAL, "You have a map (%s) that can't be located.\n\nMake sure it is in the correct directory and or format! (No map packs!)", mapStr); // NOTE: if we get here, then the game is basically over, The host can't send the file for whatever reason... // Which also means, that we can't continue. debug(LOG_NET, "***Host has a file issue, and is being forced to quit!***"); NETbeginEncode(NETbroadcastQueue(), NET_HOST_DROPPED); NETend(); abort(); } // get the file's size. fileSize_64 = PHYSFS_fileLength(pFileHandle); debug(LOG_NET, "File is valid, sending [directory: %s] %s to client %u", PHYSFS_getRealDir(mapStr), mapStr, player); NetPlay.players[player].wzFile.pFileHandle = pFileHandle; NetPlay.players[player].wzFile.fileSize_32 = (int32_t) fileSize_64; //we don't support 64bit int nettypes. NetPlay.players[player].wzFile.currPos = 0; NETsendFile(game.map, game.hash, player); } return true; }
void recvMultiStats(NETQUEUE queue) { uint32_t playerIndex; NETbeginDecode(queue, NET_PLAYER_STATS); // Retrieve the ID number of the player for which we need to // update the stats NETuint32_t(&playerIndex); if (playerIndex >= MAX_PLAYERS) { NETend(); return; } if (playerIndex != queue.index && queue.index != NET_HOST_ONLY) { HandleBadParam("NET_PLAYER_STATS given incorrect params.", playerIndex, queue.index); NETend(); return; } // we don't what to update ourselves, we already know our score (FIXME: rewrite setMultiStats()) if (!myResponsibility(playerIndex)) { // Retrieve the actual stats NETuint32_t(&playerStats[playerIndex].played); NETuint32_t(&playerStats[playerIndex].wins); NETuint32_t(&playerStats[playerIndex].losses); NETuint32_t(&playerStats[playerIndex].totalKills); NETuint32_t(&playerStats[playerIndex].totalScore); NETuint32_t(&playerStats[playerIndex].recentKills); NETuint32_t(&playerStats[playerIndex].recentScore); EcKey::Key identity; NETbytes(&identity); EcKey::Key prevIdentity; if (!playerStats[playerIndex].identity.empty()) { prevIdentity = playerStats[playerIndex].identity.toBytes(EcKey::Public); } playerStats[playerIndex].identity.clear(); if (!identity.empty()) { playerStats[playerIndex].identity.fromBytes(identity, EcKey::Public); } if (identity != prevIdentity) { ingame.PingTimes[playerIndex] = PING_LIMIT; } } NETend(); }
// process a destroy feature msg. bool recvDestroyFeature(NETQUEUE queue) { FEATURE *pF; uint32_t id; NETbeginDecode(queue, GAME_DEBUG_REMOVE_FEATURE); NETuint32_t(&id); NETend(); if (!getDebugMappingStatus() && bMultiPlayer) { debug(LOG_WARNING, "Failed to remove feature for player %u.", NetPlay.players[queue.index].position); return false; } pF = IdToFeature(id,ANYPLAYER); if (pF == NULL) { debug(LOG_FEATURE, "feature id %d not found (probably already destroyed)", id); return false; } debug(LOG_FEATURE, "p%d feature id %d destroyed (%s)", pF->player, pF->id, pF->psStats->pName); // Remove the feature locally turnOffMultiMsg(true); destroyFeature(pF, gameTime - deltaGameTime + 1); // deltaGameTime is actually 0 here, since we're between updates. However, the value of gameTime - deltaGameTime + 1 will not change when we start the next tick. turnOffMultiMsg(false); return true; }
BOOL recvAlliance(BOOL allowAudio) { uint8_t to, from, state; int32_t value; NETbeginDecode(NET_ALLIANCE); NETuint8_t(&from); NETuint8_t(&to); NETuint8_t(&state); NETint32_t(&value); NETend(); switch (state) { case ALLIANCE_NULL: break; case ALLIANCE_REQUESTED: requestAlliance(from, to, false, allowAudio); break; case ALLIANCE_FORMED: formAlliance(from, to, false, allowAudio, true); break; case ALLIANCE_BROKEN: breakAlliance(from, to, false, allowAudio); break; default: debug(LOG_ERROR, "Unknown alliance state recvd."); return false; break; } return true; }
void recvPlayerGameTime(NETQUEUE queue) { uint32_t latencyTicks = 0; uint32_t checkTime = 0; uint32_t checkCrc = 0; NETbeginDecode(queue, GAME_GAME_TIME); NETuint32_t(&latencyTicks); NETuint32_t(&checkTime); NETuint32_tLarge(&checkCrc); NETuint16_t(&wantedLatencies[queue.index]); NETend(); gameQueueTime[queue.index] = checkTime + latencyTicks * GAME_TICKS_PER_UPDATE; // gameTime when future messages shall be processed. gameQueueCheckTime[queue.index] = checkTime; gameQueueCheckCrc[queue.index] = checkCrc; if (!checkDebugSync(checkTime, checkCrc)) { crcError = true; if (NetPlay.players[queue.index].allocated) { NETsetPlayerConnectionStatus(CONNECTIONSTATUS_DESYNC, queue.index); } } if (updateReadyTime == 0 && checkPlayerGameTime(NET_ALL_PLAYERS)) { updateReadyTime = wzGetTicks(); // This is the time we were able to tick. } }
// //////////////////////////////////////////////////////////////////////////// // Set Player's stats // send stats to all players when bLocal is false BOOL setMultiStats(SDWORD player, PLAYERSTATS plStats, BOOL bLocal) { uint32_t playerIndex = (uint32_t)player; if (playerIndex >= MAX_PLAYERS) { return true; } // First copy over the data into our local array memcpy(&playerStats[playerIndex], &plStats, sizeof(plStats)); if (!bLocal) { // Now send it to all other players NETbeginEncode(NETbroadcastQueue(), NET_PLAYER_STATS); // Send the ID of the player's stats we're updating NETuint32_t(&playerIndex); // Send over the actual stats NETuint32_t(&playerStats[playerIndex].played); NETuint32_t(&playerStats[playerIndex].wins); NETuint32_t(&playerStats[playerIndex].losses); NETuint32_t(&playerStats[playerIndex].totalKills); NETuint32_t(&playerStats[playerIndex].totalScore); NETuint32_t(&playerStats[playerIndex].recentKills); NETuint32_t(&playerStats[playerIndex].recentScore); NETuint32_t(&playerStats[playerIndex].killsToAdd); NETuint32_t(&playerStats[playerIndex].scoreToAdd); NETend(); } return true; }
void recvMultiPlayerFeature(NETQUEUE queue) { FEATURE_TYPE subType = FEAT_TREE; // Dummy initialisation. uint32_t x, y, id; unsigned int i; NETbeginDecode(queue, GAME_FEATURES); { NETenum(&subType); NETuint32_t(&x); NETuint32_t(&y); NETuint32_t(&id); } NETend(); // Find the feature stats list that contains the feature type we want to build for (i = 0; i < numFeatureStats; ++i) { // If we found the correct feature type if (asFeatureStats[i].subType == subType) { // Create a feature of the specified type at the given location FEATURE *result = buildFeature(&asFeatureStats[i], x, y, false); result->id = id; break; } } }
// recv lassat info on the receiving end. BOOL recvLasSat(NETQUEUE queue) { BASE_OBJECT *psObj; UBYTE player,targetplayer; STRUCTURE *psStruct; uint32_t id,targetid; // TODO Add some kind of checking, so that things don't get lasatted by bunkers. NETbeginDecode(queue, GAME_LASSAT); NETuint8_t(&player); NETuint32_t(&id); NETuint32_t(&targetid); NETuint8_t(&targetplayer); NETend(); psStruct = IdToStruct (id, player); psObj = IdToPointer(targetid, targetplayer); if (psStruct && psObj) { // Give enemy no quarter, unleash the lasat proj_SendProjectile(&psStruct->asWeaps[0], NULL, player, psObj->pos, psObj, true, 0); psStruct->asWeaps[0].lastFired = gameTime; // Play 5 second countdown message audio_QueueTrackPos( ID_SOUND_LAS_SAT_COUNTDOWN, psObj->pos.x, psObj->pos.y, psObj->pos.z); } return true; }
// //////////////////////////////////////////////////////////////////////////// // give radar information void giftRadar(uint8_t from, uint8_t to, bool send) { uint32_t dummy = 0; if (send) { uint8_t subType = RADAR_GIFT; NETbeginEncode(NETgameQueue(selectedPlayer), GAME_GIFT); NETuint8_t(&subType); NETuint8_t(&from); NETuint8_t(&to); NETuint32_t(&dummy); NETend(); } // If we are recieving the gift else { hqReward(from, to); if (to == selectedPlayer) { CONPRINTF(ConsoleString, (ConsoleString, _("%s Gives You A Visibility Report"), getPlayerName(from))); } } }
static void giftAutoGame(uint8_t from, uint8_t to, bool send) { uint32_t dummy = 0; if (send) { uint8_t subType = AUTOGAME_GIFT; NETbeginEncode(NETgameQueue(selectedPlayer), GAME_GIFT); NETuint8_t(&subType); NETuint8_t(&from); NETuint8_t(&to); NETuint32_t(&dummy); NETend(); debug(LOG_SYNC, "We (%d) are telling %d we want to enable/disable a autogame", from, to); } // If we are recieving the "gift" else { if (to == selectedPlayer) { NetPlay.players[from].autoGame = !NetPlay.players[from].autoGame ; CONPRINTF(ConsoleString, (ConsoleString, "%s has %s the autoGame command", getPlayerName(from), NetPlay.players[from].autoGame ? "Enabled" : "Disabled")); debug(LOG_SYNC, "We (%d) are being told that %d has %s autogame", selectedPlayer, from, NetPlay.players[from].autoGame ? "Enabled" : "Disabled"); } } }
bool recvGift(NETQUEUE queue) { uint8_t type, from, to; int audioTrack; uint32_t droidID; NETbeginDecode(queue, GAME_GIFT); NETuint8_t(&type); NETuint8_t(&from); NETuint8_t(&to); NETuint32_t(&droidID); NETend(); if (!canGiveOrdersFor(queue.index, from)) { debug(LOG_WARNING, "Gift (%d) from %d, to %d, queue.index %d", (int)type, (int)from, (int)to, (int)queue.index); syncDebug("Wrong player."); return false; } // Handle the gift depending on what it is switch (type) { case RADAR_GIFT: audioTrack = ID_SENSOR_DOWNLOAD; giftRadar(from, to, false); break; case DROID_GIFT: audioTrack = ID_UNITS_TRANSFER; recvGiftDroids(from, to, droidID); break; case STRUCTURE_GIFT: audioTrack = ID_GIFT; recvGiftStruct(from, to, droidID); break; case RESEARCH_GIFT: audioTrack = ID_TECHNOLOGY_TRANSFER; giftResearch(from, to, false); break; case POWER_GIFT: audioTrack = ID_POWER_TRANSMIT; giftPower(from, to, droidID, false); break; case AUTOGAME_GIFT: audioTrack = ID_SOUND_NEXUS_SYNAPTIC_LINK; giftAutoGame(from, to, false); break; default: debug(LOG_ERROR, "recvGift: Unknown Gift recvd"); return false; break; } // If we are on the receiving end play an audio alert. if (bMultiPlayer && to == selectedPlayer) { audio_QueueTrack(audioTrack); } return true; }
// recv lassat info on the receiving end. BOOL recvLasSat() { BASE_OBJECT *psObj; UBYTE player,targetplayer; STRUCTURE *psStruct; uint32_t id,targetid; NETbeginDecode(NET_LASSAT); NETuint8_t(&player); NETuint32_t(&id); NETuint32_t(&targetid); NETuint8_t(&targetplayer); NETend(); psStruct = IdToStruct (id, player); psObj = IdToPointer(targetid, targetplayer); if (psStruct && psObj) { // Give enemy no quarter, unleash the lasat proj_SendProjectile(&psStruct->asWeaps[0], NULL, player, psObj->pos, psObj, true, 0); // Play 5 second countdown message audio_QueueTrackPos( ID_SOUND_LAS_SAT_COUNTDOWN, psObj->pos.x, psObj->pos.y, psObj->pos.z); } return true; }
// send complete game info set! void sendOptions() { bool dummy = true; unsigned int i; if (!NetPlay.isHost || !bHosted) // Only host should act, and only if the game hasn't started yet. { ASSERT(false, "Host only routine detected for client or not hosting yet!"); return; } NETbeginEncode(NETbroadcastQueue(), NET_OPTIONS); // First send information about the game NETuint8_t(&game.type); NETstring(game.map, 128); NETuint8_t(&game.maxPlayers); NETstring(game.name, 128); NETbool(&dummy); NETuint32_t(&game.power); NETuint8_t(&game.base); NETuint8_t(&game.alliance); NETbool(&game.scavengers); for (i = 0; i < MAX_PLAYERS; i++) { NETuint8_t(&game.skDiff[i]); } // Send the list of who is still joining for (i = 0; i < MAX_PLAYERS; i++) { NETbool(&ingame.JoiningInProgress[i]); } // Same goes for the alliances for (i = 0; i < MAX_PLAYERS; i++) { unsigned int j; for (j = 0; j < MAX_PLAYERS; j++) { NETuint8_t(&alliances[i][j]); } } // Send the number of structure limits to expect NETuint32_t(&ingame.numStructureLimits); debug(LOG_NET, "(Host) Structure limits to process on client is %u", ingame.numStructureLimits); // Send the structures changed for (i = 0; i < ingame.numStructureLimits; i++) { NETuint32_t(&ingame.pStructureLimits[i].id); NETuint32_t(&ingame.pStructureLimits[i].limit); } updateLimitFlags(); NETuint8_t(&ingame.flags); NETend(); }
// //////////////////////////////////////////////////////////////////////////// // Set Player's stats // send stats to all players when bLocal is false bool setMultiStats(uint32_t playerIndex, PLAYERSTATS plStats, bool bLocal) { if (playerIndex >= MAX_PLAYERS) { return true; } // First copy over the data into our local array playerStats[playerIndex] = plStats; if (!bLocal) { // Now send it to all other players NETbeginEncode(NETbroadcastQueue(), NET_PLAYER_STATS); // Send the ID of the player's stats we're updating NETuint32_t(&playerIndex); // Send over the actual stats NETuint32_t(&playerStats[playerIndex].played); NETuint32_t(&playerStats[playerIndex].wins); NETuint32_t(&playerStats[playerIndex].losses); NETuint32_t(&playerStats[playerIndex].totalKills); NETuint32_t(&playerStats[playerIndex].totalScore); NETuint32_t(&playerStats[playerIndex].recentKills); NETuint32_t(&playerStats[playerIndex].recentScore); NETend(); } return true; }
// //////////////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////////////// // New research stuff, so you can see what others are up to! // inform others that I'm researching this. bool sendResearchStatus(STRUCTURE *psBuilding, uint32_t index, uint8_t player, bool bStart) { if (!myResponsibility(player) || gameTime < 5) { return true; } NETbeginEncode(NETgameQueue(selectedPlayer), GAME_RESEARCHSTATUS); NETuint8_t(&player); NETbool(&bStart); // If we know the building researching it then send its ID if (psBuilding) { NETuint32_t(&psBuilding->id); } else { uint32_t zero = 0; NETuint32_t(&zero); } // Finally the topic in question NETuint32_t(&index); NETend(); // Tell UI to remove from the list of available research. MakeResearchStartedPending(&asPlayerResList[player][index]); return true; }
BOOL recvDemolishFinished(NETQUEUE queue) { STRUCTURE *psStruct; DROID *psDroid; uint32_t structID, droidID; NETbeginDecode(queue, GAME_DEMOLISH); NETuint32_t(&structID); NETuint32_t(&droidID); NETend(); psStruct = IdToStruct(structID, ANYPLAYER); if (!IdToDroid(droidID, ANYPLAYER, &psDroid)) { debug(LOG_ERROR, "recvDemolishFinished: Packet with bad droid ID received. Discarding!"); return false; } if (psStruct) { // Demolish it // Should never get here, if in synch. removeStruct(psStruct, true); if (psDroid && psDroid->psTarStats) { // Update droid if reqd psDroid->psTarStats = NULL; } } return true; }
// //////////////////////////////////////////////////////////////////////////// // Accept a droid which was destroyed on another machine BOOL recvDestroyDroid(NETQUEUE queue) { DROID* psDroid; NETbeginDecode(queue, GAME_DROIDDEST); { uint32_t id; // Retrieve the droid NETuint32_t(&id); if (!IdToDroid(id, ANYPLAYER, &psDroid)) { debug(LOG_DEATH, "droid %d on request from player %d can't be found? Must be dead already?", id, queue.index ); return false; } } NETend(); // If the droid has not died on our machine yet, destroy it if(!psDroid->died) { turnOffMultiMsg(true); debug(LOG_DEATH, "Killing droid %d on request from player %d - huh?", psDroid->id, queue.index); destroyDroid(psDroid); turnOffMultiMsg(false); } else { debug(LOG_DEATH, "droid %d is confirmed dead by player %d.", psDroid->id, queue.index); } return true; }
// //////////////////////////////////////////////////////////////////////////// // give technologies. static void giftResearch(uint8_t from, uint8_t to, bool send) { int i; uint32_t dummy = 0; if (send) { uint8_t giftType = RESEARCH_GIFT; NETbeginEncode(NETgameQueue(selectedPlayer), GAME_GIFT); NETuint8_t(&giftType); NETuint8_t(&from); NETuint8_t(&to); NETuint32_t(&dummy); NETend(); } else if (alliancesCanGiveResearchAndRadar(game.alliance)) { if (to == selectedPlayer) { CONPRINTF(ConsoleString, (ConsoleString, _("%s Gives You Technology Documents"), getPlayerName(from))); } // For each topic for (i = 0; i < asResearch.size(); i++) { // If they have it and we don't research it if (IsResearchCompleted(&asPlayerResList[from][i]) && !IsResearchCompleted(&asPlayerResList[to][i])) { MakeResearchCompleted(&asPlayerResList[to][i]); researchResult(i, to, false, NULL, true); } } } }
// //////////////////////////////////////////////////////////////////////////// // acknowledge the destruction of a structure, from another player. bool recvDestroyStructure(NETQUEUE queue) { uint32_t structID; STRUCTURE *psStruct; NETbeginDecode(queue, GAME_DEBUG_REMOVE_STRUCTURE); NETuint32_t(&structID); NETend(); if (!getDebugMappingStatus() && bMultiPlayer) { debug(LOG_WARNING, "Failed to remove structure for player %u.", NetPlay.players[queue.index].position); return false; } // Struct to destory psStruct = IdToStruct(structID, ANYPLAYER); if (psStruct) { turnOffMultiMsg(true); // Remove the struct from remote players machine destroyStruct(psStruct, gameTime - deltaGameTime + 1); // deltaGameTime is actually 0 here, since we're between updates. However, the value of gameTime - deltaGameTime + 1 will not change when we start the next tick. turnOffMultiMsg(false); // NOTE: I do not think this should be here! technologyGiveAway(psStruct); } return true; }
// Actually send the droid info. void sendQueuedDroidInfo() { // Sort queued orders, to group the same order to multiple droids. std::sort(queuedOrders.begin(), queuedOrders.end()); std::vector<QueuedDroidInfo>::iterator eqBegin, eqEnd; for (eqBegin = queuedOrders.begin(); eqBegin != queuedOrders.end(); eqBegin = eqEnd) { // Find end of range of orders which differ only by the droid ID. for (eqEnd = eqBegin + 1; eqEnd != queuedOrders.end() && eqEnd->orderCompare(*eqBegin) == 0; ++eqEnd) {} NETbeginEncode(NETgameQueue(selectedPlayer), GAME_DROIDINFO); NETQueuedDroidInfo(&*eqBegin); uint32_t num = eqEnd - eqBegin; NETuint32_t(&num); uint32_t prevDroidId = 0; for (unsigned n = 0; n < num; ++n) { uint32_t droidId = (eqBegin + n)->droidId; // Encode deltas between droid IDs, since the deltas are smaller than the actual droid IDs, and will encode to less bytes on average. uint32_t deltaDroidId = droidId - prevDroidId; NETuint32_t(&deltaDroidId); prevDroidId = droidId; } NETend(); } // Sent the orders. Don't send them again. queuedOrders.clear(); }
void recvMultiPlayerFeature(NETQUEUE queue) { uint32_t ref = 0xff, x = 0, y = 0, id = 0; unsigned int i; NETbeginDecode(queue, GAME_DEBUG_ADD_FEATURE); { NETuint32_t(&ref); NETuint32_t(&x); NETuint32_t(&y); NETuint32_t(&id); } NETend(); if (!getDebugMappingStatus() && bMultiPlayer) { debug(LOG_WARNING, "Failed to add feature for player %u.", NetPlay.players[queue.index].position); return; } // Find the feature stats list that contains the feature type we want to build for (i = 0; i < numFeatureStats; ++i) { // If we found the correct feature type if (asFeatureStats[i].ref == ref) { // Create a feature of the specified type at the given location FEATURE *result = buildFeature(&asFeatureStats[i], x, y, false); result->id = id; break; } } }
// //////////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////////// // Power Checking. Send a power level check every now and again. static BOOL sendPowerCheck() { uint8_t player; if (powerCheckLastSent > gameTime) { powerCheckLastSent = 0; } // Only send if not done recently if (gameTime - powerCheckLastSent < POWER_PERIOD) { return true; } powerCheckLastSent = gameTime; for (player = 0; player < MAX_PLAYERS; ++player) { powerCheckLastPower[player] = getPrecisePower(player); if (myResponsibility(player)) { if (!isInSync()) // Don't really send anything, unless out of synch. { NETbeginEncode(NETgameQueue(selectedPlayer), GAME_CHECK_POWER); NETuint8_t(&player); NETuint32_t(&gameTime); NETint64_t(&powerCheckLastPower[player]); NETend(); } } } return true; }
// // At this time, we do NOT support messages for beacons // bool sendBeacon(int32_t locX, int32_t locY, int32_t forPlayer, int32_t sender, const char* pStr) { int sendPlayer; //debug(LOG_WZ, "sendBeacon: '%s'",pStr); //find machine that is hosting this human or AI sendPlayer = whosResponsible(forPlayer); if(sendPlayer >= MAX_PLAYERS) { debug(LOG_ERROR, "sendAIMessage() - whosResponsible() failed."); return false; } // I assume this is correct, looks like it sends it to ONLY that person, and the routine // kf_AddHelpBlip() iterates for each player it needs. NETbeginEncode(NETnetQueue(sendPlayer), NET_BEACONMSG); // send to the player who is hosting 'to' player (might be himself if human and not AI) NETint32_t(&sender); // save the actual sender // save the actual player that is to get this msg on the source machine (source can host many AIs) NETint32_t(&forPlayer); // save the actual receiver (might not be the same as the one we are actually sending to, in case of AIs) NETint32_t(&locX); // save location NETint32_t(&locY); // const_cast: need to cast away constness because of the const-incorrectness of NETstring (const-incorrect when sending/encoding a packet) NETstring((char*)pStr, MAX_CONSOLE_STRING_LENGTH); // copy message in. NETend(); return true; }
void recvMultiStats(NETQUEUE queue) { uint32_t playerIndex; NETbeginDecode(queue, NET_PLAYER_STATS); // Retrieve the ID number of the player for which we need to // update the stats NETuint32_t(&playerIndex); if (playerIndex >= MAX_PLAYERS) { return; } // we don't what to update ourselves, we already know our score (FIXME: rewrite setMultiStats()) if (!myResponsibility(playerIndex)) { // Retrieve the actual stats NETuint32_t(&playerStats[playerIndex].played); NETuint32_t(&playerStats[playerIndex].wins); NETuint32_t(&playerStats[playerIndex].losses); NETuint32_t(&playerStats[playerIndex].totalKills); NETuint32_t(&playerStats[playerIndex].totalScore); NETuint32_t(&playerStats[playerIndex].recentKills); NETuint32_t(&playerStats[playerIndex].recentScore); NETuint32_t(&playerStats[playerIndex].killsToAdd); NETuint32_t(&playerStats[playerIndex].scoreToAdd); } NETend(); }
// send a newly created template to other players bool sendTemplate(uint32_t player, DROID_TEMPLATE *pTempl) { NETbeginEncode(NETgameQueue(selectedPlayer), GAME_TEMPLATE); NETuint32_t(&player); NETtemplate(pTempl); return NETend(); }
void recvProcessDebugMappings(NETQUEUE queue) { bool val = false; NETbeginDecode(queue, GAME_DEBUG_MODE); NETbool(&val); NETend(); bool oldDebugMode = getDebugMappingStatus(); processDebugMappings(queue.index, val); bool newDebugMode = getDebugMappingStatus(); char const *cmsg; if (val) { sasprintf((char**)&cmsg, _("%s wants to enable debug mode. Enabled: %s, Disabled: %s."), getPlayerName(queue.index), getWantedDebugMappingStatuses(true).c_str(), getWantedDebugMappingStatuses(false).c_str()); } else { sasprintf((char**)&cmsg, _("%s wants to disable debug mode. Enabled: %s, Disabled: %s."), getPlayerName(queue.index), getWantedDebugMappingStatuses(true).c_str(), getWantedDebugMappingStatuses(false).c_str()); } addConsoleMessage(cmsg, DEFAULT_JUSTIFY, SYSTEM_MESSAGE); if (!oldDebugMode && newDebugMode) { addConsoleMessage(_("Debug mode now enabled!"), DEFAULT_JUSTIFY, SYSTEM_MESSAGE); } else if (oldDebugMode && !newDebugMode) { addConsoleMessage(_("Debug mode now disabled!"), DEFAULT_JUSTIFY, SYSTEM_MESSAGE); } }
// //////////////////////////////////////////////////////////////////////////// // give Power void giftPower(uint8_t from, uint8_t to, BOOL send) { UDWORD gifval; uint32_t dummy = 0; if (from == ANYPLAYER) { gifval = OILDRUM_POWER; } else { // Give 1/3 of our power away gifval = getPower(from) / 3; usePower(from, gifval); } addPower(to, gifval); if (send) { uint8_t giftType = POWER_GIFT; NETbeginEncode(NET_GIFT, NET_ALL_PLAYERS); NETuint8_t(&giftType); NETuint8_t(&from); NETuint8_t(&to); NETuint32_t(&dummy); NETend(); } else if (to == selectedPlayer) { CONPRINTF(ConsoleString,(ConsoleString,_("%s Gives You %u Power"),getPlayerName(from),gifval)); } }