Reconstructing units from a save

LyTning94

Dragonborn
Joined
Nov 10, 2010
Messages
397
Location
Skyrim
Is anyone aware of how the game reconstructs units from a save? To be more specific, what info does the game write to the save file which enables it to reconstruct the unit upon loading?

Basically, I'm looking for a way to either take information from the save file or create an entirely new file which would allow me to reconstruct units from one game in another game.
 
CvUnit::read

CvUnit::write

these two methods is all you need.
 
What is the FDataStreamBase* parameter in CvUnit::read() and CvUnit::write()? Is it the file to write/read to?
 
So...how would I go about calling the function???
 
Please say more about what you are trying to accomplish. The game already reconstructs everything from the save game file on its own, you do not need to call these functions separately.
 
yes, all you need to do is to modify them. For example if you want to add an integer to cvunit to store a particular value, you would have to add a line to both the read and write method. It is important to know that read and write operations are done in the exact same order and you must preserve that if you modify the methods.

Just download the source of Fall from Heaven and look at the sourcefile of cvunit.cpp There you can see how to modify the methods if you want to add a variable.
 
I must not have explained myself clearly.

What I'm trying to do is save the information of certain units to a file so I can load those specific units in another game, on another map.

So I thought I could write() to a file and then read() from that file in another game. The problem is I only want certain units, and I want the map to be different, so I can't use a save game.
 
Are you trying to allow persistent units? That is, you want to have a unit in the second game, which has the same promotions as the first game? I don't think you need a whole savegame for that. In the first game, write some python which prints the information in plain text. Then in the second game, write python which reads the plain text. The amount of imformation is pretty small; is there anything besides the list of promotions, and maybe current experience?
 
Just writing/reading the list of promotions won't be enough - you'll have to call setHasPromotion for each promotion to update the other relevant members.
You'll also need the unit type.

You might also want other properties such as leader (if you attached a warlord to it), and transport (if it's on a ship).

Do you want to save everything? That includes all of the above, plus position, how many turns is the unit fortified, the damage it has taken etc.
If so, and you want a more complicated but robust solution, you could create a subclass which implements FDataStreamBase, and then you can use it to read/write any game entity you want.
 
I shouldn't need anything besides promotions, damage, turns fortified, the unit type, and the owner. I don't think it'll be necessary to create a subclass.

Since I know nothing at all about Python, how would I go about writing/reading the info to a file?
 
It will be difficult for you to write this python, if you do not know anything about python. There are several threads here which describe good ways to learn python.
 
Would it be possible to do it in the SDK, like with ofstream/ifstream?

EDIT: I skimmed over a tutorial on python and found another on file I/O, which I read through. It appears simple enough. What I'm wondering, though, is how I would go about calling my function. Should I call the function in CvEventManager.py or call it directly from the SDK (I believe that's possible, isn't it?)
 
If the majority of your function will be in python (as I recommend) you may as well make it all in python. It is much quicker to incrementally revise python as you are developing. You rarely need to exit the game. With sdk changes you have to wait for each recompile and then restart the game.
 
I've written the rest of my function, so I'm ready to start on the python part.

I'm planning on writing a python function called writeUnitInfo(), which will, well, write the unit info to a file. To call this function, I wrote this in the SDK (based on what I have seen elsewhere):

Code:
CyUnit* pyUnit = new CyUnit(pLoopUnit);
CyArgsList argsList;
argsList.add(gDLL->getPythonIFace()->makePythonObject(pyUnit));
long lResult=0;
gDLL->getPythonIFace()->callFunction(PYGameModule, "writeUnitInfo", argsList.makeFunctionArgs(), &lResult);
delete pyUnit;

From what I've seen elsewhere, the output of the python function is assigned to lResult, and can then be used in the SDK. Am I correct in this?

I haven't started working on the python function yet, but in a tutorial I read on python I/O, I read about the pickle function. Could I use this to write/read my unit info?
 
I changed some things around, and now instead of passing the unit itself to the function, I'm passing the info itself.

Code:
if (GET_PLAYER((PlayerTypes)info.getData2()).isHuman())
{
	CvPlot* pPlot = GET_PLAYER((PlayerTypes)info.getData2()).getUnit(info.getData1())->plot();
	CLLNode<IDInfo>* pUnitNode;
	CvUnit* pLoopUnit;
	int i = 0;
	int iNumPromotions = 0;
	int j;
	CyArgsList argsList;
	long lResult=0;

	argsList.add((int)GET_PLAYER((PlayerTypes)info.getData2()).getLeaderType());
	argsList.add((int)GET_PLAYER((PlayerTypes)info.getData2()).getCivilizationType());

	pUnitNode = pPlot->headUnitNode();

	while (pUnitNode != NULL)
	{
		pLoopUnit = ::getUnit(pUnitNode->m_data);
		pUnitNode = pPlot->nextUnitNode(pUnitNode);				
		i++;

		if (pPopupReturn->getCheckboxBitfield(i) && pPopupReturn->getCheckboxBitfield(i) > 0 && pLoopUnit->getOwner() == (PlayerTypes)info.getData2() && pLoopUnit->getMoves() < pLoopUnit->maxMoves())
		{
			for (j = 0; j < GC.getNumPromotionInfos(); j++)
			{
				if (pLoopUnit->isHasPromotion((PromotionTypes)j))
				{
					iNumPromotions++;
				}
			}
			argsList.add((iNumPromotions + 4));
			argsList.add((int)pLoopUnit->getUnitType());
			argsList.add(pLoopUnit->currHitPoints());
			argsList.add(pLoopUnit->getMoves());
			argsList.add(pLoopUnit->getFortifyTurns());
			for (j = 0; j < GC.getNumPromotionInfos(); j++)
			{
				if (pLoopUnit->isHasPromotion((PromotionTypes)j))
				{
					argsList.add(j);
				}
			}
		}
	}
	gDLL->getPythonIFace()->callFunction(PYGameModule, "writeAttackerUnitInfo", argsList.makeFunctionArgs(), &lResult);
}

And here is my python code in a new file I placed in my Assets/Python folder:

Code:
import pickle

def writeAttackerUnitInfo(argsList):
   file = open('AttackingUnit.info', 'w')
   pickle.dump(argsList, file)
   file.close()

When I test it, it does nothing as far as I can tell. Am I calling the function right from the SDK? Is there something in my python I'm doing wrong? Do I need to create the file before opening it in python (it doesn't exist right now)? Sorry for all the questions; I'm new to anything that involves python.
 
Here is my guess:

That PyGameModule in the call represents a specific Python Module, i.e. a specific file. In this case is is CvGameUtils.py. So it is looking for the writeAttackerUnitInfo function in CvGameUtils.py.

So you can either figure out how to point it at your new file or move your function to CvGameUtils.py (it may need to be a member of the CvGameUtils class as well, not just in the file).
 
When I test it, it does nothing as far as I can tell. Am I calling the function right from the SDK? Is there something in my python I'm doing wrong? Do I need to create the file before opening it in python (it doesn't exist right now)? Sorry for all the questions; I'm new to anything that involves python.

you need to update pythons/entrypoints/CvGameInterface.py for your python callback
 
Okay, I copied over CvGameInterface.py and CvGameUtils.py and added this code to CvGameUtils

Code:
def writeAttackerUnitInfo(argsList):
            file = open('AttackingUnit.Info', 'w')
            pickle.dump(argsList, file)
            file.close()
            return True

and this to CvEventInterface

Code:
def writeAttackerUnitInfo(argsList):
    return gameUtils().writeAttackerUnitInfo(argsList)

When I tried to load my mod, it came up with a crapload of python errors, including one saying 'Pickle: Module not found'.

I downloaded the python language (or whatever the terminology is) from http://www.python.org/download/releases/2.4.4, and found multiple python files with pickle in the filename. I'm assuming pickle is included in the object files in CvGameCoreDLL/Python24/libs, so I image it can be used in a mod. Where do I put the file so it can be imported?
 
if you want to import a python file, just put it somewhere in the python folder (or subfolder).

I hope with CvEventInfertace you mean CvGameInterface (not sure if there is an eventinterface, but it would be used for other things)
 
Back
Top Bottom