Fold AI savegame logic into game_io

Bug #1535424 reported by SirVer
8
This bug affects 1 person
Affects Status Importance Assigned to Milestone
widelands
Fix Released
Low
TiborB

Bug Description

Tibor and myself have been thinking about how the AI can serialize data into savegames correctly. This bug should figure out the design in a discussion and track it's implementation.

Let's start by hashing out the requirements. There are the following scenarios I can think about?

- Game starts with AI, saved and is restarted with AI.
This is the simplest - the AI can just reload its state from the saved game and continue as if there was no interruption.

- Game starts without AI, saved and is restarted with a human player replaced with AI.
This is lazy initialization and it can happen in any situation. But if the AI can handle this properly, why does it even need to save any state?

- Game starts with AI, saved. On load a human player plays the AI, but this player eventually drops. What happens now?

Question:
- did I forget a scenario?
- what is the AI actually saving right now?
- why can this not be recalculated like on lazy initialization.

Related branches

SirVer (sirver)
Changed in widelands:
status: New → Incomplete
milestone: none → build19-rc1
Revision history for this message
TiborB (tiborb95) wrote :

So input from me is expected here:)

The purpose of saving ai data is to provide some continuance after game is quited and reloaded. Most common scenario is AI|AI|AI|AI - player plays one map over multiple sessions.

AI generates huge amount of data (observers, info on buildable flags, data related to attacking), but saves only handful of them.

Currently AI has reserved:
8 x uint16_t
8 x uint32_t
8 x int32_t

This is saved as a part of player object - the space is allocated regardless of who is playing the position right now.

AI can from this data say if they are "uninitialized" (all zeros) or already contains some data.

Human player does not touch that data. And these data can "survive" if a human player plays after AI player.

Data IA stores are divided into two groups

1.) a parameters, that are generated once and are intended to give some "personality" to AI. AI is using many parameters and many of them have no "right" value, but allow range of values.

Examples:
ai_personality_military_loneliness_
ai_personality_attack_margin_
ai_personality_wood_difference_
ai_productionsites_ratio_
ai_personality_early_militarysites

2.) Run-time variables - that are changed during the game like:
colony_scan_area_
last_attacked_player_
expedition_start_time_
ships_utilization_
least_military_score_
target_military_score_
no_more_expeditions_

All remaining data of AI are regenerated after each initialization...

OK, scenarios

Generally no problems with scenarios like:
Human|AI
AI|Human
AI|AI|AI
Human|Human|Human

what can be small problem (but not significant) is scenario:
AI|Human|AI
Because some "run-time" data will not be actual. AI has no idea, that a player used to play on that slot. Worst thing could be that AI will be tricked that expedition lasts too long and decide that there are no more opportunities to create a colonisation port and gave up. (But it is not able to cancel expedition, it would only set no_more_expeditions_=true).
All other runtime variables - if not actual - are completely harmless

Questions? :)

Revision history for this message
SirVer (sirver) wrote :

I think the personality variables fit nicely in the Player class (like it is currently), but I am unsure about the run-time variables. For example, this scenario worries me:

1) AI starts playing, saves a handle to a ship in the run-time variables.
2) Player takes over after reload and sinks the ship.
3) AI takes over after reload again and expects the ship to be there still - or will we figure out on load that some variables have gone stale?

Otherwise I think having the data in Player is probably fine. I dislike the reserved slot approach, instead I suggest having a struct somewhere that knows how to save itself:

struct AiPersistentState {
string some_string;
int colony_scan_area;
bool last_attacked_player;
uint expedition_start_time;
OPtr<Immovable>* ship;
}

and a AiPersistentState* Player::mutable_ai_persistent_state() function that can be used for mutating the state.

Player can then serialize this in it's load/save cycle independently. We can also give this sub packet a separate PACKET_VERSION so that we can mutate it in a backwards compatible way.

Revision history for this message
TiborB (tiborb95) wrote :

Currently AI does not preserve (over save/load) identification of ship in expedition. Instead, when game is restarted as it collects info on all own ships, it queries their status and see which one (if any) is in expedition. Unless there are two of them in expedition at the same time not serious problem.

Of course it can happen that ship X was in expedition, a human player played, and on load ship Y is in expedition. AI has no idea that it is different ship.

Or even worse, if a human player has two ships in expedition, AI will not cope with this. I realized this just now....Solution to this would be cancel expedition for the second ship, but I think the code is not functional properly now....

Separate struct for AI data sounds good, though I am not sure I can code it. Is there any similar code in the game? If I had an example it would be easier.

Also I would put there all data (including personality) I dont think they are that different to run-time data.

I am experimenting right now with this:

OPtr<Ship>* expedition_ship_;

But it refuses to compile:

ai_ship_tweaks/src/ai/defaultai.h:340:2: error: 'OPtr' does not name a type
  OPtr<Ship>* expedition_ship_;
  ^

?

Revision history for this message
TiborB (tiborb95) wrote :

I figured it out (storing persistent data) - I think. I will push tonigh and you will have the oportunity to review...

Revision history for this message
TiborB (tiborb95) wrote :

OK, changes are in branch now, please look at it, they are still dirty, unfinished and not tested enough. Let me know if I can go on and move also personality data there...

you can start with:
Widelands::Player::AiPersistentState* persistent_data

new files added
game_player_ai_persistent_packet.*

Revision history for this message
TiborB (tiborb95) wrote :

I am closing it as we came up with good design and it is already in the trunk.

Changed in widelands:
importance: Undecided → Low
assignee: nobody → TiborB (tiborb95)
status: Incomplete → Fix Committed
GunChleoc (gunchleoc)
Changed in widelands:
status: Fix Committed → Fix Released
Revision history for this message
GunChleoc (gunchleoc) wrote :

Fixed in build19-rc1.

To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.