Are you, in fact, a pregnant lady who lives in the apartment next door to Superdeath's parents? - Commodore

Create an account  

 
Observer mode in Civ?

(March 12th, 2013, 10:13)novice Wrote: Is anybody interested in contributing to this experiment? I was thinking of doing a proof of concept with a python mod dumping the map state to a text file whenever the game is saved, and a simple web viewer displaying the info. If somebody wanted to contribute on the mod part that would be cool, it's not really my area of expertise.

I tried adding some simple code to hook into the game and output info to a file, but I seem to have run into issues where the python code has very limited permissions. We don't really want to have to run Civ in Administrator mode or anything. Maybe there's a better way to output the info, I notice Civ has message logs and debug logs but I don't know how that framework functions. Well we know there's a good way to solve this, since e.g. the spanish AptMod does the same thing conceptually - I just don't know what the best practice is, personally.

By the way, Seven: The file \Beyond the Sword\Assets\Python\EntryPoints\CvAppInterface.py has methods onSave() and onLoad() that look like hooks into the save process to me. I don't know if studying them will reveal any information about the save file format itself, maybe it won't.

I don't see what the problem is with Civ4 in admin mode. If it is a problem, you could set up a server to communicate with Civ4 and write it out.

I think your problem is that your user account isn't able to write to any of those directories. Try writing to your documents folder:
http://stackoverflow.com/questions/12905...ng-to-file
In Soviet Russia, Civilization Micros You!

"Right, as the world goes, is only in question between equals in power, while the strong do what they can and the weak suffer what they must."
“I have never understood why it is "greed" to want to keep the money you have earned but not greed to want to take somebody else's money.”
Reply

How did this go?
Reply

(March 17th, 2013, 07:12)nabaxo Wrote: How did this go?

Posting data to a (REST) web service seems to work fine using urllib2 and urllib. And a web service is probably needed anyway if you're using the mod on a pitboss server and want to run the observer web application on a different server. Just need to code a simple web service that accepts the data, or maybe use an FTP server as the server component and just upload data directly from memory to the FTP server.

This plumbing problem should actually be very similar to what the spanish APT mod has solved, although I'm not sure their solution would be a good reference.

Anyway, this should be very doable but I'm not sure who's going to do it...
I have to run.
Reply

It all sounds very cool, I wish I was better at coding.
Reply

Proof of concept, best viewed in Chrome:
http://test02.geodata.no/webviewer/index.html

Python snippet that produces the json file that's displayed in the web viewer:
Code:
#novice Observer mod:
from PyHelpers import PyGame, PyPlayer

