View Full Version : Problems with CvEventInterface


Hephaistion
Aug 05, 2007, 10:18 AM
To any Python-heads who'd like to help me:

I've been trying to get my BtS mod to use Dr.G's CvCustomEventManager and have been getting some major headaches and have not been able to figure out how to cure them myself.

At the moment I'm just trying to implement some very simple code to prevent a city building a building (pagan temple) if a religion is present in the city. Now, I know the code works because I've used it after adding it directly into a copy of CvGameUtils under 'def cannotConstruct' and enabling that callback function in PythonCallbacks.xml. I want to use the CustomEventManager, though, so I can more easily keep track of my mods and make them modder-friendly for others.

So I have Dr. G's CvCustomEventManager import my utilities file, HephUtils.py. At first, this file would not get imported at all. THen I added CvEventInterface in the EntryPoints folder from Civ4lerts (I also tried another version from EnhancedCUlturalDecay mod). The game loads up my modded files, but I get a whole load of errors saying it can't find CvEventInterface.

Here's my CvCustomEventManager:

import CvEventManager

# HephMod ##########################
import HephUtils

################################################## ###


class CvCustomEventManager(CvEventManager.CvEventManager , object):

and

def __init__(self, *args, **kwargs):
super(CvCustomEventManager, self).__init__(*args, **kwargs)
# map the initial EventHandlerMap values into the new data structure
for eventType, eventHandler in self.EventHandlerMap.iteritems():
self.setEventHandler(eventType, eventHandler)
# --> INSERT EVENT HANDLER INITIALIZATION HERE <--
HephUtils.HephUtils(self)

HephUtils:

import CvUtil
from CvPythonExtensions import *

# globals
gc = CyGlobalContext()

class HephUtils:

def cannotConstruct(self,argsList):
pCity = argsList[0]
eBuilding = argsList[1]
bContinue = argsList[2]
bTestVisible = argsList[3]
bIgnoreCost = argsList[4]

#player can't build pagan temple if they have a religion
if eBuilding == gc.getInfoTypeForString("BUILDING_TP_PAGAN_TEMPLE"):
if pCity.isHasReligion(gc.getInfoTypeForString("RELIGION_JUDAISM")) or pCity.isHasReligion(gc.getInfoTypeForString("RELIGION_CHRISTIANITY")) or pCity.isHasReligion(gc.getInfoTypeForString("RELIGION_ISLAM")) or pCity.isHasReligion(gc.getInfoTypeForString("RELIGION_HINDUISM")) or pCity.isHasReligion(gc.getInfoTypeForString("RELIGION_BUDDHISM")) or pCity.isHasReligion(gc.getInfoTypeForString("RELIGION_CONFUCIANISM")) or pCity.isHasReligion(gc.getInfoTypeForString("RELIGION_TAOISM")):
return True

return False

CvEventInterface (in EntryPoints):

import CvUtil

from CvPythonExtensions import *

import CvCustomEventManager

normalEventManager = CvCustomEventManager.CvCustomEventManager()

def getEventManager():
return normalEventManager

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, PythonErr:

Traceback (most recent call last):
ERR: Call function onEvent failed. Can't find module CvEventInterface
File "<string>", line 1, in ?
ERR: Call function onEvent failed. Can't find module CvEventInterface
ERR: Call function onEvent failed. Can't find module CvEventInterface
File "<string>", line 52, in load_module
ERR: Call function onEvent failed. Can't find module CvEventInterface
ERR: Call function onEvent failed. Can't find module CvEventInterface
File "CvEventInterface", line 18, in ?
ERR: Call function onEvent failed. Can't find module CvEventInterface
ERR: Call function onEvent failed. Can't find module CvEventInterface
File "CvCustomEventManager", line 73, in __init__
ERR: Call function onEvent failed. Can't find module CvEventInterface
ERR: Call function onEvent failed. Can't find module CvEventInterface
TypeError
ERR: Call function onEvent failed. Can't find module CvEventInterface
ERR: Call function onEvent failed. Can't find module CvEventInterface
:
ERR: Call function onEvent failed. Can't find module CvEventInterface
ERR: Call function onEvent failed. Can't find module CvEventInterface
this constructor takes no arguments
ERR: Call function onEvent failed. Can't find module CvEventInterface
ERR: Call function onEvent failed. Can't find module CvEventInterface

