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.terrainAnalyzer = sharedAI.terrainAnalyzer;
this.techModifications = sharedAI._techModifications[this.player];
this.playerData = sharedAI.playersData[this.player];
this.gameState = sharedAI.gameState[this.player];
this.gameState.ai = this;
this.sharedScript = sharedAI;
this.timeElapsed = sharedAI.timeElapsed;
this.circularMap = sharedAI.circularMap;
this.gameType = sharedAI.gameType;
this.barterPrices = sharedAI.barterPrices;
this.CustomInit(this.gameState, this.sharedScript);
};

View File

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

View File

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

View File

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

View File

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

View File

@ -127,7 +127,9 @@ AIInterface.prototype.GetRepresentation = function()
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)
{
var state = this.GetNonEntityRepresentation();
@ -157,10 +159,11 @@ AIInterface.prototype.ChangedEntity = function(ent)
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
// for events that AIProxy won't capture.
/**
* 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
* for events that AIProxy won't capture.
*/
AIInterface.prototype.PushEvent = function(type, msg)
{
if (this.events[type] === undefined)
@ -195,11 +198,12 @@ AIInterface.prototype.OnTerritoriesChanged = function(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.
// this relies on the fact that any "value" in a technology can only ever change
// one template value, and that the naming is the same (with / in place of .)
// it's not incredibly fast but it's not incredibly slow.
/**
* When a new technology is researched, check which templates it affects,
* and send the updated values to the AI.
* this relies on the fact that any "value" in a technology can only ever change
* one template value, and that the naming is the same (with / in place of .)
*/
AIInterface.prototype.OnTemplateModification = function(msg)
{
let cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager);
@ -223,7 +227,8 @@ AIInterface.prototype.OnTemplateModification = function(msg)
for (let name of this.templates)
{
let template = cmpTemplateManager.GetTemplateWithoutValidation(name);
if (!template || !template[msg.component])
continue;
for (let valName of msg.valueNames)
{
// let's get the base template value.
@ -243,9 +248,9 @@ AIInterface.prototype.OnTemplateModification = function(msg)
let oldValue = +item;
let newValue = ApplyValueModificationsToTemplate(valName, oldValue, msg.player, template);
// 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);
// 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 ?
if(newValue == oldValue)
@ -253,9 +258,9 @@ AIInterface.prototype.OnTemplateModification = function(msg)
if (!this.changedTemplateInfo[msg.player])
this.changedTemplateInfo[msg.player] = {};
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
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)
continue;
let template = cmpTemplateManager.GetTemplateWithoutValidation(templateName);
if (!template || !template[msg.component])
continue;
for (let valName of msg.valueNames)
{
// let's get the base template value.
@ -289,16 +296,17 @@ AIInterface.prototype.OnGlobalValueModification = function(msg)
let oldValue = +item;
let newValue = ApplyValueModificationsToEntity(valName, oldValue, ent);
// 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);
// 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 ?
if (newValue == oldValue)
continue;
if (!this.changedEntityTemplateInfo[ent])
this.changedEntityTemplateInfo[ent] = [{"variable": valName, "value": newValue}];
this.changedEntityTemplateInfo[ent] = [{ "variable": valName, "value": newValue }];
else
this.changedEntityTemplateInfo[ent].push({"variable": valName, "value": newValue});
this.changedEntityTemplateInfo[ent].push({ "variable": valName, "value": newValue });
}
}
};