#novice for Observer mod
def dumpGameState():
    try:
            print("Dumping game state...")
            cyMap = CyMap()
            cyGame = CyGame()
            pyGame = PyGame()
            #testvar = 123/0
            plots = []
            players = []
            for p in pyGame.getCivPlayerList():
                cities = []
                for c in p.getCityList():
                    cities.append({
                        "ID": c.getID(),
                        "x": c.getX(),
                        "y": c.getY(),
                        #"index": c.getIndex(),
                        "name": c.getName().replace("'", ""),
                        "owner": c.getOwner(),
                        "isBarbarian" : c.isBarbarian(),
                        "size" : c.getPopulation()
                    })
                players.append({
                    "isAlive" : p.isAlive(),
                    "ID" : p.getID(),
                    "name" : p.getName(),
                    "color" : p.getPlayer().getPlayerColor(),
                    "team" : p.getTeamID(),
                    "gold" : p.getGold(),
                    "maintenanceCosts" : p.getTotalMaintenance(),
                    "unitCosts": p.calculateUnitCost(),
                    "unitSupply" : p.calculateUnitSupply(),
                    "goldCommerceRate" : p.getGoldCommerceRate(),
                    "researchCommerceRate" : p.getResearchCommerceRate(),
                    "cultureCommerceRate" : p.getCultureCommerceRate(),
                    "beakersPerTurn" : p.calculateResearchRate(),
                    "goldPerTurn" : p.getGoldPerTurn(),
                    "techs" : p.getResearchedTechList(),
                    "currentTechName" : p.getCurrentTechName(),
                    "civType" : p.getPlayer().getCivilizationType(),
                    "civDescription" : p.getCivDescription().replace("'", ""),
                    "civName" : p.getCivilizationName().replace("'", ""),
                    "civShortDescription" : p.getCivilizationShortDescription().replace("'", ""),
                    "civAdjective": p.getCivilizationAdjective().replace("'", ""),
                    "leaderName" : p.getLeaderName().replace("'", ""),
                    "leaderType": p.getLeaderType(),
                    "cities": cities
                })
            for x in range(cyMap.getGridWidth()):
                for y in range(cyMap.getGridHeight()):
                    plot = cyMap.plot(x, y)
                    visible = [];
                    culture = [];
                    for p in range(len(players)):
                        culture.append(plot.getCulture(p))
                    for t in range(cyGame.countCivTeamsEverAlive()):
                        visible.append(plot.isRevealed(t, False))
                    plots.append({"x": x, "y": y,
                        "bonus": plot.getBonusType(plot.getTeam()),
                        "terrain": plot.getTerrainType(),
                        "improvement": plot.getImprovementType(),
                        "feature": { "type" : plot.getFeatureType(), "variety": plot.getFeatureVariety() },
                        "river" : { "id" : plot.getRiverID(), "nsDir" : int(plot.getRiverNSDirection()), "weDir" : int(plot.getRiverWEDirection()) },
                        "isGoody": plot.isGoody(),
                        "isImpassable" : plot.isImpassable(),
                        "isFreshWater" : plot.isFreshWater(),
                        "routeType" : plot.getRouteType(),
                        "plotType" : int(plot.getPlotType()),
                        "visible": visible,
                        "culture" : culture,
                        "owner" : plot.calculateCulturalOwner()
                    })
            jsondata = {
                "game": {
                    "name": cyGame.getName().replace("'", ""),
                    "turn": cyGame.getGameTurn(),
                    "year": cyGame.getGameTurnYear(),
                    "isCircumnavigated" : cyGame.isCircumnavigated(),
                    "isPbem" : cyGame.isPbem(),
                    "isPitboss" : cyGame.isPitboss(),
                    "isPitbossHost" : cyGame.isPitbossHost()
                },
                "players" : players,
                "map": {
                    "isWrapX" : cyMap.isWrapX(),
                    "isWrapY" : cyMap.isWrapY(),
                    "width" : cyMap.getGridWidth(),
                    "height" : cyMap.getGridHeight(),
                    "plots": plots
                }
            }
            filename = cyGame.getName() + " Turn " + str(cyGame.getGameTurn())
            outputfile = open("c:/temp/" + filename + ".json", "w")
            jsonstring = str(jsondata)
            jsonstring = jsonstring.replace(": u'", ": \"")
            jsonstring = jsonstring.replace("'", "\"")
            jsonstring = jsonstring.replace("False", "false")
            jsonstring = jsonstring.replace("True", "true")
            jsonstring = jsonstring.replace("}", "}\n")
            outputfile.write(jsonstring)
            outputfile.close()
        except Exception, err:
            print("Error dumping game data: " + str(err))
I have to run.
Reply

novice, that is a great smile Do you intend to carry on and see how far you can go?
Current games (All): RtR: PB80 Civ 6: PBEM23

Ended games (Selection): BTS games: PB1, PB3, PBEM2, PBEM4, PBEM5B, PBEM50. RB mod games: PB5, PB15, PB27, PB37, PB42, PB46, PB71. FFH games: PBEMVII, PBEMXII. Civ 6:  PBEM22 Games ded lurked: PB18
Reply

This looks amazing!
Reply

Way to settle your capital with no food. tongue
Reply

Looks sweet. =D
Reply

That is fantastic. Really eager to see how far this is taken.
Reply



Forum Jump: