Problem reading/writing map data

LyTning94

Dragonborn
Joined
Nov 10, 2010
Messages
397
Location
Skyrim
I'm working on a modcomp that allows you to have multiple maps in the same game, but am having trouble saving/loading these maps. Since CvMap::read() is called from the exe, I can't do something like this:

Code:
for (i = 0; i < GC.getNumMapInfos(); i++)
{
      GC.getMapByIndex((MapTypes)i).read();
}

so instead I added a loop inside the read() and write() functions themselves:

Code:
void CvMap::read(FDataStreamBase* pStream)
{
	CvMapInitData defaultMapData;

	uint uiFlag=0;
	pStream->Read(&uiFlag);	// flags for expansion

	for (int i = 0; i < GC.getNumMapInfos(); i++)
	{
		// Init data before load
		GC.getMapByIndex((MapTypes)i).reset(&defaultMapData);

		pStream->Read((int*)(&(GC.getMapByIndex((MapTypes)i).m_eType)));
		pStream->Read(&(GC.getMapByIndex((MapTypes)i).m_iGridWidth));
		pStream->Read(&(GC.getMapByIndex((MapTypes)i).m_iGridHeight));
		pStream->Read(&(GC.getMapByIndex((MapTypes)i).m_iLandPlots));
		pStream->Read(&(GC.getMapByIndex((MapTypes)i).m_iOwnedPlots));
		pStream->Read(&(GC.getMapByIndex((MapTypes)i).m_iTopLatitude));
		pStream->Read(&(GC.getMapByIndex((MapTypes)i).m_iBottomLatitude));
		pStream->Read(&(GC.getMapByIndex((MapTypes)i).m_iNextRiverID));

		pStream->Read(&(GC.getMapByIndex((MapTypes)i).m_bWrapX));
		pStream->Read(&(GC.getMapByIndex((MapTypes)i).m_bWrapY));

		FAssertMsg((0 < GC.getNumBonusInfos()), "GC.getNumBonusInfos() is not greater than zero but an array is being allocated");
		pStream->Read(GC.getNumBonusInfos(), GC.getMapByIndex((MapTypes)i).m_paiNumBonus);
		pStream->Read(GC.getNumBonusInfos(), GC.getMapByIndex((MapTypes)i).m_paiNumBonusOnLand);

		if (GC.getMapByIndex((MapTypes)i).numPlotsINLINE() > 0)
		{
			m_pMapPlots = new CvPlot[GC.getMapByIndex((MapTypes)i).numPlotsINLINE()];
			int iI;
			for (iI = 0; iI < GC.getMapByIndex((MapTypes)i).numPlotsINLINE(); iI++)
			{
				GC.getMapByIndex((MapTypes)i).m_pMapPlots[iI].read(pStream);
			}
		}

		// call the read of the free list CvArea class allocations
		ReadStreamableFFreeListTrashArray(GC.getMapByIndex((MapTypes)i).m_areas, pStream);

		GC.getMapByIndex((MapTypes)i).setup();
	}
}

// save object to a stream
// used during save
//
void CvMap::write(FDataStreamBase* pStream)
{
	int iI;

	uint uiFlag=0;
	pStream->Write(uiFlag);		// flag for expansion

	for (int i = 0; i < GC.getNumMapInfos(); i++)
	{
		pStream->Write((int)GC.getMapByIndex((MapTypes)i).m_eType);
		pStream->Write(GC.getMapByIndex((MapTypes)i).m_iGridWidth);
		pStream->Write(GC.getMapByIndex((MapTypes)i).m_iGridHeight);
		pStream->Write(GC.getMapByIndex((MapTypes)i).m_iLandPlots);
		pStream->Write(GC.getMapByIndex((MapTypes)i).m_iOwnedPlots);
		pStream->Write(GC.getMapByIndex((MapTypes)i).m_iTopLatitude);
		pStream->Write(GC.getMapByIndex((MapTypes)i).m_iBottomLatitude);
		pStream->Write(GC.getMapByIndex((MapTypes)i).m_iNextRiverID);

		pStream->Write(GC.getMapByIndex((MapTypes)i).m_bWrapX);
		pStream->Write(GC.getMapByIndex((MapTypes)i).m_bWrapY);

		FAssertMsg((0 < GC.getNumBonusInfos()), "GC.getNumBonusInfos() is not greater than zero but an array is being allocated");
		if (GC.getMapByIndex((MapTypes)i).m_paiNumBonus == NULL && GC.getMapByIndex((MapTypes)i).m_paiNumBonusOnLand == NULL)			// for maps objects which have been created, but not fully initialized
		{
			GC.getMapByIndex((MapTypes)i).m_paiNumBonus = new int[GC.getNumBonusInfos()];
			GC.getMapByIndex((MapTypes)i).m_paiNumBonusOnLand = new int[GC.getNumBonusInfos()];
			for (iI = 0; iI < GC.getNumBonusInfos(); iI++)
			{
				GC.getMapByIndex((MapTypes)i).m_paiNumBonus[iI] = 0;
				GC.getMapByIndex((MapTypes)i).m_paiNumBonusOnLand[iI] = 0;
			}
		}
		pStream->Write(GC.getNumBonusInfos(), GC.getMapByIndex((MapTypes)i).m_paiNumBonus);
		pStream->Write(GC.getNumBonusInfos(), GC.getMapByIndex((MapTypes)i).m_paiNumBonusOnLand);

		for (iI = 0; iI < GC.getMapByIndex((MapTypes)i).numPlotsINLINE(); iI++)
		{
			GC.getMapByIndex((MapTypes)i).m_pMapPlots[iI].write(pStream);
		}

		// call the read of the free list CvArea class allocations
		WriteStreamableFFreeListTrashArray(GC.getMapByIndex((MapTypes)i).m_areas, pStream);
	}
}

Everything appears to save fine, but when I load a saved game, the units are unable to move to another plot. When I mouseover a plot, the little red circle appears as if the plot is impassible or something. I traced the problem down to CvSelectionGroup::generatePath(), where bSuccess is false here:

Code:
bSuccess = gDLL->getFAStarIFace()->GeneratePath(&GC.getPathFinder(), pFromPlot->getX_INLINE(), pFromPlot->getY_INLINE(), pToPlot->getX_INLINE(), pToPlot->getY_INLINE(), false, iFlags, bReuse);

I compared pToPlot in the original game and in the loaded save, and the only difference I can see (besides different memory addresses, obviously) is that in the loaded game m_pFlagSymbol is NULL. I'm not sure if this is relevant or not.

Any ideas what could be causing this?
 
That is a call to the pathfinder which is located in the exe. But it uses several calls into the DLL to find out if a unit can move into a certain plot and similar things. So likely one of those calls does not return the right information.
 
Right, but where are those calls at?

EDIT: Do you mean the functions in CvGameCoreUtils that take a FAStarNode* as a parameter? I set a breakpoint in all those functions and none of them are called.
 
So... any ideas?

There must be something wrong with my read() and write() functions which is causing this, but I don't know what that would be.
 
So... any ideas?

There must be something wrong with my read() and write() functions which is causing this, but I don't know what that would be.
I think I found the issue:
m_pMapPlots = new CvPlot[GC.getMapByIndex((MapTypes)i).numPlotsINLINE()];

This always stores the array in the main map object instead of in the right map.
 
Well, that definitely was a coding mistake; thanks for pointing it out. Unfortunately, it didn't fix the problem. :(
 
Okay, I added GC.getMapByIndex((MapTypes)1).init() to the top of write() and now it works fine. I'm not sure what it is in init() that needed to be done, but it works so that's all that matters.
 
Back
Top Bottom