What exactly does isNone() check?

Baldyr

"Hit It"
Joined
Dec 5, 2009
Messages
5,530
Location
Sweden
So I've come to rely on the isNone() functions/methods in for the various Cy classes to rule out possible issues with non-valid instances. But what exactly do these check?

Because I'm currently having issues with checking unit scriptData; A CyUnit instance that would get recognized as "None" is also returning an empty string with CyUnit.getScriptData(). This would of course seem like a good feature, if it weren't for the fact that those units are alive and well - stomping around the game map! :eek: They haven't been killed in combat or disbanded, but they will none-the-less temporarily register as "None". (The next turn, or another turn down the line, they are mostly back as valid instances again.) This is causing issues for me as I'm trying to locate these units by looking up their scriptData strings. My code is either not recognizing the units (with a isNone() check) or unable to fetch the scriptData (which would be an empty string value).

What exactly makes a CyUnit instance become "None" - and be valid again on the next turn? This assuming that the unit haven't been killed and thus the vacant slot being "None" before it is once again occupied by a valid CyUnit instance.

Oh, and the units all have UNITAI_EXPLORE - next up I will change this to NO_UNITAI just to rule out any problems with that...
 
Oh, and the units all have UNITAI_EXPLORE - next up I will change this to NO_UNITAI just to rule out any problems with that...
My preliminary experiments are pointing at the unit AI setting being the culprit. (UNITAI_ANIMAL is more aggressive than UNITAI_EXPLORE but doesn't seem to make the units go invalid occasionally...)
 
I'm not absolutely certain about this but I believe that under certain conditions the game will replace a unit object with a new unit object, When this happens it doesn't delete the old unit object unit the end of the turn - it just makes it not valid. This doesn't directly answer your question but if it is accurate like I think it is. It will at least give you a better understanding of what happens.
 
So I can't really rely on unit scriptData for identifying units, then? Because the game might just have dropped that CyUnit instance temporarily. :rolleyes:
 
...or another way to look at the problem: I can't use on BeginGameTurn to do much about anything involving units, because some of them might not be valid - yet. What about EndGameTurn then? But wouldn't that also be at "end of the turn"?

When do all available units become valid? On BeginPlayerTurn?
 
...or another way to look at the problem: I can't use on BeginGameTurn to do much about anything involving units, because some of them might not be valid - yet. What about EndGameTurn then? But wouldn't that also be at "end of the turn"?
layerTurn
When do all available units become valid? On BeginP?

I'm not certain if my description is causing your problem. If it is, all you need to do is check if "not CyUnit.isNone()" before checking your scriptdata. BeginPlayerTurn probably wouldn't help since it is called at the beginning of the end of the player's turn.
 
I'm not certain if my description is causing your problem.
It does seem like you are correct. Especially barbarian units seem to go offline regularly between turns (or anytime i try to check them :rolleyes:).

If it is, all you need to do is check if "not CyUnit.isNone()" before checking your scriptdata.
That doesn't help a bit, since instead of getting an empty string I won't even be looking up the string value. I won't find the unit in either case. And this is causing my work not to... well, work. :p
 
I'm not absolutely certain about this but I believe that under certain conditions the game will replace a unit object with a new unit object, When this happens it doesn't delete the old unit object unit the end of the turn - it just makes it not valid.

e.g when upgrading.
The old instance is then still present, but not more valid.

So if you've done something onBeginGameTurn, and you upgrade the unit in between, then your saved instance is not more valid.
 
That doesn't help a bit, since instead of getting an empty string I won't even be looking up the string value. I won't find the unit in either case. And this is causing my work not to... well, work. :p

You should ignore any CyUnit's that return True for isNone(). If a given unit is not valid just go onto the next unit until you find the valid CyUnit for the one you want. Also, you might find it more convenient to store script data as a dictionary that way you can add and remove different objects associated with the unit easily.
 
You should ignore any CyUnit's that return True for isNone(). If a given unit is not valid just go onto the next unit until you find the valid CyUnit for the one you want.
Aha, you mean that while one instance becomes invalid another one has already been created? But no, this is not what is happening when I try to do this... :(

Lets say, for the sake of argument, that a Civ has 3 units in total. And that I have given them all the same string value of "Rebel" as script data. On one turn my debug code would list all three units with their associated strings:
Code:
unit 0 Rebel
unit 1 Rebel
unit 2 Rebel
But on another turn, all of a sudden, one unit might not be valid. If I don't implement isNone() as a check I will get something like this:
Code:
unit 0 Rebel
unit 1
unit 2 Rebel
And with the isNone() check:
Code:
unit 0 Rebel
unit 2 Rebel
I've never seen (without the check):
Code:
unit 0 Rebel
unit 1
unit 2 Rebel
unit 3 Rebel
Or (with the check):
Code:
unit 0 Rebel
unit 2 Rebel
unit 3 Rebel
There are simply valid CyUnit instances missing, from time to time. And on the next turn they are usually valid again. :crazyeye: The barbarian Civ seems to be the worst offender, by the way... And unit AI type seems to have some effect on this.

Also, you might find it more convenient to store script data as a dictionary that way you can add and remove different objects associated with the unit easily.
Yeah, but I'm just storing "flags" to identify individual units. So when I cycle through all the units belonging to that Civ, as in the example above, I either collect the CyUnit instances of every unit with the specified flag - or the CyPlot instances of the plots they are currently occupying.
 
So when I cycle through all the units belonging to that Civ

Cycle through how, exactly?

If you are doing something like
Code:
		for iUnit in range(pPlayer.getNumUnits()):
			pUnit = pPlayer.getUnit(iUnit)
then that is your problem. There can be values in the list that do not point to valid units. Just because pPlayer.getNumUnits() says there are 3 units does not mean they are units 0, 1, and 2. They could be 0, 2, and 3 but the above code only checks 0, 1, and 2 and never looks at 3. Checking to see if the unit is valid or not before using it for anything stops you from using an invalid unit (unit 1, in this example) for something, but it does not change the loop counter to try more units past the original end of the list (it still only goes up to 2 so you'll never see unit 3).

You should either call the pyPlayer.getUnitList() function (as defined in PyHelpers.py), or copy it or its contents for your own purposes. It iterates over the player's units correctly:
Code:
	def getUnitList(self):
		' UnitList - All of the players alive units '
		lUnit = []
		(loopUnit, iter) = self.player.firstUnit(false)
		while( loopUnit ):
			if ( not loopUnit.isDead() ): #is the unit alive and valid?
				lUnit.append(loopUnit) #add unit instance to list
			(loopUnit, iter) = self.player.nextUnit(iter, false)
		return lUnit
You can either use the list this provides, or remove the list stuff and just do what it is you want to do inside the loop instead of adding the unit to a list.
 
then that is your problem. There can be values in the list that do not point to valid units. Just because pPlayer.getNumUnits() says there are 3 units does not mean they are units 0, 1, and 2. They could be 0, 2, and 3 but the above code only checks 0, 1, and 2 and never looks at 3. Checking to see if the unit is valid or not before using it for anything stops you from using an invalid unit (unit 1, in this example) for something, but it does not change the loop counter to try more units past the original end of the list (it still only goes up to 2 so you'll never see unit 3).
Aha, I didn't realize that getNumUnits() only will give me the number of valid units. I was supposing it would also count the invalid instances - and thus I would have to use isNone() to weed those instances out. :p

You should either call the pyPlayer.getUnitList() function (as defined in PyHelpers.py), or copy it or its contents for your own purposes.
Ok, its basically the same as PyPlayer.getCityList() - and I know that I need to use that for looping cities. Why didn't I think of also using getUnitList()? :crazyeye:

Thanks a bunch - now I'm off to rewrite my stuff! :p
 
Back
Top Bottom