Feature #2439 ยป 0001-common-Add-world-and-per-player-knowledge-generation.patch
| common/game.c | ||
|---|---|---|
|
punit->homecity);
|
||
|
}
|
||
|
map_world_unit_changed(punit);
|
||
|
unit_list_remove(unit_tile(punit)->units, punit);
|
||
|
owner = unit_owner(punit);
|
||
| common/map.c | ||
|---|---|---|
|
return pspresent;
|
||
|
}
|
||
|
/* The world generation. It changes whenever something a pathfinder reads
|
||
|
* may have changed: terrain, extras and their owner, tile owner, city
|
||
|
* centers and their owner, diplomatic states, settings, the set of
|
||
|
* players, the units that can transport or are transported, and turn
|
||
|
* and phase boundaries. Tile knowledge has its own per-player counter
|
||
|
* (map_knowledge_changed()). Caches of pathfinding results compare it
|
||
|
* on every lookup; a change that turns out to be irrelevant only costs
|
||
|
* a recomputation. */
|
||
|
static unsigned int world_generation = 0;
|
||
|
/* Per player slot: changes whenever the set of tiles the player knows
|
||
|
* changes. Pathfinding reads tile knowledge only when the parameter is
|
||
|
* not omniscient, so caches of such results compare this as well as
|
||
|
* the world generation. */
|
||
|
static unsigned int knowledge_generation[MAX_NUM_PLAYER_SLOTS];
|
||
|
/*******************************************************************//**
|
||
|
Return whether ptile is a tile of the current map, and not a virtual
|
||
|
tile (tile_virtual_new()), which no pathfinder reads.
|
||
|
***********************************************************************/
|
||
|
static bool map_world_tile_is_real(const struct tile *ptile)
|
||
|
{
|
||
|
return (wld.map.tiles != nullptr
|
||
|
&& ptile >= wld.map.tiles
|
||
|
&& ptile < wld.map.tiles + MAP_INDEX_SIZE);
|
||
|
}
|
||
|
/*******************************************************************//**
|
||
|
Something pathfinding may read has changed, or may have. Issues a new
|
||
|
world generation.
|
||
|
***********************************************************************/
|
||
|
void map_world_changed(void)
|
||
|
{
|
||
|
world_generation++;
|
||
|
}
|
||
|
/*******************************************************************//**
|
||
|
As map_world_changed(), but only when ptile is a real map tile: the
|
||
|
change of a virtual tile changes nothing any pathfinder reads.
|
||
|
@param ptile Tile that changed
|
||
|
***********************************************************************/
|
||
|
void map_world_tile_changed(const struct tile *ptile)
|
||
|
{
|
||
|
if (map_world_tile_is_real(ptile)) {
|
||
|
map_world_changed();
|
||
|
}
|
||
|
}
|
||
|
/*******************************************************************//**
|
||
|
The tile, orders or presence of punit is about to change.
|
||
|
Pathfinding (pf_get_move_scope(), pf_transport_check()) reads the
|
||
|
units on a tile only as possible transports: their owner, type,
|
||
|
orders, transport depth and the transports carrying them. Pathfinders
|
||
|
that read other units (get_zoc, get_TB or is_action_possible
|
||
|
callbacks) do not cache their results. So only a unit that can
|
||
|
transport, or that is transported, changes the world generation.
|
||
|
@param punit Unit about to change
|
||
|
***********************************************************************/
|
||
|
void map_world_unit_changed(const struct unit *punit)
|
||
|
{
|
||
|
if (unit_type_get(punit)->transport_capacity > 0
|
||
|
|| unit_transport_get(punit) != nullptr) {
|
||
|
map_world_changed();
|
||
|
}
|
||
|
}
|
||
|
/*******************************************************************//**
|
||
|
Return the current world generation; see map_world_changed().
|
||
|
***********************************************************************/
|
||
|
unsigned int map_world_generation(void)
|
||
|
{
|
||
|
return world_generation;
|
||
|
}
|
||
|
/*******************************************************************//**
|
||
|
The set of tiles pplayer knows has changed, or may have.
|
||
|
@param pplayer Player whose knowledge changed
|
||
|
***********************************************************************/
|
||
|
void map_knowledge_changed(const struct player *pplayer)
|
||
|
{
|
||
|
knowledge_generation[player_index(pplayer)]++;
|
||
|
}
|
||
|
/*******************************************************************//**
|
||
|
Return the current knowledge generation of pplayer; see
|
||
|
map_knowledge_changed().
|
||
|
@param pplayer Player whose knowledge generation to return
|
||
|
@return Knowledge generation
|
||
|
***********************************************************************/
|
||
|
unsigned int map_knowledge_generation(const struct player *pplayer)
|
||
|
{
|
||
|
return knowledge_generation[player_index(pplayer)];
|
||
|
}
|
||
|
/*******************************************************************//**
|
||
|
Returns TRUE if we are at a stage of the game where the map
|
||
|
has not yet been generated/loaded.
|
||
| common/map.h | ||
|---|---|---|
|
enum direction8 rand_direction(void);
|
||
|
enum direction8 opposite_direction(enum direction8 dir);
|
||
|
void map_world_changed(void);
|
||
|
void map_world_tile_changed(const struct tile *ptile);
|
||
|
void map_world_unit_changed(const struct unit *punit);
|
||
|
unsigned int map_world_generation(void);
|
||
|
void map_knowledge_changed(const struct player *pplayer);
|
||
|
unsigned int map_knowledge_generation(const struct player *pplayer);
|
||
|
#ifdef __cplusplus
|
||
|
}
|
||
|
#endif /* __cplusplus */
|
||
| common/tile.c | ||
|---|---|---|
|
if (BORDERS_DISABLED != game.info.borders
|
||
|
/* City tiles are always owned by the city owner. */
|
||
|
|| (tile_city(ptile) != nullptr || ptile->owner != nullptr)) {
|
||
|
if (ptile->owner != pplayer) {
|
||
|
map_world_tile_changed(ptile);
|
||
|
}
|
||
|
ptile->owner = pplayer;
|
||
|
ptile->claimer = claimer;
|
||
|
}
|
||
| ... | ... | |
|
****************************************************************************/
|
||
|
void tile_set_worked(struct tile *ptile, struct city *pcity)
|
||
|
{
|
||
|
struct city *new_center = (pcity != nullptr
|
||
|
&& is_city_center(pcity, ptile)
|
||
|
? pcity : nullptr);
|
||
|
if (tile_city(ptile) != new_center) {
|
||
|
/* A city center appears or goes. Which city works a tile is not
|
||
|
* read by pathfinding. */
|
||
|
map_world_tile_changed(ptile);
|
||
|
}
|
||
|
ptile->worked = pcity;
|
||
|
}
|
||
| ... | ... | |
|
tile_city(ptile)->id);
|
||
|
#endif /* 0 */
|
||
|
map_world_tile_changed(ptile);
|
||
|
ptile->terrain = pterrain;
|
||
|
if (ptile->resource != nullptr) {
|
||
|
if (pterrain != nullptr
|
||
| ... | ... | |
|
void tile_add_extra(struct tile *ptile, const struct extra_type *pextra)
|
||
|
{
|
||
|
if (pextra != nullptr) {
|
||
|
map_world_tile_changed(ptile);
|
||
|
BV_SET(ptile->extras, extra_index(pextra));
|
||
|
}
|
||
|
}
|
||
| ... | ... | |
|
void tile_remove_extra(struct tile *ptile, const struct extra_type *pextra)
|
||
|
{
|
||
|
if (pextra != nullptr) {
|
||
|
map_world_tile_changed(ptile);
|
||
|
BV_CLR(ptile->extras, extra_index(pextra));
|
||
|
if (ptile->resource == pextra) {
|
||
|
ptile->resource = nullptr;
|
||
| common/unit.c | ||
|---|---|---|
|
void free_unit_orders(struct unit *punit)
|
||
|
{
|
||
|
if (punit->has_orders) {
|
||
|
/* unit_has_orders() decides whether a pathfinder may disembark
|
||
|
* from this unit as a transport. */
|
||
|
map_world_unit_changed(punit);
|
||
|
punit->goto_tile = nullptr;
|
||
|
free(punit->orders.list);
|
||
|
punit->orders.list = nullptr;
|
||
| ... | ... | |
|
fc_assert_ret_val(!unit_list_search(ptrans->transporting, pcargo), FALSE);
|
||
|
if (force || can_unit_load(pcargo, ptrans)) {
|
||
|
map_world_changed();
|
||
|
pcargo->transporter = ptrans;
|
||
|
unit_list_append(ptrans->transporting, pcargo);
|
||
| ... | ... | |
|
}
|
||
|
/* For the server (also safe for the client). */
|
||
|
map_world_changed();
|
||
|
pcargo->transporter = nullptr;
|
||
|
return TRUE;
|
||
| server/citytools.c | ||
|---|---|---|
|
map_clear_border(pcenter);
|
||
|
/* city_thaw_workers_queue() later */
|
||
|
map_world_changed();
|
||
|
pcity->owner = ptaker;
|
||
|
pcity->capital = CAPITAL_NOT;
|
||
|
pcity->acquire_t = CACQ_CONQUEST;
|
||
| server/cityturn.c | ||
|---|---|---|
|
/* If city has a rally point set, give the unit a move order. */
|
||
|
if (pcity->rally_point.length) {
|
||
|
map_world_unit_changed(punit);
|
||
|
punit->has_orders = TRUE;
|
||
|
punit->orders.length = pcity->rally_point.length;
|
||
|
punit->orders.vigilant = pcity->rally_point.vigilant;
|
||
| server/diplhand.c | ||
|---|---|---|
|
max = dst_closest(max, state1->max_state);
|
||
|
map_world_changed();
|
||
|
state1->type = type;
|
||
|
state2->type = type;
|
||
|
state1->max_state = max;
|
||
| server/edithand.c | ||
|---|---|---|
|
conn_list_do_buffer(game.est_connections);
|
||
|
square_iterate(&(wld.map), ptile_center, size - 1, ptile) {
|
||
|
/* Pathfinding reads the extras owner. */
|
||
|
map_world_changed();
|
||
|
ptile->extras_owner = plr_eowner;
|
||
|
edit_tile_extra_handling(ptile, extra_by_number(id), removal, TRUE);
|
||
|
} square_iterate_end;
|
||
| ... | ... | |
|
}
|
||
|
if (ptile->extras_owner != eowner) {
|
||
|
/* Pathfinding reads the extras owner. */
|
||
|
map_world_changed();
|
||
|
ptile->extras_owner = eowner;
|
||
|
changed = TRUE;
|
||
|
}
|
||
| server/maphand.c | ||
|---|---|---|
|
**************************************************************************/
|
||
|
void map_set_known(struct tile *ptile, struct player *pplayer)
|
||
|
{
|
||
|
if (!dbv_isset(&pplayer->tile_known, tile_index(ptile))) {
|
||
|
/* Pathfinding reads tile knowledge. */
|
||
|
map_knowledge_changed(pplayer);
|
||
|
}
|
||
|
dbv_set(&pplayer->tile_known, tile_index(ptile));
|
||
|
}
|
||
| ... | ... | |
|
**************************************************************************/
|
||
|
void map_clear_known(struct tile *ptile, struct player *pplayer)
|
||
|
{
|
||
|
if (dbv_isset(&pplayer->tile_known, tile_index(ptile))) {
|
||
|
/* Pathfinding reads tile knowledge. */
|
||
|
map_knowledge_changed(pplayer);
|
||
|
}
|
||
|
dbv_clr(&pplayer->tile_known, tile_index(ptile));
|
||
|
}
|
||
| ... | ... | |
|
} whole_map_iterate_end;
|
||
|
dbv_init(&pplayer->tile_known, MAP_INDEX_SIZE);
|
||
|
map_knowledge_changed(pplayer);
|
||
|
}
|
||
|
/**********************************************************************//**
|
||
| ... | ... | |
|
reality_changed = TRUE;
|
||
|
}
|
||
|
if (extra_owner(ptile) == pplayer) {
|
||
|
map_world_changed();
|
||
|
ptile->extras_owner = nullptr;
|
||
|
reality_changed = TRUE;
|
||
|
}
|
||
| ... | ... | |
|
/* This MUST be before potentially recursive call to map_claim_base(),
|
||
|
* so that the recursive call will get new owner == base_loser and
|
||
|
* abort recursion. */
|
||
|
map_world_changed();
|
||
|
ptile->extras_owner = powner;
|
||
|
extra_type_by_cause_iterate(EC_BASE, pextra) {
|
||
| ... | ... | |
|
}
|
||
|
} extra_type_by_cause_iterate_end;
|
||
|
map_world_changed();
|
||
|
ptile->extras_owner = pplayer;
|
||
|
}
|
||
|
} else {
|
||
| server/plrhand.c | ||
|---|---|---|
|
map_claim_ownership(ptile, nullptr, nullptr, FALSE);
|
||
|
}
|
||
|
if (extra_owner(ptile) == pplayer) {
|
||
|
map_world_changed();
|
||
|
ptile->extras_owner = nullptr;
|
||
|
}
|
||
|
} whole_map_iterate_end;
|
||
| ... | ... | |
|
map_claim_base(ptile, pextra, new_owner, old_owner);
|
||
|
} extra_type_by_cause_iterate_end;
|
||
|
map_world_changed();
|
||
|
ptile->extras_owner = new_owner;
|
||
|
}
|
||
|
}
|
||
| ... | ... | |
|
}
|
||
|
/* Do the change */
|
||
|
/* Pathfinding reads diplomatic states. */
|
||
|
map_world_changed();
|
||
|
ds_plrplr2->type = ds_plr2plr->type = new_type;
|
||
|
ds_plrplr2->turns_left = ds_plr2plr->turns_left = 16;
|
||
| ... | ... | |
|
if (nullptr == pplayer) {
|
||
|
return nullptr;
|
||
|
}
|
||
|
/* Pathfinding results are keyed by player. */
|
||
|
map_world_changed();
|
||
|
if (allow_ai_type_fallbacking) {
|
||
|
pplayer->savegame_ai_type_name = fc_strdup(ai_tname);
|
||
| ... | ... | |
|
/* Save player slot */
|
||
|
pslot = pplayer->slot;
|
||
|
/* Pathfinding results are keyed by player. */
|
||
|
map_world_changed();
|
||
|
log_normal(_("Removing player %s."), player_name(pplayer));
|
||
| server/scripting/api_server_edit.c | ||
|---|---|---|
|
} trade_partners_iterate_end;
|
||
|
}
|
||
|
map_knowledge_changed(pplayer);
|
||
|
dbv_clr(&pplayer->tile_known, tile_index(ptile));
|
||
|
send_tile_info(pplayer->connections, ptile, TRUE);
|
||
| server/settings.c | ||
|---|---|---|
|
****************************************************************************/
|
||
|
void setting_changed(struct setting *pset)
|
||
|
{
|
||
|
/* Settings (borders, restrictinfra, citymindist, ...) are read by
|
||
|
* pathfinding. */
|
||
|
map_world_changed();
|
||
|
pset->setdef = SETDEF_CHANGED;
|
||
|
}
|
||
| server/srv_main.c | ||
|---|---|---|
|
&& state->auto_cancel_turn != game.info.turn) {
|
||
|
state->turns_left--;
|
||
|
if (state->turns_left <= 0) {
|
||
|
map_world_changed();
|
||
|
state->type = DS_PEACE;
|
||
|
state2->type = DS_PEACE;
|
||
|
state->turns_left = 0;
|
||
| ... | ... | |
|
"You are now at war with the %s."),
|
||
|
player_name(plr1),
|
||
|
nation_plural_for_player(plr1));
|
||
|
map_world_changed();
|
||
|
state->type = DS_WAR;
|
||
|
state2->type = DS_WAR;
|
||
|
state->turns_left = 0;
|
||
| ... | ... | |
|
static void begin_turn(bool is_new_turn)
|
||
|
{
|
||
|
log_debug("Begin turn");
|
||
|
map_world_changed();
|
||
|
event_cache_remove_old();
|
||
| ... | ... | |
|
static void begin_phase(bool is_new_phase)
|
||
|
{
|
||
|
log_debug("Begin phase");
|
||
|
map_world_changed();
|
||
|
conn_list_do_buffer(game.est_connections);
|
||
| ... | ... | |
|
static void end_phase(void)
|
||
|
{
|
||
|
log_debug("Endphase");
|
||
|
map_world_changed();
|
||
|
/*
|
||
|
* This empties the client Messages window; put this before
|
||
| ... | ... | |
|
static void end_turn(void)
|
||
|
{
|
||
|
log_debug("Endturn");
|
||
|
map_world_changed();
|
||
|
/* Hack: Because observer players never get an end-phase packet we send
|
||
|
* one here. */
|
||
| server/unithand.c | ||
|---|---|---|
|
unit_list_remove(old_owner->units, punit);
|
||
|
unit_list_prepend(new_owner->units, punit);
|
||
|
map_world_changed();
|
||
|
punit->owner = new_owner;
|
||
|
/* Activate AI control of the new owner. */
|
||
| ... | ... | |
|
return;
|
||
|
}
|
||
|
map_world_unit_changed(punit);
|
||
|
punit->has_orders = TRUE;
|
||
|
punit->orders.length = length;
|
||
|
punit->orders.index = 0;
|
||
| server/unittools.c | ||
|---|---|---|
|
int old_hp = unit_type_get(punit)->hp;
|
||
|
int lvls;
|
||
|
/* A transport's type is read by pathfinding. */
|
||
|
map_world_changed();
|
||
|
punit->utype = to_unit;
|
||
|
/* New type may not have the same veteran system, and we may want to
|
||
| ... | ... | |
|
FALSE);
|
||
|
unit_list_prepend(pplayer->units, punit);
|
||
|
map_world_unit_changed(punit);
|
||
|
unit_list_prepend(ptile->units, punit);
|
||
|
unit_make_contact(punit, ptile, nullptr);
|
||
|
if (pcity && !unit_has_type_flag(punit, UTYF_NOHOME)) {
|
||
| ... | ... | |
|
/* Remove unit from the source tile. */
|
||
|
fc_assert(unit_tile(punit) == psrctile);
|
||
|
map_world_unit_changed(punit);
|
||
|
#ifndef FREECIV_NDEBUG
|
||
|
bool success =
|
||
|
#endif
|
||