// //////////////////////////////////////////////////////////////////////////// // 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; }
// //////////////////////////////////////////////////////////////////////////// // 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; }
// 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; }
// 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; }
void recvPlayerLeft(NETQUEUE queue) { uint32_t playerIndex = 0; NETbeginDecode(queue, GAME_PLAYER_LEFT); NETuint32_t(&playerIndex); NETend(); turnOffMultiMsg(true); clearPlayer(playerIndex, false); // don't do it quietly turnOffMultiMsg(false); }
// //////////////////////////////////////////////////////////////////////////// // acknowledge the destruction of a structure, from another player. BOOL recvDestroyStructure(NETMSG * m) { UDWORD s; STRUCTURE *psStr; NetGet(m,0,s); // struct to destory psStr = IdToStruct(s,ANYPLAYER); if (psStr) { turnOffMultiMsg(TRUE); destroyStruct(psStr); // remove the struct from remote players machine. turnOffMultiMsg(FALSE); technologyGiveAway(psStr); return (TRUE); } return (TRUE); }
// //////////////////////////////////////////////////////////////////////////// // Accept a droid which was destroyed on another machine bool recvDestroyDroid(NETQUEUE queue) { DROID* psDroid; NETbeginDecode(queue, GAME_DEBUG_REMOVE_DROID); { uint32_t id; // Retrieve the droid NETuint32_t(&id); psDroid = IdToDroid(id, ANYPLAYER); if (!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 (!getDebugMappingStatus()) { debug(LOG_WARNING, "Failed to remove droid for player %u.", NetPlay.players[queue.index].position); return false; } // 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, gameTime); turnOffMultiMsg(false); } else { debug(LOG_DEATH, "droid %d is confirmed dead by player %d.", psDroid->id, queue.index); } return true; }
// //////////////////////////////////////////////////////////////////////////// // Accept a droid which was destroyed on another machine bool recvDestroyDroid(NETQUEUE queue) { DROID *psDroid; NETbeginDecode(queue, GAME_DEBUG_REMOVE_DROID); { uint32_t id; // Retrieve the droid NETuint32_t(&id); psDroid = IdToDroid(id, ANYPLAYER); if (!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 (!getDebugMappingStatus() && bMultiPlayer) { debug(LOG_WARNING, "Failed to remove droid for player %u.", NetPlay.players[queue.index].position); return false; } // 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, 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); } else { debug(LOG_DEATH, "droid %d is confirmed dead by player %d.", psDroid->id, queue.index); } return true; }
void recvPlayerLeft(NETQUEUE queue) { uint32_t playerIndex = 0; NETbeginDecode(queue, GAME_PLAYER_LEFT); NETuint32_t(&playerIndex); NETend(); addConsolePlayerLeftMessage(playerIndex); if (whosResponsible(playerIndex) != queue.index) { return; } turnOffMultiMsg(true); clearPlayer(playerIndex, false); // don't do it quietly turnOffMultiMsg(false); NetPlay.players[playerIndex].allocated = false; NETsetPlayerConnectionStatus(CONNECTIONSTATUS_PLAYER_DROPPED, playerIndex); debug(LOG_INFO, "** player %u has dropped, in-game!", playerIndex); }
void recvPlayerLeft(NETQUEUE queue) { uint32_t playerIndex = 0; NETbeginDecode(queue, GAME_PLAYER_LEFT); NETuint32_t(&playerIndex); NETend(); if (whosResponsible(playerIndex) != queue.index) { return; } turnOffMultiMsg(true); clearPlayer(playerIndex, false); // don't do it quietly turnOffMultiMsg(false); NetPlay.players[playerIndex].allocated = false; char buf[256]; ssprintf(buf, _("%s has Left the Game"), getPlayerName(playerIndex)); addConsoleMessage(buf, DEFAULT_JUSTIFY, SYSTEM_MESSAGE); NETsetPlayerConnectionStatus(CONNECTIONSTATUS_PLAYER_DROPPED, playerIndex); debug(LOG_INFO, "** player %u has dropped, in-game!", playerIndex); }
// //////////////////////////////////////////////////////////////////////////// // acknowledge the destruction of a structure, from another player. BOOL recvDestroyStructure(NETQUEUE queue) { uint32_t structID; STRUCTURE *psStruct; NETbeginDecode(queue, GAME_STRUCTDEST); NETuint32_t(&structID); NETend(); // Struct to destory psStruct = IdToStruct(structID,ANYPLAYER); if (psStruct) { turnOffMultiMsg(true); // Remove the struct from remote players machine destroyStruct(psStruct); turnOffMultiMsg(false); // NOTE: I do not think this should be here! technologyGiveAway(psStruct); } return true; }
bool recvAlliance(NETQUEUE queue, bool allowAudio) { uint8_t to, from, state; int32_t value; NETbeginDecode(queue, GAME_ALLIANCE); NETuint8_t(&from); NETuint8_t(&to); NETuint8_t(&state); NETint32_t(&value); NETend(); switch (state) { case ALLIANCE_NULL: break; case ALLIANCE_REQUESTED: turnOffMultiMsg(true); requestAlliance(from, to, false, allowAudio); turnOffMultiMsg(false); break; case ALLIANCE_FORMED: turnOffMultiMsg(true); formAlliance(from, to, false, allowAudio, true); turnOffMultiMsg(false); break; case ALLIANCE_BROKEN: turnOffMultiMsg(true); breakAlliance(from, to, false, allowAudio); turnOffMultiMsg(false); break; default: debug(LOG_ERROR, "Unknown alliance state recvd."); return false; break; } return true; }
// //////////////////////////////////////////////////////////////////////////// // receive droid information form other players. bool recvDroidInfo(NETQUEUE queue) { NETbeginDecode(queue, GAME_DROIDINFO); { QueuedDroidInfo info; memset(&info, 0x00, sizeof(info)); NETQueuedDroidInfo(&info); STRUCTURE_STATS *psStats = NULL; if (info.subType == LocOrder && (info.order == DORDER_BUILD || info.order == DORDER_LINEBUILD)) { // Find structure target for (unsigned typeIndex = 0; typeIndex < numStructureStats; typeIndex++) { if (asStructureStats[typeIndex].ref == info.structRef) { psStats = asStructureStats + typeIndex; break; } } } switch (info.subType) { case ObjOrder: syncDebug("Order=%s,%d(%d)", getDroidOrderName(info.order), info.destId, info.destType); break; case LocOrder: syncDebug("Order=%s,(%d,%d)", getDroidOrderName(info.order), info.pos.x, info.pos.y); break; case SecondaryOrder: syncDebug("SecondaryOrder=%d,%08X", (int)info.secOrder, (int)info.secState); break; } DROID_ORDER_DATA sOrder = infoToOrderData(info, psStats); uint32_t num = 0; NETuint32_t(&num); for (unsigned n = 0; n < num; ++n) { // Get the next droid ID which is being given this order. uint32_t deltaDroidId = 0; NETuint32_t(&deltaDroidId); info.droidId += deltaDroidId; DROID *psDroid = IdToDroid(info.droidId, info.player); if (!psDroid) { debug(LOG_NEVER, "Packet from %d refers to non-existent droid %u, [%s : p%d]", queue.index, info.droidId, isHumanPlayer(info.player) ? "Human" : "AI", info.player); syncDebug("Droid %d missing", info.droidId); continue; // Can't find the droid, so skip this droid. } CHECK_DROID(psDroid); syncDebugDroid(psDroid, '<'); switch (info.subType) { case ObjOrder: case LocOrder: /* * If the current order not is a command order and we are not a * commander yet are in the commander group remove us from it. */ if (hasCommander(psDroid)) { psDroid->psGroup->remove(psDroid); } if (sOrder.psObj != TargetMissing) // Only do order if the target didn't die. { if (!info.add) { orderDroidListEraseRange(psDroid, 0, psDroid->listSize + 1); // Clear all non-pending orders, plus the first pending order (which is probably the order we just received). orderDroidBase(psDroid, &sOrder); // Execute the order immediately (even if in the middle of another order. } else { orderDroidAdd(psDroid, &sOrder); // Add the order to the (non-pending) list. Will probably overwrite the corresponding pending order, assuming all pending orders were written to the list. } } break; case SecondaryOrder: // Set the droids secondary order turnOffMultiMsg(true); secondarySetState(psDroid, info.secOrder, info.secState); turnOffMultiMsg(false); break; } syncDebugDroid(psDroid, '>'); CHECK_DROID(psDroid); } } NETend(); return true; }
// //////////////////////////////////////////////////////////////////////////// // receive a check and update the local world state accordingly BOOL recvDroidCheck(NETQUEUE queue) { uint8_t count; int i; uint32_t synchTime; NETbeginDecode(queue, GAME_CHECK_DROID); // Get the number of droids to expect NETuint8_t(&count); NETuint32_t(&synchTime); // Get game time. for (i = 0; i < count; i++) { DROID * pD; PACKAGED_CHECK pc, pc2; Position precPos; NETPACKAGED_CHECK(&pc); // Find the droid in question if (!IdToDroid(pc.droidID, pc.player, &pD)) { NETlogEntry("Recvd Unknown droid info. val=player", SYNC_FLAG, pc.player); debug(LOG_SYNC, "Received checking info for an unknown (as yet) droid. player:%d ref:%d", pc.player, pc.droidID); continue; } syncDebugDroid(pD, '<'); if (pD->gameCheckDroid == NULL) { debug(LOG_SYNC, "We got a droid %u synch, but we couldn't find the droid!", pc.droidID); continue; // Can't synch, since we didn't save data to be able to calculate a delta. } pc2 = *(PACKAGED_CHECK *)pD->gameCheckDroid; // pc2 should be declared here, as const. if (pc2.gameTime != synchTime + MIN_DELAY_BETWEEN_DROID_SYNCHS) { debug(LOG_SYNC, "We got a droid %u synch, but we didn't choose the same droid to synch.", pc.droidID); ((PACKAGED_CHECK *)pD->gameCheckDroid)->gameTime = synchTime + MIN_DELAY_BETWEEN_DROID_SYNCHS; // Get droid synch time back in synch. continue; // Can't synch, since we didn't save data to be able to calculate a delta. } #define MERGECOPY(x, y, z) if (pc.y != pc2.y) { debug(LOG_SYNC, "Droid %u out of synch, changing "#x" from %"z" to %"z".", pc.droidID, x, pc.y); x = pc.y; } #define MERGEDELTA(x, y, z) if (pc.y != pc2.y) { debug(LOG_SYNC, "Droid %u out of synch, changing "#x" from %"z" to %"z".", pc.droidID, x, x + pc.y - pc2.y); x += pc.y - pc2.y; } // player not synched here... precPos = droidGetPrecisePosition(pD); MERGEDELTA(precPos.x, pos.x, "d"); MERGEDELTA(precPos.y, pos.y, "d"); MERGEDELTA(precPos.z, pos.z, "d"); droidSetPrecisePosition(pD, precPos); MERGEDELTA(pD->rot.direction, rot.direction, "d"); MERGEDELTA(pD->rot.pitch, rot.pitch, "d"); MERGEDELTA(pD->rot.roll, rot.roll, "d"); MERGEDELTA(pD->body, body, "u"); if (pD->body > pD->originalBody) { pD->body = pD->originalBody; debug(LOG_SYNC, "Droid %u body was too high after synch, reducing to %u.", pc.droidID, pD->body); } MERGEDELTA(pD->experience, experience, "u"); if (pc.pos.x != pc2.pos.x || pc.pos.y != pc2.pos.y) { // snap droid(if on ground) to terrain level at x,y. if ((asPropulsionStats + pD->asBits[COMP_PROPULSION].nStat)->propulsionType != PROPULSION_TYPE_LIFT) // if not airborne. { pD->pos.z = map_Height(pD->pos.x, pD->pos.y); } } // Doesn't cover all cases, but at least doesn't actively break stuff randomly. switch (pc.order) { case DORDER_MOVE: if (pc.order != pc2.order || pc.orderX != pc2.orderX || pc.orderY != pc2.orderY) { debug(LOG_SYNC, "Droid %u out of synch, changing order from %s to %s(%d, %d).", pc.droidID, getDroidOrderName(pc2.order), getDroidOrderName(pc.order), pc.orderX, pc.orderY); // reroute the droid. orderDroidLoc(pD, pc.order, pc.orderX, pc.orderY, ModeImmediate); } break; case DORDER_ATTACK: if (pc.order != pc2.order || pc.targetID != pc2.targetID) { BASE_OBJECT *obj = IdToPointer(pc.targetID, ANYPLAYER); if (obj != NULL) { debug(LOG_SYNC, "Droid %u out of synch, changing order from %s to %s(%u).", pc.droidID, getDroidOrderName(pc2.order), getDroidOrderName(pc.order), pc.targetID); // remote droid is attacking, not here tho! orderDroidObj(pD, pc.order, IdToPointer(pc.targetID, ANYPLAYER), ModeImmediate); } else { debug(LOG_SYNC, "Droid %u out of synch, would change order from %s to %s(%u), but can't find target.", pc.droidID, getDroidOrderName(pc2.order), getDroidOrderName(pc.order), pc.targetID); } } break; case DORDER_NONE: case DORDER_GUARD: if (pc.order != pc2.order) { DROID_ORDER_DATA sOrder; memset(&sOrder, 0, sizeof(DROID_ORDER_DATA)); sOrder.order = pc.order; debug(LOG_SYNC, "Droid %u out of synch, changing order from %s to %s.", pc.droidID, getDroidOrderName(pc2.order), getDroidOrderName(pc.order)); turnOffMultiMsg(true); moveStopDroid(pD); orderDroidBase(pD, &sOrder); turnOffMultiMsg(false); } break; default: break; // Don't know what to do, but at least won't be actively breaking anything. } MERGECOPY(pD->secondaryOrder, secondaryOrder, "u"); // The old code set this after changing orders, so doing that in case. #undef MERGECOPY #undef MERGEDELTA syncDebugDroid(pD, '>'); // ...and repeat! } NETend(); return true; }
void formAlliance(uint8_t p1, uint8_t p2, BOOL prop, BOOL allowAudio, BOOL allowNotification) { DROID *psDroid; char tm1[128]; // Don't add message if already allied if (bMultiPlayer && alliances[p1][p2] != ALLIANCE_FORMED && allowNotification) { sstrcpy(tm1, getPlayerName(p1)); CONPRINTF(ConsoleString,(ConsoleString,_("%s Forms An Alliance With %s"),tm1,getPlayerName(p2))); } alliances[p1][p2] = ALLIANCE_FORMED; alliances[p2][p1] = ALLIANCE_FORMED; if (game.alliance == ALLIANCES_TEAMS) // this is for shared vision only { alliancebits[p1] |= 1 << p2; alliancebits[p2] |= 1 << p1; } if (allowAudio && (p1 == selectedPlayer || p2== selectedPlayer)) { audio_QueueTrack(ID_ALLIANCE_ACC); } if (bMultiMessages && prop) { sendAlliance(p1, p2, ALLIANCE_FORMED, false); } // Not campaign and alliances are transitive if (game.alliance == ALLIANCES_TEAMS) { giftRadar(p1, p2, false); giftRadar(p2, p1, false); } // Clear out any attacking orders turnOffMultiMsg(true); for (psDroid = apsDroidLists[p1]; psDroid; psDroid = psDroid->psNext) // from -> to { if (psDroid->order == DORDER_ATTACK && psDroid->psTarget && psDroid->psTarget->player == p2) { orderDroid(psDroid, DORDER_STOP); } } for (psDroid = apsDroidLists[p2]; psDroid; psDroid = psDroid->psNext) // to -> from { if (psDroid->order == DORDER_ATTACK && psDroid->psTarget && psDroid->psTarget->player == p1) { orderDroid(psDroid,DORDER_STOP); } } turnOffMultiMsg(false); }