[PYTHONCOMP] Python utility library (includes INI file reading)

I know, all I do is cause more work for you Dr Elmer Jiggle, :D.
 
I've just finished a marathon game that incorporates Dr. Jiggle's Alert mod, and I'm sold. These alerts greatly improved my ability to keep my head in the game, so I'm going to rebuild my mod around Dr. Jiggle's CvEventManager. He has already given me much help in rebuilding my mod, although there remain a few forked mods that no longer work. More later - I'll be working on this throughout the evening.

And I picked up a few Python books to help me better understand what everyone is saying here in this thread :lol:

I'm glad to have found this thread.
 
Thanks, Spocko.

Someday I'd like to add a bunch more alerts (see the comments in Civ4lerts.py) for things like trade opportunities and terrain improvement issues, but I haven't been playing Civ4 a lot recently, so my motivation has been low. Just the city growth alert alone makes the mod indispensible for me, but it could really be so much more.
 
Dr Elmer Jiggle said:
Thanks, Spocko.

Someday I'd like to add a bunch more alerts (see the comments in Civ4lerts.py) for things like trade opportunities and terrain improvement issues, but I haven't been playing Civ4 a lot recently, so my motivation has been low. Just the city growth alert alone makes the mod indispensible for me, but it could really be so much more.
If you want when I have some time I can take a look at the events you aren't reporting and write some code for them and send you those changes.
 
I'm trying to figure out why only a few (out of 15 or so) forked mods have ceased to work upon my incorporating Dr. Jiggle's CvCustomEventManager into my personal mod.

I'm wondering if my problem is due to my using three eventmanager files: Dr. Jiggle's CvCustomEventManager, my own CvSpockoEventManager, and a modified version of the original CvEventManager. How do these three files work together?

I've described below how they relate to each other.

My specific question is how does the system reconcile the fact that both CvEventManager and CvSpockoEventManager have the function "onLoadGame" although they are different?

CvSpockoEventManager has the following code:
Code:
     def onLoadGame(self, argsList):
          'Called when game is loaded'
          self.parent.onLoadGame(self, argsList)
          self.initValues()
CvEventManager has the following code:
Code:
     def onLoadGame(self, argsList):
## 12monkeys - Re-Init Interceptor Mission - begin
          RIM.firsttime = true
## 12monkeys - Re-Init Interceptor Mission - end
          return 0
... and it seems that 12monkeys' RIM mod is working fine.

Here's how the three eventmanagers are related to each other, starting with CvEventInterface:

CvEventInterface has the following statements:
Code:
     import CvCustomEventManager
     customEventManager = CvCustomEventManager.CvCustomEventManager()
     def getEventManager():
          return customEventManager
CvCustomEventManager (from Dr. Jiggle) has the following statements:
Code:
     import CvSpockoEventManager
     class CvCustomEventManager(CvSpockoEventManager.CvSpockoEventManager, object):
          def __init__(self, *args, **kwargs):
          super(CvCustomEventManager, self).__init__(*args, **kwargs)
CvSpockoEventManager has the following statements:
Code:
     import CvEventManager
     class CvSpockoEventManager(CvEventManager.CvEventManager):
          def __init__(self):
               # initialize base class
               self.parent = CvEventManager.CvEventManager
               self.parent.__init__(self)
CvEventManager has the following statements:
Code:
     class CvEventManager:
          def __init__(self):
I think that once I understand this, I'll begin to see how I can clean up my mod.

Thanks for your time!

EDIT: To post these attachments, I had to rename CvEventManager to be CvEventMgrTEXT... While it is annoying that we cannot post the same file to more than one posting :crazyeye: I can see how this limitation prevents spamming ;)
 

Attachments

  • CvCustomEventManagerTXT.txt
    5.1 KB · Views: 97
  • CvSpockoEventManagerTXT.txt
    12.8 KB · Views: 96
  • CvEventMgrTEXT.txt
    35.4 KB · Views: 93
A couple of things.
1) Can you post all of the event manager classes that are causing you problems so we can debug it easier.

2) Wrap your code using the code tags so your code looks like:
Code:
				<UnitCombat>
					<UnitCombatType>UNITCOMBAT_RECON</UnitCombatType>
					<bUnitCombat>1</bUnitCombat>
				</UnitCombat>
 
