Automatic Ship Design for the AI

Programmers discuss here anything related to FreeOrion programming. Primarily for the developers to discuss.

Moderator: Committer

Message
Author
Morlic
AI Contributor
Posts: 296
Joined: Tue Feb 17, 2015 11:54 am

Re: Automatic Ship Design for the AI

#31 Post by Morlic »

I do not have any objections if you want to write a naming function.

Something to keep in mind:
We have the problem that we do not know the possible hulls and parts in the code. Any abbreviation system might give 2 similar designs the same name which makes it hard to determine whether the design already exists or needs to be added (or just is completely ugly and unreadable).

Maybe we should introduce a dictionary. So we have an internal name which is HULLNAME_PARTNAME1_PARTNAME2 which is used to determine whether such design already exists.
This name is then connected with the ingame designname which may exist more than once.

We might then simply have a list of possible design names (each subclass has its own table)
For example, we could have a different name for a new hull (the 3rd hull used gets the 3rd name whatever the 3rd hull is). Different slots might then be simply named by a running index ("Lynx v1", "Lynx v2" -> new hull: "Atlas v1", "Atlas v2"). If we have more hulls than names, the last type would just keep incrementing the running index.
Alternatives could be indexing by rating instead of hull and obviously a better running index (something related to stats/parts).

This would then obviously not be reproducible from game to game. Maybe we can somehow use a hashfunction instead to look up the names. That would be somewhat reproducible but I am not too confident it scales all that well if similar names exist and the naming list isn't much longer than the hull count in the game...
If I provided any code, scripts or other content here, it's released under GPL 2.0 and CC-BY-SA 3.0

User avatar
Cjkjvfnby
AI Contributor
Posts: 539
Joined: Tue Jun 24, 2014 9:55 pm

Re: Automatic Ship Design for the AI

#32 Post by Cjkjvfnby »

Morlic wrote:I do not have any objections if you want to write a naming function.

Something to keep in mind:
We have the problem that we do not know the possible hulls and parts in the code.

It is not big trouble. Since I can get design hull and parts in code from design I did not need name to compare designs and other stuff.

I want to request next changes in C++ interface:
  • add fo.issueRemoveDesign(disign_id) or fo.issueObsoleteDesign(disign_id) (obsolete designs should be removed or not shown in empire.allDesigns)
This changes can be done via extend_free_orion_AI_interface.py first. (changing c++ implementation will require to change only one line in python code after it)
  • change return type empire.allDesigns(and others) from IntSet to IntVector (sorted unique items, for consistency with universe methods)
  • change return type of IssueCreateShipDesignOrder from int to bool, bool is more suitable for current case)
  • smart add parts to hull in fo.IssueCreateShipDesignOrder (partlist order will be ignored, so you can shuffle it and get exact same design. Only number of slots should be matter, not order)
  • change shipDesign.name and shipDesign.description form function to property that return untranslated name. (for consistency with other code, if I need translated name I can translate it with UserString)
If I provided any code, scripts or other content here, it's released under GPL 2.0 and CC-BY-SA 3.0

Morlic
AI Contributor
Posts: 296
Joined: Tue Feb 17, 2015 11:54 am

Re: Automatic Ship Design for the AI

#33 Post by Morlic »

In ProductionAI.addDesigns():

Code: Select all

for name, desc, hull, partslist, icon, model in needsAdding:
            try:
                res=fo.issueCreateShipDesignOrder( name, desc, hull, partslist, icon, model, False)
                print "added %s Design %s, with result %d"%(shipType, name, res)
            except:
                print "Error: exception triggered and caught adding %s %s: "%(shipType, name), traceback.format_exc()
        # the following loop is added since the above call into C++ code seems to be the garbage collector from
        # automatically reclaiming these
        while len(needsAdding) > 0:
            design_tup = needsAdding.pop()
            partslist = design_tup[3]
            while len(partslist) > 0:
                this_part = partslist.pop()
                del this_part
            del design_tup
