From 08340ca18aeeb7744e80d0da19b82c400f0a006d Mon Sep 17 00:00:00 2001 From: phosit Date: Fri, 29 Aug 2025 21:39:23 +0200 Subject: [PATCH] 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. --- .../simulation/components/AIInterface.js | 2 +- .../public/simulation/components/AIProxy.js | 221 +++++++++--------- 2 files changed, 113 insertions(+), 110 deletions(-) diff --git a/binaries/data/mods/public/simulation/components/AIInterface.js b/binaries/data/mods/public/simulation/components/AIInterface.js index a9537e9c7f..8c04d81138 100644 --- a/binaries/data/mods/public/simulation/components/AIInterface.js +++ b/binaries/data/mods/public/simulation/components/AIInterface.js @@ -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(); diff --git a/binaries/data/mods/public/simulation/components/AIProxy.js b/binaries/data/mods/public/simulation/components/AIProxy.js index 89df8d441c..260989a29b 100644 --- a/binaries/data/mods/public/simulation/components/AIProxy.js +++ b/binaries/data/mods/public/simulation/components/AIProxy.js @@ -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.)