// //////////////////////////////////////////////////////////////////////////// // Send a new Droid to the other players bool SendDroid(DROID_TEMPLATE *pTemplate, uint32_t x, uint32_t y, uint8_t player, uint32_t id, const INITIAL_DROID_ORDERS *initialOrdersP) { if (!bMultiMessages) { return true; } ASSERT_OR_RETURN(false, x != 0 && y != 0, "SendDroid: Invalid droid coordinates"); ASSERT_OR_RETURN(false, player < MAX_PLAYERS, "invalid player %u", player); // Dont send other droids during campaign setup if (ingame.localJoiningInProgress) { return true; } // Only send the droid if we are responsible if (!myResponsibility(player)) { // Don't build if we are not responsible return false; } debug(LOG_SYNC, "Droid sent with id of %u", id); NETbeginEncode(NETgameQueue(selectedPlayer), GAME_DEBUG_ADD_DROID); { Position pos(x, y, 0); bool haveInitialOrders = initialOrdersP != NULL; int32_t droidType = pTemplate->droidType; NETuint8_t(&player); NETuint32_t(&id); NETPosition(&pos); NETqstring(pTemplate->name); NETint32_t(&droidType); NETuint8_t(&pTemplate->asParts[COMP_BODY]); NETuint8_t(&pTemplate->asParts[COMP_BRAIN]); NETuint8_t(&pTemplate->asParts[COMP_PROPULSION]); NETuint8_t(&pTemplate->asParts[COMP_REPAIRUNIT]); NETuint8_t(&pTemplate->asParts[COMP_ECM]); NETuint8_t(&pTemplate->asParts[COMP_SENSOR]); NETuint8_t(&pTemplate->asParts[COMP_CONSTRUCT]); NETint8_t(&pTemplate->numWeaps); for (int i = 0; i < pTemplate->numWeaps; i++) { NETuint8_t(&pTemplate->asWeaps[i]); } NETbool(&haveInitialOrders); if (haveInitialOrders) { INITIAL_DROID_ORDERS initialOrders = *initialOrdersP; NETuint32_t(&initialOrders.secondaryOrder); NETint32_t(&initialOrders.moveToX); NETint32_t(&initialOrders.moveToY); NETuint32_t(&initialOrders.factoryId); // For making scripts happy. } } debug(LOG_LIFE, "===> sending Droid from %u id of %u ", player, id); return NETend(); }
// //////////////////////////////////////////////////////////////////////////// // INFORM others that a building has been completed. BOOL SendBuildFinished(STRUCTURE *psStruct) { uint8_t player = psStruct->player; ASSERT( player < MAX_PLAYERS, "invalid player %u", player); NETbeginEncode(NETgameQueue(selectedPlayer), GAME_BUILDFINISHED); NETuint32_t(&psStruct->id); // ID of building // Along with enough info to build it (if needed) NETuint32_t(&psStruct->pStructureType->ref); NETPosition(&psStruct->pos); NETuint8_t(&player); return NETend(); }
// //////////////////////////////////////////////////////////////////////////// // INFORM others that a building has been completed. BOOL SendBuildFinished(STRUCTURE *psStruct) { uint32_t power = getPower( (uint32_t) psStruct->player); uint8_t player = psStruct->player; ASSERT( player < MAX_PLAYERS, "invalid player %u", player); NETbeginEncode(NET_BUILDFINISHED, NET_ALL_PLAYERS); NETuint32_t(&power); // send how much power we got. NETuint32_t(&psStruct->id); // ID of building // Along with enough info to build it (if needed) NETuint32_t(&psStruct->pStructureType->ref); NETPosition(&psStruct->pos); NETuint8_t(&player); return NETend(); }
// //////////////////////////////////////////////////////////////////////////// // Send a new Droid to the other players BOOL SendDroid(const DROID_TEMPLATE* pTemplate, uint32_t x, uint32_t y, uint8_t player, uint32_t id, const INITIAL_DROID_ORDERS *initialOrdersP) { if (!bMultiMessages) return true; ASSERT(x != 0 && y != 0, "SendDroid: Invalid droid coordinates"); ASSERT( player < MAX_PLAYERS, "invalid player %u", player); // Dont send other droids during campaign setup if (ingame.localJoiningInProgress) { return true; } // Only send the droid if we are responsible if (!myResponsibility(player)) { // Don't build if we are not responsible return false; } debug(LOG_SYNC, "Droid sent with id of %u", id); NETbeginEncode(NETgameQueue(selectedPlayer), GAME_DROID); { Position pos = { x, y, 0 }; uint32_t templateID = pTemplate->multiPlayerID; BOOL haveInitialOrders = initialOrdersP != NULL; NETuint8_t(&player); NETuint32_t(&id); NETPosition(&pos); NETuint32_t(&templateID); NETbool(&haveInitialOrders); if (haveInitialOrders) { INITIAL_DROID_ORDERS initialOrders = *initialOrdersP; NETuint32_t(&initialOrders.secondaryOrder); NETint32_t(&initialOrders.moveToX); NETint32_t(&initialOrders.moveToY); NETuint32_t(&initialOrders.factoryId); // For making scripts happy. } } debug(LOG_LIFE, "===> sending Droid from %u id of %u ",player,id); return NETend(); }
/** Broadcast that droid is being unloaded from a transporter * * \sa sendDroidEmbark(),recvDroidEmbark(),recvDroidDisEmbark() */ BOOL sendDroidDisEmbark(const DROID* psDroid, const DROID* psTransporter) { if (!bMultiMessages) return true; NETbeginEncode(NETgameQueue(selectedPlayer), GAME_DROIDDISEMBARK); { uint8_t player = psDroid->player; uint32_t droidID = psDroid->id; uint32_t transporterID = psTransporter->id; Position pos = droidGetPrecisePosition(psDroid); NETuint8_t(&player); NETuint32_t(&droidID); NETuint32_t(&transporterID); NETPosition(&pos); } return NETend(); }
// //////////////////////////////////////////////////////////////////////////// // receive droid creation information from other players BOOL recvDroid(NETQUEUE queue) { DROID_TEMPLATE* pT; DROID* psDroid; uint8_t player; uint32_t id; Position pos; uint32_t templateID; BOOL haveInitialOrders; INITIAL_DROID_ORDERS initialOrders; NETbeginDecode(queue, GAME_DROID); { NETuint8_t(&player); NETuint32_t(&id); NETPosition(&pos); NETuint32_t(&templateID); NETbool(&haveInitialOrders); if (haveInitialOrders) { NETuint32_t(&initialOrders.secondaryOrder); NETint32_t(&initialOrders.moveToX); NETint32_t(&initialOrders.moveToY); NETuint32_t(&initialOrders.factoryId); // For making scripts happy. } pT = IdToTemplate(templateID, player); } NETend(); ASSERT( player < MAX_PLAYERS, "invalid player %u", player); debug(LOG_LIFE, "<=== getting Droid from %u id of %u ",player,id); if ((pos.x == 0 && pos.y == 0) || pos.x > world_coord(mapWidth) || pos.y > world_coord(mapHeight)) { debug(LOG_ERROR, "Received bad droid position (%d, %d) from %d about p%d (%s)", (int)pos.x, (int)pos.y, queue.index, player, isHumanPlayer(player) ? "Human" : "AI"); return false; } // If we can not find the template ask for the entire droid instead if (!pT) { debug(LOG_ERROR, "Packet from %d refers to non-existent template %u, [%s : p%d]", queue.index, templateID, isHumanPlayer(player) ? "Human" : "AI", player); return false; } // Create that droid on this machine. psDroid = reallyBuildDroid(pT, pos.x, pos.y, player, false); // If we were able to build the droid set it up if (psDroid) { psDroid->id = id; addDroid(psDroid, apsDroidLists); if (haveInitialOrders) { psDroid->secondaryOrder = initialOrders.secondaryOrder; orderDroidLoc(psDroid, DORDER_MOVE, initialOrders.moveToX, initialOrders.moveToY, ModeImmediate); cbNewDroid(IdToStruct(initialOrders.factoryId, ANYPLAYER), psDroid); } } else { debug(LOG_ERROR, "Packet from %d cannot create droid for p%d (%s)!", queue.index, player, isHumanPlayer(player) ? "Human" : "AI"); #ifdef DEBUG CONPRINTF(ConsoleString, (ConsoleString, "MULTIPLAYER: Couldn't build a remote droid, relying on checking to resync")); #endif return false; } return true; }
/** Receive info about a droid that is being unloaded from a transporter * * \sa sendDroidEmbark(),recvDroidEmbark(),sendDroidDisEmbark() */ BOOL recvDroidDisEmbark(NETQUEUE queue) { DROID *psFoundDroid = NULL, *psTransporterDroid = NULL; DROID *psCheckDroid = NULL; NETbeginDecode(queue, GAME_DROIDDISEMBARK); { uint8_t player; uint32_t droidID; uint32_t transporterID; Position pos; NETuint8_t(&player); NETuint32_t(&droidID); NETuint32_t(&transporterID); NETPosition(&pos); NETend(); // find the transporter first if (!IdToDroid(transporterID, player, &psTransporterDroid)) { // Possible it already died? (sync error?) debug(LOG_WARNING, "player's %d transport droid %d wasn't found?", player, transporterID); return false; } // we need to find the droid *in* the transporter psCheckDroid = psTransporterDroid ->psGroup->psList; while (psCheckDroid) { // is this the one we want? if( psCheckDroid->id == droidID) { psFoundDroid = psCheckDroid; break; } // not found, so check next one in *group* psCheckDroid = psCheckDroid->psGrpNext; } // don't continue if we couldn't find it. if (!psFoundDroid) { // I don't think this could ever be possible...but debug(LOG_ERROR, "Couldn't find droid %d to disembark from player %d's transporter?", droidID, player); return false; } // remove it from the transporter grpLeave(psFoundDroid->psGroup, psFoundDroid); // and add it back to the bloody droid list addDroid(psFoundDroid, apsDroidLists); // Add it back into the world at the x/y droidSetPrecisePosition(psFoundDroid, pos); if (!droidOnMap(psFoundDroid)) { debug(LOG_ERROR, "droid %d disembarked was NOT on map?", psFoundDroid->id); return false; } updateDroidOrientation(psFoundDroid); // Initialise the movement data initDroidMovement(psFoundDroid); } return true; }
// //////////////////////////////////////////////////////////////////////////// BOOL recvBuildFinished(NETQUEUE queue) { uint32_t structId; STRUCTURE *psStruct; Position pos; uint32_t type,typeindex; uint8_t player; NETbeginDecode(queue, GAME_BUILDFINISHED); NETuint32_t(&structId); // get the struct id. NETuint32_t(&type); // Kind of building. NETPosition(&pos); // pos NETuint8_t(&player); NETend(); ASSERT( player < MAX_PLAYERS, "invalid player %u", player); psStruct = IdToStruct(structId,ANYPLAYER); if (psStruct) { // make it complete. psStruct->currentBuildPts = psStruct->pStructureType->buildPoints+1; if (psStruct->status != SS_BUILT) { debug(LOG_SYNC, "Synch error, structure %u was not complete, and should have been.", structId); psStruct->status = SS_BUILT; buildingComplete(psStruct); } debug(LOG_SYNC, "Created normal building %u for player %u", psStruct->id, player); return true; } // The building wasn't started, so we'll have to just plonk it down in the map. // Find the structures stats for (typeindex=0; // Find structure target (typeindex<numStructureStats ) && (asStructureStats[typeindex].ref != type); typeindex++); // Check for similar buildings, to avoid overlaps if (TileHasStructure(mapTile(map_coord(pos.x), map_coord(pos.y)))) { // Get the current structure psStruct = getTileStructure(map_coord(pos.x), map_coord(pos.y)); if (asStructureStats[typeindex].type == psStruct->pStructureType->type) { // Correct type, correct location, just rename the id's to sync it.. (urgh) psStruct->id = structId; psStruct->status = SS_BUILT; buildingComplete(psStruct); debug(LOG_SYNC, "Created modified building %u for player %u", psStruct->id, player); #if defined (DEBUG) NETlogEntry("structure id modified", SYNC_FLAG, player); #endif return true; } } // Build the structure psStruct = buildStructure(&(asStructureStats[typeindex]), pos.x, pos.y, player, true); if (psStruct) { psStruct->id = structId; psStruct->status = SS_BUILT; buildingComplete(psStruct); debug(LOG_SYNC, "Huge synch error, forced to create building %u for player %u", psStruct->id, player); #if defined (DEBUG) NETlogEntry("had to plonk down a building", SYNC_FLAG, player); #endif } else { debug(LOG_SYNC, "Gigantic synch error, unable to create building for player %u", player); NETlogEntry("had to plonk down a building, BUT FAILED!", SYNC_FLAG, player); } return false; }
// //////////////////////////////////////////////////////////////////////////// // receive droid creation information from other players bool recvDroid(NETQUEUE queue) { DROID_TEMPLATE t, *pT = &t; DROID *psDroid; uint8_t player; uint32_t id; Position pos; bool haveInitialOrders; INITIAL_DROID_ORDERS initialOrders; NETbeginDecode(queue, GAME_DEBUG_ADD_DROID); { int32_t droidType; NETuint8_t(&player); NETuint32_t(&id); NETPosition(&pos); NETqstring(pT->name); pT->id = pT->name; NETint32_t(&droidType); NETuint8_t(&pT->asParts[COMP_BODY]); NETuint8_t(&pT->asParts[COMP_BRAIN]); NETuint8_t(&pT->asParts[COMP_PROPULSION]); NETuint8_t(&pT->asParts[COMP_REPAIRUNIT]); NETuint8_t(&pT->asParts[COMP_ECM]); NETuint8_t(&pT->asParts[COMP_SENSOR]); NETuint8_t(&pT->asParts[COMP_CONSTRUCT]); NETint8_t(&pT->numWeaps); for (int i = 0; i < pT->numWeaps; i++) { NETuint8_t(&pT->asWeaps[i]); } NETbool(&haveInitialOrders); if (haveInitialOrders) { NETuint32_t(&initialOrders.secondaryOrder); NETint32_t(&initialOrders.moveToX); NETint32_t(&initialOrders.moveToY); NETuint32_t(&initialOrders.factoryId); // For making scripts happy. } pT->droidType = (DROID_TYPE)droidType; } NETend(); if (!getDebugMappingStatus() && bMultiPlayer) { debug(LOG_WARNING, "Failed to add droid for player %u.", NetPlay.players[queue.index].position); return false; } ASSERT_OR_RETURN(false, player < MAX_PLAYERS, "invalid player %u", player); debug(LOG_LIFE, "<=== getting Droid from %u id of %u ", player, id); if ((pos.x == 0 && pos.y == 0) || pos.x > world_coord(mapWidth) || pos.y > world_coord(mapHeight)) { debug(LOG_ERROR, "Received bad droid position (%d, %d) from %d about p%d (%s)", (int)pos.x, (int)pos.y, queue.index, player, isHumanPlayer(player) ? "Human" : "AI"); return false; } // Create that droid on this machine. psDroid = reallyBuildDroid(pT, pos, player, false); // If we were able to build the droid set it up if (psDroid) { psDroid->id = id; addDroid(psDroid, apsDroidLists); if (haveInitialOrders) { psDroid->secondaryOrder = initialOrders.secondaryOrder; psDroid->secondaryOrderPending = psDroid->secondaryOrder; orderDroidLoc(psDroid, DORDER_MOVE, initialOrders.moveToX, initialOrders.moveToY, ModeImmediate); cbNewDroid(IdToStruct(initialOrders.factoryId, ANYPLAYER), psDroid); } syncDebugDroid(psDroid, '+'); } else { debug(LOG_ERROR, "Packet from %d cannot create droid for p%d (%s)!", queue.index, player, isHumanPlayer(player) ? "Human" : "AI"); #ifdef DEBUG CONPRINTF(ConsoleString, (ConsoleString, "MULTIPLAYER: Couldn't build a remote droid, relying on checking to resync")); #endif return false; } return true; }