Could someone explain this a little bit more to me? I do not fully understand what and why this is happening. Under which circumstances is such behaviour to be expected and garbage collection to be dealt manually with in the python code?
If I provided any code, scripts or other content here, it's released under GPL 2.0 and CC-BY-SA 3.0

User avatar
Dilvish
AI Lead and Programmer Emeritus
Posts: 4768
Joined: Sat Sep 22, 2012 6:25 pm

Re: Automatic Ship Design for the AI

#34 Post by Dilvish »

Morlic wrote:Could someone explain this a little bit more to me? I do not fully understand what and why this is happening. Under which circumstances is such behaviour to be expected and garbage collection to be dealt manually with in the python code?
I think that's code I added out of an abundance of caution when we were trying to deal with rather severe memory leak issues; it may or may not be actually needed/helpful, and I don't recall if I actually did any experiments to try checking about this particular piece. FO does still have a fair bit of memory leakage (just not as horrendously bad as it was for a while), and my recollection is that valgrind/memcheck points to the boost python code for at least some of that. Memory management gets more tricky when pointers get passed between the C++ code and the python code. The boost interface lets us *fairly clearly* control which side keeps responsibility for C++ pointers/objects we pass into python, but it's not so clear for me about Python objects that get passed to the C++ code. When/how is the python automatic garbage collector going to know that the C++ side is no longer using an object?

The AI code that I started with did have a number of places where the original authors had forced garbage collection. It could be simply that they were more used to C programming and this was unnecessary, but without being more sure about the boost python interface I prefered to err on the side of caution.

So, in this particular place, I wasn't sure if the python garbage collector would be able to determine that those objects were no longer necessary, particularly regarding the partslist object, and so I forced deletion. This aspect of the setup is simply not clear to me. If it is (or becomes) clear to you, then please explain it and we'll have better code. :D

**edit (much later) some additional info I just located: I just found a pretty good discussion here: http://stackoverflow.com/a/17684703; it also includes some info that may be more helpful in the future regarding interaction with C threads. The key take away for this discussion would be that when the C++ code explicitly accepts the argument as a boost::python::list (which is the case here) then the boost wrapper for this can be considered to act as a kind of smartpointer that interacts just fine with the python garbage collector. And if the C++ code did not take it as a boost::python object then boost would have made a copy to be dealt with on the C++ side and again no issue for the python garbage collector.
If I provided any code, scripts or other content here, it's released under GPL 2.0 and CC-BY-SA 3.0

User avatar
Cjkjvfnby
AI Contributor
Posts: 539
Joined: Tue Jun 24, 2014 9:55 pm

Re: Automatic Ship Design for the AI

#35 Post by Cjkjvfnby »

Dilvish wrote:
Morlic wrote:Could someone explain this a little bit more to me? I do not fully understand what and why this is happening. Under which circumstances is such behaviour to be expected and garbage collection to be dealt manually with in the python code?
I think that's code I added out of an abundance of caution when we were trying to deal with rather severe memory leak issues; it may or may not be actually needed/helpful, and I don't recall if I actually did any experiments to try checking about this particular piece. FO does still have a fair bit of memory leakage (just not as horrendously bad as it was for a while), and my recollection is that valgrind/memcheck points to the boost python code for at least some of that. Memory management gets more tricky when pointers get passed between the C++ code and the python code. The boost interface lets us *fairly clearly* control which side keeps responsibility for C++ pointers/objects we pass into python, but it's not so clear for me about Python objects that get passed to the C++ code. When/how is the python automatic garbage collector going to know that the C++ side is no longer using an object?

The AI code that I started with did have a number of places where the original authors had forced garbage collection. It could be simply that they were more used to C programming and this was unnecessary, but without being more sure about the boost python interface I prefered to err on the side of caution.

So, in this particular place, I wasn't sure if the python garbage collector would be able to determine that those objects were no longer necessary, particularly regarding the partslist object, and so I forced deletion. This aspect of the setup is simply not clear to me. If it is (or becomes) clear to you, then please explain it and we'll have better code. :D
Quick look shows that it is just strings not boost objects. There is no reason to delete them manually.

