1
0
forked from 0ad/0ad

AI: fix serialization of template changes, fixes #3993, refs #3858

This was SVN commit r18219.
This commit is contained in:
mimo 2016-05-22 20:25:41 +00:00
parent a951762d6c
commit 6171f66d06
6 changed files with 67 additions and 55 deletions

View File

@ -44,21 +44,12 @@ m.BaseAI.prototype.Init = function(state, playerID, sharedAI)
this.accessibility = sharedAI.accessibility; this.accessibility = sharedAI.accessibility;
this.terrainAnalyzer = sharedAI.terrainAnalyzer; this.terrainAnalyzer = sharedAI.terrainAnalyzer;
this.techModifications = sharedAI._techModifications[this.player];
this.playerData = sharedAI.playersData[this.player];
this.gameState = sharedAI.gameState[this.player]; this.gameState = sharedAI.gameState[this.player];
this.gameState.ai = this; this.gameState.ai = this;
this.sharedScript = sharedAI; this.sharedScript = sharedAI;
this.timeElapsed = sharedAI.timeElapsed; this.timeElapsed = sharedAI.timeElapsed;
this.circularMap = sharedAI.circularMap;
this.gameType = sharedAI.gameType;
this.barterPrices = sharedAI.barterPrices;
this.CustomInit(this.gameState, this.sharedScript); this.CustomInit(this.gameState, this.sharedScript);
}; };

View File

