I have been held up multiple times, but as foreshadowed a while back a
big change in the way players see the map has just occurred.  The main
visibility data structure remains the "canSeeTiles", but the old
PlayerExploredTiles are gone (well, going).

PETs used to live in a Map<Player, PET> within Tile.  This has been
replaced with a Map<Player, Tile> called cachedTiles, where the Tile
value is either the actual tile, or a copy made with the newfangled
FreeColObject.copy() routine via Tile.getTileToCache().  cachedTiles
lives solely on the server, and the tile values it contains are what
are used to serialize to the client (European ATM) players.

The contents of cachedTiles are set in various ways.  It starts empty,
but when a player explores a tile (i.e sees it for the first time) an
entry will be made for that player.  The entry will contain the tile
itself.  Indeed the rule is that if a player can see a tile, the
cachedTile must be the tile itself.  Therefore in the routine that
constructs the canSeeTiles the cachedTile is set (with Tile.seeTile).
This works for exploration as sighting the tile is implicit, and the
definition of an explored tile (on the server side) is one where there
is a cachedTile entry for the player.

So when a player can no longer see an explored tile, what is its
value?  We could make a copy of the current state of the tile at the
point it goes invisible, however this would require an expensive scan
through all the map tiles whenever we call makeCanSeeTiles.  The
latest point at which it is vital to make a copy is whenever a
permanent visible change is made to a tile that a player can not see
(where "permanent" means any change other than units moving through).
We need to capture the old state of the tile then, so that if the game
is then saved, on reload the player continues to see the old view of
the tile.  This is what we do wrong ATM --- reloading can reveal
information that players do not know (tile type changes, missionary
and settlement changes, these are only partially handled).  The other
benefit from this lazy caching is that it avoids unnecessary
FreeColObject.copy() calls when the visibility changes an arbitrary
number of times without a permanent change to the tile.

Therefore, prior to making tile changes, there should now be a call to
Tile.cacheUnseen().  This reverses an existing pattern, where after
making a tile change we called Tile.updatePlayerExploredTiles.  All
these calls are safely within the server, and no cases have been
missed, and I have a flying pig for sale.  Alternately a copy of the
tile can be taken and cached later if it is unclear whether it will
be needed.

There are rough patches remaining.

- Tile owningSettlements are a bit of a problem because the
  settlements may not have been seen, or no longer exist, etc.  This is
  a really special case where we are caching a reference to something
  not within the tile itself.  I may have to simplify these to only
  apply when the settlement is visible or at least still exists in
  which case there will be an information leak.

- Stockade levels seen by clients are not handled correctly yet.  The
  plan here is to serialize stockade-class buildings to the clients.
  I think this is better than the existing hack where we send a
  special stockade key to the clients, as this leads to confusing code
  where we have to work out whether the key is present and whether to
  use it.  If we send the building, the same code works in both client
  and server.  A patch is in testing.

- Serialization of Tile is not entirely obvious, but OTOH all the PET
  code distributed around the other classes is now gone (hooray), so at
  least the hairiness is all in one place.

- Except... the invisible native settlement information (wanted goods,
  skill) is handled independently (with another Map in Tile), as that
  should not be updated except when a player unit is in close contact.
  So there is still some special handling in IndianSettlement for this.

- The PlayerExploredTile class is still around, but only used to read
  old saved files.  When a PET is read, a deeply ugly routine therein
  makes an effort to set up a cached tile with the same effect, but
  this is somewhat fictional.  Fortunately it is a one-off effect.
  PlayerExploredTile can be removed completely at the next save format
  break.

- Testing is limited.  My 7-AI games do not regress, but AIs cheat on
  map visibility so that is not much comfort.  The
  play-one-turn,save,reload mode works so at least the serialization
  is getting a workout.  I need to pause and play for a bit.

What we got out of this:

- The hairy error-prone save-reload-vulnerable code in
  PlayerExploredTile and elsewhere that partially hid map changes you
  can not see is gone.  Serialization is now about as simple as I
  think it can be short of the DOM-removal.

- We now have a general solution to the problem of keeping a player's
  view of the map consistent in spite of unseen changes.  The view no
  longer changes with save-reload.

Cheers,
Mike Pope

Attachment: signature.asc
Description: PGP signature

------------------------------------------------------------------------------
Introducing Performance Central, a new site from SourceForge and 
AppDynamics. Performance Central is your source for news, insights, 
analysis and resources for efficient Application Performance Management. 
Visit us today!
http://pubads.g.doubleclick.net/gampad/clk?id=48897511&iu=/4140/ostg.clktrk
_______________________________________________
Freecol-developers mailing list
Freecol-developers@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/freecol-developers

Reply via email to