// ============================================================== // This file is part of Glest (www.glest.org) // // Copyright (C) 2001-2008 MartiƱo Figueroa // // You can redistribute this code and/or modify it under // the terms of the GNU General Public License as published // by the Free Software Foundation; either version 2 of the // License, or (at your option) any later version // ============================================================== #include "commander.h" #include "world.h" #include "unit.h" #include "conversion.h" #include "upgrade.h" #include "command.h" #include "command_type.h" #include "network_manager.h" #include "console.h" #include "config.h" #include "platform_util.h" #include "game.h" #include "game_settings.h" #include "game.h" using namespace Shared::Graphics; using namespace Shared::Util; using namespace Shared::Platform; namespace Glest { namespace Game { // ===================================================== // class Commander // ===================================================== Commander::Commander () { this->world = NULL; this-> pauseNetworkCommands = false; } Commander::~ Commander () { } void Commander::init (World * world) { this->world = world; } bool Commander::canSubmitCommandType (const Unit * unit, const CommandType * commandType) const { bool canSubmitCommand = true; const MorphCommandType * mct = dynamic_cast < const MorphCommandType * >(commandType); if (mct && unit->getCommandSize () > 0) { Command * cur_command = unit->getCurrCommand (); if (cur_command != NULL) { const MorphCommandType * cur_mct = dynamic_cast < const MorphCommandType * >(cur_command->getCommandType ()); if (cur_mct && unit->getCurrSkill () && unit->getCurrSkill ()->getClass () == scMorph) { const UnitType * morphUnitType = mct->getMorphUnit (); const UnitType * cur_morphUnitType = cur_mct->getMorphUnit (); if (morphUnitType != NULL && cur_morphUnitType != NULL && morphUnitType->getId () == cur_morphUnitType->getId ()) { canSubmitCommand = false; } } } } return canSubmitCommand; } std::pair < CommandResult, string > Commander::tryGiveCommand (const Selection * selection, const CommandType * commandType, const Vec2i & pos, const UnitType * unitType, CardinalDir facing, bool tryQueue, Unit * targetUnit) const { if (SystemFlags::getSystemSettingType (SystemFlags::debugSystem). enabled) SystemFlags::OutputDebug (SystemFlags::debugSystem, "In [%s::%s Line: %d]\n", extractFileFromDirectoryPath (__FILE__). c_str (), __FUNCTION__, __LINE__); if (this->pauseNetworkCommands == true) { return std::pair < CommandResult, string > (crFailUndefined, ""); } std::pair < CommandResult, string > result (crFailUndefined, ""); if (selection->isEmpty () == false && commandType != NULL) { Vec2i refPos; CommandResultContainer results; refPos = world->getMap ()->computeRefPos (selection); const Unit * builderUnit = world->getMap ()->findClosestUnitToPos (selection, pos, unitType); int builderUnitId = builderUnit->getId (); CommandStateType commandStateType = cst_None; int commandStateValue = -1; int unitCommandGroupId = -1; if (selection->getCount () > 1) { unitCommandGroupId = world->getNextCommandGroupId (); } //give orders to all selected units for (int i = 0; i < selection->getCount (); ++i) { const Unit * unit = selection->getUnit (i); std::pair < CommandResult, string > resultCur (crFailUndefined, ""); bool canSubmitCommand = canSubmitCommandType (unit, commandType); if (canSubmitCommand == true) { int unitId = unit->getId (); Vec2i currPos = world->getMap ()->computeDestPos (refPos, unit-> getPosNotThreadSafe (), pos); Vec2i usePos = currPos; const CommandType * useCommandtype = commandType; if (dynamic_cast < const BuildCommandType * >(commandType) != NULL) { usePos = pos; if (builderUnit->getId () != unitId) { useCommandtype = unit->getType ()-> getFirstRepairCommand (unitType); commandStateType = cst_linkedUnit; commandStateValue = builderUnitId; } else { commandStateType = cst_None; commandStateValue = -1; } } if (useCommandtype != NULL) { NetworkCommand networkCommand (this->world, nctGiveCommand, unitId, useCommandtype->getId (), usePos, unitType->getId (), (targetUnit != NULL ? targetUnit->getId () : -1), facing, tryQueue, commandStateType, commandStateValue, unitCommandGroupId); //every unit is ordered to a the position resultCur = pushNetworkCommand (&networkCommand); } } results.push_back (resultCur); } return computeResult (results); } return std::pair < CommandResult, string > (crFailUndefined, ""); } std::pair < CommandResult, string > Commander::tryGiveCommand (const Unit * unit, const CommandType * commandType, const Vec2i & pos, const UnitType * unitType, CardinalDir facing, bool tryQueue, Unit * targetUnit, int unitGroupCommandId) const { if (SystemFlags::getSystemSettingType (SystemFlags::debugSystem). enabled) SystemFlags::OutputDebug (SystemFlags::debugSystem, "In [%s::%s Line: %d]\n", extractFileFromDirectoryPath (__FILE__). c_str (), __FUNCTION__, __LINE__); if (this->pauseNetworkCommands == true) { return std::pair < CommandResult, string > (crFailUndefined, ""); } Chrono chrono; if (SystemFlags::getSystemSettingType (SystemFlags::debugPerformance). enabled) chrono.start (); assert (this->world != NULL); assert (unit != NULL); assert (commandType != NULL); assert (unitType != NULL); if (SystemFlags::getSystemSettingType (SystemFlags::debugPerformance). enabled && chrono.getMillis () > 0) SystemFlags::OutputDebug (SystemFlags::debugPerformance, "In [%s::%s] Line: %d took msecs: %lld\n", extractFileFromDirectoryPath (__FILE__). c_str (), __FUNCTION__, __LINE__, chrono.getMillis ()); std::pair < CommandResult, string > result (crFailUndefined, ""); bool canSubmitCommand = canSubmitCommandType (unit, commandType); if (canSubmitCommand == true) { NetworkCommand networkCommand (this->world, nctGiveCommand, unit->getId (), commandType->getId (), pos, unitType->getId (), (targetUnit != NULL ? targetUnit->getId () : -1), facing, tryQueue, cst_None, -1, unitGroupCommandId); if (SystemFlags:: getSystemSettingType (SystemFlags::debugPerformance).enabled && chrono.getMillis () > 0) SystemFlags::OutputDebug (SystemFlags::debugPerformance, "In [%s::%s] Line: %d took msecs: %lld\n", extractFileFromDirectoryPath (__FILE__). c_str (), __FUNCTION__, __LINE__, chrono.getMillis ()); result = pushNetworkCommand (&networkCommand); } if (SystemFlags::getSystemSettingType (SystemFlags::debugPerformance). enabled && chrono.getMillis () > 0) SystemFlags::OutputDebug (SystemFlags::debugPerformance, "In [%s::%s] Line: %d took msecs: %lld\n", extractFileFromDirectoryPath (__FILE__). c_str (), __FUNCTION__, __LINE__, chrono.getMillis ()); return result; } std::pair < CommandResult, string > Commander::tryGiveCommand (const Selection * selection, CommandClass commandClass, const Vec2i & pos, const Unit * targetUnit, bool tryQueue) const { if (this->pauseNetworkCommands == true) { return std::pair < CommandResult, string > (crFailUndefined, ""); } std::pair < CommandResult, string > result (crFailUndefined, ""); if (selection->isEmpty () == false) { Vec2i refPos, currPos; CommandResultContainer results; refPos = world->getMap ()->computeRefPos (selection); int unitCommandGroupId = -1; if (selection->getCount () > 1) { unitCommandGroupId = world->getNextCommandGroupId (); } //give orders to all selected units for (int i = 0; i < selection->getCount (); ++i) { const Unit * unit = selection->getUnit (i); const CommandType * ct = unit->getType ()->getFirstCtOfClass (commandClass); if (ct != NULL) { std::pair < CommandResult, string > resultCur (crFailUndefined, ""); bool canSubmitCommand = canSubmitCommandType (unit, ct); if (canSubmitCommand == true) { int targetId = targetUnit == NULL ? Unit::invalidId : targetUnit->getId (); int unitId = selection->getUnit (i)->getId (); Vec2i currPos = world->getMap ()->computeDestPos (refPos, selection-> getUnit (i)-> getPosNotThreadSafe (), pos); NetworkCommand networkCommand (this->world, nctGiveCommand, unitId, ct->getId (), currPos, -1, targetId, -1, tryQueue, cst_None, -1, unitCommandGroupId); //every unit is ordered to a different pos resultCur = pushNetworkCommand (&networkCommand); } results.push_back (resultCur); } else { results.push_back (std::pair < CommandResult, string > (crFailUndefined, "")); } } return computeResult (results); } else { return std::pair < CommandResult, string > (crFailUndefined, ""); } } std::pair < CommandResult, string > Commander::tryGiveCommand (const Selection * selection, const CommandType * commandType, const Vec2i & pos, const Unit * targetUnit, bool tryQueue) const { if (this->pauseNetworkCommands == true) { return std::pair < CommandResult, string > (crFailUndefined, ""); } std::pair < CommandResult, string > result (crFailUndefined, ""); if (!selection->isEmpty () && commandType != NULL) { Vec2i refPos; CommandResultContainer results; refPos = world->getMap ()->computeRefPos (selection); int unitCommandGroupId = -1; if (selection->getCount () > 1) { unitCommandGroupId = world->getNextCommandGroupId (); } //give orders to all selected units for (int i = 0; i < selection->getCount (); ++i) { const Unit * unit = selection->getUnit (i); assert (unit != NULL); std::pair < CommandResult, string > resultCur (crFailUndefined, ""); bool canSubmitCommand = canSubmitCommandType (unit, commandType); if (canSubmitCommand == true) { int targetId = targetUnit == NULL ? Unit::invalidId : targetUnit->getId (); int unitId = unit->getId (); Vec2i currPos = world->getMap ()->computeDestPos (refPos, unit-> getPosNotThreadSafe (), pos); NetworkCommand networkCommand (this->world, nctGiveCommand, unitId, commandType->getId (), currPos, -1, targetId, -1, tryQueue, cst_None, -1, unitCommandGroupId); //every unit is ordered to a different position resultCur = pushNetworkCommand (&networkCommand); } results.push_back (resultCur); } return computeResult (results); } else { return std::pair < CommandResult, string > (crFailUndefined, ""); } } //auto command std::pair < CommandResult, string > Commander::tryGiveCommand (const Selection * selection, const Vec2i & pos, const Unit * targetUnit, bool tryQueue, int unitCommandGroupId) const { if (this->pauseNetworkCommands == true) { return std::pair < CommandResult, string > (crFailUndefined, ""); } if (SystemFlags::getSystemSettingType (SystemFlags::debugSystem). enabled) SystemFlags::OutputDebug (SystemFlags::debugSystem, "In [%s::%s Line: %d]\n", extractFileFromDirectoryPath (__FILE__). c_str (), __FUNCTION__, __LINE__); std::pair < CommandResult, string > result (crFailUndefined, ""); if (selection->isEmpty () == false) { Vec2i refPos, currPos; CommandResultContainer results; if (unitCommandGroupId == -1 && selection->getCount () > 1) { unitCommandGroupId = world->getNextCommandGroupId (); } //give orders to all selected units refPos = world->getMap ()->computeRefPos (selection); for (int i = 0; i < selection->getCount (); ++i) { //every unit is ordered to a different pos const Unit * unit = selection->getUnit (i); assert (unit != NULL); currPos = world->getMap ()->computeDestPos (refPos, unit-> getPosNotThreadSafe (), pos); //get command type const CommandType * commandType = unit->computeCommandType (pos, targetUnit); //give commands if (commandType != NULL) { int targetId = targetUnit == NULL ? Unit::invalidId : targetUnit->getId (); int unitId = unit->getId (); std::pair < CommandResult, string > resultCur (crFailUndefined, ""); bool canSubmitCommand = canSubmitCommandType (unit, commandType); if (canSubmitCommand == true) { NetworkCommand networkCommand (this->world, nctGiveCommand, unitId, commandType->getId (), currPos, -1, targetId, -1, tryQueue, cst_None, -1, unitCommandGroupId); resultCur = pushNetworkCommand (&networkCommand); } results.push_back (resultCur); } else if (unit->isMeetingPointSettable () == true) { NetworkCommand command (this->world, nctSetMeetingPoint, unit->getId (), -1, currPos, -1, -1, -1, false, cst_None, -1, unitCommandGroupId); std::pair < CommandResult, string > resultCur = pushNetworkCommand (&command); results.push_back (resultCur); } else { results.push_back (std::pair < CommandResult, string > (crFailUndefined, "")); } } result = computeResult (results); } return result; } CommandResult Commander::tryCancelCommand (const Selection * selection) const { if (this->pauseNetworkCommands == true) { return crFailUndefined; } int unitCommandGroupId = -1; if (selection->getCount () > 1) { unitCommandGroupId = world->getNextCommandGroupId (); } for (int i = 0; i < selection->getCount (); ++i) { NetworkCommand command (this->world, nctCancelCommand, selection->getUnit (i)->getId (), -1, Vec2i (0), -1, -1, -1, false, cst_None, -1, unitCommandGroupId); pushNetworkCommand (&command); } return crSuccess; } void Commander::trySetMeetingPoint (const Unit * unit, const Vec2i & pos) const { if (this->pauseNetworkCommands == true) { return; } NetworkCommand command (this->world, nctSetMeetingPoint, unit->getId (), -1, pos); pushNetworkCommand (&command); } void Commander::trySwitchTeam (const Faction * faction, int teamIndex) const { if (this->pauseNetworkCommands == true) { return; } NetworkCommand command (this->world, nctSwitchTeam, faction->getIndex (), teamIndex); pushNetworkCommand (&command); } void Commander::trySwitchTeamVote (const Faction * faction, SwitchTeamVote * vote) const { if (this->pauseNetworkCommands == true) { return; } NetworkCommand command (this->world, nctSwitchTeamVote, faction->getIndex (), vote->factionIndex, Vec2i (0), vote->allowSwitchTeam); pushNetworkCommand (&command); } void Commander::tryDisconnectNetworkPlayer (const Faction * faction, int playerIndex) const { NetworkCommand command (this->world, nctDisconnectNetworkPlayer, faction->getIndex (), playerIndex); pushNetworkCommand (&command); } void Commander::tryPauseGame (bool joinNetworkGame, bool clearCaches) const { NetworkCommand command (this->world, nctPauseResume, 1); command. commandTypeId = (clearCaches == true ? 1 : 0); command. unitTypeId = (joinNetworkGame == true ? 1 : 0); pushNetworkCommand (&command); } void Commander::tryResumeGame (bool joinNetworkGame, bool clearCaches) const { NetworkCommand command (this->world, nctPauseResume, 0); command. commandTypeId = (clearCaches == true ? 1 : 0); command. unitTypeId = (joinNetworkGame == true ? 1 : 0); pushNetworkCommand (&command); } void Commander::tryNetworkPlayerDisconnected (int factionIndex) const { //printf("tryNetworkPlayerDisconnected factionIndex: %d\n",factionIndex); //if(this->pauseNetworkCommands == true) { // return; //} NetworkCommand command (this->world, nctPlayerStatusChange, factionIndex, npst_Disconnected); pushNetworkCommand (&command); } // ==================== PRIVATE ==================== std::pair < CommandResult, string > Commander::computeResult (const CommandResultContainer & results) const { std::pair < CommandResult, string > result (crFailUndefined, ""); switch (results.size ()) { case 0: return std::pair < CommandResult, string > (crFailUndefined, ""); case 1: return results. front (); default:for (int i = 0; i < (int) results.size (); ++i) { if (results[i].first != crSuccess) { return std::pair < CommandResult, string > (crSomeFailed, results[i]. second); } } break; } return std::pair < CommandResult, string > (crSuccess, ""); } std::pair < CommandResult, string > Commander::pushNetworkCommand (const NetworkCommand * networkCommand) const { GameNetworkInterface * gameNetworkInterface = NetworkManager::getInstance ().getGameNetworkInterface (); std::pair < CommandResult, string > result (crSuccess, ""); //validate unit const Unit * unit = NULL; if (networkCommand->getNetworkCommandType () != nctSwitchTeam && networkCommand->getNetworkCommandType () != nctSwitchTeamVote && networkCommand->getNetworkCommandType () != nctPauseResume && networkCommand->getNetworkCommandType () != nctPlayerStatusChange && networkCommand->getNetworkCommandType () != nctDisconnectNetworkPlayer) { unit = world->findUnitById (networkCommand->getUnitId ()); if (unit == NULL) { char szBuf[8096] = ""; snprintf (szBuf, 8096, "In [%s::%s - %d] Command refers to non existent unit id = %d. Game out of synch.", extractFileFromDirectoryPath (__FILE__).c_str (), __FUNCTION__, __LINE__, networkCommand->getUnitId ()); GameNetworkInterface * gameNetworkInterface = NetworkManager::getInstance ().getGameNetworkInterface (); if (gameNetworkInterface != NULL) { char szMsg[8096] = ""; snprintf (szMsg, 8096, "Player detected an error: Command refers to non existent unit id = %d. Game out of synch.", networkCommand->getUnitId ()); gameNetworkInterface-> sendTextMessage (szMsg, -1, true, ""); } throw megaglest_runtime_error (szBuf); } } //add the command to the interface gameNetworkInterface->requestCommand (networkCommand); //calculate the result of the command if (unit != NULL && networkCommand->getNetworkCommandType () == nctGiveCommand) { //printf("In [%s::%s Line: %d] result.first = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,result.first); Command * command = buildCommand (networkCommand); result = unit->checkCommand (command); delete command; } return result; } void Commander::signalNetworkUpdate (Game * game) { updateNetwork (game); } bool Commander::getReplayCommandListForFrame (int worldFrameCount) { bool haveReplyCommands = false; if (replayCommandList.empty () == false) { if (SystemFlags::VERBOSE_MODE_ENABLED) printf ("worldFrameCount = %d replayCommandList.size() = " MG_SIZE_T_SPECIFIER "\n", worldFrameCount, replayCommandList.size ()); std::vector < NetworkCommand > replayList; for (unsigned int i = 0; i < replayCommandList.size (); ++i) { std::pair < int, NetworkCommand > & cmd = replayCommandList[i]; if (cmd.first <= worldFrameCount) { replayList.push_back (cmd.second); haveReplyCommands = true; } } if (haveReplyCommands == true) { replayCommandList.erase (replayCommandList.begin (), replayCommandList.begin () + replayList.size ()); if (SystemFlags::VERBOSE_MODE_ENABLED) printf ("worldFrameCount = %d GIVING COMMANDS replayList.size() = " MG_SIZE_T_SPECIFIER "\n", worldFrameCount, replayList.size ()); for (int i = 0; i < (int) replayList.size (); ++i) { giveNetworkCommand (&replayList[i]); } GameNetworkInterface * gameNetworkInterface = NetworkManager::getInstance ().getGameNetworkInterface (); gameNetworkInterface->setKeyframe (worldFrameCount); } } return haveReplyCommands; } bool Commander::hasReplayCommandListForFrame () const { return (replayCommandList.empty () == false); } int Commander::getReplayCommandListForFrameCount () const { return (int) replayCommandList. size (); } void Commander::updateNetwork (Game * game) { if (world == NULL) { return; } NetworkManager & networkManager = NetworkManager::getInstance (); //check that this is a keyframe if (game != NULL) { GameSettings * gameSettings = game->getGameSettings (); if (networkManager.isNetworkGame () == false || (world->getFrameCount () % gameSettings->getNetworkFramePeriod ()) == 0) { if (SystemFlags:: getSystemSettingType (SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug (SystemFlags::debugSystem, "In [%s::%s Line: %d] networkManager.isNetworkGame() = %d,world->getFrameCount() = %d, gameSettings->getNetworkFramePeriod() = %d\n", extractFileFromDirectoryPath (__FILE__).c_str (), __FUNCTION__, __LINE__, networkManager.isNetworkGame (), world->getFrameCount (), gameSettings-> getNetworkFramePeriod ()); if (getReplayCommandListForFrame (world->getFrameCount ()) == false) { GameNetworkInterface * gameNetworkInterface = NetworkManager::getInstance ().getGameNetworkInterface (); if (SystemFlags:: getSystemSettingType (SystemFlags::debugPerformance). enabled) perfTimer.start (); //update the keyframe gameNetworkInterface->updateKeyframe (world-> getFrameCount ()); if (SystemFlags:: getSystemSettingType (SystemFlags::debugPerformance). enabled && perfTimer.getMillis () > 0) SystemFlags::OutputDebug (SystemFlags::debugPerformance, "In [%s::%s Line: %d] gameNetworkInterface->updateKeyframe for %d took %lld msecs\n", extractFileFromDirectoryPath (__FILE__).c_str (), __FUNCTION__, __LINE__, world->getFrameCount (), perfTimer.getMillis ()); if (SystemFlags:: getSystemSettingType (SystemFlags::debugPerformance). enabled) perfTimer.start (); //give pending commands if (SystemFlags::VERBOSE_MODE_ENABLED) printf ("START process: %d network commands in frame: %d\n", gameNetworkInterface->getPendingCommandCount (), this->world->getFrameCount ()); for (int i = 0; i < gameNetworkInterface->getPendingCommandCount (); ++i) { giveNetworkCommand (gameNetworkInterface-> getPendingCommand (i)); } if (SystemFlags::VERBOSE_MODE_ENABLED) printf ("END process: %d network commands in frame: %d\n", gameNetworkInterface->getPendingCommandCount (), this->world->getFrameCount ()); if (SystemFlags:: getSystemSettingType (SystemFlags::debugPerformance). enabled && perfTimer.getMillis () > 0) SystemFlags::OutputDebug (SystemFlags::debugPerformance, "In [%s::%s Line: %d] giveNetworkCommand took %lld msecs, PendingCommandCount = %d\n", extractFileFromDirectoryPath (__FILE__).c_str (), __FUNCTION__, __LINE__, perfTimer.getMillis (), gameNetworkInterface-> getPendingCommandCount ()); gameNetworkInterface->clearPendingCommands (); if (SystemFlags::VERBOSE_MODE_ENABLED) printf ("Cleared network commands in frame: %d\n", this->world->getFrameCount ()); } } } } void Commander::addToReplayCommandList (NetworkCommand & command, int worldFrameCount) { replayCommandList.push_back (make_pair (worldFrameCount, command)); } void Commander::giveNetworkCommand (NetworkCommand * networkCommand) const { Chrono chrono; if (SystemFlags::getSystemSettingType (SystemFlags::debugPerformance). enabled) chrono. start (); if (SystemFlags::getSystemSettingType (SystemFlags::debugPerformance). enabled && chrono.getMillis () > 0) SystemFlags::OutputDebug (SystemFlags::debugPerformance, "In [%s::%s Line: %d] took msecs: %lld [START]\n", extractFileFromDirectoryPath (__FILE__). c_str (), __FUNCTION__, __LINE__, chrono.getMillis ()); world-> getGame ()-> addNetworkCommandToReplayList (networkCommand, world->getFrameCount ()); networkCommand-> preprocessNetworkCommand (this->world); if (SystemFlags::getSystemSettingType (SystemFlags::debugPerformance). enabled && chrono.getMillis () > 0) SystemFlags::OutputDebug (SystemFlags::debugPerformance, "In [%s::%s Line: %d] took msecs: %lld [after networkCommand->preprocessNetworkCommand]\n", extractFileFromDirectoryPath (__FILE__). c_str (), __FUNCTION__, __LINE__, chrono.getMillis ()); bool commandWasHandled = false; // Handle special commands first (that just use network command members as placeholders) switch (networkCommand->getNetworkCommandType ()) { case nctSwitchTeam: { if (SystemFlags::getSystemSettingType (SystemFlags::debugSystem). enabled) SystemFlags::OutputDebug (SystemFlags::debugSystem, "In [%s::%s Line: %d] found nctSwitchTeam\n", extractFileFromDirectoryPath (__FILE__).c_str (), __FUNCTION__, __LINE__); commandWasHandled = true; int factionIndex = networkCommand->getUnitId (); int newTeam = networkCommand->getCommandTypeId (); // Auto join empty team or ask players to join bool autoJoinTeam = true; for (int i = 0; i < world->getFactionCount (); ++i) { if (newTeam == world->getFaction (i)->getTeam ()) { autoJoinTeam = false; break; } } if (autoJoinTeam == true) { Faction * faction = world->getFaction (factionIndex); int oldTeam = faction->getTeam (); faction->setTeam (newTeam); GameSettings * settings = world->getGameSettingsPtr (); settings->setTeam (factionIndex, newTeam); world->getStats ()->setTeam (factionIndex, newTeam); if (factionIndex == world->getThisFactionIndex ()) { world->setThisTeamIndex (newTeam); GameNetworkInterface * gameNetworkInterface = NetworkManager::getInstance (). getGameNetworkInterface (); if (gameNetworkInterface != NULL) { Lang & lang = Lang::getInstance (); const vector < string > languageList = settings->getUniqueNetworkPlayerLanguages (); for (unsigned int i = 0; i < languageList.size (); ++i) { char szMsg[8096] = ""; if (lang. hasString ("PlayerSwitchedTeam", languageList[i]) == true) { snprintf (szMsg, 8096, lang. getString ("PlayerSwitchedTeam", languageList[i]). c_str (), settings-> getNetworkPlayerName (factionIndex). c_str (), oldTeam, newTeam); } else { snprintf (szMsg, 8096, "Player %s switched from team# %d to team# %d.", settings-> getNetworkPlayerName (factionIndex). c_str (), oldTeam, newTeam); } bool localEcho = lang.isLanguageLocal (languageList[i]); gameNetworkInterface->sendTextMessage (szMsg, -1, localEcho, languageList [i]); } } world->getGame ()->reInitGUI (); } } else { for (int i = 0; i < world->getFactionCount (); ++i) { if (newTeam == world->getFaction (i)->getTeam ()) { Faction * faction = world->getFaction (factionIndex); SwitchTeamVote vote; vote.factionIndex = factionIndex; vote.allowSwitchTeam = false; vote.oldTeam = faction->getTeam (); vote.newTeam = newTeam; vote.voted = false; world->getFaction (i)->setSwitchTeamVote (vote); } } } if (SystemFlags:: getSystemSettingType (SystemFlags::debugPerformance).enabled && chrono.getMillis () > 0) SystemFlags::OutputDebug (SystemFlags::debugPerformance, "In [%s::%s Line: %d] took msecs: %lld [after unit->setMeetingPos]\n", extractFileFromDirectoryPath (__FILE__).c_str (), __FUNCTION__, __LINE__, chrono.getMillis ()); if (SystemFlags::getSystemSettingType (SystemFlags::debugSystem). enabled) SystemFlags::OutputDebug (SystemFlags::debugSystem, "In [%s::%s Line: %d] found nctSetMeetingPoint\n", extractFileFromDirectoryPath (__FILE__).c_str (), __FUNCTION__, __LINE__); } break; case nctSwitchTeamVote: { if (SystemFlags::getSystemSettingType (SystemFlags::debugSystem). enabled) SystemFlags::OutputDebug (SystemFlags::debugSystem, "In [%s::%s Line: %d] found nctSwitchTeamVote\n", extractFileFromDirectoryPath (__FILE__).c_str (), __FUNCTION__, __LINE__); commandWasHandled = true; int votingFactionIndex = networkCommand->getUnitId (); int factionIndex = networkCommand->getCommandTypeId (); bool allowSwitchTeam = networkCommand->getUnitTypeId () != 0; Faction * faction = world->getFaction (votingFactionIndex); SwitchTeamVote * vote = faction->getSwitchTeamVote (factionIndex); if (vote == NULL) { throw megaglest_runtime_error ("vote == NULL"); } vote->voted = true; vote->allowSwitchTeam = allowSwitchTeam; // Join the new team if > 50 % said yes int newTeamTotalMemberCount = 0; int newTeamVotedYes = 0; int newTeamVotedNo = 0; for (int i = 0; i < world->getFactionCount (); ++i) { if (vote->newTeam == world->getFaction (i)->getTeam ()) { newTeamTotalMemberCount++; SwitchTeamVote * teamVote = world->getFaction (i)->getSwitchTeamVote (factionIndex); if (teamVote != NULL && teamVote->voted == true) { if (teamVote->allowSwitchTeam == true) { newTeamVotedYes++; } else { newTeamVotedNo++; } } } } // If > 50% of team vote yes, switch th eplayers team if (newTeamTotalMemberCount > 0 && newTeamVotedYes > 0 && static_cast < float >(newTeamVotedYes) / static_cast < float >(newTeamTotalMemberCount) > 0.5) { Faction * faction = world->getFaction (factionIndex); int oldTeam = faction->getTeam (); faction->setTeam (vote->newTeam); GameSettings * settings = world->getGameSettingsPtr (); settings->setTeam (factionIndex, vote->newTeam); world->getStats ()->setTeam (factionIndex, vote->newTeam); if (factionIndex == world->getThisFactionIndex ()) { world->setThisTeamIndex (vote->newTeam); GameNetworkInterface * gameNetworkInterface = NetworkManager::getInstance (). getGameNetworkInterface (); if (gameNetworkInterface != NULL) { Lang & lang = Lang::getInstance (); const vector < string > languageList = settings->getUniqueNetworkPlayerLanguages (); for (unsigned int i = 0; i < languageList.size (); ++i) { char szMsg[8096] = ""; if (lang. hasString ("PlayerSwitchedTeam", languageList[i]) == true) { snprintf (szMsg, 8096, lang. getString ("PlayerSwitchedTeam", languageList[i]). c_str (), settings-> getNetworkPlayerName (factionIndex). c_str (), oldTeam, vote->newTeam); } else { snprintf (szMsg, 8096, "Player %s switched from team# %d to team# %d.", settings-> getNetworkPlayerName (factionIndex). c_str (), oldTeam, vote->newTeam); } bool localEcho = lang.isLanguageLocal (languageList[i]); gameNetworkInterface->sendTextMessage (szMsg, -1, localEcho, languageList [i]); } } world->getGame ()->reInitGUI (); } } else if (newTeamTotalMemberCount == (newTeamVotedYes + newTeamVotedNo)) { if (factionIndex == world->getThisFactionIndex ()) { GameSettings * settings = world->getGameSettingsPtr (); Faction * faction = world->getFaction (factionIndex); int oldTeam = faction->getTeam (); GameNetworkInterface * gameNetworkInterface = NetworkManager::getInstance (). getGameNetworkInterface (); if (gameNetworkInterface != NULL) { Lang & lang = Lang::getInstance (); const vector < string > languageList = settings->getUniqueNetworkPlayerLanguages (); for (unsigned int i = 0; i < languageList.size (); ++i) { char szMsg[8096] = ""; if (lang. hasString ("PlayerSwitchedTeamDenied", languageList[i]) == true) { snprintf (szMsg, 8096, lang. getString ("PlayerSwitchedTeamDenied", languageList[i]).c_str (), settings-> getNetworkPlayerName (factionIndex). c_str (), oldTeam, vote->newTeam); } else { snprintf (szMsg, 8096, "Player %s was denied the request to switch from team# %d to team# %d.", settings-> getNetworkPlayerName (factionIndex). c_str (), oldTeam, vote->newTeam); } bool localEcho = lang.isLanguageLocal (languageList[i]); gameNetworkInterface->sendTextMessage (szMsg, -1, localEcho, languageList [i]); } } } } if (SystemFlags:: getSystemSettingType (SystemFlags::debugPerformance).enabled && chrono.getMillis () > 0) SystemFlags::OutputDebug (SystemFlags::debugPerformance, "In [%s::%s Line: %d] took msecs: %lld [after unit->setMeetingPos]\n", extractFileFromDirectoryPath (__FILE__).c_str (), __FUNCTION__, __LINE__, chrono.getMillis ()); if (SystemFlags::getSystemSettingType (SystemFlags::debugSystem). enabled) SystemFlags::OutputDebug (SystemFlags::debugSystem, "In [%s::%s Line: %d] found nctSetMeetingPoint\n", extractFileFromDirectoryPath (__FILE__).c_str (), __FUNCTION__, __LINE__); } break; case nctDisconnectNetworkPlayer: { if (SystemFlags::getSystemSettingType (SystemFlags::debugSystem). enabled) SystemFlags::OutputDebug (SystemFlags::debugSystem, "In [%s::%s Line: %d] found nctDisconnectNetworkPlayer\n", extractFileFromDirectoryPath (__FILE__).c_str (), __FUNCTION__, __LINE__); commandWasHandled = true; NetworkManager & networkManager = NetworkManager::getInstance (); NetworkRole role = networkManager.getNetworkRole (); //GameSettings *settings = world->getGameSettingsPtr(); if (role == nrServer) { //int factionIndex = networkCommand->getUnitId(); int playerIndex = networkCommand->getCommandTypeId (); GameNetworkInterface * gameNetworkInterface = NetworkManager::getInstance ().getGameNetworkInterface (); if (gameNetworkInterface != NULL) { ServerInterface * server = networkManager.getServerInterface (); if (server != NULL && server->isClientConnected (playerIndex) == true) { MutexSafeWrapper safeMutex (server->getSlotMutex (playerIndex), CODE_AT_LINE); ConnectionSlot * slot = server->getSlot (playerIndex, false); if (slot != NULL) { safeMutex.ReleaseLock (); NetworkMessageQuit networkMessageQuit; slot->sendMessage (&networkMessageQuit); sleep (5); //printf("Sending nctDisconnectNetworkPlayer\n"); server = networkManager.getServerInterface (false); if (server != NULL) { MutexSafeWrapper safeMutex2 (server-> getSlotMutex (playerIndex), CODE_AT_LINE); slot = server->getSlot (playerIndex, false); if (slot != NULL) { safeMutex2.ReleaseLock (); slot->close (); } } } } } } if (SystemFlags::getSystemSettingType (SystemFlags::debugSystem). enabled) SystemFlags::OutputDebug (SystemFlags::debugSystem, "In [%s::%s Line: %d] found nctDisconnectNetworkPlayer\n", extractFileFromDirectoryPath (__FILE__).c_str (), __FUNCTION__, __LINE__); } break; case nctPauseResume: { if (SystemFlags::getSystemSettingType (SystemFlags::debugSystem). enabled) SystemFlags::OutputDebug (SystemFlags::debugSystem, "In [%s::%s Line: %d] found nctPauseResume\n", extractFileFromDirectoryPath (__FILE__).c_str (), __FUNCTION__, __LINE__); commandWasHandled = true; bool pauseGame = networkCommand->getUnitId () != 0; bool clearCaches = (networkCommand->getCommandTypeId () == 1); bool joinNetworkGame = (networkCommand->getUnitTypeId () == 1); Game * game = this->world->getGame (); //printf("nctPauseResume pauseGame = %d\n",pauseGame); game->setPaused (pauseGame, true, clearCaches, joinNetworkGame); if (SystemFlags::getSystemSettingType (SystemFlags::debugSystem). enabled) SystemFlags::OutputDebug (SystemFlags::debugSystem, "In [%s::%s Line: %d] found nctPauseResume\n", extractFileFromDirectoryPath (__FILE__).c_str (), __FUNCTION__, __LINE__); } break; case nctPlayerStatusChange: { if (SystemFlags::getSystemSettingType (SystemFlags::debugSystem). enabled) SystemFlags::OutputDebug (SystemFlags::debugSystem, "In [%s::%s Line: %d] found nctPlayerStatusChange\n", extractFileFromDirectoryPath (__FILE__).c_str (), __FUNCTION__, __LINE__); commandWasHandled = true; int factionIndex = networkCommand->getUnitId (); int playerStatus = networkCommand->getCommandTypeId (); if (SystemFlags::getSystemSettingType (SystemFlags::debugSystem). enabled) SystemFlags::OutputDebug (SystemFlags::debugSystem, "nctPlayerStatusChange factionIndex = %d playerStatus = %d\n", factionIndex, playerStatus); //printf("#1 nctPlayerStatusChange factionIndex = %d playerStatus = %d\n",factionIndex,playerStatus); GameSettings * settings = world->getGameSettingsPtr (); if (playerStatus == npst_Disconnected) { //printf("Commander nctPlayerStatusChange factionIndex: %d\n",factionIndex); settings->setNetworkPlayerStatuses (factionIndex, npst_Disconnected); //printf("nctPlayerStatusChange -> faction->getPersonalityType() = %d index [%d] control [%d] networkstatus [%d]\n", // world->getFaction(factionIndex)->getPersonalityType(),world->getFaction(factionIndex)->getIndex(),world->getFaction(factionIndex)->getControlType(),settings->getNetworkPlayerStatuses(factionIndex)); //printf("#2 nctPlayerStatusChange factionIndex = %d playerStatus = %d\n",factionIndex,playerStatus); settings->setFactionControl (factionIndex, ctCpuUltra); settings->setResourceMultiplierIndex (factionIndex, settings-> getFallbackCpuMultiplier ()); //Game *game = this->world->getGame(); //game->get Faction * faction = this->world->getFaction (factionIndex); faction->setControlType (ctCpuUltra); if (!world->getGame ()->getGameOver () && !this->world->getGame ()-> factionLostGame (factionIndex)) { // use the fallback multiplier here // mark player as "leaver" this->world->getStats ()-> setPlayerLeftBeforeEnd (factionIndex, true); // set disconnect time for endgame stats this->world->getStats ()->setTimePlayerLeft (factionIndex, this->world-> getStats ()-> getFramesToCalculatePlaytime ()); } } if (SystemFlags::getSystemSettingType (SystemFlags::debugSystem). enabled) SystemFlags::OutputDebug (SystemFlags::debugSystem, "In [%s::%s Line: %d] found nctPlayerStatusChange\n", extractFileFromDirectoryPath (__FILE__).c_str (), __FUNCTION__, __LINE__); } break; } if (commandWasHandled == false) { Unit * unit = world->findUnitById (networkCommand->getUnitId ()); if (SystemFlags:: getSystemSettingType (SystemFlags::debugPerformance).enabled && chrono.getMillis () > 0) SystemFlags::OutputDebug (SystemFlags::debugPerformance, "In [%s::%s Line: %d] took msecs: %lld [after world->findUnitById]\n", extractFileFromDirectoryPath (__FILE__). c_str (), __FUNCTION__, __LINE__, chrono.getMillis ()); if (SystemFlags::VERBOSE_MODE_ENABLED) printf ("Running command NetworkCommandType = %d, unitid = %d [%p] factionindex = %d\n", networkCommand->getNetworkCommandType (), networkCommand->getUnitId (), unit, (unit != NULL ? unit->getFactionIndex () : -1)); //execute command, if unit is still alive if (unit != NULL) { switch (networkCommand->getNetworkCommandType ()) { case nctGiveCommand: { assert (networkCommand->getCommandTypeId () != CommandType::invalidId); if (SystemFlags:: getSystemSettingType (SystemFlags::debugSystem). enabled) SystemFlags::OutputDebug (SystemFlags::debugSystem, "In [%s::%s Line: %d] found nctGiveCommand networkCommand->getUnitId() = %d\n", extractFileFromDirectoryPath (__FILE__).c_str (), __FUNCTION__, __LINE__, networkCommand->getUnitId ()); Command * command = buildCommand (networkCommand); if (SystemFlags:: getSystemSettingType (SystemFlags::debugPerformance). enabled && chrono.getMillis () > 0) SystemFlags::OutputDebug (SystemFlags::debugPerformance, "In [%s::%s Line: %d] took msecs: %lld [after buildCommand]\n", extractFileFromDirectoryPath (__FILE__).c_str (), __FUNCTION__, __LINE__, chrono.getMillis ()); if (SystemFlags:: getSystemSettingType (SystemFlags::debugSystem). enabled) SystemFlags::OutputDebug (SystemFlags::debugSystem, "In [%s::%s Line: %d] command = %p\n", extractFileFromDirectoryPath (__FILE__).c_str (), __FUNCTION__, __LINE__, command); unit->giveCommand (command, (networkCommand->getWantQueue () != 0)); if (SystemFlags:: getSystemSettingType (SystemFlags::debugPerformance). enabled && chrono.getMillis () > 0) SystemFlags::OutputDebug (SystemFlags::debugPerformance, "In [%s::%s Line: %d] took msecs: %lld [after unit->giveCommand]\n", extractFileFromDirectoryPath (__FILE__).c_str (), __FUNCTION__, __LINE__, chrono.getMillis ()); if (SystemFlags:: getSystemSettingType (SystemFlags::debugSystem). enabled) SystemFlags::OutputDebug (SystemFlags::debugSystem, "In [%s::%s Line: %d] found nctGiveCommand networkCommand->getUnitId() = %d\n", extractFileFromDirectoryPath (__FILE__).c_str (), __FUNCTION__, __LINE__, networkCommand->getUnitId ()); } break; case nctCancelCommand: { if (SystemFlags:: getSystemSettingType (SystemFlags::debugSystem). enabled) SystemFlags::OutputDebug (SystemFlags::debugSystem, "In [%s::%s Line: %d] found nctCancelCommand\n", extractFileFromDirectoryPath (__FILE__).c_str (), __FUNCTION__, __LINE__); unit->cancelCommand (); if (SystemFlags:: getSystemSettingType (SystemFlags::debugPerformance). enabled && chrono.getMillis () > 0) SystemFlags::OutputDebug (SystemFlags::debugPerformance, "In [%s::%s Line: %d] took msecs: %lld [after unit->cancelCommand]\n", extractFileFromDirectoryPath (__FILE__).c_str (), __FUNCTION__, __LINE__, chrono.getMillis ()); if (SystemFlags:: getSystemSettingType (SystemFlags::debugSystem). enabled) SystemFlags::OutputDebug (SystemFlags::debugSystem, "In [%s::%s Line: %d] found nctCancelCommand\n", extractFileFromDirectoryPath (__FILE__).c_str (), __FUNCTION__, __LINE__); } break; case nctSetMeetingPoint: { if (SystemFlags:: getSystemSettingType (SystemFlags::debugSystem). enabled) SystemFlags::OutputDebug (SystemFlags::debugSystem, "In [%s::%s Line: %d] found nctSetMeetingPoint\n", extractFileFromDirectoryPath (__FILE__).c_str (), __FUNCTION__, __LINE__); unit->setMeetingPos (networkCommand->getPosition ()); if (SystemFlags:: getSystemSettingType (SystemFlags::debugPerformance). enabled && chrono.getMillis () > 0) SystemFlags::OutputDebug (SystemFlags::debugPerformance, "In [%s::%s Line: %d] took msecs: %lld [after unit->setMeetingPos]\n", extractFileFromDirectoryPath (__FILE__).c_str (), __FUNCTION__, __LINE__, chrono.getMillis ()); if (SystemFlags:: getSystemSettingType (SystemFlags::debugSystem). enabled) SystemFlags::OutputDebug (SystemFlags::debugSystem, "In [%s::%s Line: %d] found nctSetMeetingPoint\n", extractFileFromDirectoryPath (__FILE__).c_str (), __FUNCTION__, __LINE__); } break; default: assert (false); break; } } else { if (SystemFlags:: getSystemSettingType (SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug (SystemFlags::debugSystem, "In [%s::%s Line: %d] NULL Unit for id = %d, networkCommand->getNetworkCommandType() = %d\n", extractFileFromDirectoryPath (__FILE__).c_str (), __FUNCTION__, __LINE__, networkCommand->getUnitId (), networkCommand-> getNetworkCommandType ()); } } if (SystemFlags::getSystemSettingType (SystemFlags::debugPerformance). enabled && chrono.getMillis () > 0) SystemFlags::OutputDebug (SystemFlags::debugPerformance, "In [%s::%s Line: %d] took msecs: %lld [END]\n", extractFileFromDirectoryPath (__FILE__). c_str (), __FUNCTION__, __LINE__, chrono.getMillis ()); } // Reconstruct a network command received. Command * Commander::buildCommand (const NetworkCommand * networkCommand) const { // Check a new command is actually being given (and not a cancel command, switch team etc.). assert (networkCommand->getNetworkCommandType () == nctGiveCommand); if (SystemFlags::getSystemSettingType (SystemFlags::debugSystem). enabled) SystemFlags::OutputDebug (SystemFlags::debugSystem, "In [%s::%s Line: %d] networkCommand [%s]\n", extractFileFromDirectoryPath (__FILE__). c_str (), __FUNCTION__, __LINE__, networkCommand->toString ().c_str ()); // Check there is a world. if (world == NULL) { char szBuf[8096] = ""; snprintf (szBuf, 8096, "In [%s::%s Line: %d] world == NULL for unit with id: %d", extractFileFromDirectoryPath (__FILE__).c_str (), __FUNCTION__, __LINE__, networkCommand->getUnitId ()); throw megaglest_runtime_error (szBuf); } // Get the unit. Unit * target = NULL; const CommandType * ct = NULL; const Unit * unit = world->findUnitById (networkCommand->getUnitId ()); // Validate unit is in game. if (unit == NULL) { char szBuf[8096] = ""; snprintf (szBuf, 8096, "In [%s::%s Line: %d] Can not find unit with id: %d. Game out of synch.", extractFileFromDirectoryPath (__FILE__).c_str (), __FUNCTION__, __LINE__, networkCommand->getUnitId ()); SystemFlags::OutputDebug (SystemFlags::debugError, "%s\n", szBuf); if (SystemFlags::getSystemSettingType (SystemFlags::debugSystem). enabled) SystemFlags::OutputDebug (SystemFlags::debugSystem, "%s\n", szBuf); GameNetworkInterface * gameNetworkInterface = NetworkManager::getInstance ().getGameNetworkInterface (); if (gameNetworkInterface != NULL) { char szMsg[8096] = ""; snprintf (szMsg, 8096, "Player detected an error: Can not find unit with id: %d. Game out of synch.", networkCommand->getUnitId ()); gameNetworkInterface->sendTextMessage (szMsg, -1, true, ""); } throw megaglest_runtime_error (szBuf); } // Get the command type for the unit. ct = unit->getType ()->findCommandTypeById (networkCommand-> getCommandTypeId ()); // Check that the unit from the network command is the same faction as the unit in the local game. if (unit->getFaction ()->getIndex () != networkCommand->getUnitFactionIndex ()) { char szBuf[8096] = ""; snprintf (szBuf, 8096, "In [%s::%s Line: %d]\nUnit / Faction mismatch for network command = [%s]\n%s\nfor unit = %d\n[%s]\n[%s]\nactual local factionIndex = %d.\nGame out of synch.", __FILE__, __FUNCTION__, __LINE__, networkCommand->toString ().c_str (), unit->getType ()->getCommandTypeListDesc ().c_str (), unit->getId (), unit->getFullName (false).c_str (), unit->getDesc (false).c_str (), unit->getFaction ()->getIndex ()); SystemFlags::OutputDebug (SystemFlags::debugError, "%s\n", szBuf); if (SystemFlags::getSystemSettingType (SystemFlags::debugSystem). enabled) SystemFlags::OutputDebug (SystemFlags::debugSystem, "%s\n", szBuf); //std::string worldLog = world->DumpWorldToLog(); world->DumpWorldToLog (); // Broadcast the error if player is still connected and print locally. GameNetworkInterface * gameNetworkInterface = NetworkManager::getInstance ().getGameNetworkInterface (); if (gameNetworkInterface != NULL && gameNetworkInterface->isConnected () == true) { char szMsg[8096] = ""; snprintf (szMsg, 8096, "Player detected an error: Unit / Faction mismatch for unitId: %d", networkCommand->getUnitId ()); gameNetworkInterface->sendTextMessage (szMsg, -1, true, ""); snprintf (szMsg, 8096, "Local faction index = %d, remote index = %d. Game out of synch.", unit->getFaction ()->getIndex (), networkCommand->getUnitFactionIndex ()); gameNetworkInterface->sendTextMessage (szMsg, -1, true, ""); } // Else if it's a network game but the user disconnected, print the error locally only. else if (gameNetworkInterface != NULL) { char szMsg[8096] = ""; snprintf (szMsg, 8096, "Player detected an error: Connection lost, possible Unit / Faction mismatch for unitId: %d", networkCommand->getUnitId ()); gameNetworkInterface->sendTextMessage (szMsg, -1, true, ""); snprintf (szMsg, 8096, "Local faction index = %d, remote index = %d. Game out of synch.", unit->getFaction ()->getIndex (), networkCommand->getUnitFactionIndex ()); gameNetworkInterface->sendTextMessage (szMsg, -1, true, ""); } // Kill the game. std::string sError = "Error [#1]: Game is out of sync (Unit / Faction mismatch)\nplease check log files for details."; throw megaglest_runtime_error (sError); } const UnitType * unitType = world->findUnitTypeById (unit->getFaction ()->getType (), networkCommand->getUnitTypeId ()); // debug test! //throw megaglest_runtime_error("Test missing command type!"); //validate command type // !!!Test out of synch behaviour //ct = NULL; // Check if the command was for the unit before it morphed, if so cancel it. bool isCancelPreMorphCommand = false; if (ct == NULL && unit->getPreMorphType () != NULL) { const CommandType * ctPreMorph = unit->getPreMorphType ()->findCommandTypeById (networkCommand-> getCommandTypeId ()); if (ctPreMorph != NULL) { ct = unit->getType ()->getFirstCtOfClass (ccStop); isCancelPreMorphCommand = true; } } // Throw an error if a valid command for the unit is still not found. if (ct == NULL) { char szBuf[8096] = ""; snprintf (szBuf, 8096, "In [%s::%s Line: %d]\nCan not find command type for network command = [%s]\n%s\nfor unit = %d\n[%s]\n[%s]\nactual local factionIndex = %d.\nUnit Type Info:\n[%s]\nNetwork unit type:\n[%s]\nisCancelPreMorphCommand: %d\nGame out of synch.", extractFileFromDirectoryPath (__FILE__).c_str (), __FUNCTION__, __LINE__, networkCommand->toString ().c_str (), unit->getType ()->getCommandTypeListDesc ().c_str (), unit->getId (), unit->getFullName (false).c_str (), unit->getDesc (false).c_str (), unit->getFaction ()->getIndex (), unit->getType ()->toString ().c_str (), (unitType != NULL ? unitType->getName (false).c_str () : "null"), isCancelPreMorphCommand); SystemFlags::OutputDebug (SystemFlags::debugSystem, "%s\n", szBuf); SystemFlags::OutputDebug (SystemFlags::debugError, "%s\n", szBuf); world->DumpWorldToLog (); GameNetworkInterface * gameNetworkInterface = NetworkManager::getInstance ().getGameNetworkInterface (); if (gameNetworkInterface != NULL) { char szMsg[8096] = ""; snprintf (szMsg, 8096, "Player detected an error: Can not find command type: %d for unitId: %d [%s]. isCancelPreMorphCommand: %d Game out of synch.", networkCommand->getCommandTypeId (), networkCommand->getUnitId (), (unitType != NULL ? unitType->getName (false).c_str () : "null"), isCancelPreMorphCommand); gameNetworkInterface->sendTextMessage (szMsg, -1, true, ""); } std::string sError = "Error [#3]: Game is out of sync, please check log files for details."; //abort(); throw megaglest_runtime_error (sError); } CardinalDir facing; // Get direction of the command target unit. if (isCancelPreMorphCommand == false) { // If target is a building. if (ct->getClass () == ccBuild) { // Check the target building ID is valid. If not, throw an error. /// TODO: What is happening here? The error returned does not match the condition. Why is there a constant of 4? if (networkCommand->getTargetId () < 0 || networkCommand->getTargetId () >= 4) { char szBuf[8096] = ""; snprintf (szBuf, 8096, "networkCommand->getTargetId() >= 0 && networkCommand->getTargetId() < 4, [%s]", networkCommand->toString ().c_str ()); throw megaglest_runtime_error (szBuf); } facing = CardinalDir (networkCommand->getTargetId ()); } // Get the target unit if the ID is valid. else if (networkCommand->getTargetId () != Unit::invalidId) { target = world->findUnitById (networkCommand->getTargetId ()); } } // Create the command. Command * command = NULL; if (isCancelPreMorphCommand == false) { if (unitType != NULL) { command = new Command (ct, networkCommand->getPosition (), unitType, facing); } else if (target == NULL) { command = new Command (ct, networkCommand->getPosition ()); } else { command = new Command (ct, target); } } else { command = new Command (ct, NULL); } // Add in any special state CommandStateType commandStateType = networkCommand->getCommandStateType (); int commandStateValue = networkCommand->getCommandStateValue (); command->setStateType (commandStateType); command->setStateValue (commandStateValue); command->setUnitCommandGroupId (networkCommand-> getUnitCommandGroupId ()); if (SystemFlags::getSystemSettingType (SystemFlags::debugSystem). enabled) SystemFlags::OutputDebug (SystemFlags::debugSystem, "In [%s::%s Line: %d]\n", extractFileFromDirectoryPath (__FILE__). c_str (), __FUNCTION__, __LINE__); //issue command return command; } } } //end namespace