Its not the added unit classes as such I was worried about, but rather enabling the callback itself in PythonCallbackDefines.xml. Because the core game engine is making a Python callback anytime a unit is to be moved - and compared to the C++ code Python is awfully slow. And not just once per unit movement, but probably once for any tile that the AI is even
considering (for path-finding, calculations and general decision making I guess).
But it would however be
possible to only define the tRestrictedUnitClasses array once in any game, but that involves more than just copy-pasting some lines of code into one single location in one single file. Because its not
optimal to fetch those unit class identifiers every single time the unit classes are evaluated. Pointless repetition of code is probably what causes lag in the game in the first place!
edit: You could actually try out this augmented code:
Code:
[B] tRestrictedUnitClasses = False[/B]
def unitCannotMoveInto(self,argsList):
ePlayer = argsList[0]
iUnitId = argsList[1]
iPlotX = argsList[2]
iPlotY = argsList[3]
# start movement restriction
[B]if not self.tRestrictedUnitClasses:
self.tRestrictedUnitClasses = (
gc.getInfoTypeForString("UNITCLASS_LIANDRA"),
gc.getInfoTypeForString("UNITCLASS_SAMPLE"),
)[/B]
pUnit = gc.getPlayer(ePlayer).getUnit(iUnitId)
eUnitType = pUnit.getUnitType()
eUnitClass = gc.getUnitInfo(eUnitType).getUnitClassType()
if eUnitClass in self.tRestrictedUnitClasses:
pPlot = gc.getMap().plot(iPlotX, iPlotY)
return pPlot.getOwner() != ePlayer
# end movement restriction
return False
Changes marked. This
should define the array once only, theoretically saving some nano-seconds each time, adding up to a full micro second in the course of a full game, or something.
It would also be possible to build a data-base of sorts of all unit types and their unit classes, so that the unit class of any given unit type is only checked once. And the same could be done with actual CyUnit instances - their unit type/class would only be checked once - but this doesn't permit unit upgrades...
But I'm not sure if indexing a Python dictionary really
is faster than calling a handful SDK methods...
edit: Ok, its simply too much fun not to do this, so here's a quick solution for the unit types vs unit classes:
Code:
tRestrictedUnitClasses = False
[B]unitClassDict = dict()[/B]
def unitCannotMoveInto(self,argsList):
ePlayer = argsList[0]
iUnitId = argsList[1]
iPlotX = argsList[2]
iPlotY = argsList[3]
if not self.tRestrictedUnitClasses:
self.tRestrictedUnitClasses = (
gc.getInfoTypeForString("UNITCLASS_LIANDRA"),
gc.getInfoTypeForString("UNITCLASS_SAMPLE"),
)
pUnit = gc.getPlayer(ePlayer).getUnit(iUnitId)
eUnitType = pUnit.getUnitType()
[B] eUnitClass = self.unitClassDict.get(eUnitType, None)
if eUnitClass == None:
eUnitClass = gc.getUnitInfo(eUnitType).getUnitClassType()
self.unitClassDict[eUnitType] = eUnitClass[/B]
if eUnitClass in self.tRestrictedUnitClasses:
pPlot = gc.getMap().plot(iPlotX, iPlotY)
return pPlot.getOwner() != ePlayer
return False
Anyone interested in learning Python should probably pay attention.
edit: I decided to take it up another notch:
Code:
# initiate class variables
tRestrictedUnitClasses = False
unitClassDict = dict()
[B]playerUnitDict = dict()
iCurrentGameTurn = 0[/B]
def unitCannotMoveInto(self,argsList):
ePlayer = argsList[0]
iUnitId = argsList[1]
iPlotX = argsList[2]
iPlotY = argsList[3]
# set unit class array once only
if not self.tRestrictedUnitClasses:
self.tRestrictedUnitClasses = (
gc.getInfoTypeForString("UNITCLASS_LIANDRA"),
gc.getInfoTypeForString("UNITCLASS_SAMPLE"),
)
# check each unit's type only once every turn
[B] iGameTurn = gc.getGame().getGameTurn()
tPlayerUnit = ePlayer, iUnitId
if iGameTurn == self.iCurrentGameTurn:
eUnitType = playerUnitDict.get(tPlayerUnit, None)
else:
eUnitType = None
self.iCurrentGameTurn = iGameTurn
if eUnitType == None:
eUnitType = gc.getPlayer(ePlayer).getUnit(iUnitId).getUnitType()
self.playerUnitDict[tPlayerUnit] = eUnitType[/B]
# fetch each unit type's class only once
eUnitClass = self.unitClassDict.get(eUnitType, None)
if eUnitClass == None:
eUnitClass = gc.getUnitInfo(eUnitType).getUnitClassType()
self.unitClassDict[eUnitType] = eUnitClass
# return True if restriction condition is met
if eUnitClass in self.tRestrictedUnitClasses:
pPlot = gc.getMap().plot(iPlotX, iPlotY)
return pPlot.getOwner() != ePlayer
# else return default False
return False
Now, none of this is actually tested and might contain any number of errors. But the idea is not to check anything more than once, hopefully saving valuable computing time. This exercise also demonstrates why it would make more sense to implement any new game rules in the SDK!