// NOTICE: the packet is already set-up for decoding via recvGift() static void recvGiftStruct(uint8_t from, uint8_t to, uint32_t structID) { STRUCTURE *psStruct = IdToStruct(structID, from); if (psStruct) { syncDebugStructure(psStruct, '<'); giftSingleStructure(psStruct, to, false); syncDebugStructure(psStruct, '>'); if (to == selectedPlayer) { CONPRINTF(ConsoleString, (ConsoleString, _("%s Gives you a %s"), getPlayerName(from), objInfo(psStruct))); } } else { debug(LOG_ERROR, "Bad structure id %u, from %u to %u", structID, from, to); } }
/*called when a Template is deleted in the Design screen*/ void deleteTemplateFromProduction(DROID_TEMPLATE *psTemplate, unsigned player, QUEUE_MODE mode) { STRUCTURE *psStruct; STRUCTURE *psList; //see if any factory is currently using the template for (unsigned i = 0; i < 2; ++i) { psList = NULL; switch (i) { case 0: psList = apsStructLists[player]; break; case 1: psList = mission.apsStructLists[player]; break; } for (psStruct = psList; psStruct != NULL; psStruct = psStruct->psNext) { if (StructIsFactory(psStruct)) { FACTORY *psFactory = &psStruct->pFunctionality->factory; if (psFactory->psAssemblyPoint->factoryInc < asProductionRun[psFactory->psAssemblyPoint->factoryType].size()) { ProductionRun &productionRun = asProductionRun[psFactory->psAssemblyPoint->factoryType][psFactory->psAssemblyPoint->factoryInc]; for (unsigned inc = 0; inc < productionRun.size(); ++inc) { if (productionRun[inc].psTemplate->multiPlayerID == psTemplate->multiPlayerID && mode == ModeQueue) { //just need to erase this production run entry productionRun.erase(productionRun.begin() + inc); --inc; } } } if (psFactory->psSubject == NULL) { continue; } // check not being built in the factory for the template player if (psTemplate->multiPlayerID == psFactory->psSubject->multiPlayerID && mode == ModeImmediate) { syncDebugStructure(psStruct, '<'); syncDebug("Clearing production"); // Clear the factory's subject, and returns power. cancelProduction(psStruct, ModeImmediate, false); // Check to see if anything left to produce. (Also calls cancelProduction again, if nothing left to produce, which is a no-op. But if other things are left to produce, doesn't call cancelProduction, so wouldn't return power without the explicit cancelProduction call above.) doNextProduction(psStruct, NULL, ModeImmediate); //tell the interface intManufactureFinished(psStruct); syncDebugStructure(psStruct, '>'); } } } } }
void recvStructureInfo(NETQUEUE queue) { uint8_t player = 0; uint32_t structId = 0; uint32_t templateId = 0; uint8_t structureInfo; STRUCTURE * psStruct; DROID_TEMPLATE *psTempl = NULL; NETbeginDecode(queue, GAME_STRUCTUREINFO); NETuint8_t(&player); NETuint32_t(&structId); NETuint8_t(&structureInfo); if (structureInfo == STRUCTUREINFO_MANUFACTURE) { NETuint32_t(&templateId); if (templateId != 0) { psTempl = IdToTemplate(templateId, player); if (psTempl == NULL) { debug(LOG_SYNC, "Synch error, don't have tempate id %u, so can't change production of factory %u!", templateId, structId); } } } NETend(); psStruct = IdToStruct(structId, player); syncDebug("player%d,structId%u%c,structureInfo%u,templateId%u%c", player, structId, psStruct == NULL? '^' : '*', structureInfo, templateId, psTempl == NULL? '^' : '*'); if (psStruct == NULL) { debug(LOG_SYNC, "Couldn't find structure %u to change production.", structId); return; } CHECK_STRUCTURE(psStruct); if (StructIsFactory(psStruct)) { if (psStruct->pFunctionality->factory.pendingCount == 0) { ++psStruct->pFunctionality->factory.pendingCount; } if (--psStruct->pFunctionality->factory.pendingCount == 0) { // Subject is now synchronised, remove pending. psStruct->pFunctionality->factory.psSubjectPending = NULL; psStruct->pFunctionality->factory.statusPending = FACTORY_NOTHING_PENDING; } } syncDebugStructure(psStruct, '<'); switch (structureInfo) { case STRUCTUREINFO_MANUFACTURE: structSetManufacture(psStruct, psTempl, ModeImmediate); break; case STRUCTUREINFO_CANCELPRODUCTION: cancelProduction(psStruct, ModeImmediate); break; case STRUCTUREINFO_HOLDPRODUCTION: holdProduction(psStruct, ModeImmediate); break; case STRUCTUREINFO_RELEASEPRODUCTION: releaseProduction(psStruct, ModeImmediate); break; case STRUCTUREINFO_HOLDRESEARCH: holdResearch(psStruct, ModeImmediate); break; case STRUCTUREINFO_RELEASERESEARCH: releaseResearch(psStruct, ModeImmediate); break; default: debug(LOG_ERROR, "Invalid structureInfo %d", structureInfo); } syncDebugStructure(psStruct, '>'); CHECK_STRUCTURE(psStruct); }
// receive checking info about a structure and update local world state BOOL recvStructureCheck(NETQUEUE queue) { uint32_t synchTime; STRUCTURE *pS; BOOL hasCapacity = true; int j; Rotation rot; uint8_t player, ourCapacity; uint32_t body; uint32_t ref; uint32_t type; NETbeginDecode(queue, GAME_CHECK_STRUCT); NETuint8_t(&player); NETuint32_t(&synchTime); NETuint32_t(&ref); NETuint32_t(&body); NETuint32_t(&type); NETRotation(&rot); if (player >= MAX_PLAYERS) { debug(LOG_ERROR, "Bad GAME_CHECK_STRUCT received!"); NETend(); return false; } if (structureCheckLastSent != synchTime) { debug(LOG_ERROR, "We got a structure synch at the wrong time."); } if (ref != structureCheckLastId[player]) { debug(LOG_ERROR, "We got a structure %u synch, but had chosen %u instead.", ref, structureCheckLastId[player]); NETend(); return false; } // If the structure exists our job is easy pS = IdToStruct(ref, player); if (pS) { syncDebugStructure(pS, '<'); if (pS->pStructureType->type != structureCheckLastType[player] || type != structureCheckLastType[player]) { debug(LOG_ERROR, "GAME_CHECK_STRUCT received, wrong structure type!"); NETend(); return false; } // Check its finished if (pS->status != SS_BUILT) { pS->rot = rot; pS->id = ref; pS->status = SS_BUILT; buildingComplete(pS); } // If the structure has a capacity switch (pS->pStructureType->type) { case REF_RESEARCH: ourCapacity = ((RESEARCH_FACILITY *) pS->pFunctionality)->capacity; j = researchModuleStat; break; case REF_FACTORY: case REF_VTOL_FACTORY: ourCapacity = ((FACTORY *) pS->pFunctionality)->capacity; j = factoryModuleStat; break; case REF_POWER_GEN: ourCapacity = ((POWER_GEN *) pS->pFunctionality)->capacity; j = powerModuleStat; break; default: hasCapacity = false; break; } // So long as the struct has a capacity fetch it from the packet if (hasCapacity) { uint8_t actualCapacity = 0; NETuint8_t(&actualCapacity); // If our capacity is different upgrade ourself for (; ourCapacity < actualCapacity; ourCapacity++) { debug(LOG_SYNC, "Structure %u out of synch, adding module.", ref); buildStructure(&asStructureStats[j], pS->pos.x, pS->pos.y, pS->player, false); // Check it is finished if (pS && pS->status != SS_BUILT) { pS->id = ref; pS->status = SS_BUILT; buildingComplete(pS); } } } #define MERGEDELTA(x, y, ya, z) if (y != ya) { debug(LOG_SYNC, "Structure %u out of synch, changing "#x" from %"z" to %"z".", ref, x, x + y - ya); x += y - ya; } MERGEDELTA(pS->body, body, structureCheckLastBody[player], "u"); MERGEDELTA(pS->rot.direction, rot.direction, structureCheckLastDirection[player].direction, "d"); MERGEDELTA(pS->rot.pitch, rot.pitch, structureCheckLastDirection[player].pitch, "d"); MERGEDELTA(pS->rot.roll, rot.roll, structureCheckLastDirection[player].roll, "d"); #undef MERGEDELTA syncDebugStructure(pS, '>'); } else { debug(LOG_ERROR, "We got a structure %u synch, but can't find the structure.", ref); } NETend(); return true; }
/*called when a Template is deleted in the Design screen*/ void deleteTemplateFromProduction(DROID_TEMPLATE *psTemplate, unsigned player, QUEUE_MODE mode) { STRUCTURE *psStruct; STRUCTURE *psList; //see if any factory is currently using the template for (unsigned i = 0; i < 2; ++i) { psList = NULL; switch (i) { case 0: psList = apsStructLists[player]; break; case 1: psList = mission.apsStructLists[player]; break; } for (psStruct = psList; psStruct != NULL; psStruct = psStruct->psNext) { if (StructIsFactory(psStruct)) { FACTORY *psFactory = &psStruct->pFunctionality->factory; if (psFactory->psAssemblyPoint->factoryInc < asProductionRun[psFactory->psAssemblyPoint->factoryType].size()) { ProductionRun &productionRun = asProductionRun[psFactory->psAssemblyPoint->factoryType][psFactory->psAssemblyPoint->factoryInc]; for (unsigned inc = 0; inc < productionRun.size(); ++inc) { if (productionRun[inc].psTemplate->multiPlayerID == psTemplate->multiPlayerID && mode == ModeQueue) { //just need to erase this production run entry productionRun.erase(productionRun.begin() + inc); --inc; } } } if (psFactory->psSubject == NULL) { continue; } // check not being built in the factory for the template player if (psTemplate->multiPlayerID == psFactory->psSubject->multiPlayerID && mode == ModeImmediate) { syncDebugStructure(psStruct, '<'); syncDebug("Clearing production"); // Clear the factory's subject. psFactory->psSubject = NULL; if (player == productionPlayer) { //check to see if anything left to produce DROID_TEMPLATE *psNextTemplate = factoryProdUpdate(psStruct, NULL); //power is returned by factoryProdAdjust() if (psNextTemplate) { structSetManufacture(psStruct, psNextTemplate, ModeQueue); // ModeQueue because production lists aren't synchronised. } } //tell the interface intManufactureFinished(psStruct); syncDebugStructure(psStruct, '>'); } } } } }
void recvStructureInfo(NETQUEUE queue) { uint8_t player = 0; uint32_t structId = 0; uint32_t templateId = 0; uint8_t structureInfo; STRUCTURE *psStruct; DROID_TEMPLATE *psTempl = NULL; NETbeginDecode(queue, GAME_STRUCTUREINFO); NETuint8_t(&player); NETuint32_t(&structId); NETuint8_t(&structureInfo); if (structureInfo == STRUCTUREINFO_MANUFACTURE) { NETuint32_t(&templateId); if (templateId != 0) { // For autogames, where we want the AI to take us over, our templates are not setup... so let's use any AI's templates. if (!NetPlay.players[player].autoGame) { psTempl = IdToTemplate(templateId, player); } else { psTempl = IdToTemplate(templateId, ANYPLAYER); } if (psTempl == NULL) { debug(LOG_SYNC, "Synch error, don't have tempate id %u, so can't change production of factory %u!", templateId, structId); } } } NETend(); psStruct = IdToStruct(structId, player); syncDebug("player%d,structId%u%c,structureInfo%u,templateId%u%c", player, structId, psStruct == NULL ? '^' : '*', structureInfo, templateId, psTempl == NULL ? '^' : '*'); if (psStruct == NULL) { debug(LOG_SYNC, "Couldn't find structure %u to change production.", structId); return; } if (!canGiveOrdersFor(queue.index, psStruct->player)) { syncDebug("Wrong player."); return; } CHECK_STRUCTURE(psStruct); if (StructIsFactory(psStruct)) { popStatusPending(psStruct->pFunctionality->factory); } else if (psStruct->pStructureType->type == REF_RESEARCH) { popStatusPending(psStruct->pFunctionality->researchFacility); } syncDebugStructure(psStruct, '<'); switch (structureInfo) { case STRUCTUREINFO_MANUFACTURE: structSetManufacture(psStruct, psTempl, ModeImmediate); break; case STRUCTUREINFO_CANCELPRODUCTION: cancelProduction(psStruct, ModeImmediate, false); break; case STRUCTUREINFO_HOLDPRODUCTION: holdProduction(psStruct, ModeImmediate); break; case STRUCTUREINFO_RELEASEPRODUCTION: releaseProduction(psStruct, ModeImmediate); break; case STRUCTUREINFO_HOLDRESEARCH: holdResearch(psStruct, ModeImmediate); break; case STRUCTUREINFO_RELEASERESEARCH: releaseResearch(psStruct, ModeImmediate); break; default: debug(LOG_ERROR, "Invalid structureInfo %d", structureInfo); } syncDebugStructure(psStruct, '>'); CHECK_STRUCTURE(psStruct); }