TheLopez said:
A couple of things.
1) Can you post all of the event manager classes that are causing you problems so we can debug it easier.

2) Wrap your code using the code tags so your code looks like:
Code:
				<UnitCombat>
					<UnitCombatType>UNITCOMBAT_RECON</UnitCombatType>
					<bUnitCombat>1</bUnitCombat>
				</UnitCombat>

Whoa! Thanks for the tip about using
Code:
 tags!  I've attached the three eventmanager files to my earlier post - thanks TheLopez!!
 
One thing I've noticed that isn't going to solve your problem but that will be a good idea in general is that you're calling the superclass event handler from all of your handlers. You don't need to do that anymore. CvCustomEventManager already does that, so you're actually calling all those handlers twice. It probably won't make a difference in most cases, but it could cause strange behavior depending on exactly what those handler functions do.

I'll look at this again later, but I don't see anything obvious at first glance. My intuition is that it's something about your modified CvEventManager class. That's the base class of both CvSpockoEventManager and CvCustomEventManager, and I wouldn't be surprised if one of the modifications is causing a problem for one or both of those classes. Can you post that file?
 
Spocko said:
My specific question is how does the system reconcile the fact that both CvEventManager and CvSpockoEventManager have the function "onLoadGame" although they are different?

The normal flow of control for any event handler, including onLoadGame would be something like the sequence shown below. I'll use onLoadGame as the example, but there's not much that varies from event type to event type.

  1. CvCustomEventManager.handleEvent is called
  2. A dispatcher for the event type is looked up in a dictionary. Usually this returns _handleDefaultEvent, but for onLoadGame it will return _handleOnLoadEvent
  3. The dispatcher is called to process all registered event handlers
    • Call the base class event handler, CvEventManager.onLoad
    • Call CvSpockoEventManager.onLoad
    • ... call any other registered onLoadGame handler functions

Some additional comments ...

You don't really need to worry much about the dispatcher thing. It's just a way of dealing with the fact that some event handlers return values or have other special semantics that require slightly different processing. For example, if a keyboard handler returns 1, then subsequent handlers are ignored.

The inner list of event handler invocations in step 3 is deliberately unnumbered. Although I think the current implementation does call the handlers in the same order in which they were registered, and with the default handler first, I'm not sure I want to make that guarantee. Just assume that your handler will be called at some point but not necessarily first, second, or last. For example, it's conceivable that the base class handler would be called after yours.

Having written all that, I'm not convinced that the problems you're seeing are related to event handling, unless those other mods also use a custom event handler. There really shouldn't be any crossover effects on non-event based mods.
 
Dr Elmer Jiggle said:
One thing I've noticed that isn't going to solve your problem but that will be a good idea in general is that you're calling the superclass event handler from all of your handlers. You don't need to do that anymore. CvCustomEventManager already does that, so you're actually calling all those handlers twice. It probably won't make a difference in most cases, but it could cause strange behavior depending on exactly what those handler functions do.

I'll look at this again later, but I don't see anything obvious at first glance. My intuition is that it's something about your modified CvEventManager class. That's the base class of both CvSpockoEventManager and CvCustomEventManager, and I wouldn't be surprised if one of the modifications is causing a problem for one or both of those classes. Can you post that file?

What you say rings true, because when I start a new game, the Dawn of Man window displays twice. But, being a newbie to OOP and Python, I don't know how to take action on this - I'd like to not be calling all those handlers twice, but I don't know what to comment out in which EventManager file.

The inner list of event handler invocations in step 3 is deliberately unnumbered. Although I think the current implementation does call the handlers in the same order in which they were registered, and with the default handler first, I'm not sure I want to make that guarantee. Just assume that your handler will be called at some point but not necessarily first, second, or last. For example, it's conceivable that the base class handler would be called after yours.

I'm interpreting this as meaning that several files can include a "def takeAction" block of statements, and all of these blocks would eventually be called by the system. For example, if three files that are called via imports have the following three blocks:

Code:
{CvEventManager}
def takeAction
  statement A
  statement B

{CvCustomEventManager}
def takeAction
  statement J
  statement K

