1. We have added a Gift Upgrades feature that allows you to gift an account upgrade to another member, just in time for the holiday season. You can see the gift option when going to the Account Upgrades screen, or on any user profile screen.
    Dismiss Notice

OOS problems and how to fix them

Discussion in 'Bugs and Crashes' started by 45°38'N-13°47'E, Jan 20, 2014.

  1. 45°38'N-13°47'E

    45°38'N-13°47'E Chieftain

    Joined:
    Jun 7, 2008
    Messages:
    5,833
    Location:
    Just wonder...
    I've checked the code and I've imported everything from rev5588 into AND, except the part on "deferred vote" because that part was causing an issue displaying resolutions on the Victory Screen / Resolution screen and UN or AP Members screen. I couldn't get around it; as a consequence I removed those lines, but I don't think this has anything to do with our current OOS. Everything else was imported correctly.
     
  2. 45°38'N-13°47'E

    45°38'N-13°47'E Chieftain

    Joined:
    Jun 7, 2008
    Messages:
    5,833
    Location:
    Just wonder...
    Is it something very recent? I'm almost certain I've imported everything from C2C; can you point me at the source file in C2C? I can check myself what's different with our code. Thank you.

    Edit: Nevermind, I think I got it, it's in cvunit.cpp and .h, I guess you're referring to

    Code:
    int CvUnit::visibilityRange(const CvPlot* pPlot) const
    in rev6113

    I haven't imported that part of the code because I thought it was part of Super Forts, which I've left out of AND. I see what I can do. Thank you again AIAndy, I'll let you know if this works.
     
  3. 45°38'N-13°47'E

    45°38'N-13°47'E Chieftain

    Joined:
    Jun 7, 2008
    Messages:
    5,833
    Location:
    Just wonder...
    No, it doesn't work. I've updated visibility code in the dll (I've left out only the part regarding improvement visibility which was made for SuperForts if I'm not mistaken). But I still have OOS when moving some caravel; almost always when my opponent moves her caravels; actually always until now in the last 50 turns or so (turn 290/600 now). The only different thing that comes to my mind is that she has proven the world round and hence she has 1 more movement, it's the only difference I guess between her caravels and mine. I wonder why she goes OOS while I don't logs display her caravel in a different position to what I see, while my caravels don't have this problem.
     
  4. Thunderbrd

    Thunderbrd C2C War Dog

    Joined:
    Jan 2, 2010
    Messages:
    25,165
    Gender:
    Male
    Location:
    Las Vegas
  5. 45°38'N-13°47'E

    45°38'N-13°47'E Chieftain

    Joined:
    Jun 7, 2008
    Messages:
    5,833
    Location:
    Just wonder...
    No, I don't think so, because sometimes we were able to clear the OOS by moving the caravel one tile back. So OOS happened before last movement in this case.
     
  6. Thunderbrd

    Thunderbrd C2C War Dog

    Joined:
    Jan 2, 2010
    Messages:
    25,165
    Gender:
    Male
    Location:
    Las Vegas
    Wouldn't be a problem with circumnavigation then. I doubted that anyhow. I'm not terribly familiar with routing codes sadly.
     
  7. 45°38'N-13°47'E

    45°38'N-13°47'E Chieftain

    Joined:
    Jun 7, 2008
    Messages:
    5,833
    Location:
    Just wonder...
    I've had a look at previous C2C revisions; the only spot were I know something has changed for sea pathing is in rev3789

    a function has been added

    Code:
    void	CvPath::trimBefore(const CvPlot* pPlot)
    {
    	CvPathNode*	pNode = m_startNode;
    
    	while( pNode != NULL )
    	{
    		if ( pNode->m_plot == pPlot )
    		{
    			m_startNode = pNode;
    			break;
    		}
    
    		pNode = pNode->m_firstChild;
    	}
    }
    and also this part of code in

    bool CvPathGenerator::generatePath

    has been changed from

    Code:
    bool	CvPathGenerator::generatePath(const CvPlot* pFrom, const CvPlot* pTo, CvSelectionGroup* pGroup, int iFlags, int iMaxTurns)
    {
    	CvPathNode*	root;
    
    	PROFILE_FUNC();
    
    	m_bFoundRoute = false;
    
    	m_generatedPath.Set(NULL);
    	m_iSeq++;
    
    	unsigned int iGroupMembershipChecksum = 0;
    	CLLNode<IDInfo>* pUnitNode;
    	CvUnit* pLoopUnit;
    
    	pUnitNode = pGroup->headUnitNode();
    
    	while (pUnitNode != NULL)
    	{
    		pLoopUnit = ::getUnit(pUnitNode->m_data);
    		pUnitNode = pGroup->nextUnitNode(pUnitNode);
    
    		CheckSum(iGroupMembershipChecksum, pLoopUnit->getID());
    	}
    
    	if ( m_currentGroupMembershipChecksum != iGroupMembershipChecksum || m_iFlags != iFlags )
    	{
    		CvSelectionGroup::setGroupToCacheFor(pGroup);
    
    		if ( !pGroup->AI_isControlled() )
    		{
    			m_useAIPathingAlways = getBugOptionBOOL("MainInterface__UseAIPathing", false);
    		}
    	}
    
    	bool bRequiresWar;
    
    	if ( !m_TerminusValidFunc(pGroup, pTo->getX_INLINE(), pTo->getY_INLINE(), iFlags, bRequiresWar) )
    	{
    		return false;
    	}
    
    	if ( bRequiresWar )
    	{
    		iFlags |= MOVE_TERMINUS_DECLARES_WAR;
    	}
    
    #ifdef TRACE_PATHING
    	OutputDebugString(CvString::format("Generate path from (%d,%d) to (%d,%d)\n", pFrom->getX_INLINE(), pFrom->getY_INLINE(), pTo->getX_INLINE(), pTo->getY_INLINE()).c_str());
    #endif
    
    	if ( m_iTurn != GC.getGameINLINE().getGameTurn() || m_currentGroupMembershipChecksum != iGroupMembershipChecksum || m_iFlags != iFlags || pFrom != m_pFrom )
    	{
    		m_nodeAllocationPool->reset();
    		m_plotInfo->reset();
    		m_iTurn = GC.getGameINLINE().getGameTurn();
    
    		m_pReplacedNonTerminalNode = NULL;
    		m_pBestTerminalNode = NULL;
    	}
    to

    Code:
    bool	CvPathGenerator::generatePath(const CvPlot* pFrom, const CvPlot* pTo, CvSelectionGroup* pGroup, int iFlags, int iMaxTurns)
    {
    	CvPathNode*	root;
    
    	PROFILE_FUNC();
    
    	m_bFoundRoute = false;
    
    	m_iSeq++;
    
    	unsigned int iGroupMembershipChecksum = 0;
    	CLLNode<IDInfo>* pUnitNode;
    	CvUnit* pLoopUnit;
    
    	pUnitNode = pGroup->headUnitNode();
    
    	while (pUnitNode != NULL)
    	{
    		pLoopUnit = ::getUnit(pUnitNode->m_data);
    		pUnitNode = pGroup->nextUnitNode(pUnitNode);
    
    		CheckSum(iGroupMembershipChecksum, pLoopUnit->getID());
    	}
    
    	if ( m_currentGroupMembershipChecksum != iGroupMembershipChecksum || m_iFlags != iFlags )
    	{
    		CvSelectionGroup::setGroupToCacheFor(pGroup);
    
    		if ( !pGroup->AI_isControlled() )
    		{
    			m_useAIPathingAlways = getBugOptionBOOL("MainInterface__UseAIPathing", false);
    		}
    	}
    
    	bool bRequiresWar;
    
    	if ( !m_TerminusValidFunc(pGroup, pTo->getX_INLINE(), pTo->getY_INLINE(), iFlags, bRequiresWar) )
    	{
    		m_generatedPath.Set(NULL);
    		return false;
    	}
    
    	if ( bRequiresWar )
    	{
    		iFlags |= MOVE_TERMINUS_DECLARES_WAR;
    	}
    
    #ifdef TRACE_PATHING
    	OutputDebugString(CvString::format("Generate path from (%d,%d) to (%d,%d)\n", pFrom->getX_INLINE(), pFrom->getY_INLINE(), pTo->getX_INLINE(), pTo->getY_INLINE()).c_str());
    #endif
    [COLOR="Red"]
    	bool bSameGroup = (m_iTurn == GC.getGameINLINE().getGameTurn() && m_currentGroupMembershipChecksum == iGroupMembershipChecksum && m_iFlags == iFlags);
    
    	//	Optimize the case where we'e just stepping along the previously calculated path (as continueMission() does)
    	if ( bSameGroup && m_generatedPath.lastPlot() == pTo )
    	{
    		if ( m_generatedPath.containsNode(pFrom) )
    		{
    			bool bValid = true;
    
    			m_generatedPath.trimBefore(pFrom);
    
    			//	Validate we can still follow this path (visibility may have changed)
    			for(CvPath::const_iterator itr = m_generatedPath.begin(); itr != m_generatedPath.end(); ++itr)
    			{
    				if ( itr.plot() != pFrom && !moveToValid(pGroup, itr.plot(), iFlags) )
    				{
    					bValid = false;
    					break;
    				}
    			}
    
    			if ( bValid )
    			{
    				return true;
    			}
    		}
    	}
    
    	m_generatedPath.Set(NULL);
    
    	if ( !bSameGroup || pFrom != m_pFrom )[/COLOR]
    	{
    		m_nodeAllocationPool->reset();
    		m_plotInfo->reset();
    		m_iTurn = GC.getGameINLINE().getGameTurn();
    
    		m_pReplacedNonTerminalNode = NULL;
    		m_pBestTerminalNode = NULL;
    	}
    if this can be of any help. I guess changes have been made in other files too in that revision.
     
  8. AIAndy

    AIAndy Chieftain

    Joined:
    Jun 8, 2011
    Messages:
    3,396
    That could well be the culprit, as it causes path reusage on the computer of the player that planned a move and then executed it a bit later in the simultaneous turn.
    And I guess it is not certain that that would be entirely the same path calculated on the other computer if something happened in the meantime.
    As a solution I would suggest to add a check to
    if ( bSameGroup && m_generatedPath.lastPlot() == pTo )
    that pGroup is not controlled by a human player.
     
  9. Thunderbrd

    Thunderbrd C2C War Dog

    Joined:
    Jan 2, 2010
    Messages:
    25,165
    Gender:
    Male
    Location:
    Las Vegas
    We have a potential fix coming for ANOTHER OOS? VERY cool! Guys... this thread is an absolute miracle!
    @AIAndy: Could you take care of that adjustment for us this time? I've got some other things demanding attention here!
     
  10. AIAndy

    AIAndy Chieftain

    Joined:
    Jun 8, 2011
    Messages:
    3,396
    I committed the source code change now (without compiling the DLL).
     
  11. Toffer90

    Toffer90 C2C Modder

    Joined:
    Oct 16, 2011
    Messages:
    5,446
    Location:
    Norway
    Awesome that OOS now has a dedicated thread.

    Should I post my future OOS logs here instead of there?

    @AIAndy: If you haven't already, could you take a look at a particular OOS we had? It's logs are found in the link; [OOS-2, OOS-3, OOS-7, OOS-8, OOS-12-13] are the logs representing this OOS.
    It's reproducible so the cause should not be too hard to find.
     
  12. 45°38'N-13°47'E

    45°38'N-13°47'E Chieftain

    Joined:
    Jun 7, 2008
    Messages:
    5,833
    Location:
    Just wonder...
    Great! I can test probably tomorrow if it works. But I have noted there's another part of the code almost identical to the one you changed about 1000 lines before your change, so I guess we have to add a isHuman check there too, correct?

    Edit: sorry I can't be more precise but I'm not near my pc now.
     
  13. Thunderbrd

    Thunderbrd C2C War Dog

    Joined:
    Jan 2, 2010
    Messages:
    25,165
    Gender:
    Male
    Location:
    Las Vegas
    Cool! That works for me as it'll thus just get integrated into the next build. Thanks!:D
     
  14. 45°38'N-13°47'E

    45°38'N-13°47'E Chieftain

    Joined:
    Jun 7, 2008
    Messages:
    5,833
    Location:
    Just wonder...
    I've made some test and that position OOS is still there. :(
    But I got another idea if it can help. From the logs I've seen that it's kinda like one of the players is lagging behind of one or more moves. I mean, my pc shows my opponents caravel in a certain position, while my opponent's pc shows the same caravel further along the projected path for that turn. If my opponent is able to move back to the position logged on my pc, that OOS is cleared. Same happens if the caravel is mine. What I've been thinking of is: position of a unit is definitely a global issue, while probably remaining moves are a local issue. In fact, the OOS is cleared moving that unit back because then position is the same for both pc,but moves left should then be different on both pc because on mine that caravel hasn't moved beyond that critical point,while on my opponent's pc that caravel has moved back and forth. So my point is: could there be a spot in the code where movements left and positions are mixed up? Since one is something global while the other is something local this could definitely lead to OOS. What do you think?
     
  15. Thunderbrd

    Thunderbrd C2C War Dog

    Joined:
    Jan 2, 2010
    Messages:
    25,165
    Gender:
    Male
    Location:
    Las Vegas
    The # of moves differs at the end of the turn but since it resets during the beginning of the turn sequence its not keeping the game out of synch if they're on the same position. The # of moves total doesn't seem to differ in the displays from one computer to the next from what I can tell. So the error must be somewhere between plots. Perhaps one computer continues after a pause while another does not based on the difference in a getActivePlayer check (which should be found and changed to getOwner check for that unit) somewhere during the move sequence between plots.
     
  16. 45°38'N-13°47'E

    45°38'N-13°47'E Chieftain

    Joined:
    Jun 7, 2008
    Messages:
    5,833
    Location:
    Just wonder...
    Ok, I'm hunting down those ActivePlayer entries, starting from CvPlot and CvPathgenerator and connected cpp files. Here's what I've found which COULD be connected to our problem (keep in mind that I don't know if this use of getActivePlayer is legit or not):

    in CvPlot.cpp

    Code:
    [COLOR="Red"]void CvPlot::updateCenterUnit()[/COLOR]
    {
    	PROFILE_FUNC();
    
    	CvUnit* pOldCenterUnit = getCenterUnit();
    	CvUnit* pNewCenterUnit;
    
    	if ( m_bInhibitCenterUnitCalculation || !shouldHaveFullGraphics() )
    	{
    		//	Because we are inhibitting recalculation until all the adjusting code has run
    		//	(rather than have it update multiple times) the currently cached center unit
    		//	might become an invalid pointer in the interim.  To protect against this we unconditionally
    		//	set the recorded center unit to NULL (without marking the plot dirty which would force a repaint).
    		//	This makes the interim safe state, and the correct value will be calculated once the
    		//	inhibitted section is exited
    		m_pCenterUnit = NULL;
    		return;
    	}
    	else
    	{
    		pNewCenterUnit = NULL;
    	}
    
    	if (!isActiveVisible(true))
    	{
    		pNewCenterUnit = NULL;
    	}
    	else
    	{
    		pNewCenterUnit = getSelectedUnit();
    
    		if (pNewCenterUnit != NULL && !pNewCenterUnit->atPlot(this))
    		{
    			pNewCenterUnit = NULL;
    		}
    
    		if (pNewCenterUnit == NULL)
    		{
    			pNewCenterUnit = getBestDefender(GC.getGameINLINE().[COLOR="Red"]getActivePlayer[/COLOR](), NO_PLAYER, NULL, false, false, true);
    		}
    
    		if (pNewCenterUnit == NULL)
    		{
    			pNewCenterUnit = getBestDefender(GC.getGameINLINE().[COLOR="Red"]getActivePlayer[/COLOR]());
    		}
    
    		if (pNewCenterUnit == NULL)
    		{
    			pNewCenterUnit = getBestDefender(NO_PLAYER, GC.getGameINLINE().[COLOR="Red"]getActivePlaye[/COLOR]r(), gDLL->getInterfaceIFace()->getHeadSelectedUnit(), true);
    		}
    
    		if (pNewCenterUnit == NULL)
    		{
    			pNewCenterUnit = getBestDefender(NO_PLAYER, GC.getGameINLINE().[COLOR="Red"]getActivePlayer[/COLOR](), gDLL->getInterfaceIFace()->getHeadSelectedUnit());
    		}
    
    		if (pNewCenterUnit == NULL)
    		{
    			pNewCenterUnit = getBestDefender(NO_PLAYER, GC.getGameINLINE().[COLOR="Red"]getActivePlayer[/COLOR]());
    		}
    	}
    
    	if ( pNewCenterUnit != pOldCenterUnit )
    
    etc.etc (probably not relevant)
    
    and further down:

    Code:
    [COLOR="Red"]void CvPlot::updateFlagSymbol()[/COLOR]
    {
    	PROFILE_FUNC();
    
    	if ( !shouldHaveFullGraphics() )
    	{
    		return;
    	}
    
    	PlayerTypes ePlayer = NO_PLAYER;
    	PlayerTypes ePlayerOffset = NO_PLAYER;
    
    	CvUnit* pCenterUnit = getCenterUnit();
    
    	//get the plot's unit's flag
    	//The plot check is to account for units in the delayed-death cycle
    	if (pCenterUnit != NULL && pCenterUnit->plot() == this)
    	{
    		//OutputDebugString(CvString::format("Updating flag symbol for (%d,%d).  Center unit is %08lx\n", m_iX, m_iY, pCenterUnit).c_str());
    		ePlayer = pCenterUnit->getVisualOwner();
    	}
    
    	//get moving unit's flag
    	if (gDLL->getInterfaceIFace()->getSingleMoveGotoPlot() == this)
    	{
    		if(ePlayer == NO_PLAYER)
    		{
    			ePlayer = GC.getGameINLINE().[COLOR="Red"]getActivePlayer[/COLOR]();
    		}
    		else
    		{
    			ePlayerOffset = GC.getGameINLINE().[COLOR="Red"]getActivePlayer[/COLOR]();
    		}
    	}
    Then I've found somethine else a bit suspicious to my untrained eyes in CvSelectionGroup.cpp:

    Code:
    [COLOR="Red"]void CvSelectionGroup::updateMission[/COLOR]()
    {
    	FAssert(getOwnerINLINE() != NO_PLAYER);
    
    	if (getMissionTimer() > 0)
    	{
    		changeMissionTimer(-1);
    
    		if (getMissionTimer() == 0)
    		{
    			if (getActivityType() == ACTIVITY_MISSION)
    			{
    				continueMission();
    			}
    			else
    			{
    				if (getOwnerINLINE() == GC.getGameINLINE().[COLOR="Red"]getActivePlayer[/COLOR]())
    				{
    					if (gDLL->getInterfaceIFace()->getHeadSelectedUnit() == NULL)
    					{
    						gDLL->getInterfaceIFace()->changeCycleSelectionCounter(1);
    					}
    				}
    			}
    		}
    	}
    }
    I call it suspicious because looking at

    Code:
    [COLOR="Red"]bool CvSelectionGroup::startMission[/COLOR]()
    {
    	PROFILE_FUNC();
    
    	CLLNode<IDInfo>* pUnitNode;
    	CvUnit* pLoopUnit;
    	bool bDelete;
    	bool bAction;
    	bool bNuke;
    	bool bNotify;
    	bool bResult;
    
    	FAssert(!isBusy());
    	FAssert(getOwnerINLINE() != NO_PLAYER);
    	FAssert(headMissionQueueNode() != NULL);
    
    	[COLOR="Red"]if (!GC.getGameINLINE().isMPOption(MPOPTION_SIMULTANEOUS_TURNS))[/COLOR]
    	{
    		if (!GET_PLAYER(getOwnerINLINE()).isTurnActive())
    		{
    			if (getOwnerINLINE() == GC.getGameINLINE().[COLOR="Red"]getActivePlayer[/COLOR]())
    			{
    				if (IsSelected())
    				{
    					gDLL->getInterfaceIFace()->changeCycleSelectionCounter(1);
    				}
    			}
    
    			return false;
    		}
    	}
    
    you can see that there's a call for getActivePlayer but there's also a check for MPOPTION_SIMULTANEOUS_TURNS. Shouldn't there be a similar check for UpdateMission too?
    Then there's a call for getActivePlayer in bool CvSelectionGroup::continueMission(int iSteps)

    Code:
    	if ((getNumUnits() > 0) && (headMissionQueueNode() != NULL))
    	{
    		if (bAction)
    		{
    			if (bDone || !canAllMove())
    			{
    				if (plot()->isVisibleToWatchingHuman())
    				{
    					updateMissionTimer(iSteps);
    
    					if (showMoves())
    					{
    						if (GC.getGameINLINE().[COLOR="Red"]getActivePlayer[/COLOR]() != NO_PLAYER)
    						{
    							if (getOwnerINLINE() != GC.getGameINLINE().[COLOR="Red"]getActivePlayer[/COLOR]())
    							{
    								if (plot()->isActiveVisible(false) && !isInvisible(GC.getGameINLINE().getActiveTeam()) && plot()->isInViewport())
    								{
    									gDLL->getInterfaceIFace()->lookAt(plot()->getPoint(), CAMERALOOKAT_NORMAL);
    								}
    							}
    						}
    					}
    				}
    			}
    		}
    
    		if (bDone)
    		{
    			if (!isBusy())
    			{
    				if (getOwnerINLINE() == GC.getGameINLINE().[COLOR="Red"]getActivePlayer[/COLOR]())
    				{
    					if (IsSelected())
    					{
    						if ((headMissionQueueNode()->m_data.eMissionType == MISSION_MOVE_TO) ||
    // BUG - Sentry Actions - start
    #ifdef _MOD_SENTRY
    							(headMissionQueueNode()->m_data.eMissionType == MISSION_MOVE_TO_SENTRY) ||
    #endif
    // BUG - Sentry Actions - end
    							(headMissionQueueNode()->m_data.eMissionType == MISSION_ROUTE_TO) ||
    							(headMissionQueueNode()->m_data.eMissionType == MISSION_MOVE_TO_UNIT))
    						{
    							gDLL->getInterfaceIFace()->changeCycleSelectionCounter((GET_PLAYER(getOwnerINLINE()).isOption(PLAYEROPTION_QUICK_MOVES)) ? 1 : 2);
    						}
    					}
    				}
    
    and few lines later

    Code:
    		else
    		{
    			if (canAllMove())
    			{
    				//	If the recursion fails that is not an overall failure, since this step did
    				//	something
    				continueMission(iSteps + 1);
    			}
    			else if (!isBusy())
    			{
    				if (getOwnerINLINE() == GC.getGameINLINE().[COLOR="Red"]getActivePlayer[/COLOR]())
    				{
    					if (IsSelected())
    					{
    						gDLL->getInterfaceIFace()->changeCycleSelectionCounter(1);
    					}
    				}
    			}
    		}
    	}
    
    	return !bFailed;
    }
    Further down there's an entry in CvSelectionGroup::updateMissionTimer(int iSteps)

    Code:
    		if (isHuman() && (isAutomated() || (GET_PLAYER((GC.getGameINLINE().isNetworkMultiPlayer()) ? getOwnerINLINE() : GC.getGameINLINE().[COLOR="Red"]getActivePlayer[/COLOR]()).isOption(PLAYEROPTION_QUICK_MOVES))))
    		{
    			iTime = std::min(iTime, 1);
    		}
    	}
    And some more entries here

    Code:
    void CvSelectionGroup::clearMissionQueue()
    {
    	FAssert(getOwnerINLINE() != NO_PLAYER);
    
    	deactivateHeadMission();
    
    	m_missionQueue.clear();
    
    	if ((getOwnerINLINE() == GC.getGameINLINE().[COLOR="Red"]getActivePlayer[/COLOR]()) && IsSelected())
    	{
    		gDLL->getInterfaceIFace()->setDirty(Waypoints_DIRTY_BIT, true);
    		gDLL->getInterfaceIFace()->setDirty(SelectionButtons_DIRTY_BIT, true);
    		gDLL->getInterfaceIFace()->setDirty(InfoPane_DIRTY_BIT, true);
    	}
    }
    here

    Code:
    bool CvSelectionGroup::insertAtEndMissionQueue(MissionData mission, bool bStart)
    {
    	PROFILE_FUNC();
    
    	FAssert(getOwnerINLINE() != NO_PLAYER);
    
    	m_missionQueue.insertAtEnd(mission);
    
    	if ((getLengthMissionQueue() == 1) && bStart)
    	{
    		if ( !activateHeadMission())
    		{
    			return false;
    		}
    	}
    
    	if ((getOwnerINLINE() == GC.getGameINLINE().[COLOR="Red"]getActivePlayer[/COLOR]()) && IsSelected())
    	{
    		gDLL->getInterfaceIFace()->setDirty(Waypoints_DIRTY_BIT, true);
    		gDLL->getInterfaceIFace()->setDirty(SelectionButtons_DIRTY_BIT, true);
    		gDLL->getInterfaceIFace()->setDirty(InfoPane_DIRTY_BIT, true);
    	}
    
    	return true;
    }
    
    here

    Code:
    CLLNode<MissionData>* CvSelectionGroup::deleteMissionQueueNode(CLLNode<MissionData>* pNode)
    {
    	CLLNode<MissionData>* pNextMissionNode;
    
    	FAssertMsg(pNode != NULL, "Node is not assigned a valid value");
    	FAssert(getOwnerINLINE() != NO_PLAYER);
    
    	if (pNode == headMissionQueueNode())
    	{
    		deactivateHeadMission();
    	}
    
    	pNextMissionNode = m_missionQueue.deleteNode(pNode);
    
    	if (pNextMissionNode == headMissionQueueNode())
    	{
    		activateHeadMission();
    	}
    
    	if ((getOwnerINLINE() == GC.getGameINLINE().[COLOR="Red"]getActivePlayer[/COLOR]()) && IsSelected())
    	{
    		gDLL->getInterfaceIFace()->setDirty(Waypoints_DIRTY_BIT, true);
    		gDLL->getInterfaceIFace()->setDirty(SelectionButtons_DIRTY_BIT, true);
    		gDLL->getInterfaceIFace()->setDirty(InfoPane_DIRTY_BIT, true);
    	}
    
    	return pNextMissionNode;
    }
    and finally here

    Code:
    void CvSelectionGroup::deactivateHeadMission()
    {
    	FAssert(getOwnerINLINE() != NO_PLAYER);
    
    	if (headMissionQueueNode() != NULL)
    	{
    		if (getActivityType() == ACTIVITY_MISSION)
    		{
    			setActivityType(ACTIVITY_AWAKE);
    		}
    
    		setMissionTimer(0);
    
    		if (getOwnerINLINE() == GC.getGameINLINE().[COLOR="Red"]getActivePlayer[/COLOR]())
    		{
    			if (IsSelected())
    			{
    				gDLL->getInterfaceIFace()->changeCycleSelectionCounter(1);
    			}
    		}
    	}
    }
    
    As I've said, I've no idea if one or all of those entries are correct or not. I've only pointed out where getActivePlayer is used, possibly in conjuction with units movement or position. Does it help any of you in understanding where the problem could be?
     
  17. AIAndy

    AIAndy Chieftain

    Joined:
    Jun 8, 2011
    Messages:
    3,396
    Those all look like local graphics changes to me which is why they use the active player to make a local (async) statement. So no, I don't think those are responsible for the problem.

    Is the movement amount displayed when you hover over the problematic units the same on both computers?

    If the ships move further on the computer of the one moving the ships than on the other computer this might be a false cancelling of the mission before the end of the path is reached.
     
  18. 45°38'N-13°47'E

    45°38'N-13°47'E Chieftain

    Joined:
    Jun 7, 2008
    Messages:
    5,833
    Location:
    Just wonder...
    Well, I'm back again testing this OOS problem. It looks like you might be right about a false cancelling of the mission. Here's an example of what happened (see screenshot): my wife's ship was north of that barbarian ship, she was coming from north and stopped there; she had 2 movements left so she commanded her ship to move 2 tiles south, right there where you can see it in the screenshot near Nicaea (ship moved one tile southwest, then one tile southeast, the city wasn't in sight before that move, although its border were). That's when the OOS happened. Randomlogs are identical, while OOS logs show

    Code:
    Player 1, Unit ID: 65553, Galley
    X: 8, [COLOR="Red"]Y: 34[/COLOR]
    Damage: 0
    Experience: 0
    Level: 1
    Promotions:
    on my pc and

    Code:
    Player 1, Unit ID: 65553, Galley 1 (Bibracte)
    X: 8, [COLOR="Red"]Y: 32[/COLOR]
    Damage: 0
    Experience: 0
    Level: 1
    Promotions:
    on hers. As you can see, it looks like the ship moved on her pc only. Y: 34 is the correct position shown in the screenshot (taken on her pc), but while on her pc that position is correct, logs indicate that on my pc that ship was always 1 tile north of the barbarian ship. Probably when it happened other times that OOS was always caused by presence of other units (barbarian or not) or by presence of storms.

    I'm wondering if the problem could be in cvreachableplotset.cpp since there are some entries in the SVN logs explaining that changes have been made to sea pathing in that file.
     

    Attached Files:

  19. Toffer90

    Toffer90 C2C Modder

    Joined:
    Oct 16, 2011
    Messages:
    5,446
    Location:
    Norway
    I have experienced this OOS many times. It always happens when an interrupted go-to order is reissued to the same destination. if you change the destination or move tile by tile it doesn't happen. I have both experienced it with boats and land units, and with/without any cultural borders involved.
    Seems like the other computer skips the path calculation bit thinking it has already done it earlier when the same destination is ordered the second time, which would mean that it also cancels the second order due to the old path goes through the obstacle that made it cancel the first time.

    Hope the information helps but don't take my speculations too seriously as I'm no programmer.
     
  20. AIAndy

    AIAndy Chieftain

    Joined:
    Jun 8, 2011
    Messages:
    3,396
    It is an important information and the change we added earlier in this investigation does deactivate that kind of optimization for human players. There might be some more path caching somewhere though.
     

Share This Page