This code mutates argument(remove all items from newDesigns[3]) so removing it may case effect in other places.
If I provided any code, scripts or other content here, it's released under GPL 2.0 and CC-BY-SA 3.0

User avatar
Dilvish
AI Lead and Programmer Emeritus
Posts: 4768
Joined: Sat Sep 22, 2012 6:25 pm

Re: Automatic Ship Design for the AI

#36 Post by Dilvish »

Cjkjvfnby wrote:Quick look shows that it is just strings not boost objects. There is no reason to delete them manually.
This code mutates argument(remove all items from newDesigns[3]) so removing it may case effect in other places.
No, look again, it's not just strings. My main concern was about the partslist, but looking at the code it looks like after emptying out the partslist I accidentally deleted the enclosing tuple instead of the partlist itself, which probably leaves the partslist around if the concern about passing it to the C++ code represents a real issue. The tuple doesn't get passed as such to the C++ code so there was no reason for it to be manually deleted.

I can understand you'd prefer to avoid argument mutation. The code could be adjusted to make a copy of the partslist which is then passed to the C++ code and thereafter deleted. If you'd like to read up on this issue and get us a more definitive answer on whether we really need to do this at all that would be great. In the meantime I'd rather be safe than sorry, even if this is a relatively small amount of memory at stake.
If I provided any code, scripts or other content here, it's released under GPL 2.0 and CC-BY-SA 3.0

Morlic
AI Contributor
Posts: 296
Joined: Tue Feb 17, 2015 11:54 am

Re: Automatic Ship Design for the AI

#37 Post by Morlic »

In ProductionAI.getBestShipRatings():

Code: Select all

    locDetail.sort(reverse=True)
    tally = 0
    idx = 0
    for detail in locDetail:
        idx += 1
        if detail[0] < 0.7 * bestCostRating:
            break
        weight = math.exp(10*detail[0]/bestCostRating - 10)
        tally += weight
        detail[0]= tally
    for detail in locDetail:
        detail[0] /= tally
    return locDetail
What is supposed to be happening here? On first glance, this looks like an attempt of implementing a weighting system which went horribly wrong.
With weight being strictly positive, tally is monotonously increasing. So we end up with better ratings for the worse designs. This does not make any sense to me at all.
Also, as weight <= 1 and typical ratings are in the order of some hundred to thousands, this totally screws things up anyway.

Maybe the line

Code: Select all

detail[0]=tally
is intended to read

Code: Select all

detail[0]*=weight
Then I guess the code would make some sense - if the ship design isn't the best, we rate it even lower to make sure we only build the best ships.
However, this still does not make much sense. Assuming we have 5 shipyards which have all the same best design and thus rating, we would end up with multiplying each localRating with a factor of 0.2.
Now looking at the break condition, this will lead to a rating worse than the cutoff. So this does still not make sense.
So maybe we actually want to divide tally by the final idx to get the average weight. But this will screw up comparison between turns when a different number of locations with decent designs exist.

So yeah, I can not make any sense whatsoever out of this piece of code, so please explain the intention if you wrote this. Otherwise, this will be removed with the framework update.
If I provided any code, scripts or other content here, it's released under GPL 2.0 and CC-BY-SA 3.0

User avatar
Dilvish
AI Lead and Programmer Emeritus
Posts: 4768
Joined: Sat Sep 22, 2012 6:25 pm

Re: Automatic Ship Design for the AI

#38 Post by Dilvish »

Morlic wrote:What is supposed to be happening here? On first glance, this looks like an attempt of implementing a weighting system which went horribly wrong.
Sorry it looked that way, I suppose some comments would have helped :D

Code: Select all

r8031 | dilvish-fo | 2015-03-13 08:42:04 -0700 (Fri, 13 Mar 2015) | 1 line
Added explanatory comments regarding the getBestShipRatings() rating & selection approach
r8032 | dilvish-fo | 2015-03-13 08:49:31 -0700 (Fri, 13 Mar 2015) | 1 line
slight augmentation of the commentary added in r8031
Does this help clarify? It's certainly not the only approach that could be taken, just the one I chose.

