Mercanaries Mod and BUG 4.0

Afforess

The White Wizard
Joined
Jul 31, 2007
Messages
12,239
Location
Austin, Texas
I'm trying to merge Strategyonlys updated Mercanaries Modcomp with RoM, which uses BUG 4.0. I'm have some questions about CvEventInterface.py, and how to merge it, as the Mercanaries mod uses a CustomEventManager. Hopefully you'll forgive my ignorance, I'm terrible with python.

The Merc Mod uses this EventInterface:

Code:
import CvUtil

from CvPythonExtensions import *

#<MERC START>
[B]import CvCustomEventManager

normalEventManager = CvCustomEventManager.CvCustomEventManager()[/B]
#<MERC END>

[B]def getEventManager():
    return normalEventManager[/B]

def onEvent(argsList):
    'Called when a game event happens - return 1 if the event was consumed'
    return getEventManager().handleEvent(argsList)

def applyEvent(argsList):
    context, playerID, netUserData, popupReturn = argsList
    return getEventManager().applyEvent(argsList)

def beginEvent(context, argsList=-1):
    return getEventManager().beginEvent(context, argsList)

And BUG 4.0 uses this one.


Code:
import BugEventManager

# **********************************
# GJD modifications start here
# **********************************
[B]
eventManager = BugEventManager.BugEventManager()

def getEventManager():
    return eventManager[/B]

# **********************************
# GJD modifications end here
# **********************************

def onEvent(argsList):
    """Called when a game event happens - return 1 if the event was consumed."""
    return getEventManager().handleEvent(argsList)

def applyEvent(argsList):
    context, playerID, netUserData, popupReturn = argsList
    return getEventManager().applyEvent(argsList)

def beginEvent(context, argsList = -1):
    return getEventManager().beginEvent(context, argsList)

def initAfterReload():
    """
    Initialize BUG and fires PythonReloaded event after reloading Python modules while game is still running.
    
    The first time this module is loaded after the game launches, the global context is not yet ready,
    and thus BUG cannot be initialized. When the Python modules are reloaded after being changed, however,
    this will reinitialize BUG and the main interface.
    """
    import BugInit
    if BugInit.init():
        try:
            import CvScreensInterface
            CvScreensInterface.reinitMainInterface()
        except:
            import BugUtil
            BugUtil.error("BugInit - failure rebuilding main interface after reloading Python modules")
        getEventManager().fireEvent("PythonReloaded")

# initialize BUG after Python modules have been reloaded
initAfterReload()

Now, the problem is the bolded areas. Both mods seems to use the same function a different way, and I am not sure how to merge these files without damaging one of the mods.
 
Look in Mercenaries Mod's CvCustomEventManager module. It should import and initialize an event manager of its own that handles the events for that mod. You should not modify CvEventInterface from BUG. You will also ditch CvCustomEventManager when done.

You need to hook that imported module you found in CvCEM to BUG's event manager using a Config XML file. The docs have sample code and there are plenty of examples in BUG. Your entry will use the <events> tag to point to the module and class name (often the same) of the module imported above.

Code:
<events module="MercenariesEventManager" class="MercenariesEventManager"/>
 
Okay. I got rid of the CEM and just added the CvMercEventManager to the init.xml. I got the game to load the main interface anyways. But mercenaries isn't quite working. I'm getting some tracebacks, and I don't know what the problem is.

Traceback (most recent call last):

File "CvEventInterface", line 30, in onEvent

File "BugEventManager", line 330, in handleEvent

File "BugEventManager", line 335, in _dispatchEvent

File "BugEventManager", line 347, in _handleDefaultEvent

File "CvMercEventManager", line 143, in onBeginGameTurn

File "MercenaryUtils", line 1488, in addMercenariesToPool

File "MercenaryUtils", line 453, in getEraAppropriateRandomMercenary

File "MercenaryUtils", line 1371, in saveMercenary

File "MercenaryUtils", line 2385, in getDictionaryRepresentation

AttributeError: 'NoneType' object has no attribute 'getType'
ERR: Python function onEvent failed, module CvEventInterface
Traceback (most recent call last):

MercanaryUtil around lines 2385 is

Code:
	def getDictionaryRepresentation(self):
	
		objDict = {}
		objDict["strMercenaryName"] = self.strMercenaryName

		tmpPromotionList = []
		
		# Add all of the promotions into the tmpPromotionList using their promotion type ID number
		for i in range (len(self.promotionList)):
			if(gc.getInfoTypeForString(self.promotionList[i].getType()) not in tmpPromotionList):
				tmpPromotionList.append(gc.getInfoTypeForString(self.promotionList[i].getType()))
	
		objDict["promotionList"] = tmpPromotionList
				
		objDict["iHireCost"] = self.iHireCost

		objDict["bHired"] = self.bHired

		objDict["iOwner"] = self.iOwner

		if(self.iOwner != -1 and self.objUnit != None):
			objDict["iUnitID"] = self.objUnit.getID()
		else:	
			objDict["iUnitID"] = -1

		objDict["iUnitInfo"] = gc.getInfoTypeForString(self.objUnitInfo.getType())
		
		objDict["iExperienceLevel"] = self.iExperienceLevel

		objDict["iNextExperienceLevel"] = self.iNextExperienceLevel
		
		objDict["iLevel"] = self.iLevel

		objDict["iBuilder"] = self.iBuilder

		objDict["iPlacementTurn"] = self.iPlacementTurn
		
		return objDict
 
MercanaryUtil around lines 2385 is

Code:
		if(self.iOwner != -1 and self.objUnit != None):
			objDict["iUnitID"] = self.objUnit.getID()
		else:	
			objDict["iUnitID"] = -1

		objDict["iUnitInfo"] = gc.getInfoTypeForString(self.objUnitInfo.getType())

I'm thinking this has a problem.

The if checks to see if "self.objUnit" is not None, but then after the end of the else block (which is run when it doesn't exist) it proceeds to try to use "self.objUnitInfo.getType()". This would fit the error message: if "self.objUnitInfo" doesn't exist then it is presumably a "NoneType object" and a nonexistant object can't have any attribute including a "getType" method.
 
I'm thinking this has a problem.

The if checks to see if "self.objUnit" is not None, but then after the end of the else block (which is run when it doesn't exist) it proceeds to try to use "self.objUnitInfo.getType()". This would fit the error message: if "self.objUnitInfo" doesn't exist then it is presumably a "NoneType object" and a nonexistant object can't have any attribute including a "getType" method.

Unless I'm interpreting the code wrong (completely possible), I don't think that's an issue.

Code:
[COLOR=Lime]       if(self.iOwner != -1 and self.objUnit != None):
            objDict["iUnitID"] = self.objUnit.getID()[/COLOR]
       [COLOR=Red] else:    
            objDict["iUnitID"] = -1[/COLOR]

     [COLOR=Purple]   objDict["iUnitInfo"] = gc.getInfoTypeForString(self.objUnitInfo.getType())[/COLOR]

These are all different segments of code. The if(self.iOwner... runs if there is an owner, and a unit. The else runs if there isn't. Neither of these affect the objDict code. That line is independent of the if, else segments. So I don't see how that's an issue; unless I'm interpreting this very wrong, which, is very possible.
 
Well, the error is clearly that self.objUnitInfo is None given that is the only line I see calling getType(), and the error means you're calling getType() on a variable that has None as a value. None is like NULL in C++. It signifies that the variable doesn't point to any object, and you cannot call any methods (object functions) on it.

Find where it is set to a value and find out why it's not getting set in this case. It looks like perhaps it gets set before calling other functions. Normally you'd pass the object to those other functions, but sometimes people use this method just like they'd use global variables.
 
Well, the error is clearly that self.objUnitInfo is None given that is the only line I see calling getType(), and the error means you're calling getType() on a variable that has None as a value. None is like NULL in C++. It signifies that the variable doesn't point to any object, and you cannot call any methods (object functions) on it.

Find where it is set to a value and find out why it's not getting set in this case. It looks like perhaps it gets set before calling other functions. Normally you'd pass the object to those other functions, but sometimes people use this method just like they'd use global variables.

The wierd thing is, I never modified this file. I just drag and dropped it into my python folder, from the Merc mod, and the mercenaries mod plays fine by itself, so I don't know why this is an issue.
 
When you use the <events> element for BUG, it initializes the event manager object in exactly the same way as CvCustomEventManager does: it imports the module which runs any module-level code, and it instantiates the class you name which should hook up the events.

Can you post the relavent files (the event manager and util module)?
 
When you use the <events> element for BUG, it initializes the event manager object in exactly the same way as CvCustomEventManager does: it imports the module which runs any module-level code, and it instantiates the class you name which should hook up the events.

Can you post the relavent files (the event manager and util module)?


Yeah. Sure.

View attachment 228759
 
Unless I'm interpreting the code wrong (completely possible), I don't think that's an issue.

Code:
[COLOR=Lime]       if(self.iOwner != -1 and self.objUnit != None):
            objDict["iUnitID"] = self.objUnit.getID()[/COLOR]
       [COLOR=Red] else:    
            objDict["iUnitID"] = -1[/COLOR]

     [COLOR=Purple]   objDict["iUnitInfo"] = gc.getInfoTypeForString(self.objUnitInfo.getType())[/COLOR]

These are all different segments of code. The if(self.iOwner... runs if there is an owner, and a unit. The else runs if there isn't. Neither of these affect the objDict code. That line is independent of the if, else segments. So I don't see how that's an issue; unless I'm interpreting this very wrong, which, is very possible.

I wasn't very clear...

It checks to see if self.objUnit actually exists before running it's getID method.

It does not do the same for self.objUnitInfo. It isn't the same thing as self.objUnit, but if one of them can be non-existant why not the other? Why only check for one?

The names of the two things are very similar - I suspect that they are both be set in the same place. Or, in this case, probably both never set to anything.

In any event, the error given means that you are trying to run a method of an object that doesn't exist. This error is not from self.objUnit since that is checked to see if it exists before it's getID method is used (ignoring the point that it isn't using .getType so can't be the call in question anyway). It can, however, be caused by self.objUnitInfo since it is never checked to see if it exists before trying to use its getType method.
 
Anyhow,

You need to either figure out why the thing that is missing was never set, or check to see if it exists before trying to use it. The first is the better solution.
 
I didn't see anything obvious, but there's a lot of code there. Any luck on this on your end?
 
I haven't gotten any farther with this, but mainly because I haven't tried. I've been rather busy with other projects.
 
Top Bottom