Massive Humans vs Humans Game/Lets Player Tracker

Who do you think will win?

  • AstralPhaser

    Votes: 5 7.5%
  • Il Principe

    Votes: 2 3.0%
  • Koshling

    Votes: 14 20.9%
  • Hydromancerx

    Votes: 17 25.4%
  • Vokarya

    Votes: 4 6.0%
  • Acularius

    Votes: 3 4.5%
  • Thunderbrd

    Votes: 8 11.9%
  • ls612

    Votes: 5 7.5%
  • JosEPh_II

    Votes: 8 11.9%
  • Praetyre

    Votes: 1 1.5%
  • Epi3b1rD

    Votes: 0 0.0%

  • Total voters
    67
Interesting. It looks like we hit the maximum barbarian unit cap problem. I'm not entirely sure but to me it looks like there could be a bug in the FFreeList system that's causing this to happen prematurely. Problem is, I'm not terribly familiar with that stuff and while I could test some theories, I'd far prefer to relegate this to Koshling if he's willing, as I have a lot more faith in his skill in managing this. I'm sure we can find a workaround, even if just to build in a shortcircuit to keep further barb units from being trained if its going to cause a crash like this - it IS a unit being trained, not spawned, that is causing the problem.

Suffice it to say this is not a task I feel qualified to resolve on my own. Perhaps repairing this could be a big help with the main mod.

Koshling... can you offer some assistance here?
 
