Skip to content

Commit

Permalink
Split TradeRoutePathCache into UI and DLL instances (#10250)
Browse files Browse the repository at this point in the history
  • Loading branch information
seroperson committed Sep 28, 2023
1 parent be9296c commit 3d3043f
Show file tree
Hide file tree
Showing 7 changed files with 117 additions and 27 deletions.
11 changes: 2 additions & 9 deletions CvGameCoreDLL_Expansion2/CvCity.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -400,7 +400,6 @@ CvCity::CvCity() :
, m_aiYieldFromPillage()
, m_aiYieldFromPillageGlobal()
, m_aiNumTimesAttackedThisTurn()
, m_aiLongestPotentialTradeRoute()
, m_aiNumProjects()
, m_aiYieldFromKnownPantheons()
, m_aiGoldenAgeYieldMod()
Expand Down Expand Up @@ -1432,7 +1431,6 @@ void CvCity::reset(int iID, PlayerTypes eOwner, int iX, int iY, bool bConstructo
m_iBaseTourism = 0;
m_iBaseTourismBeforeModifiers = 0;
m_aiNumTimesAttackedThisTurn.resize(REALLY_MAX_PLAYERS);
m_aiLongestPotentialTradeRoute.resize(NUM_DOMAIN_TYPES);
m_aiNumProjects.resize(GC.getNumProjectInfos());
m_aiSpecialistRateModifier.resize(GC.getNumSpecialistInfos());
m_aiYieldFromVictory.resize(NUM_YIELD_TYPES);
Expand Down Expand Up @@ -1485,10 +1483,6 @@ void CvCity::reset(int iID, PlayerTypes eOwner, int iX, int iY, bool bConstructo
{
m_aiNumTimesAttackedThisTurn[iI] = 0;
}
for (iI = 0; iI < NUM_DOMAIN_TYPES; iI++)
{
m_aiLongestPotentialTradeRoute[iI] = 0;
}
#endif
m_miInstantYieldsTotal.clear();
m_aiBaseYieldRateFromReligion.resize(NUM_YIELD_TYPES);
Expand Down Expand Up @@ -2970,15 +2964,15 @@ int CvCity::GetTradeRouteLandDistanceModifier() const
// --------------------------------------------------------------------------------
int CvCity::GetLongestPotentialTradeRoute(DomainTypes eDomain) const
{
return m_aiLongestPotentialTradeRoute[eDomain];
return GC.getGame().GetGameTrade()->GetLongestPotentialTradeRoute(GetID(), eDomain);
}
// --------------------------------------------------------------------------------
void CvCity::SetLongestPotentialTradeRoute(int iValue, DomainTypes eDomain)
{
VALIDATE_OBJECT
CvAssertMsg(eDomain >= 0, "eIndex1 is expected to be non-negative (invalid Index)");
CvAssertMsg(eDomain < NUM_DOMAIN_TYPES, "eIndex1 is expected to be within maximum bounds (invalid Index)");
m_aiLongestPotentialTradeRoute[eDomain] = iValue;
GC.getGame().GetGameTrade()->GetLongestPotentialTradeRoute(GetID(), eDomain);
}

bool CvCity::AreOurBordersTouching(PlayerTypes ePlayer)
Expand Down Expand Up @@ -33071,7 +33065,6 @@ void CvCity::Serialize(City& city, Visitor& visitor)
visitor(city.m_iCachedEmpireSizeModifier);
visitor(city.m_iYieldMediansCachedTurn);
visitor(city.m_aiNumProjects);
visitor(city.m_aiLongestPotentialTradeRoute);
visitor(city.m_aiNumTimesAttackedThisTurn);
visitor(city.m_aiYieldFromKnownPantheons);
visitor(city.m_aiYieldFromVictory);
Expand Down
2 changes: 0 additions & 2 deletions CvGameCoreDLL_Expansion2/CvCity.h
Original file line number Diff line number Diff line change
Expand Up @@ -1921,7 +1921,6 @@ class CvCity
int m_iCachedEmpireSizeModifier;
int m_iYieldMediansCachedTurn;
std::vector<int> m_aiNumProjects;
std::vector<int> m_aiLongestPotentialTradeRoute;
std::vector<int> m_aiNumTimesAttackedThisTurn;
std::vector<int> m_aiYieldFromKnownPantheons;
std::vector<int> m_aiYieldFromVictory;
Expand Down Expand Up @@ -2311,7 +2310,6 @@ SYNC_ARCHIVE_VAR(int, m_iCachedTechNeedModifier)
SYNC_ARCHIVE_VAR(int, m_iCachedEmpireSizeModifier)
SYNC_ARCHIVE_VAR(int, m_iYieldMediansCachedTurn)
SYNC_ARCHIVE_VAR(std::vector<int>, m_aiNumProjects)
SYNC_ARCHIVE_VAR(std::vector<int>, m_aiLongestPotentialTradeRoute)
SYNC_ARCHIVE_VAR(std::vector<int>, m_aiNumTimesAttackedThisTurn)
SYNC_ARCHIVE_VAR(std::vector<int>, m_aiYieldFromKnownPantheons)
SYNC_ARCHIVE_VAR(std::vector<int>, m_aiYieldFromVictory)
Expand Down
30 changes: 28 additions & 2 deletions CvGameCoreDLL_Expansion2/CvGame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ CvGame::CvGame() :
, m_bSavedOnce(false)
#endif
, m_bArchaeologyTriggered(false)
, m_bIsDesynced(false)
, m_lastTurnAICivsProcessed(-1)
, m_processPlayerAutoMoves(false)
, m_cityDistancePathLength(NO_DOMAIN) //for now!
Expand Down Expand Up @@ -1166,6 +1167,7 @@ void CvGame::uninit()
m_bEverRightClickMoved = false;
m_bCombatWarned = false;
m_bArchaeologyTriggered = false;
m_bIsDesynced = false;

m_eHandicap = NO_HANDICAP;
m_ePausePlayer = NO_PLAYER;
Expand Down Expand Up @@ -5981,6 +5983,22 @@ bool CvGame::isSimultaneousTeamTurns() const
return true;
}


bool CvGame::isDesynced() const
{
if (!isNetworkMultiPlayer()) {
return false;
}
return m_bIsDesynced;
}
void CvGame::setDesynced(bool bNewValue)
{
if (!isNetworkMultiPlayer()) {
return;
}
m_bIsDesynced = bNewValue;
}

// --------------------------------------------------------------------------------
bool CvGame::isFinalInitialized() const
{
Expand Down Expand Up @@ -8800,9 +8818,17 @@ void CvGame::doTurn()

LogGameState();

//autosave after doing a turn
if (isNetworkMultiPlayer())
if (isNetworkMultiPlayer()) {
//autosave after doing a turn
gDLL->AutoSave(false, false);

if (isDesynced()) {
setDesynced(false);

CvString output; CvString::format(output, "Session is running in desynced state, undefined behaviour may appear. Please, fill the issue on GitHub.");
gGlobals.getDLLIFace()->sendChat(output, CHATTARGET_ALL, NO_PLAYER);
}
}
}

// --------------------------------------------------------------------------------
Expand Down
4 changes: 4 additions & 0 deletions CvGameCoreDLL_Expansion2/CvGame.h
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,9 @@ class CvGame
bool isPitboss() const;
bool isSimultaneousTeamTurns() const;

bool isDesynced() const;
void setDesynced(bool bNewValue);

bool isFinalInitialized() const;
void setFinalInitialized(bool bNewValue);

Expand Down Expand Up @@ -893,6 +896,7 @@ class CvGame
bool m_bEndGameTechResearched;
bool m_bTunerEverConnected;
bool m_bDynamicTurnsSimultMode; //if playing dynamic turn mode, are we currently running simultaneous turns?
bool m_bIsDesynced; // whether the game was desynced or not as a result of the very last sync
PlayerTypes m_eWaitDiploPlayer;
TechTypes m_eTechAstronomy;

Expand Down
2 changes: 2 additions & 0 deletions CvGameCoreDLL_Expansion2/CvSerialize.h
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,8 @@ class CvSyncVar : public CvSyncVarBase<typename VarTraits::ValueType>
if (!result) {
std::string desyncValues = std::string("Desync values, current ") + FSerialization::toString(currentValue()) + "; other " + FSerialization::toString(other) + std::string("\n");
gGlobals.getDLLIFace()->netMessageDebugLog(desyncValues);

gGlobals.getGame().setDesynced(true);
}

return result; // Place a conditional breakpoint here to help debug sync errors.
Expand Down
81 changes: 68 additions & 13 deletions CvGameCoreDLL_Expansion2/CvTradeClasses.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,51 @@ void CvGameTrade::DoTurn (void)
BuildPolicyDifference();
}

int CvGameTrade::GetLongestPotentialTradeRoute(int iCityIndex, DomainTypes eDomain) {
std::map<int, std::map<DomainTypes, int>>::const_iterator cityIt = m_aiLongestPotentialTradeRoute.find(iCityIndex);
if (cityIt == m_aiLongestPotentialTradeRoute.end()) {
return -1;
}

std::map<DomainTypes, int>::const_iterator domainIt = (cityIt->second).find(eDomain);
if (domainIt == (cityIt->second).end()) {
return -1;
}

return domainIt->second;
}

void CvGameTrade::SetLongestPotentialTradeRoute(int iValue, int iCityIndex, DomainTypes eDomain) {
m_aiLongestPotentialTradeRoute[iCityIndex].insert(std::make_pair(eDomain, iValue));
}

TradePathLookup& CvGameTrade::GetTradePathsCache(bool bWater) {
if (gDLL->IsGameCoreThread()) {
if (bWater) {
return m_aPotentialTradePathsWater;
}
else {
return m_aPotentialTradePathsLand;
}
}
else {
if (bWater) {
return m_aPotentialTradePathsWaterUi;
}
else {
return m_aPotentialTradePathsLandUi;
}
}
}
std::map<PlayerTypes,int>& CvGameTrade::GetTradePathsCacheUpdateCounter() {
if (gDLL->IsGameCoreThread()) {
return m_lastTradePathUpdate;
}
else {
return m_lastTradePathUpdateUi;
}
}

// helper function
bool HaveTradePathInCache(const TradePathLookup& cache, int iCityPlotA, int iCityPlotB)
{
Expand Down Expand Up @@ -129,7 +174,7 @@ const std::map<int, SPath>& CvGameTrade::GetAllPotentialTradeRoutesFromCity(CvCi
//make sure we're up to date
UpdateTradePathCache(pOriginCity->getOwner());

const TradePathLookup& cache = bWater ? m_aPotentialTradePathsWater : m_aPotentialTradePathsLand;
const TradePathLookup& cache = GetTradePathsCache(bWater);
TradePathLookup::const_iterator it = cache.find(pOriginCity->plot()->GetPlotIndex());
if (it != cache.end())
return it->second;
Expand All @@ -147,7 +192,7 @@ bool CvGameTrade::HavePotentialTradePath(bool bWater, CvCity* pOriginCity, CvCit
UpdateTradePathCache(eOriginPlayer);

//can't use const here, otherwise the [] operator does not work ...
TradePathLookup& cache = bWater ? m_aPotentialTradePathsWater : m_aPotentialTradePathsLand;
TradePathLookup& cache = GetTradePathsCache(bWater);

int iCityPlotA = pOriginCity->plot()->GetPlotIndex();
int iCityPlotB = pDestCity->plot()->GetPlotIndex();
Expand Down Expand Up @@ -182,6 +227,11 @@ void CvGameTrade::InvalidateTradePathTeamCache(TeamTypes eTeam)
void CvGameTrade::InvalidateTradePathCache(PlayerTypes ePlayer)
{
m_lastTradePathUpdate[ePlayer] = -1;
m_lastTradePathUpdateUi[ePlayer] = -1;
m_aPotentialTradePathsWater.clear();
m_aPotentialTradePathsWaterUi.clear();
m_aPotentialTradePathsLand.clear();
m_aPotentialTradePathsLandUi.clear();
}

void CvGameTrade::UpdateTradePathCache(PlayerTypes ePlayer1)
Expand All @@ -190,9 +240,10 @@ void CvGameTrade::UpdateTradePathCache(PlayerTypes ePlayer1)
if (!kPlayer1.isAlive() || kPlayer1.isBarbarian() || kPlayer1.isMinorCiv())
return;

std::map<PlayerTypes, int> lastTradePathUpdate = GetTradePathsCacheUpdateCounter();
//check if we have anything to do
std::map<PlayerTypes,int>::iterator lastUpdate = m_lastTradePathUpdate.find(ePlayer1);
if (lastUpdate!=m_lastTradePathUpdate.end() && lastUpdate->second==GC.getGame().getGameTurn())
std::map<PlayerTypes,int>::iterator lastUpdate = lastTradePathUpdate.find(ePlayer1);
if (lastUpdate!=lastTradePathUpdate.end() && lastUpdate->second==GC.getGame().getGameTurn())
return;

//do not check whether we are at war here! the trade route cache is also used for military target selection
Expand All @@ -211,9 +262,13 @@ void CvGameTrade::UpdateTradePathCache(PlayerTypes ePlayer1)
int iOriginCityLoop = 0;
for (CvCity* pOriginCity = kPlayer1.firstCity(&iOriginCityLoop); pOriginCity != NULL; pOriginCity = kPlayer1.nextCity(&iOriginCityLoop))
{
CvPlot* pCityPlot = pOriginCity->plot();
int iCityPlotIndex = pCityPlot->GetPlotIndex();
TradePathLookup& m_aLandPaths = GetTradePathsCache(false);
TradePathLookup& m_aWaterPaths = GetTradePathsCache(true);
//throw away the old data before adding the new
m_aPotentialTradePathsLand[pOriginCity->plot()->GetPlotIndex()].clear();
m_aPotentialTradePathsWater[pOriginCity->plot()->GetPlotIndex()].clear();
m_aLandPaths[iCityPlotIndex].clear();
m_aWaterPaths[iCityPlotIndex].clear();

//first see how far we can go from this city on water
int iMaxNormDistSea = kPlayer1.GetTrade()->GetTradeRouteRange(DOMAIN_SEA, pOriginCity);
Expand All @@ -223,16 +278,16 @@ void CvGameTrade::UpdateTradePathCache(PlayerTypes ePlayer1)
//get all paths
//paths from origin city to dest city
//map<index of dest's city plot, path to this city>
map<int,SPath> waterpaths = GC.GetStepFinder().GetMultiplePaths( pOriginCity->plot(), vDestPlots, data );
map<int,SPath> waterpaths = GC.GetStepFinder().GetMultiplePaths(pCityPlot, vDestPlots, data );
for (map<int,SPath>::iterator it=waterpaths.begin(); it!=waterpaths.end(); ++it)
{
CvPlot* plot = GC.getMap().plotByIndex(it->first);
// if this is the origin city, nothing to do
if (pOriginCity->plot() == plot)
if (pCityPlot == plot)
continue;

CvCity* pDestCity = plot->getPlotCity();
AddTradePathToCache(m_aPotentialTradePathsWater,pOriginCity->plot()->GetPlotIndex(),pDestCity->plot()->GetPlotIndex(),it->second);
AddTradePathToCache(m_aWaterPaths,iCityPlotIndex,pDestCity->plot()->GetPlotIndex(),it->second);
}

//now for land routes
Expand All @@ -241,21 +296,21 @@ void CvGameTrade::UpdateTradePathCache(PlayerTypes ePlayer1)
data.ePathType = PT_TRADE_LAND;

//get all paths
map<int,SPath> landpaths = GC.GetStepFinder().GetMultiplePaths( pOriginCity->plot(), vDestPlots, data );
map<int,SPath> landpaths = GC.GetStepFinder().GetMultiplePaths( pCityPlot, vDestPlots, data );
for (map<int,SPath>::iterator it=landpaths.begin(); it!=landpaths.end(); ++it)
{
CvPlot* plot = GC.getMap().plotByIndex(it->first);
// if this is the origin city, nothing to do
if (pOriginCity->plot() == plot)
if (pCityPlot == plot)
continue;

CvCity* pDestCity = plot->getPlotCity();
AddTradePathToCache(m_aPotentialTradePathsLand,pOriginCity->plot()->GetPlotIndex(),pDestCity->plot()->GetPlotIndex(),it->second);
AddTradePathToCache(m_aLandPaths,iCityPlotIndex,pDestCity->plot()->GetPlotIndex(),it->second);
}

}

m_lastTradePathUpdate[ePlayer1]=GC.getGame().getGameTurn();
GetTradePathsCacheUpdateCounter()[ePlayer1]=GC.getGame().getGameTurn();

for (CvCity* pOriginCity = kPlayer1.firstCity(&iOriginCityLoop); pOriginCity != NULL; pOriginCity = kPlayer1.nextCity(&iOriginCityLoop))
{
Expand Down
14 changes: 13 additions & 1 deletion CvGameCoreDLL_Expansion2/CvTradeClasses.h
Original file line number Diff line number Diff line change
Expand Up @@ -217,12 +217,24 @@ class CvGameTrade
void InvalidateTradePathCache(PlayerTypes iPlayer);
void InvalidateTradePathTeamCache(TeamTypes eTeam);

protected:
void SetLongestPotentialTradeRoute(int iValue, int iCityIndex, DomainTypes eDomain);
int GetLongestPotentialTradeRoute(int iCityIndex, DomainTypes eDomain);

private:
TradePathLookup& GetTradePathsCache(bool bWater);
std::map<PlayerTypes,int>& GetTradePathsCacheUpdateCounter();

protected:

// std::map<city index, std::map<DomainTypes, longest length>>
std::map<int, std::map<DomainTypes, int>> m_aiLongestPotentialTradeRoute;
TradeConnectionList m_aTradeConnections;
TradePathLookup m_aPotentialTradePathsLand;
TradePathLookup m_aPotentialTradePathsWater;
TradePathLookup m_aPotentialTradePathsLandUi;
TradePathLookup m_aPotentialTradePathsWaterUi;
std::map<PlayerTypes,int> m_lastTradePathUpdate;
std::map<PlayerTypes,int> m_lastTradePathUpdateUi;
std::vector<vector<int>> m_routesPerPlayer;
std::map<int, SPath> m_dummyTradePaths; //always empty, just for us to return a reference

Expand Down

0 comments on commit 3d3043f

Please sign in to comment.