@ -16,10 +16,10 @@ m.Template = m.Class({
get: function(string) get: function(string)
{ {
var value = this._template; var value = this._template;
if (this._auraTemplateModif && this._auraTemplateModif.has(string)) if (this._entityModif && this._entityModif.has(string))
return this._auraTemplateModif.get(string); return this._entityModif.get(string);
else if (this._techModif && this._techModif.has(string)) else if (this._templateModif && this._templateModif.has(string))
return this._techModif.get(string); return this._templateModif.get(string);
if (!this._tpCache.has(string)) if (!this._tpCache.has(string))
{ {
@ -565,11 +565,16 @@ m.Entity = m.Class({
this._templateName = entity.template; this._templateName = entity.template;
this._entity = entity; this._entity = entity;
this._auraTemplateModif = new Map(); // template modification from auras. this is only for this entity.
this._ai = sharedAI; this._ai = sharedAI;
if (!sharedAI._techModifications[entity.owner][this._templateName]) // save a reference to the template tech modifications
sharedAI._techModifications[entity.owner][this._templateName] = new Map(); if (!sharedAI._templatesModifications[entity.owner][this._templateName])
this._techModif = sharedAI._techModifications[entity.owner][this._templateName]; // save a reference to the template tech modifications sharedAI._templatesModifications[entity.owner][this._templateName] = new Map();
this._templateModif = sharedAI._templatesModifications[entity.owner][this._templateName];
// save a reference to the entity tech/aura modifications
if (!sharedAI._entitiesModifications.has(entity.id))
sharedAI._entitiesModifications.set(entity.id, new Map());
this._entityModif = sharedAI._entitiesModifications.get(entity.id);
}, },
toString: function() { toString: function() {

View File

@ -20,7 +20,6 @@ m.GameState.prototype.init = function(SharedScript, state, player) {
this.entities = SharedScript.entities; this.entities = SharedScript.entities;
this.player = player; this.player = player;
this.playerData = SharedScript.playersData[this.player]; this.playerData = SharedScript.playersData[this.player];
this.techModifications = SharedScript._techModifications[this.player];
this.barterPrices = SharedScript.barterPrices; this.barterPrices = SharedScript.barterPrices;
this.gameType = SharedScript.gameType; this.gameType = SharedScript.gameType;
@ -61,7 +60,6 @@ m.GameState.prototype.update = function(SharedScript, state) {
this._entities = SharedScript._entities; this._entities = SharedScript._entities;
this.entities = SharedScript.entities; this.entities = SharedScript.entities;
this.playerData = SharedScript.playersData[this.player]; this.playerData = SharedScript.playersData[this.player];
this.techModifications = SharedScript._techModifications[this.player];
this.barterPrices = SharedScript.barterPrices; this.barterPrices = SharedScript.barterPrices;
}; };
@ -133,7 +131,7 @@ m.GameState.prototype.getTemplate = function(type)
if (!this.templates[type]) if (!this.templates[type])
return null; return null;
return new m.Template(this.templates[type], this.techModifications); return new m.Template(this.templates[type]);
}; };
m.GameState.prototype.applyCiv = function(str) m.GameState.prototype.applyCiv = function(str)

View File

@ -18,7 +18,8 @@ m.SharedScript = function(settings)
// array of entity collections // array of entity collections
this._entityCollections = new Map(); this._entityCollections = new Map();
this._techModifications = {}; this._entitiesModifications = new Map(); // entities modifications
this._templatesModifications = {}; // template modifications
// each name is a reference to the actual one. // each name is a reference to the actual one.
this._entityCollectionsName = new Map(); this._entityCollectionsName = new Map();
this._entityCollectionsByDynProp = {}; this._entityCollectionsByDynProp = {};
@ -38,8 +39,9 @@ m.SharedScript.prototype.Serialize = function()
{ {
return { return {
"players": this._players, "players": this._players,
"techTp": this._techTemplates, "techTemplates": this._techTemplates,
"techModifications": this._techModifications, "templatesModifications": this._templatesModifications,
"entitiesModifications": this._entitiesModifications,
"metadata": this._entityMetadata "metadata": this._entityMetadata
}; };
}; };
@ -49,8 +51,9 @@ m.SharedScript.prototype.Serialize = function()
m.SharedScript.prototype.Deserialize = function(data) m.SharedScript.prototype.Deserialize = function(data)
{ {
this._players = data.players; this._players = data.players;
this._techTemplates = data.techTp; this._techTemplates = data.techTemplates;
this._techModifications = data.techModifications; this._templatesModifications = data.templatesModifications;
this._entitiesModifications = data.entitiesModifications;
this._entityMetadata = data.metadata; this._entityMetadata = data.metadata;
this._derivedTemplates = {}; this._derivedTemplates = {};
@ -123,8 +126,11 @@ m.SharedScript.prototype.GetTemplate = function(name)
m.SharedScript.prototype.init = function(state, deserialization) m.SharedScript.prototype.init = function(state, deserialization)
{ {
if (!deserialization) if (!deserialization)
{
this._entitiesModifications = new Map();
for (let i = 0; i < state.players.length; ++i) for (let i = 0; i < state.players.length; ++i)
this._techModifications[i] = {}; this._templatesModifications[i] = {};
}
this.ApplyTemplatesDelta(state); this.ApplyTemplatesDelta(state);
@ -310,6 +316,7 @@ m.SharedScript.prototype.ApplyEntitiesDelta = function(state)
this.entities.removeEnt(entity); this.entities.removeEnt(entity);
this._entities.delete(evt.entity); this._entities.delete(evt.entity);
this._entitiesModifications.delete(evt.entity)
for (let j in this._players) for (let j in this._players)
delete this._entityMetadata[this._players[j]][evt.entity]; delete this._entityMetadata[this._players[j]][evt.entity];
} }
@ -332,9 +339,11 @@ m.SharedScript.prototype.ApplyEntitiesDelta = function(state)
if (!this._entities.has(+id)) if (!this._entities.has(+id))
continue; // dead, presumably. continue; // dead, presumably.
let changes = state.changedEntityTemplateInfo[id]; let changes = state.changedEntityTemplateInfo[id];
let entity = this._entities.get(+id); if (!this._entitiesModifications.has(+id))
this._entitiesModifications.set(+id, new Map());
let modif = this._entitiesModifications.get(+id);
for (let change of changes) for (let change of changes)
entity._auraTemplateModif.set(change.variable, change.value); modif.set(change.variable, change.value);
} }
Engine.ProfileStop(); Engine.ProfileStop();
}; };
@ -349,10 +358,11 @@ m.SharedScript.prototype.ApplyTemplatesDelta = function(state)
for (let template in playerDiff) for (let template in playerDiff)
{ {
let changes = playerDiff[template]; let changes = playerDiff[template];
if (!this._techModifications[player][template]) if (!this._templatesModifications[player][template])
this._techModifications[player][template] = new Map(); this._templatesModifications[player][template] = new Map();
let modif = this._templatesModifications[player][template];
for (let change of changes) for (let change of changes)
this._techModifications[player][template].set(change.variable, change.value); modif.set(change.variable, change.value);
} }
} }
Engine.ProfileStop(); Engine.ProfileStop();

View File

@ -127,7 +127,7 @@ m.createBorderMap = function(gameState)
var border = Math.round(80 / map.cellSize); var border = Math.round(80 / map.cellSize);
var passabilityMap = gameState.sharedScript.passabilityMap; var passabilityMap = gameState.sharedScript.passabilityMap;
var obstructionMask = gameState.getPassabilityClassMask("unrestricted"); var obstructionMask = gameState.getPassabilityClassMask("unrestricted");
if (gameState.ai.circularMap) if (gameState.circularMap)
{ {
let ic = (width - 1) / 2; let ic = (width - 1) / 2;
let radcut = (ic - border) * (ic - border); let radcut = (ic - border) * (ic - border);

View File

@ -127,7 +127,9 @@ AIInterface.prototype.GetRepresentation = function()
return state; return state;
}; };
// Intended to be called first, during the map initialization: no caching /**
* Intended to be called first, during the map initialization: no caching
*/
AIInterface.prototype.GetFullRepresentation = function(flushEvents) AIInterface.prototype.GetFullRepresentation = function(flushEvents)
{ {
var state = this.GetNonEntityRepresentation(); var state = this.GetNonEntityRepresentation();
@ -157,10 +159,11 @@ AIInterface.prototype.ChangedEntity = function(ent)
this.changedEntities[ent] = 1; this.changedEntities[ent] = 1;
}; };
// AIProxy sets up a load of event handlers to capture interesting things going on /**
// in the world, which we will report to AI. Handle those, and add a few more handlers * AIProxy sets up a load of event handlers to capture interesting things going on
// for events that AIProxy won't capture. * in the world, which we will report to AI. Handle those, and add a few more handlers
* for events that AIProxy won't capture.
*/
AIInterface.prototype.PushEvent = function(type, msg) AIInterface.prototype.PushEvent = function(type, msg)
{ {
if (this.events[type] === undefined) if (this.events[type] === undefined)
@ -195,11 +198,12 @@ AIInterface.prototype.OnTerritoriesChanged = function(msg)
this.events.TerritoriesChanged.push(msg); this.events.TerritoriesChanged.push(msg);
}; };
// When a new technology is researched, check which templates it affects, /**
// and send the updated values to the AI. * When a new technology is researched, check which templates it affects,
// this relies on the fact that any "value" in a technology can only ever change * and send the updated values to the AI.
// one template value, and that the naming is the same (with / in place of .) * this relies on the fact that any "value" in a technology can only ever change
// it's not incredibly fast but it's not incredibly slow. * one template value, and that the naming is the same (with / in place of .)
*/
AIInterface.prototype.OnTemplateModification = function(msg) AIInterface.prototype.OnTemplateModification = function(msg)
{ {
let cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager); let cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager);
@ -223,7 +227,8 @@ AIInterface.prototype.OnTemplateModification = function(msg)
for (let name of this.templates) for (let name of this.templates)
{ {
let template = cmpTemplateManager.GetTemplateWithoutValidation(name); let template = cmpTemplateManager.GetTemplateWithoutValidation(name);
if (!template || !template[msg.component])
continue;
for (let valName of msg.valueNames) for (let valName of msg.valueNames)
{ {
// let's get the base template value. // let's get the base template value.
@ -243,9 +248,9 @@ AIInterface.prototype.OnTemplateModification = function(msg)
let oldValue = +item; let oldValue = +item;
let newValue = ApplyValueModificationsToTemplate(valName, oldValue, msg.player, template); let newValue = ApplyValueModificationsToTemplate(valName, oldValue, msg.player, template);
// Apply the same roundings as in the components // Apply the same roundings as in the components
if (valName === "Player/MaxPopulation" || valName === "Cost/Population" || valName === "Cost/PopulationBonus") if (valName === "Player/MaxPopulation" || valName === "Cost/Population" ||
valName === "Cost/PopulationBonus")
newValue = Math.round(newValue); newValue = Math.round(newValue);
// TODO in some cases, we can have two opposite changes which bring us to the old value, // TODO in some cases, we can have two opposite changes which bring us to the old value,
// and we should keep it. But how to distinguish it ? // and we should keep it. But how to distinguish it ?
if(newValue == oldValue) if(newValue == oldValue)
@ -253,9 +258,9 @@ AIInterface.prototype.OnTemplateModification = function(msg)
if (!this.changedTemplateInfo[msg.player]) if (!this.changedTemplateInfo[msg.player])
this.changedTemplateInfo[msg.player] = {}; this.changedTemplateInfo[msg.player] = {};
if (!this.changedTemplateInfo[msg.player][name]) if (!this.changedTemplateInfo[msg.player][name])
this.changedTemplateInfo[msg.player][name] = [{"variable": valName, "value": newValue}]; this.changedTemplateInfo[msg.player][name] = [{ "variable": valName, "value": newValue }];
else else
this.changedTemplateInfo[msg.player][name].push({"variable": valName, "value": newValue}); this.changedTemplateInfo[msg.player][name].push({ "variable": valName, "value": newValue });
} }
} }
}; };
@ -270,6 +275,8 @@ AIInterface.prototype.OnGlobalValueModification = function(msg)
if (!templateName || !templateName.length) if (!templateName || !templateName.length)
continue; continue;
let template = cmpTemplateManager.GetTemplateWithoutValidation(templateName); let template = cmpTemplateManager.GetTemplateWithoutValidation(templateName);
if (!template || !template[msg.component])
continue;
for (let valName of msg.valueNames) for (let valName of msg.valueNames)
{ {
// let's get the base template value. // let's get the base template value.
@ -289,16 +296,17 @@ AIInterface.prototype.OnGlobalValueModification = function(msg)
let oldValue = +item; let oldValue = +item;
let newValue = ApplyValueModificationsToEntity(valName, oldValue, ent); let newValue = ApplyValueModificationsToEntity(valName, oldValue, ent);
// Apply the same roundings as in the components // Apply the same roundings as in the components
if (valName === "Player/MaxPopulation" || valName === "Cost/Population" || valName === "Cost/PopulationBonus") if (valName === "Player/MaxPopulation" || valName === "Cost/Population" ||
valName === "Cost/PopulationBonus")
newValue = Math.round(newValue); newValue = Math.round(newValue);
// TODO in some cases, we can have two opposite changes which bring us to the old value, // TODO in some cases, we can have two opposite changes which bring us to the old value,
// and we should keep it. But how to distinguish it ? // and we should keep it. But how to distinguish it ?
if (newValue == oldValue) if (newValue == oldValue)
continue; continue;
if (!this.changedEntityTemplateInfo[ent]) if (!this.changedEntityTemplateInfo[ent])
this.changedEntityTemplateInfo[ent] = [{"variable": valName, "value": newValue}]; this.changedEntityTemplateInfo[ent] = [{ "variable": valName, "value": newValue }];
else else
this.changedEntityTemplateInfo[ent].push({"variable": valName, "value": newValue}); this.changedEntityTemplateInfo[ent].push({ "variable": valName, "value": newValue });
} }
} }
}; };