Code: Select all

    # Since we haven't yet implemented a way to target military ship construction at/near particular locations
    # where they are most in need, and also because our rating system is presumably useful-but-not-perfect, we want to 
    # distribute the construction across the Resource Group and across similarly rated designs, preferentially choosing
    # the best rated design/loc combo, but if there are multiple design/loc combos with the same or similar ratings then
    # we want some chance of choosing  those alternate designs/locations.
    
    # The approach to this taken below is to treat the ratings akin to an energy to be used in a statistic mechanics type 
    # partition function.  'tally' will compute the normalization constant.
    # so first go through and calculate the tally as well as convert each individual contribution to
    # the running total up to that point, to facilitate later sampling.  Then those running totals are
    # renormalized by the final tally, so that a later random number selector in the range [0,1) can be
    # used to select the chosen design/loc 
If I provided any code, scripts or other content here, it's released under GPL 2.0 and CC-BY-SA 3.0

Morlic
AI Contributor
Posts: 296
Joined: Tue Feb 17, 2015 11:54 am

Re: Automatic Ship Design for the AI

#39 Post by Morlic »

That comments helped a lot. Thanks.


I got most of the stuff working now. With only scouts using the old design-process (detection is kinda tricky to implement sadly), the AI seems to handle building its own ships fine.

I got a weird bug though and after hours of looking through code and logs I am still not sure whether it comes from my code or is actually on the C++ side or is some sideeffect of whatever other python module:
After about 100-200 turns, the designIDs seem to be unstable. I create a design, it has the designID x. I can access the design as usual. Next turn, it suddenly has the designID x+1.
If I added two designs in the turn with IDs x and y, the next turn they suddenly have IDs x+2 and y+2.

If I reload the game, the bug is not reproducible.

When calling fo.getShipDesign(x), None is returned. When calling empire.allShipDesigns, x is not in the list anymore (it definitely was the turn before as the id x was actually looked up directly from empire.allShipDesigns)

So I have a dict for the design names {name : id}, the relevant code part is:

Code: Select all

    designID = next((shipDesignID for shipDesignID in empire.allShipDesigns if designName == fo.getShipDesign(shipDesignID).name(False)),None)
    if designID is not None:
        CACHE_DESIGNID_BY_NAME[designName] = designID

Code: Select all

sd.CACHE_DESIGNID_BY_NAME["AI_TESTDESIGN_PART_FU_RAMSCOOP_SH_BASIC_MEDIUM"]
274
sd.CACHE_DESIGNID_BY_NAME["AI_TESTDESIGN_PART_FU_DEUTERIUM_TANK_SH_BASIC_MEDIUM"]
275
So 274,275 should definitely be in empire.allShipDesigns... At least in this turn, because the very next turn we have:

Code: Select all

print [id for id in fo.getEmpire().allShipDesigns]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 210, 211, 214, 215, 216, 217, 220, 221, 224, 225, 226, 227, 228, 231, 232, 241, 242, 243, 245, 246, 247, 248, 249, 250, 255, 258, 259, 262, 266, 267, 268, 269, 270, 271, 272, 273, 276, 277]

print sd.CACHE_DESIGNID_BY_NAME
{'AI_TESTDESIGN_PART_SR_WEAPON_1_2_SH_BASIC_MEDIUM': 210, 'Outposter v2': 259, 'Outposter v1': 106, 'AI_TESTDESIGN_PART_SR_WEAPON_1_1_SH_BASIC_MEDIUM': 96, 'AI_TESTDESIGN_HULL_SH_BASIC_MEDIUM': 88, 'AI_TESTDESIGN_PART_DT_DETECTOR_2_SH_BASIC_MEDIUM': 241, 'AI_TESTDESIGN_PART_AR_STD_PLATE_SH_BASIC_MEDIUM': 93, 'Decoy v1': 108, 'AI_TESTDESIGN_PART_SR_WEAPON_2_1_SH_BASIC_MEDIUM': 242, 'AI_TESTDESIGN_HULL_SH_SPATIAL_FLUX': 231, 'AI_TESTDESIGN_PART_SH_DEFLECTOR_SH_BASIC_MEDIUM': 270, 'Orbital Seeder v1': 105, 'AI_TESTDESIGN_PART_SR_WEAPON_2_3_SH_BASIC_MEDIUM': 245, 'AI_TESTDESIGN_HULL_SH_ASTEROID': 267, 'Warship v12': 271, 'StormTroopers v3': 262, 'Warship v10': 249, 'Warship v11': 250, 'Warship v9': 247, 'AI_TESTDESIGN_PART_SH_DEFENSE_GRID_SH_BASIC_MEDIUM': 224, 'AI_TESTDESIGN_PART_AR_ROCK_PLATE_SH_BASIC_MEDIUM': 269, 'AI_TESTDESIGN_PART_SH_ROBOTIC_INTERFACE_SHIELDS_SH_BASIC_MEDIUM': 227, 'AI_TESTDESIGN_HULL_SH_SMALL_ASTEROID': 268, 'AI_TESTDESIGN_PART_GT_TROOP_POD_SH_BASIC_MEDIUM': 95, 'AI_TESTDESIGN_HULL_SH_ROBOTIC': 226, 'AI_TESTDESIGN_PART_FU_RAMSCOOP_SH_BASIC_MEDIUM': 274, 'AI_TESTDESIGN_PART_SR_WEAPON_2_2_SH_BASIC_MEDIUM': 243, 'AI_TESTDESIGN_PART_AR_ZORTRIUM_PLATE_SH_BASIC_MEDIUM': 220, 'AI_TESTDESIGN_PART_FU_BASIC_TANK_SH_BASIC_MEDIUM': 99, 'AI_TESTDESIGN_HULL_SH_HEAVY_ASTEROID': 273, 'AI_TESTDESIGN_PART_CO_OUTPOST_POD_SH_BASIC_MEDIUM': 98, 'AI_TESTDESIGN_HULL_SH_STANDARD': 92, 'Seeder v1': 104, 'Seeder v2': 258, 'AI_TESTDESIGN_PART_SR_WEAPON_1_4_SH_BASIC_MEDIUM': 216, 'AI_TESTDESIGN_PART_SR_WEAPON_1_3_SH_BASIC_MEDIUM': 214, 'AI_TESTDESIGN_HULL_SH_BASIC_SMALL': 89, 'AI_TESTDESIGN_HULL_SH_CORE_BASE': 91, 'AI_TESTDESIGN_PART_DT_DETECTOR_1_SH_BASIC_MEDIUM': 94, 'AI_TESTDESIGN_HULL_SH_ORGANIC': 255, 'Warship v13': 272, 'AI_TESTDESIGN_PART_SR_WEAPON_2_4_SH_BASIC_MEDIUM': 248, 'AI_TESTDESIGN_PART_AI_TEST_CORE_SH_CORE_BASE': 100, 'AI_TESTDESIGN_PART_FU_IMPROVED_ENGINE_COUPLINGS_SH_BASIC_MEDIUM': 266, 'SpaceInvaders v1': 102, 'Warship v5': 221, 'Warship v8': 246, 'StormTroopers v2': 232, 'StormTroopers v1': 103, 'Warship v6': 225, 'AI_TESTDESIGN_PART_FU_DEUTERIUM_TANK_SH_BASIC_MEDIUM': 275, 'Warship v1': 101, 'Warship v2': 211, 'Warship v3': 215, 'Warship v4': 217, 'AI_TESTDESIGN_HULL_SH_COLONY_BASE': 90, 'AI_TESTDESIGN_PART_CO_COLONY_POD_SH_BASIC_MEDIUM': 97, 'Warship v7': 228}
Disregarding the default designs (0:54) and the hardcoded designs for the AI (107-148), all designs but the ones added in the last turn are still correct and map to the empire.allShipDesigns 1:1.
The dict is not modified at any other place in the code than the one I gave above. Even if it was possible there was a stupid bug like this - it was a game between two AIs and the other one had been exterminated. So noone else could have issued another shipdesign, so the last IDs should be continuous.