ERR: Call function onEvent failed. Can't find module CvEventInterface
ERR: Call function onEvent failed. Can't find module CvEventInterface
Failed to load python module CvEventInterface.
ERR: Call function onEvent failed. Can't find module CvEventInterface
ERR: Call function onEvent failed. Can't find module CvEventInterface
ERR: Call function onEvent failed. Can't find module CvEventInterface
ERR: Call function onEvent failed. Can't find module CvEventInterface


PythonErr2:

load_module HephUtils
Traceback (most recent call last):
File "<string>", line 1, in ?
File "<string>", line 52, in load_module
File "CvEventInterface", line 18, in ?
File "CvCustomEventManager", line 73, in __init__
TypeError: this constructor takes no arguments

What did I do wrong?

EmperorFool
Aug 05, 2007, 11:49 AM
Your CvEventInterface.py looks fine. The one I'm using (below) only differs in trivial ways (first two imports gone and name of local variable differs). You can try using it if you'd like.

However, I think the problem is that cannotConstruct is an event from CvGameUtils which, if I understand them correctly, are totally different from events that go to CvCustomEventManager. The thing is, I don't see why it would cause an error.

The errors you're getting look like parsing errors (the "<string>" lines and the fact that it cannot find CvEventInterface module). Anyway, here are the files as I'm using them in BtS.

CvEventInterface.py:


# Sid Meier's Civilization 4
# Copyright Firaxis Games 2005
#
# CvEventInterface.py
#
# These functions are App Entry Points from C++
# WARNING: These function names should not be changed
# WARNING: These functions can not be placed into a class
#
# No other modules should import this


import CvCustomEventManager

# **********************************
# GJD modifications start here
# **********************************

customEventManager = CvCustomEventManager.CvCustomEventManager()

def getEventManager():
return customEventManager

# **********************************
# 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)


CvCustomEventManager.py:


## Copyright (c) 2005-2006, Gillmer J. Derge.

## This file is part of Civilization IV Alerts mod.
##
## Civilization IV Alerts mod is free software; you can redistribute
## it and/or modify it under the terms of the GNU General Public
## License as published by the Free Software Foundation; either
## version 2 of the License, or (at your option) any later version.
##
## Civilization IV Alerts mod is distributed in the hope that it will
## be useful, but WITHOUT ANY WARRANTY; without even the implied
## warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
## See the GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with Civilization IV Alerts mod; if not, write to the Free
## Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
## 02110-1301 USA

__version__ = "$Revision: 1.3 $"
# $Source: /usr/local/cvsroot/Civ4lerts/src/main/python/CvCustomEventManager.py,v $


import CvEventManager
import ReminderEventManager
import RuffOptionsEventManager
#import autologEventManager
import Civ4lerts
import MoreCiv4lerts
#import UnitNameEventManager


##-------------------------------------------------------------------

class CvCustomEventManager(CvEventManager.CvEventManager , object):

"""Extends the standard event manager by adding support for multiple
handlers for each event.

Methods exist for both adding and removing event handlers. A set method
also exists to override the default handlers. Clients should not depend
on event handlers being called in a particular order.

This approach works best with mods that have implemented the design
pattern suggested on Apolyton by dsplaisted.

http://apolyton.net/forums/showthread.php?threadid=142916

The example given in the 8th post in the thread would be handled by adding
the following lines to the CvCustomEventManager constructor. The RealFort,
TechConquest, and CulturalDecay classes can remain unmodified.

self.addEventHandler("unitMove", rf.onUnitMove)
self.addEventHandler("improvementBuilt", rf.onImprovementBuilt)
self.addEventHandler("techAcquired", rf.onTechAcquired)
self.addEventHandler("cityAcquired", tc.onCityAcquired)
self.addEventHandler("EndGameTurn", cd.onEndGameTurn)

Note that the naming conventions for the event type strings vary from event
to event. Some use initial capitalization, some do not; some eliminate the
"on..." prefix used in the event handler function name, some do not. Look
at the unmodified CvEventManager.py source code to determine the correct
name for a particular event.

Take care with event handlers that also extend CvEventManager. Since
this event manager handles invocation of the base class handler function,
additional handlers should not also call the base class function themselves.

"""

def __init__(self, *args, **kwargs):
super(CvCustomEventManager, self).__init__(*args, **kwargs)
# map the initial EventHandlerMap values into the new data structure
for eventType, eventHandler in self.EventHandlerMap.iteritems():
self.setEventHandler(eventType, eventHandler)
# --> INSERT EVENT HANDLER INITIALIZATION HERE <--

ReminderEventManager.ReminderEventManager(self)
RuffOptionsEventManager.RuffOptionsEventManager(se lf)
#autologEventManager.autologEventManager(self)
Civ4lerts.Civ4lerts(self)
MoreCiv4lerts.MoreCiv4lerts(self)
#UnitNameEventManager.UnitNameEventManager(self)

def addEventHandler(self, eventType, eventHandler):
"""Adds a handler for the given event type.

A list of supported event types can be found in the initialization
of EventHandlerMap in the CvEventManager class.

"""
self.EventHandlerMap[eventType].append(eventHandler)

def removeEventHandler(self, eventType, eventHandler):
"""Removes a handler for the given event type.

A list of supported event types can be found in the initialization
of EventHandlerMap in the CvEventManager class. It is an error if
the given handler is not found in the list of installed handlers.

"""
self.EventHandlerMap[eventType].remove(eventHandler)

def setEventHandler(self, eventType, eventHandler):
"""Removes all previously installed event handlers for the given
event type and installs a new handler .

A list of supported event types can be found in the initialization
of EventHandlerMap in the CvEventManager class. This method is
primarily useful for overriding, rather than extending, the default
event handler functionality.

"""
self.EventHandlerMap[eventType] = [eventHandler]

def handleEvent(self, argsList):
"""Handles events by calling all installed handlers."""
self.origArgsList = argsList
flagsIndex = len(argsList) - 6
self.bDbg, self.bMultiPlayer, self.bAlt, self.bCtrl, self.bShift, self.bAllowCheats = argsList[flagsIndex:]
eventType = argsList[0]
return {
"kbdEvent": self._handleConsumableEvent,
"mouseEvent": self._handleConsumableEvent,
"OnSave": self._handleOnSaveEvent,
"OnLoad": self._handleOnLoadEvent
}.get(eventType, self._handleDefaultEvent)(eventType, argsList[1:])

def _handleDefaultEvent(self, eventType, argsList):
if self.EventHandlerMap.has_key(eventType):
for eventHandler in self.EventHandlerMap[eventType]:
# the last 6 arguments are for internal use by handleEvent
eventHandler(argsList[:len(argsList) - 6])

def _handleConsumableEvent(self, eventType, argsList):
"""Handles events that can be consumed by the handlers, such as
keyboard or mouse events.

If a handler returns non-zero, processing is terminated, and no
subsequent handlers are invoked.

"""
if self.EventHandlerMap.has_key(eventType):
for eventHandler in self.EventHandlerMap[eventType]:
# the last 6 arguments are for internal use by handleEvent
result = eventHandler(argsList[:len(argsList) - 6])
if (result > 0):
return result
return 0

# TODO: this probably needs to be more complex
def _handleOnSaveEvent(self, eventType, argsList):
"""Handles OnSave events by concatenating the results obtained
from each handler to form an overall consolidated save string.

"""
result = ""
if self.EventHandlerMap.has_key(eventType):
for eventHandler in self.EventHandlerMap[eventType]:
# the last 6 arguments are for internal use by handleEvent
result = result + eventHandler(argsList[:len(argsList) - 6])
return result

# TODO: this probably needs to be more complex
def _handleOnLoadEvent(self, eventType, argsList):
"""Handles OnLoad events."""
return self._handleDefaultEvent(eventType, argsList)


Note that I have a bunch of attached event managers -- make sure you remove them and add your own.

Have you tried the custom event manager but without your event manager attached to it to get the default game behavior?