@Koshling:
This is where the problem lies:
Code:
template <class T>
T* FFreeListTrashArray<T>::add()
{
	int iIndex;
	T* result = NULL;

	EnterCriticalSection(&m_cModifySection);

	if (m_pArray == NULL) 
	{
		init();
	}

	if ((m_iLastIndex == m_iNumSlots - 1) &&
		(m_iFreeListCount == 0))
	{
		if ((m_iNumSlots * FLTA_GROWTH_FACTOR) > FLTA_MAX_BUCKETS)
		{
			LeaveCriticalSection(&m_cModifySection);
			return NULL;
		}

		growArray();
	}

	if (m_iFreeListCount > 0)
	{
		m_iFreeListCount--;

		int iLast = FFreeList::INVALID_INDEX;
		iIndex = m_iFreeListHead;

		//	Ttry to choose a free node that is not from the current major id space so as
		//	to minimize the rate we move through the global id space
		while( iIndex != FFreeList::INVALID_INDEX && m_pArray[iIndex].iLastUsed == m_iCurrentID)
		{
			iLast = iIndex;
			iIndex = m_pArray[iIndex].iNextFreeIndex;
		}
That while loop... m_pArray[iIndex].iLastUsed is always == m_iCurrentID (1990656). That does NOT strike me as right. Then again, the whole system seems... baffling.
 
@Koshling:
This is where the problem lies:
Code:
template <class T>
T* FFreeListTrashArray<T>::add()
{
	int iIndex;
	T* result = NULL;

	EnterCriticalSection(&m_cModifySection);

	if (m_pArray == NULL) 
	{
		init();
	}

	if ((m_iLastIndex == m_iNumSlots - 1) &&
		(m_iFreeListCount == 0))
	{
		if ((m_iNumSlots * FLTA_GROWTH_FACTOR) > FLTA_MAX_BUCKETS)
		{
			LeaveCriticalSection(&m_cModifySection);
			return NULL;
		}

		growArray();
	}

	if (m_iFreeListCount > 0)
	{
		m_iFreeListCount--;

		int iLast = FFreeList::INVALID_INDEX;
		iIndex = m_iFreeListHead;

		//	Ttry to choose a free node that is not from the current major id space so as
		//	to minimize the rate we move through the global id space
		while( iIndex != FFreeList::INVALID_INDEX && m_pArray[iIndex].iLastUsed == m_iCurrentID)
		{
			iLast = iIndex;
			iIndex = m_pArray[iIndex].iNextFreeIndex;
		}
That while loop... m_pArray[iIndex].iLastUsed is always == m_iCurrentID (1990656). That does NOT strike me as right. Then again, the whole system seems... baffling.

Which line does it crash on? Is something NULL?
 
I get a first chance exception:
First-chance exception at 0x05207e70 (CvGameCoreDLL.dll) in Civ4BeyondSword.exe: 0xC0000005: Access violation reading location 0x9493453c.
At
Code:
	if (m_iFreeListCount > 0)
	{
		m_iFreeListCount--;

		int iLast = FFreeList::INVALID_INDEX;
		iIndex = m_iFreeListHead;

		//	Ttry to choose a free node that is not from the current major id space so as
		//	to minimize the rate we move through the global id space
		while( iIndex != FFreeList::INVALID_INDEX && m_pArray[iIndex].iLastUsed == m_iCurrentID)
iIndex is reading -1370297228. m_pArray[iIndex].iLastUsed , when hovering over .iLastUsed I don't get any info (when stopping early here I would.) Hovering over just m_pArray[iIndex] states the values cannot be evalauted. m_iCurrentID shows 1990656

The while loop has cycled some. When I look at the value of iLast here:
Code:
		while( iIndex != FFreeList::INVALID_INDEX && m_pArray[iIndex].iLastUsed == m_iCurrentID)
		{
			iLast = iIndex;
			iIndex = m_pArray[iIndex].iNextFreeIndex;
		}
it shows 210.

When I rerun and stop there only when iIndex is 210, both m_pArray[iIndex].iLastUsed and m_iCurrentID are 1990656 and the while statement evaluates true. Not sure it matters but iLast is currently 662. It processes through the code within the while statement and immediately returns to evaluate the while statement with the code crashing negative iIndex thereafter.

If I stop at iIndex being 662, both m_pArray[iIndex].iLastUsed and m_iCurrentID are 1990656 for both its run through 662 and its subsequent reloop through 210 from there.

I have more evaluation to go but I have not yet been able to figure out how m_pArray[iIndex].iNextFreeIndex, with iIndex == 210, gets assigned as -1370297228. To me, that looks like an overflow value.
 
The whole function reads as:
Spoiler :
Code:
template <class T>
T* FFreeListTrashArray<T>::add()
{
	int iIndex;
	T* result = NULL;

	EnterCriticalSection(&m_cModifySection);

	if (m_pArray == NULL) 
	{
		init();
	}

	if ((m_iLastIndex == m_iNumSlots - 1) &&
		(m_iFreeListCount == 0))
	{
		if ((m_iNumSlots * FLTA_GROWTH_FACTOR) > FLTA_MAX_BUCKETS)
		{
			LeaveCriticalSection(&m_cModifySection);
			return NULL;
		}

		growArray();
	}

	if (m_iFreeListCount > 0)
	{
		m_iFreeListCount--;

		int iLast = FFreeList::INVALID_INDEX;
		iIndex = m_iFreeListHead;

		//	Ttry to choose a free node that is not from the current major id space so as
		//	to minimize the rate we move through the global id space
		while( iIndex != FFreeList::INVALID_INDEX && m_pArray[iIndex].iLastUsed == m_iCurrentID)
		{
			iLast = iIndex;
			iIndex = m_pArray[iIndex].iNextFreeIndex;
		}

		if ( iIndex == FFreeList::INVALID_INDEX )
		{
			//	Didn't find one - just take the free list head node
			iIndex = m_iFreeListHead;
			m_iFreeListHead = m_pArray[iIndex].iNextFreeIndex;
		}
		else
		{
			//	Foudn one - take it out of the middle of the free list
			if ( iLast == FFreeList::INVALID_INDEX )
			{
				m_iFreeListHead = m_pArray[iIndex].iNextFreeIndex;
			}
			else
			{
				m_pArray[iLast].iNextFreeIndex = m_pArray[iIndex].iNextFreeIndex;
			}
		}
	}
	else
	{
		m_iLastIndex++;
		iIndex = m_iLastIndex;
	}

	MEMORY_TRACK_EXEMPT();

	m_pArray[iIndex].pData = new T;
	m_pArray[iIndex].iNextFreeIndex = FFreeList::INVALID_INDEX;

	if ( m_pArray[iIndex].iLastUsed == m_iCurrentID )
	{
		m_iCurrentID += FLTA_MAX_BUCKETS;
	}
	m_pArray[iIndex].pData->setID(m_iCurrentID + iIndex);
	m_pArray[iIndex].iLastUsed = m_iCurrentID;

	result = m_pArray[iIndex].pData;

	LeaveCriticalSection(&m_cModifySection);

	return result;
}
Just for reference of course.
 
Can you reproduce this in a version you can modify (i.e. - one you can build and add to)? If so I'd advise adding a bunch of detailed checks and trace (index values positive and less than m_numSlots and that sort of thing) and put breakpoints on failing checks so you can get the debugger open on it live before it crashes. Could also add trace output (OutputDebugString calls) to see exactly what values everything has as it evolves to the crash state.

My best guess is that there is a bad unit id in a save or something. If so it'll be a pain to fix since you'll need to write extra code to identify and cull it in the load routines which will be a pain.

Easiest attempt to work around it might be to go back to the previous person's save and replay from there and hope it doesn't happen.
 
How would you suggest trying to replicate it?

It's not something I've seen reported widely. I MAY have encountered it before once. That's a lot of games that have been played without hitting the issue.

I also suspect that the suggested replay won't do much unless PERHAPS the barb units are interacted with differently, as it is happening on the barbarian player's turn. Praetyre apparently tried retaking his own turn a few times and it always led to the same result. I could try retaking mine and handing it back but if you're right, the likelihood of influencing the crash (or only putting it off for one round at best) is low unless somehow that unit that's a problem works itself out of the equation.

We could try to build a unit ejection mechanism when it 'finds' a bad ID like it has here, but I'm not sure how to express such coding properly, and then again another thing that's a problem for me is that I'm not clear on the intentions of most of this coding at all. It seems to me to be extremely overengineered and must be trying to take into consideration difficulties I cannot begin to imagine. Honestly, I'm struggling to follow what is happening and cannot lock onto what any of this programming is really designed to achieve.
 
To All Players,
With Whisperr now in the hospital, and T-brd attending to RL matters, these MP games are on Indefinite Hold, especially this one.

@koshling,
Without your help ThunderBrd does not have the time or experience to fix this problem. So this game is even more in jeopardy of ending prematurely. We all have priorities and RL takes the throne, and this is understood hopefully by all.

JosEPh
 
Update:
Good news is: Whisperr is home from the Hospital, Yeah!!!

Bad News is: this Massive game still has a problem and is currently stalled unless someone can help Thunderbrd. And he and Whisperr are still battling RL issues.

JosEPh
 
I'd love to help in this situation, but by checking the code I don't feel I have enough knowledge on C++ to help yet.

I suppose I can find everything in the C2C MP folder inside the source folder, is that right? I'll take a look on it at least to improve my knowledge about C++ and C2C's game code.
 
Maybe T-brd just needs to redo his turn and let Praetyre try again to get thru his? Heck I'd be willing to redo my turn too.

JosEPh
 
Pretty sure no redoing of turns would help as it's the barb's unit that is causing a problem. But I will be doing more evaluation here and trying to break down exactly what's happening and how to safely resolve it.
 
As for this game, I do intend to debug it. It's going to be a long and patient process of researching what the hell everything means that I'm interacting with and I promise I won't let it be debugged in a way that's going to screw things up worse (which will take great care.)

But there's been long pressing bugs in the main mod to address now that I'm getting some debugging time back. I must get them handled first then I can look at this again. This is probably a lurking main mod problem too but its hard to say. Anyhow, I'm not abandoning this, it's just really really REALLY complicated and will take some serious focus and probably a lot of hours. I suspect multiple weekends of deep commitment will be necessary.
 
Back
Top Bottom