After hours of looking for the bug I still have not the slightest clue what could be happening. I am not even sure what could potentially cause this.
So I tested if I actually have permission to change the ids from python side:

Code: Select all

print "Lets check if this gives an error"
    id = list(fo.getEmpire().allShipDesigns)
    print "Original ID is: ",id
    kamikazeDesign = fo.getShipDesign(id[1])
    kamikazeDesign.id += 1
    newID = list(fo.getEmpire().allShipDesigns)
    print "New ID is: ",newID
So this doesn't work (as was expected). So does this come somewhere from the C++ side? Or is there another way to potentially screw up this stuff in python? Any ideas on the issue?
If I provided any code, scripts or other content here, it's released under GPL 2.0 and CC-BY-SA 3.0

User avatar
Dilvish
AI Lead and Programmer Emeritus
Posts: 4768
Joined: Sat Sep 22, 2012 6:25 pm

Re: Automatic Ship Design for the AI

#40 Post by Dilvish »

That does sound quite frustrating. It's hard to try helping debug anything with just a few code snippets, but I do have a few comments/questions:
Morlic wrote:After about 100-200 turns, the designIDs seem to be unstable. I create a design, it has the designID x. I can access the design as usual. Next turn, it suddenly has the designID x+1.
And you have confirmed that fo.getShipDesign(x+1) in this situation does in fact return the design you expected to have id x? And, perhaps pointless to check, but I still feel compelled-- if you then check that_design.name(False) and that_design.ID() it tells you the expected name and id x+1?
If I reload the game, the bug is not reproducible.
And yet you seem to have reproduced it--- did you simply play a new game through until it happened again? And it only happens once, or is it every few turns, or every turn?
The dict is not modified at any other place in the code than the one I gave above. Even if it was possible there was a stupid bug like this - it was a game between two AIs and the other one had been exterminated. So noone else could have issued another shipdesign, so the last IDs should be continuous.
I'll agree that the presence of an enemy AI shouldn't cause this problem, because the AIs get their design numbers directly from the server prior to associating it with a design. I did want to note, though, that an AI does not stop all function merely because all of its planets and ships have been conquered/destroyed, just in case it somehow gets new life (gift from other empire, or some weird Resurrection effect, or whatever).
If I provided any code, scripts or other content here, it's released under GPL 2.0 and CC-BY-SA 3.0

Morlic
AI Contributor
Posts: 296
Joined: Tue Feb 17, 2015 11:54 am

Re: Automatic Ship Design for the AI

#41 Post by Morlic »

Well, I will attach what diff I currently have... I don't expect anyone to work through it but well, let's do it for completeness' sake.

I was mostly wondering whether you had any idea how I could potentially mess up the ID-management rather than expect a complete debugging. My attempts to even deliberately screw it up fail, so I'm running out of ideas how this could be done in python. (And I had that tiny hope that someone shows up and is like: Yeah this is a known issue, we already know the solution but saw no reason to fix it yet)

Maybe you have some other function call in mind that could potentially screw this up and that I might check on.


As for your questions:
The id x+1 does indeed correspond to the correct design and returns the expected name and id.

It is somewhat reproducible: If I start a new game, it will happen again... somewhere around turn 140-400 usually. If the bug happens, it will mostly (but not always, I freaking love these bugs :)) happen for the following designs/turns as well. One time the design changed its ID twice (in the next 2 turns after creation). Usually though, it will only happen once for each design.

As for the other AI: As long as it has no planets, no designs will be issued from my new code. The old code adds designs at turn 1. So the designIDs for the remaining AI should be continous.
Attachments

[The extension patch has been deactivated and can no longer be displayed.]

If I provided any code, scripts or other content here, it's released under GPL 2.0 and CC-BY-SA 3.0