{CvSpockoModEventManager}
def take Action
  statement X
  statement Y
... then the system would see "def takeAction" as being a block for all six statements, A,B,J,K,X, and Y - and that the system would not accept only the last block as an overriding of any previous encounters with a "def takeAction" block. If so, I see how I am not having problems just because def statements are defined differently in the three EventManager files. And it thus may not be helpful for me to try to fuse these three files together. What do you think? Am I learning? :crazyeye:

My previous post (three or four posts above) have attached text files that include the contents of my three EventManager files.

My specific problem is with respect to the "Reminder" mod that is embedded in CvEventManager - pressing Shift-R no longer invokes this handy mod. You can see in CvEventManager five blocks of edits each preceded by a comment such as "# reminder addition 1/5".

I've been waiting for the new patch to use the new files to rebuild SpockoMod. But since the patch has yet to be published, I'm thinking of rebuilding SpockoMod (which is a conglomeration of 30 or so forked mods, many of which do not touch the EventManager) this week starting with the original Civ4 CvEventManager and your CvCustomEventManager. I would just add one mod at a time and test each time to verify that each additional mod works. But before I do this, I want to work toward a greater understanding of how your CvCustomManager works so that I can rebuild SpockoMod in an informed way and so I can add new forked mods later in an informed way.

Oh, incidentally, the crown jewel of SpockoMod is that I've combined Alilum's "Alt Religion" mod and Kidinnu's "True Prophet" mod - because of this, religions are founded by Great Prophets (not by technology discovery) and the religions founded are abstract religions, not named after Earth's religions. It has been hard to see Berlin a center of Hinduism - oh, and I've renamed all cities to be abstract names that sound like they came from their respective cultures, but they're not real names (an idea forked from Alilum's "Generic City Names" mod).

Thank you for your time,
Spocko
 
Spocko said:
What you say rings true, because when I start a new game, the Dawn of Man window displays twice. But, being a newbie to OOP and Python, I don't know how to take action on this - I'd like to not be calling all those handlers twice, but I don't know what to comment out in which EventManager file.

In your CvSpockoEventManager class, all of the event handler functions look something like the example shown below.

Code:
	def onUnitMove(self, argsList):
		self.parent.onUnitMove(self, argsList)
#		rf.onUnitMove(argsList)
		ass.onUnitMove(argsList)
		sa.onUnitMove(argsList)

The "self.parent..." line is simply calling the base class's onUnitMove function. That's what you can remove. That's no longer necessary. Your event handlers only need to provide the functionality that's unique to your mod and nothing else.

I'm interpreting this as meaning that several files can include a "def takeAction" block of statements, and all of these blocks would eventually be called by the system.

They also need to register themselves with the event manager. Each of those classes in your example (well, not CvCustomEventManager, because that's the master event manager) would need something like the registerEventHandlers function that you have in CvSpockoEventManager. That would really probably be the best way to integrate the 3 classes you have now.

Rename CvEventManager to something else (so it's not redefining the base class anymore). Then go through more or less the same procedure on that class that you did with CvSpockoEventManager. Create a registerEventHandlers function and register each separate event handler function with the main event manager.

It's going to be a little more complicated, because there's a lot of redundant code that can be removed. For the most part, the only thing that really needs to stay in that class is the stuff that was added to it -- all the stuff marked by change comments. The rest is already built into CvCustomEventManager via the base class.

My specific problem is with respect to the "Reminder" mod that is embedded in CvEventManager - pressing Shift-R no longer invokes this handy mod. You can see in CvEventManager five blocks of edits each preceded by a comment such as "# reminder addition 1/5".

I'll see if I can make a simple test case that uses a keyboard event handler. It might be a problem with those.
 
Cool mod. Im starting to mess around with it now and learn this stuff so i can make my python files read from a .ini .

This is slightly off topic but two things popped into my head while working on this:

1) If you can make a python file read from a .ini can you make it write to one as well?

2) Can XML files be made to read from an .ini?
 
Dr Elmer Jiggle said:
Spocko said:
My specific problem is with respect to the "Reminder" mod that is embedded in CvEventManager - pressing Shift-R no longer invokes this handy mod. You can see in CvEventManager five blocks of edits each preceded by a comment such as "# reminder addition 1/5".

I'll see if I can make a simple test case that uses a keyboard event handler. It might be a problem with those.

That's wierd, the keyboard event handler works just fine in the mercenaries mod.
 
naf4ever said:
1) If you can make a python file read from a .ini can you make it write to one as well?

