2018-02-01 13:39:41 -06:00

2019 lines
81 KiB
C++

// ==============================================================
// 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