Call GetFullRepresentation only internally

`GetFullRepresentation` doesn't reset `this.changes` to `null`. So when
a message arrives the ai-interface will not be informed.
The ai-interface calls `GetFullRepresentation` and removed the dirty
flag from the ai interface.

This two behaviors lead to the error that the ai never receives messages
from entities which exist at game start.
This commit is contained in:
phosit 2025-08-29 21:39:23 +02:00
parent f81cf7e602
commit 08340ca18a
No known key found for this signature in database
GPG key ID: C9430B600671C268
2 changed files with 113 additions and 110 deletions

View file

@ -147,7 +147,7 @@ AIInterface.prototype.GetFullRepresentation = function(flushEvents)
state.entities = {};
// all entities are changed in the initial state.
for (const id of Engine.GetEntitiesWithInterface(IID_AIProxy))
state.entities[id] = Engine.QueryInterface(id, IID_AIProxy).GetFullRepresentation();
state.entities[id] = Engine.QueryInterface(id, IID_AIProxy).GetRepresentation();
this.changedEntities = {};
Engine.ProfileStop();

View file

@ -18,7 +18,7 @@ AIProxy.prototype.Schema =
* really and it helps performance significantly.
*
* We also add an optimisation to avoid copying non-changing values.
* The first call to GetRepresentation calls GetFullRepresentation,
* The first call to GetRepresentation calls getFullRepresentation,
* which constructs the complete entity state representation.
* After that, we simply listen to events from the rest of the gameplay code,
* and store the changed data in this.changes.
@ -27,7 +27,7 @@ AIProxy.prototype.Schema =
* will keep its old value.
*
* The event handlers should set this.changes.whatever to exactly the
* same as GetFullRepresentation would set.
* same as getFullRepresentation would set.
*/
AIProxy.prototype.Init = function()
@ -44,12 +44,121 @@ AIProxy.prototype.Deserialize = function()
this.Init();
};
function getFullRepresentation(entityID)
{
const cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager);
const ret = {
// These properties are constant and won't need to be updated
"id": entityID,
"template": cmpTemplateManager.GetCurrentTemplateName(entityID)
};
const cmpPosition = Engine.QueryInterface(entityID, IID_Position);
if (cmpPosition)
{
// Updated by OnPositionChanged
if (cmpPosition.IsInWorld())
{
const pos = cmpPosition.GetPosition2D();
ret.position = [pos.x, pos.y];
ret.angle = cmpPosition.GetRotation().y;
}
else
{
ret.position = undefined;
ret.angle = undefined;
}
}
const cmpHealth = Engine.QueryInterface(entityID, IID_Health);
if (cmpHealth)
{
// Updated by OnHealthChanged
ret.hitpoints = cmpHealth.GetHitpoints();
}
const cmpResistance = Engine.QueryInterface(entityID, IID_Resistance);
if (cmpResistance)
ret.invulnerability = cmpResistance.IsInvulnerable();
const cmpOwnership = Engine.QueryInterface(entityID, IID_Ownership);
if (cmpOwnership)
{
// Updated by OnOwnershipChanged
ret.owner = cmpOwnership.GetOwner();
}
const cmpUnitAI = Engine.QueryInterface(entityID, IID_UnitAI);
if (cmpUnitAI)
{
// Updated by OnUnitIdleChanged
ret.idle = cmpUnitAI.IsIdle();
// Updated by OnUnitStanceChanged
ret.stance = cmpUnitAI.GetStanceName();
// Updated by OnUnitAIStateChanged
ret.unitAIState = cmpUnitAI.GetCurrentState();
// Updated by OnUnitAIOrderDataChanged
ret.unitAIOrderData = cmpUnitAI.GetOrderData();
}
const cmpProductionQueue = Engine.QueryInterface(entityID, IID_ProductionQueue);
if (cmpProductionQueue)
{
// Updated by OnProductionQueueChanged
ret.trainingQueue = cmpProductionQueue.GetQueue();
}
const cmpFoundation = Engine.QueryInterface(entityID, IID_Foundation);
if (cmpFoundation)
{
// Updated by OnFoundationProgressChanged
ret.foundationProgress = cmpFoundation.GetBuildPercentage();
}
const cmpResourceDropsite = Engine.QueryInterface(entityID, IID_ResourceDropsite);
if (cmpResourceDropsite)
{
// Updated by OnDropsiteSharingChanged
ret.sharedDropsite = cmpResourceDropsite.IsShared();
}
const cmpGarrisonHolder = Engine.QueryInterface(entityID, IID_GarrisonHolder);
if (cmpGarrisonHolder)
{
// Updated by OnGarrisonedUnitsChanged
ret.garrisoned = cmpGarrisonHolder.GetEntities();
}
const cmpGarrisonable = Engine.QueryInterface(entityID, IID_Garrisonable);
if (cmpGarrisonable)
{
// Updated by OnGarrisonedStateChanged
ret.garrisonHolderID = cmpGarrisonable.HolderID();
}
const cmpTerritoryDecay = Engine.QueryInterface(entityID, IID_TerritoryDecay);
if (cmpTerritoryDecay)
ret.decaying = cmpTerritoryDecay.IsDecaying();
const cmpCapturable = Engine.QueryInterface(entityID, IID_Capturable);
if (cmpCapturable)
ret.capturePoints = cmpCapturable.GetCapturePoints();
return ret;
}
AIProxy.prototype.GetRepresentation = function()
{
// Return the full representation the first time we're called
let ret;
if (this.needsFullGet)
ret = this.GetFullRepresentation();
{
this.needsFullGet = false;
ret = getFullRepresentation(this.entity);
}
else
ret = this.changes;
@ -210,112 +319,6 @@ AIProxy.prototype.OnTerritoryDecayChanged = function(msg)
// TODO: event handlers for all the other things
AIProxy.prototype.GetFullRepresentation = function()
{
this.needsFullGet = false;
const cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager);
const ret = {
// These properties are constant and won't need to be updated
"id": this.entity,
"template": cmpTemplateManager.GetCurrentTemplateName(this.entity)
};
const cmpPosition = Engine.QueryInterface(this.entity, IID_Position);
if (cmpPosition)
{
// Updated by OnPositionChanged
if (cmpPosition.IsInWorld())
{
const pos = cmpPosition.GetPosition2D();
ret.position = [pos.x, pos.y];
ret.angle = cmpPosition.GetRotation().y;
}
else
{
ret.position = undefined;
ret.angle = undefined;
}
}
const cmpHealth = Engine.QueryInterface(this.entity, IID_Health);
if (cmpHealth)
{
// Updated by OnHealthChanged
ret.hitpoints = cmpHealth.GetHitpoints();
}
const cmpResistance = Engine.QueryInterface(this.entity, IID_Resistance);
if (cmpResistance)
ret.invulnerability = cmpResistance.IsInvulnerable();
const cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
if (cmpOwnership)
{
// Updated by OnOwnershipChanged
ret.owner = cmpOwnership.GetOwner();
}
const cmpUnitAI = Engine.QueryInterface(this.entity, IID_UnitAI);
if (cmpUnitAI)
{
// Updated by OnUnitIdleChanged
ret.idle = cmpUnitAI.IsIdle();
// Updated by OnUnitStanceChanged
ret.stance = cmpUnitAI.GetStanceName();
// Updated by OnUnitAIStateChanged
ret.unitAIState = cmpUnitAI.GetCurrentState();
// Updated by OnUnitAIOrderDataChanged
ret.unitAIOrderData = cmpUnitAI.GetOrderData();
}
const cmpProductionQueue = Engine.QueryInterface(this.entity, IID_ProductionQueue);
if (cmpProductionQueue)
{
// Updated by OnProductionQueueChanged
ret.trainingQueue = cmpProductionQueue.GetQueue();
}
const cmpFoundation = Engine.QueryInterface(this.entity, IID_Foundation);
if (cmpFoundation)
{
// Updated by OnFoundationProgressChanged
ret.foundationProgress = cmpFoundation.GetBuildPercentage();
}
const cmpResourceDropsite = Engine.QueryInterface(this.entity, IID_ResourceDropsite);
if (cmpResourceDropsite)
{
// Updated by OnDropsiteSharingChanged
ret.sharedDropsite = cmpResourceDropsite.IsShared();
}
const cmpGarrisonHolder = Engine.QueryInterface(this.entity, IID_GarrisonHolder);
if (cmpGarrisonHolder)
{
// Updated by OnGarrisonedUnitsChanged
ret.garrisoned = cmpGarrisonHolder.GetEntities();
}
const cmpGarrisonable = Engine.QueryInterface(this.entity, IID_Garrisonable);
if (cmpGarrisonable)
{
// Updated by OnGarrisonedStateChanged
ret.garrisonHolderID = cmpGarrisonable.HolderID();
}
const cmpTerritoryDecay = Engine.QueryInterface(this.entity, IID_TerritoryDecay);
if (cmpTerritoryDecay)
ret.decaying = cmpTerritoryDecay.IsDecaying();
const cmpCapturable = Engine.QueryInterface(this.entity, IID_Capturable);
if (cmpCapturable)
ret.capturePoints = cmpCapturable.GetCapturePoints();
return ret;
};
// AI event handlers:
// (These are passed directly as events to the AI scripts, rather than updating
// our proxy representation.)