[MOD] Modular Python

Where in the folder structure should it go, exactly ?

Same level as assets is correct. "DeirdraIcon.ico", "AbsarokeIcon.ico" and "Fall from Heave 2 041 Credits.rtf" should be in the same folder.

The other thing that think could be wrong is if the mod isn't in the same place as you installed Beyond the Sword.

It works in quite a simplistic way, start in the Beyond the Sword folder and look through all subfolders; when it finds a file named "modular_python_marker.txt", assume that is the mod folder.

It doesn't look through "%USERPROFILE%\My Documents\My Games" if that's where you installed the mod. Mostly because I don't know if it's possible to install mods there.

Could you tell me the full path to your install dir?

If nothing works:
Spoiler :

You could replace: (ModularEventManager.py, last lines but one)
Code:
modDir = None
for root, dirs, files in os.walk( os.getcwd() ):
    if 'modular_python_marker.txt' in files:
        modDir = root
        break
    elif 'DeirdraIcon.ico' in files:
        # A minor shortcut. Will usually bypass any subdirs of modules.
        # No harm done if it doesn't.
        dirs[:] = []
if modDir is None:
    raise ImportError( 'Cant find the install directory' )

with

Code:
modDir = "full path to the dir where you installed modular python remembering to double any backslash (\\)"

I would like to know what the problem is and fix it though.
 
My full path is D:/Games/Sid Meier's Civilization 4/Beyond the Sword/Mods/Fall Further 051 DEV_VERSION

I did try with the current release too though. didn't work.
Will give that a shot if nothing else works
 
My full path is D:/Games/Sid Meier's Civilization 4/Beyond the Sword/Mods/Fall Further 051 DEV_VERSION

Nothing strange about that path.

One more thing that could be the problem, is there a file called "DeirdraIcon.ico" in "D:/Games/Sid Meier's Civilization 4/Beyond the Sword/Mods" or "D:/Games/Sid Meier's Civilization 4/Beyond the Sword"? The pointless micro optimisation wouldn't like that.

Does this use before/after method "hooks"? I think that would be sweet...

http://code.activestate.com/recipes/366254/

No...

You register handlers for various events, and when that event gets fired all those handlers are called in order. I don't see a need for hooks.

Of course the handlers can be any callable, so they could use them.
 
You register handlers for various events, and when that event gets fired all those handlers are called in order. I don't see a need for hooks.

Of course the handlers can be any callable, so they could use them.

Sounds cool. I dunno, I think if we could have hooks on the main classes a module could just wire itself in. Just a different way to obtain the same result, I suppose.

I'm playing around with your __import__('') idea from another thread for a module I'm making. Have you found any issues with the speed for it?
 
Sounds cool. I dunno, I think if we could have hooks on the main classes a module could just wire itself in. Just a different way to obtain the same result, I suppose.

Yes, same result, different way. Basically, each event is a hook.

It's adding hooks at interesting places that takes time. Making things modular is quick, easy and fun. Making something to be modular about is the slow, dreary part.

Almost done though, I need some testing before the first beta. Then there are a few undocumented events I should deal with before v1.0 .

I'm playing around with your __import__('') idea from another thread for a module I'm making. Have you found any issues with the speed for it?

I haven't played with it myself. It's definitely slower, but I think it's on the order of 1 second /million calls so not really noticeable.
 
You said that there needs to be only one copy of this text file anywhere in BtS folder, so if Kirby has a folder with the latest public release + this, and another with the latest internal version + this, he has 2 copies. Is that possibly the issue?
 
No, not with that error message. That message indicates no marker file was found.

The problem with two marker files is that only the directory that is found first will will ever be used regardless of which mod is actually loaded.
 
What exactly do you mean by "ever" ?


As a side note, I actually have three concurrent installations of FF. One for the latest public release, one for internal playtesting, and my dev version which changes far too often to ever actyually play a game on. The latter is the one I use for testing stuff. Like this!


But the error was exactly the same after adding the marker in the described location
 
What exactly do you mean by "ever" ?

os.walk goes through the subdirectories of os.getcwd in some order. Once any modular_python_marker.txt has been found that directory is used as the mod directory.

I don't think os.walk makes any promises about the order in which subdirectories are visited, but in practice there will usually be a consistent order. Thus, regardless of which mod is actually loaded, the the modular loading of python modules will always look in the same directory.

Obviously if there is only one marker, that marker will always be found first.

I'll upload my latest version. It includes loading of CvGameUtils and a more informative error message. :D
 
Then there are the huge sawtooth if statements that I've changed to using hashes essentially. Where there previously was tens of comparisons, there is now straight jump to the appropriate place.