User avatar
Dilvish
AI Lead and Programmer Emeritus
Posts: 4768
Joined: Sat Sep 22, 2012 6:25 pm

Re: Automatic Ship Design for the AI

#42 Post by Dilvish »

That patch file seemed a bit odd, wouldn't apply properly for me, at least partly because it seems your main content was updated to r7950 and your AI was updated to r8017, but I don't think that was the entire issue. I think I wound up getting it applied well enough (there were still some rejected portions w/r/t ship_parts.txt but they were for ROF and whatnot and I don't think they really mattered).

Also, one thing I'll note we'll have to deal with down the road, is naming conventions. We have been slowly converting from the older CamelCase style to the newer PEP8 using_underscore style. You can just focus on getting your code working right, though, and we can sort out naming convention later. But to the extent you write anything new you might want to try starting to use underscores.
Morlic wrote:Maybe you have some other function call in mind that could potentially screw this up and that I might check on.
I'm afraid nothing is coming to mind that I haven't looked at and rejected.
It is somewhat reproducible: If I start a new game, it will happen again... somewhere around turn 140-400 usually.
I can't seem to replicate the problem. Could you post/link (probably too big for directly posting) a savegame from a few turns before the problem appears? If you are on Windows I would need an xml format save file. Since playing with xml serialization slows things down you might want to play it out in binary mode to get the savefile for the desired turn, then change options to xml serialization (Options->Other uncheck binary serialization) and load the savefile (you'll still be able to load the binary savefile) and then save it back, it will then be saved in xml format.
If I provided any code, scripts or other content here, it's released under GPL 2.0 and CC-BY-SA 3.0

Morlic
AI Contributor
Posts: 296
Joined: Tue Feb 17, 2015 11:54 am

Re: Automatic Ship Design for the AI

#43 Post by Morlic »

I decided to reinstall the game and on my first quick test game, the error did not occur so far.

I will post a savefile as soon as it happens again but I won't find much time for FO until next weekend.
If I provided any code, scripts or other content here, it's released under GPL 2.0 and CC-BY-SA 3.0

Morlic
AI Contributor
Posts: 296
Joined: Tue Feb 17, 2015 11:54 am

Re: Automatic Ship Design for the AI

#44 Post by Morlic »

Dilvish wrote:
It is somewhat reproducible: If I start a new game, it will happen again... somewhere around turn 140-400 usually.
I can't seem to replicate the problem. Could you post/link (probably too big for directly posting) a savegame from a few turns before the problem appears? If you are on Windows I would need an xml format save file. Since playing with xml serialization slows things down you might want to play it out in binary mode to get the savefile for the desired turn, then change options to xml serialization (Options->Other uncheck binary serialization) and load the savefile (you'll still be able to load the binary savefile) and then save it back, it will then be saved in xml format.
Just got this bug again, but I can't save it as xml in multiplayer (save button is greyed out). Does this only work in SP or am I missing something?
If I provided any code, scripts or other content here, it's released under GPL 2.0 and CC-BY-SA 3.0

Morlic
AI Contributor
Posts: 296
Joined: Tue Feb 17, 2015 11:54 am

Re: Automatic Ship Design for the AI

#45 Post by Morlic »

So when applying the advanced troop pod patch, I remembered the AI currently relies on some hardcoded part name for counting the troops per ship. As the new framework will happily include any new part in the designs, the AI broke completely (not only counting wrong but dividing by zero...). Now hotfixing this or for future parts is as simple as adding the part to a list with parts to ignore. Of course, though, any hardcoded dependencies of parts should be removed entirely along with introducing this new framework.

1) Are there any objections to exposing ShipDesign::TroopCapacity() to the interface and use that function? I suppose that would be the quickest, cleanest and easiest solution.

2) Do you have any other stuff like this in mind that currently relies on hardcoded behaviour for parts/hulls/designs? I'd prefer not to have to skim through the entire code once more but if you can't tell for sure, I guess I'll do it anyway...
If I provided any code, scripts or other content here, it's released under GPL 2.0 and CC-BY-SA 3.0

Post Reply