[MOD] Modular Python

Ok, I've not tried your manual fix yet, because something seems very wrong. I've installed the new v0.4 you uploaded. Not only am I still getting those errors, I'm still getting the OLD errors. The new one isn't showing up.

I looked in the modular event manager within my mod folder, and the new error message is there at the bottom. so I don't think I've installed it wrong (it's under assets/xml/python) and the modular_python_marker.txt is on the same level as assets, too.
 
Ok, found the problem with the error message, at least
It looks like the if modDir is None: check is returning false, because modDir isn't None, but it's still not right. I edited the end of the event manager to say:
Spoiler :
Code:
modDir = None
for root, dirs, files in os.walk( os.getcwd() ):
    if 'modular_python_marker.txt' in files:
        modDir = root
        break
if modDir is None:
    raise ImportError( 'Cant find the install directory: \nmodular_python_marker.txt is missing\nlooked in %s' % os.getcwd() )
raise ImportError( 'THIS IS A TEST. FGSDFDGSFS: \nmodular_python_marker.txt is missing\nlooked in %s' % os.getcwd() )

init()

Basically just put in a copy of your error message outside the conditional. And now I get this on startup (among the other 12 messages)

Spoiler :

Code:
---------------------------
Python Exception
---------------------------
THIS IS A TEST. FGSDFDGSFS: 
modular_python_marker.txt is missing
looked in D:\Games\Sid Meier's Civilisation IV\Beyond the Sword
---------------------------
OK   
---------------------------

A thought. Since you've got that check for the dierdra icon, could my other FF directories be interfering? All of them contain the dierdra icon of course, but only my dev version which I'm trying to use, contains the modular python marker.
 
Earlier you said:
My full path is D:/Games/Sid Meier's Civilization 4/Beyond the Sword/Mods/Fall Further 051 DEV_VERSION

And the error message is saying it looked in "D:\Games\Sid Meier's Civilisation IV\Beyond the Sword".

Code:
D:\Games\Sid Meier's Civilisation IV\Beyond the Sword
D:/Games/Sid Meier's Civilization 4/Beyond the Sword/Mods/Fall Further 051 DEV_VERSION

The slashes shouldn't make any difference, but "4"!="IV". I'm guessing one or both were written from memory, but that would certainly cause troubles. There's an "s" or "z" thing going on as well.

os.getcwd() returns the current working directory and it's entirely possible that no other function in civ cares about that. Did you move your civ directory recently?

Ok, found the problem with the error message, at least
It looks like the if modDir is None: check is returning false, because modDir isn't None, but it's still not right.

But since you're getting your error message, you aren't getting mine. If you remove your message, you shouldn't be getting any error. Or at least a brand new one.

A thought. Since you've got that check for the dierdra icon, could my other FF directories be interfering? All of them contain the dierdra icon of course, but only my dev version which I'm trying to use, contains the modular python marker.

They could, which is why I removed the check in v.4 . But I have multiple versions of Fall Further as well.

Ok, I've not tried your manual fix yet, because something seems very wrong. I've installed the new v0.4 you uploaded. Not only am I still getting those errors, I'm still getting the OLD errors. The new one isn't showing up.

If you're still getting the old errors, the old code must still be left somewhere.

It could be the pyc files. If the old one was loaded when you first tried after installing v.4 you'd get the old message. Then you changed the source, the pyc was updated and the copied exception was raised. If so, removing the unconditional raise should put it back in working order.

Yet another reason to remove pyc files.
 
The slashes shouldn't make any difference, but "4"!="IV". I'm guessing one or both were written from memory, but that would certainly cause troubles. There's an "s" or "z" thing going on as well.

os.getcwd() returns the current working directory and it's entirely possible that no other function in civ cares about that. Did you move your civ directory recently?

I did write from memory earlier, yes. The error message is correct. I haven't actually written what I posted earlier anywhere in the code, so it's not looking for the directory that I incorrectly spelled.

I completely reinstalled Civ recently, but otherwise no. Why is the current working directory the BTS one, and not the mod directory which is two levels deeper ?


But since you're getting your error message, you aren't getting mine. If you remove your message, you shouldn't be getting any error. Or at least a brand new one.

I just put that in there to see what it would return, since your error message wasn't firing. As mentioned, with or without that, I still get the original sequence of 12 errors mentioned earlier

If you're still getting the old errors, the old code must still be left somewhere.

It could be the pyc files. If the old one was loaded when you first tried after installing v.4 you'd get the old message. Then you changed the source, the pyc was updated and the copied exception was raised. If so, removing the unconditional raise should put it back in working order.

Yet another reason to remove pyc files.

I just pasted the new assets folder from 0.4 into my mod directory. It would have overwritten anything with the same name. Did you rename files, or remove old ones between this one and v0.3 ? If not, I don't see how anything would be left.

What is a pyc file ? I don't do installations of anything while civ is running. Perhaps I'm not understanding here, but I don't think anything was loaded at the time, civ wasn't running when I installed it.
 
I completely reinstalled Civ recently, but otherwise no. Why is the current working directory the BTS one, and not the mod directory which is two levels deeper ?

Eh... Because civ doesn't change the current working directory.

When a program is executed, it's current working directory is set to something, usually the directory where the executable is. After that it is up to the program to change it, or not.

Using an old shortcut to run a new installation could cause issues with the working directory.

I just put that in there to see what it would return, since your error message wasn't firing. As mentioned, with or without that, I still get the original sequence of 12 errors mentioned earlier

But have you removed that raise statement and tried running the mod? My theory is that the cache system has bitten us in the tender bits.

I just pasted the new assets folder from 0.4 into my mod directory. It would have overwritten anything with the same name. Did you rename files, or remove old ones between this one and v0.3 ? If not, I don't see how anything would be left.

What is a pyc file ? I don't do installations of anything while civ is running. Perhaps I'm not understanding here, but I don't think anything was loaded at the time, civ wasn't running when I installed it.

Unpacking the archive to the mod directory should overwrite all files, except the pyc files.

Normally Python automatically generates cached bytecode for imported modules, and stores that bytecode in pyc files. Civ usually doesn't, but apparently my code manages to create them anyway. If your old v.3 pyc file happened to be newer than the v.4 py file, maybe it wasn't regenerated. Then you changed the v.4 py code to always raise an exception, which caused the pyc file to regenerate, this time with an unconditional failure.

Removing that should cause the pyc to regenerate once again, this time bug free.

If the old error message appears again, I have no idea what could be wrong.
 
I tried removing the message I added. And now, I don't get that message on startup anymore. But I do still get the other 12 errors. I don't think the cache is at fault here


Eh... Because civ doesn't change the current working directory.

When a program is executed, it's current working directory is set to something, usually the directory where the executable is. After that it is up to the program to change it, or not.

Wouldn't this be the problem then? how is it ever going to find the marker if it's looking in the wrong directory ?
 
hmm.

Ok, now I seem to be making progress. I tried removing my half finished druid module, and it stopped generating the python errors. It seems to load up without errors now. i'll give the test module a try and see if it functions.
 
I tried removing the message I added. And now, I don't get that message on startup anymore. But I do still get the other 12 errors. I don't think the cache is at fault here

What other twelve errors? They should at least be slightly different.

Wouldn't this be the problem then? how is it ever going to find the marker if it's looking in the wrong directory ?

It looks in all subdirectories. If there was a way to get at the current mod directory we wouldn't be having these problems.
 
yep, everything seems functional now.

I haven't had my module in there all this time. I think I tried putting it in sometime this morning. I'm guessing It got accidentally fixed along the way somewhere, and my module's python failing for probably unrelated reasons was still generating the errors, even though modular python itself works.
 
eventKey: ('cannotConstructBuilding', 141)
Traceback (most recent call last):
File "ModularEventManager", line 155, in _handleGameUtilEventAfterFinalize
File "ModularGameUtils", line 285, in blockShrineOfTheChampion
NameError: global name 'pPlayer' is not defined
 
eventKey: ('cannotConstructBuilding', 141)
Traceback (most recent call last):
File "ModularEventManager", line 155, in _handleGameUtilEventAfterFinalize
File "ModularGameUtils", line 285, in blockShrineOfTheChampion
NameError: global name 'pPlayer' is not defined

Thanks.

Fix, if anyone wants it before the next version:
Spoiler :
Code:
@event.cannotConstructBuilding('BUILDING_SHRINE_OF_THE_CHAMPION')
def blockShrineOfTheChampion( data ):
    iHero = cf.getHero(data['pPlayer'])
    if iHero == -1:
        return True
    if not CyGame().isUnitClassMaxedOut(iHero, 0):
        return True
    if data['pPlayer'].getUnitClassCount(iHero) > 0:
        return True
 
error in onReligionRemove, pCity not defined

Thanks. I've been meaning to start an autoplay game to find most of these name errors, but I have to find out how to start a autoplay game, not use the computer for a while and I just haven't gotten around to it yet.

Fix:
Spoiler :

ModularEventManager.py
Code:
def onReligionRemove( argsList):
    'Religion Has been removed from a City'
    iReligion, iOwner, pRemoveCity = argsList
    data = {'iReligion':iReligion, 'iOwner':iOwner, 'pCity':pRemoveCity,}

    _handleEventKey( 'onReligionRemove', data )

    if not _LOG['RELIGIONSPREAD']:
        return
    player = PyHelpers.PyPlayer(iOwner)
    CvUtil.pyPrint('%s has been removed from Player %d Civilization %s city of %s'
        %(gc.getReligionInfo(iReligion).getDescription(), iOwner, player.getCivilizationName(), pRemoveCity.getName()))
There are no default events onReligionRemove, so it doesn't change the default game apart from removing the error message.
 
I figured out autoplay recently.

You have to enable cheatmode to start with, go into your cvilization ini, look for the Cheatcode line, and replace the 0 with chipotle

After that's done, I believe it's ctrl+shift+z ingame. With cheatcode enabled, that brings up a box which asks you how many turns to autoplay. you input a number and hit Ok, then the computer just takes over your civ and plays on it's own.

You can still only see the civ you took control of to begin with, though. not sure how/if there's a way around that.
 
Thanks for the info. Luckily, I'm not interested in actually seeing anything, just the errors that are produced.
 
Version .5 beta.
A few bugfixes.

Time to start working on documentation.
 
2 Bugs:

eventKey: ('onBuildingTypeBuilt', 175)
Traceback (most recent call last):
File "ModularEventManager", line 142, in _handleEventKeyAfterFinalize
File "fallFurtherEvents", line 2034, in towerOfElementsBuilt
ArgumentError: Python argument types in
CyInterface.addMessage(CyInterface, CyPlayer, bool, int, unicode, str, int, str, CvPythonExtensions.ColorTypes, int, int, bool, bool)
did not match C++ signature:
addMessage(class CyInterface {lvalue}, int, bool, int, class std::basic_string<unsigned short,struct std::char_traits<unsigned short>,class std::allocator<unsigned short> >, char const *, int, char const *, int, int, int, bool, bool)

eventKey: ('onBuildingTypeBuilt', 174)
Traceback (most recent call last):
File "ModularEventManager", line 142, in _handleEventKeyAfterFinalize
File "fallFurtherEvents", line 2057, in towerOfNecromancyBuilt
File "PyHelpers", line 14, in __init__
ArgumentError: Python argument types in
CyGlobalContext.getPlayer(CyGlobalContext, CyPlayer)
did not match C++ signature:
getPlayer(class CyGlobalContext {lvalue}, int)
 
2 Bugs:

eventKey: ('onBuildingTypeBuilt', 175)
Traceback (most recent call last):
File "ModularEventManager", line 142, in _handleEventKeyAfterFinalize
File "fallFurtherEvents", line 2034, in towerOfElementsBuilt
ArgumentError: Python argument types in
CyInterface.addMessage(CyInterface, CyPlayer, bool, int, unicode, str, int, str, CvPythonExtensions.ColorTypes, int, int, bool, bool)
did not match C++ signature:
addMessage(class CyInterface {lvalue}, int, bool, int, class std::basic_string<unsigned short,struct std::char_traits<unsigned short>,class std::allocator<unsigned short> >, char const *, int, char const *, int, int, int, bool, bool)

I think this will fix this problem. If not, one can simply remove the offending line: "CyInterface().addMessage(player,True,25, .....". There will be no message but at least you'll get the elemental properly.

Code:
@event.BuildingTypeBuilt('BUILDING_TOWER_OF_THE_ELEMENTS')
def towerOfElementsBuilt( data ):
    iBuildingClass = data['iBuildingClass']
    pPlot = data['pPlot']
    game = data['game']
    pPlayer = data['pPlayer']
    player = data['player']
    pCity = data['pCity']
    iBuildingType = data['iBuildingType']
    lList = ['UNIT_AIR_ELEMENTAL', 'UNIT_EARTH_ELEMENTAL', 'UNIT_FIRE_ELEMENTAL', 'UNIT_WATER_ELEMENTAL']
    iUnit = gc.getInfoTypeForString(lList[CyGame().getSorenRandNum(len(lList), "Pick Elemental")-1])
    newUnit = pPlayer.initUnit(iUnit, pCity.getX(), pCity.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_SOUTH)
    newUnit.setHasPromotion(gc.getInfoTypeForString('PROMOTION_HELD'), True)
    CyInterface().addMessage(player,True,25,CyTranslator().getText("TXT_KEY_MESSAGE_TOWER_OF_THE_ELEMENTS_SPAWN",()),'',1,gc.getUnitInfo(iUnit).getButton(),ColorTypes(8),pCity.getX(),pCity.getY(),True,True)
    iElemental = gc.getInfoTypeForString('PROMOTION_ELEMENTAL')
    iStrong = gc.getInfoTypeForString('PROMOTION_STRONG')
    apUnitList = PyPlayer(pPlayer).getUnitList()
    for pUnit in apUnitList:
        if pUnit.isHasPromotion(iElemental):
            pUnit.setHasPromotion(iStrong, True)

eventKey: ('onBuildingTypeBuilt', 174)
Traceback (most recent call last):
File "ModularEventManager", line 142, in _handleEventKeyAfterFinalize
File "fallFurtherEvents", line 2057, in towerOfNecromancyBuilt
File "PyHelpers", line 14, in __init__
ArgumentError: Python argument types in
CyGlobalContext.getPlayer(CyGlobalContext, CyPlayer)
did not match C++ signature:
getPlayer(class CyGlobalContext {lvalue}, int)

Same problem, but more critical.
Code:
@event.BuildingTypeBuilt('BUILDING_TOWER_OF_NECROMANCY')
def towerOfNecromancyBuilt( data ):
    iBuildingClass = data['iBuildingClass']
    pPlot = data['pPlot']
    game = data['game']
    pPlayer = data['pPlayer']
    player = data['player']
    pCity = data['pCity']
    iBuildingType = data['iBuildingType']
    iUndead = gc.getInfoTypeForString('PROMOTION_UNDEAD')
    iStrong = gc.getInfoTypeForString('PROMOTION_STRONG')
    iBH = gc.getInfoTypeForString('UNIT_BONE_HORDE')
    iSkeleton = gc.getInfoTypeForString('UNIT_SKELETON')
    iDiseased = gc.getInfoTypeForString('UNIT_DISEASED_CORPSE')
    iScions = gc.getInfoTypeForString('CIVILIZATION_SCIONS')
    apUnitList = PyPlayer(player).getUnitList()
    for pUnit in apUnitList:
        if pPlayer.getCivilizationType() != iScions:
            if pUnit.isHasPromotion(iUndead):
                pUnit.setHasPromotion(iStrong, True)
        else:
            if pUnit.getUnitType() == iBH:
                pUnit.setHasPromotion(iStrong, True)
            if pUnit.getUnitType() == iDiseased:
                pUnit.setHasPromotion(iStrong, True)
            if pUnit.getUnitType() == iSkeleton:
                pUnit.setHasPromotion(iStrong, True)

Both functions are in fallFurtherEvents.py .
 
Understandable. I may make a testbed mod version and run a little testing. Got a lot of time on my hands till Oct anyways.

Anything specific you'd think I could do to test the speed overhead cost?
random seed on reload disabled, save immediately after game loads up, run AIAutoplay for 100 turns and save. repeat a few times on the same save to verify that the time is reliable, then add/remove modular python and repeat, compare times. Do this in 100 turn chunks through turn 500 or so on various map/player combinations (small/crowded, large/open, and small/default, large/default). Just use a wall clock or stopwatch for comparisons

Hey Iceciro, did you ever get around to doing some testing?

I'd like to look into incorporating this in FF for patch D, since we've had too many python changes in C. But We'll need xienwolf's agreement on that, which means the performance aspects need thorough testing.
 
I haven't been able to, I've been mostly working on the OOSing and I just haven't had the time to do the testing required - Also, you can blame the Dungeon Fighter Online beta. >_>
 
Back
Top Bottom