Thank you! These were always a pet peeve of mine, even if it doesn't really speed things up much.
 
Weird thing, in version 4, sometimes modular python doesn't load into the game, and i need to manually change a py file to get it to "reload"...
 
Note - the above is just for the "events" wiring in piece. I have an event that runs at the end of the turn - it's not hooking up all the time. The modular spells are working though...
 
Weird thing, in version 4, sometimes modular python doesn't load into the game, and i need to manually change a py file to get it to "reload"...

Are you talking about that reloading that takes place when a python file is changed while civ is running, or does this happen even if you restart civ?

In any case, could you tell me if you get .pyc files to go with your .py files?

(.pyc files are compiled python bytecode. Normally they are taken care of by python itself, but...)

edit:
Or it could be that old nemesis of mine, python running before the xml is loaded. Is the event one of those where you specify a string in the decorator?

(A decorator is one of those functions before def , that start with "@".)
 
Are you talking about that reloading that takes place when a python file is changed while civ is running, or does this happen even if you restart civ?

In any case, could you tell me if you get .pyc files to go with your .py files?

(.pyc files are compiled python bytecode. Normally they are taken care of by python itself, but...)

edit:
Or it could be that old nemesis of mine, python running before the xml is loaded. Is the event one of those where you specify a string in the decorator?

(A decorator is one of those functions before def , that start with "@".)

Looks like a PYC file is being created.

The decorator is @event.EndGameTurn()
I believe it can take a string, but doesn't have to.

It's odd. When my event works, the game starts and immediately does a "Reloading Python Modules" before I can do anything.

*i'm a windows developer at my day job, so feel free to use jargon on me :-) if I don't know something, that's why i Read The Fine Manual.
 
Hooray, modular fort commanders. I want that.
Once you get it working, can I suggest merging in Maxastro's additions to it too ?

I am going for a very basic version first, without all the frills of unique commanders and the like. Plus I want to actually impart culture to each tile every turn by the commander, so you fight back against encroaching culture by building a fort or two.
 
Here's the module I'm working on (I want to use the fort-culture piece in FF with a few modifications of my own)

I've solved it.

The event actually does happen, but the lines in the beginning of your file get executed before the xml is loaded.

Code:
iFort = gc.getInfoTypeForString('IMPROVEMENT_FORT')
iCastle = gc.getInfoTypeForString('IMPROVEMENT_CASTLE')
iCitadel = gc.getInfoTypeForString('IMPROVEMENT_CITADEL')
iUnitFortClass = gc.getInfoTypeForString('UNITCLASS_FORT_COMMANDER')

When gc.getInfoTypeForString doesn't find the string it returns -1, so iFort == iCastle ==iCitadel == iUnitFortClass == -1 .

Later when the event happens, those values are all filled in. If the python is reloaded during a game, obviously the xml is already loaded.

Just move those assignments inside the functions and everything should be hunky-dory.

Or if you want to have those values cached do something similar to this: (code fragment from another module I'm working on)
Code:
[B]attachToMistressUnitcombats = None[/B]
@spell
def reqAttachMinionToMistress(caster):
[B]    global attachToMistressUnitcombats
    if attachToMistressUnitcombats is None:
        attachToMistressUnitcombats = set( gc.getInfoTypeForString( sUnitCombat ) for sUnitCombat in ['UNITCOMBAT_ADEPT','UNITCOMBAT_ARCHER','UNITCOMBAT_DISCIPLE','UNITCOMBAT_MELEE','UNITCOMBAT_MOUNTED','UNITCOMBAT_RECON',] )[/B]
    if caster.getUnitCombatType() not in attachToMistressUnitcombats:
        return False
    if caster.isHasPromotion( gc.getInfoTypeForString('PROMOTION_MISTRESS') and caster.getNumMinions() > 0 ):
        return False
    iCannotJoinArmy = gc.getInfoTypeForString('PROMOTION_CANNOT_JOIN_ARMY')
    if caster.isHasPromotion( iCannotJoinArmy ):
        return False
    pMistress = findMistress(caster)
    if pMistress != -1:
        return True
    return False

Looks like a PYC file is being created.
It's not the problem here, but I should look into preventing those. If nothing else to save confusion.

The decorator is @event.EndGameTurn()
I believe it can take a string, but doesn't have to.

Yes, name . It's used to override other handlers and common to all of them.

I was really thinking of those that can or must take two strings. :)

Like event.TechAcquired or BuildingTypeBuilt. They take an additional argument that is automatically run through gc.getInfoTypeForString later, when the xml is loaded.
 
Back
Top Bottom