Yes. The INI file stuff leverages the built in Python ConfigParser module. Along with various other things, the RawConfigParser class includes a write method to save the data.

http://www.python.org/doc/2.4.2/lib/module-ConfigParser.html

CvConfigParser extends SafeConfigParser which extends ConfigParser which extends RawConfigParser, so it picks up all the functionality of those base classes through inheritance. The only things I've added are some code to automatically search for your INI file in the various game directories (the base classes require you to tell it where to look) and support for default values (which IMHO is a stupid omission that should already be built into the base classes).

naf4ever said:
2) Can XML files be made to read from an .ini?

I don't think so, but I'm not sure I understand the question. Can you explain in more detail what you're trying to do?
 
I guess im still clinging on to my dream to be able to make XML content that has its values based off of a variable instead of just being static. That way you could do cool stuff like make a unit that has its power based on certain factors occurring in the game or a building with bonuses based off other changing criteria.

I figured if you could write to an .ini file with python and then make those values read to be used in the XML this could be accomplished.

I don't think so, but I'm not sure I understand the question. Can you explain in more detail what you're trying to do?

Danget.... I thought i read that Kael was going to implement some sort of xml parsing in his next FfH version that allows the xml values to be read off of a 3rd party file. I'll have to look into this more.
 
I don't know about writing to an ini file but using python you can create a storage device to store info in that stays with the save game.

SD toolkit by Stone-D

Several people use this for many things, like Teg_Navanis stores unit statistics. I use it determine the next name of a unit built based on land, sea or air. You can use this in many ways. Hope that helps you.
 
Dr Elmer Jiggle said:
Hmm. My subscription to this thread seems to have died. I haven't received an email about any of about the last dozen posts. Guess I have a lot to look into, including a bunch of custom event definition code from TheLopez.

Dr Elmer Jiggle, have you had a chance to review my suggestions for your library? Are you going to add them into your code base? Please let me know so I can get the "official" version of your library instead of having custom coded added to your code.

Thanks.
 
TheLopez said:
Dr Elmer Jiggle, have you had a chance to review my suggestions for your library?

Thanks for reminding me. I had forgotten about that stuff.

My intitial impression is that I don't understand why you need the CustomEvents dictionary and special handling for it. Wouldn't it work just as well if you added an entry to self.Events and let the default handlers deal with it?

It would still probably be useful to keep the add and remove functions as hooks for manipulating self.Events, but I'm not sure I see a need for overriding beginEvent and applyEvent. And the set method wouldn't make sense anymore without CustomEvents.

I'll have to look back at some of Spocko's old posts. I think I remember another case or two where something similar to this was going to be useful. Some other add/remove functions that were going to expose some of the CvEventManager parts.
 
Basically the custom event code is to handle the situations when call backs are needed to handle popup windows.
 
TheLopez said:
Basically the custom event code is to handle the situations when call backs are needed to handle popup windows.

I understand. What I'm asking, more specifically, is would the code shown below work just as well? If not, why? I don't have a good test case to run through this, but just from looking at it, it seems like they would both ultimately do the same thing.

Code:
        # removed beginEvent and addEvent overloads

	def addCustomEventDefinition(self, eventType, eventDefinition):
                # changed CustomEvents to Events
		self.Events[eventType] = eventDefinition

	def removeCustomEventDefinition(self, eventType):
                # changed CustomEvents to Events
		del self.Events[eventType]

The basic idea is that the Events dictionary already exists, and it appears to do exactly what you want from CustomEvents. Adding more entries to that dictionary for custom events shouldn't break the built in events, and the default popup handling code should still work with the custom events.

Underneath the complexity of CvEventManager, Events is really just a dictionary that maps integer event ID's to popup handler functions. Your CustomEvents is the same thing. There's really no difference that I can see between a "built in" event and a "custom" event.
 
Top Bottom