Cleanup of GetEntityState

Reviewed By: elexis
Trac Tickets: #4322

Differential Revision: https://code.wildfiregames.com/D1223
This was SVN commit r20875.
This commit is contained in:
mimo 2018-01-15 21:27:30 +00:00
parent 36400458bf
commit 30f0e80dae
7 changed files with 152 additions and 213 deletions

View file

@ -60,7 +60,7 @@
</object>
<object hotkey="session.kill">
<action on="Press">performCommand(g_Selection.toList().map(ent => GetExtendedEntityState(ent)), "delete");</action>
<action on="Press">performCommand(g_Selection.toList().map(ent => GetEntityState(ent)), "delete");</action>
</object>
<object hotkey="session.unload">

View file

@ -463,7 +463,7 @@ function updateSelectionDetails()
for (let sel of g_Selection.toList())
{
let entState = GetExtendedEntityState(sel);
let entState = GetEntityState(sel);
if (!entState)
continue;
entStates.push(entState);

View file

@ -257,7 +257,7 @@ function performAllyCommand(entity, commandName)
if (!entity)
return;
let entState = GetExtendedEntityState(entity);
let entState = GetEntityState(entity);
let playerState = GetSimState().players[Engine.GetPlayerID()];
if (!playerState.isMutualAlly[entState.player] || g_IsObserver)
return;
@ -381,7 +381,7 @@ function unloadSelection()
let ents = [];
for (let ent in g_Selection.selected)
{
let state = GetExtendedEntityState(+ent);
let state = GetEntityState(+ent);
if (!state || !state.turretParent)
continue;
if (!parent)

View file

@ -192,33 +192,20 @@ function GetSimState()
return g_SimState;
}
function GetMultipleEntityStates(ents)
{
if (!ents.length)
return null;
let entityStates = Engine.GuiInterfaceCall("GetMultipleEntityStates", ents);
for (let item of entityStates)
g_EntityStates[item.entId] = deepfreeze(item.state);
return entityStates;
}
function GetEntityState(entId)
{
if (!g_EntityStates[entId])
{
g_EntityStates[entId] = Engine.GuiInterfaceCall("GetEntityState", entId);
// Freeze all existing properties, but allow GetExtendedEntityState to extend the object
if (g_EntityStates[entId])
for (let name of Object.getOwnPropertyNames(g_EntityStates[entId]))
if (typeof prop == 'object' && prop !== null)
deepfreeze(g_EntityStates[entId][name]);
}
return g_EntityStates[entId];
}
function GetExtendedEntityState(entId)
{
let entState = GetEntityState(entId);
if (entState && !entState.extended)
{
let extension = Engine.GuiInterfaceCall("GetExtendedEntityState", entId);
for (let prop in extension)
entState[prop] = extension[prop];
entState.extended = true;
g_EntityStates[entId] = deepfreeze(entState);
}
g_EntityStates[entId] = deepfreeze(Engine.GuiInterfaceCall("GetEntityState", entId));
return g_EntityStates[entId];
}
@ -744,6 +731,8 @@ function onTick()
if (g_Selection.dirty)
{
g_Selection.dirty = false;
// When selection changed, get the entityStates of new entities
GetMultipleEntityStates(g_Selection.toList().filter(entId => !g_EntityStates[entId]));
updateGUIObjects();
@ -798,6 +787,8 @@ function onSimulationUpdate()
if (!GetSimState())
return;
GetMultipleEntityStates(g_Selection.toList());
updateCinemaPath();
handleNotifications();
updateGUIObjects();
@ -960,7 +951,7 @@ function updatePanelEntities()
for (let ent of panelEnts)
{
let panelEntState = GetExtendedEntityState(ent);
let panelEntState = GetEntityState(ent);
let template = GetTemplateData(panelEntState.template);
let panelEnt = g_PanelEntities.find(pEnt => ent == pEnt.ent);
@ -1107,7 +1098,7 @@ function updateDebug()
let selection = g_Selection.toList();
if (selection.length)
{
let entState = GetExtendedEntityState(selection[0]);
let entState = GetEntityState(selection[0]);
if (entState)
{
let template = GetTemplateData(entState.template);

View file

@ -1520,12 +1520,12 @@ function getActionInfo(action, target, selection)
// Look at the first targeted entity
// (TODO: maybe we eventually want to look at more, and be more context-sensitive?
// e.g. prefer to attack an enemy unit, even if some friendly units are closer to the mouse)
let targetState = GetExtendedEntityState(target);
let targetState = GetEntityState(target);
// Check if any entities in the selection can do some of the available actions with target
for (let entityID of selection)
{
let entState = GetExtendedEntityState(entityID);
let entState = GetEntityState(entityID);
if (!entState)
continue;

View file

@ -194,8 +194,8 @@ GuiInterface.prototype.GetRenamedEntities = function(player)
{
if (this.miragedEntities[player])
return this.renamedEntities.concat(this.miragedEntities[player]);
else
return this.renamedEntities;
return this.renamedEntities;
};
GuiInterface.prototype.ClearRenamedEntities = function()
@ -229,25 +229,42 @@ GuiInterface.prototype.GetEntityState = function(player, ent)
"template": template,
"alertRaiser": null,
"armour": null,
"attack": null,
"builder": null,
"buildingAI": null,
"buildRate": null,
"buildTime": null,
"canGarrison": null,
"deathDamage": null,
"heal": null,
"identity": null,
"isBarterMarket": null,
"fogging": null,
"foundation": null,
"garrisonHolder": null,
"gate": null,
"guard": null,
"loot": null,
"market": null,
"mirage": null,
"pack": null,
"promotion": null,
"upgrade" : null,
"player": -1,
"position": null,
"production": null,
"rallyPoint": null,
"repairRate": null,
"resourceCarrying": null,
"resourceDropsite": null,
"resourceGatherRates": null,
"resourceSupply": null,
"resourceTrickle": null,
"rotation": null,
"speed": null,
"trader": null,
"turretParent":null,
"unitAI": null,
"visibility": null,
};
@ -338,14 +355,21 @@ GuiInterface.prototype.GetEntityState = function(player, ent)
let cmpFoundation = QueryMiragedInterface(ent, IID_Foundation);
if (cmpFoundation)
{
ret.foundation = {
"progress": cmpFoundation.GetBuildPercentage(),
"numBuilders": cmpFoundation.GetNumBuilders()
};
ret.buildRate = cmpFoundation.GetBuildRate();
ret.buildTime = cmpFoundation.GetBuildTime();
}
let cmpRepairable = QueryMiragedInterface(ent, IID_Repairable);
if (cmpRepairable)
{
ret.repairable = { "numBuilders": cmpRepairable.GetNumBuilders() };
ret.repairRate = cmpRepairable.GetRepairRate();
}
let cmpOwnership = Engine.QueryInterface(ent, IID_Ownership);
if (cmpOwnership)
@ -388,7 +412,10 @@ GuiInterface.prototype.GetEntityState = function(player, ent)
let cmpResourceGatherer = Engine.QueryInterface(ent, IID_ResourceGatherer);
if (cmpResourceGatherer)
{
ret.resourceCarrying = cmpResourceGatherer.GetCarryingStatus();
ret.resourceGatherRates = cmpResourceGatherer.GetGatherRates();
}
let cmpGate = Engine.QueryInterface(ent, IID_Gate);
if (cmpGate)
@ -407,37 +434,6 @@ GuiInterface.prototype.GetEntityState = function(player, ent)
let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
ret.visibility = cmpRangeManager.GetLosVisibility(ent, player);
return ret;
};
/**
* Get additionnal entity info, rarely used in the gui
*/
GuiInterface.prototype.GetExtendedEntityState = function(player, ent)
{
let ret = {
"armour": null,
"attack": null,
"buildingAI": null,
"deathDamage": null,
"heal": null,
"isBarterMarket": null,
"loot": null,
"obstruction": null,
"turretParent":null,
"promotion": null,
"repairRate": null,
"buildRate": null,
"buildTime": null,
"resourceDropsite": null,
"resourceGatherRates": null,
"resourceSupply": null,
"resourceTrickle": null,
"speed": null,
};
let cmpIdentity = Engine.QueryInterface(ent, IID_Identity);
let cmpAttack = Engine.QueryInterface(ent, IID_Attack);
if (cmpAttack)
{
@ -468,10 +464,6 @@ GuiInterface.prototype.GetExtendedEntityState = function(player, ent)
ret.attack[type].elevationBonus = range.elevationBonus;
let cmpPosition = Engine.QueryInterface(ent, IID_Position);
let cmpUnitAI = Engine.QueryInterface(ent, IID_UnitAI);
let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
if (cmpUnitAI && cmpPosition && cmpPosition.IsInWorld())
{
// For units, take the range in front of it, no spread. So angle = 0
@ -512,28 +504,9 @@ GuiInterface.prototype.GetExtendedEntityState = function(player, ent)
if (cmpDeathDamage)
ret.deathDamage = cmpDeathDamage.GetDeathDamageStrengths();
let cmpObstruction = Engine.QueryInterface(ent, IID_Obstruction);
if (cmpObstruction)
ret.obstruction = {
"controlGroup": cmpObstruction.GetControlGroup(),
"controlGroup2": cmpObstruction.GetControlGroup2(),
};
let cmpPosition = Engine.QueryInterface(ent, IID_Position);
if (cmpPosition && cmpPosition.GetTurretParent() != INVALID_ENTITY)
ret.turretParent = cmpPosition.GetTurretParent();
let cmpRepairable = Engine.QueryInterface(ent, IID_Repairable);
if (cmpRepairable)
ret.repairRate = cmpRepairable.GetRepairRate();
let cmpFoundation = Engine.QueryInterface(ent, IID_Foundation);
if (cmpFoundation)
{
ret.buildRate = cmpFoundation.GetBuildRate();
ret.buildTime = cmpFoundation.GetBuildTime();
}
let cmpResourceSupply = QueryMiragedInterface(ent, IID_ResourceSupply);
if (cmpResourceSupply)
ret.resourceSupply = {
@ -546,10 +519,6 @@ GuiInterface.prototype.GetExtendedEntityState = function(player, ent)
"numGatherers": cmpResourceSupply.GetNumGatherers()
};
let cmpResourceGatherer = Engine.QueryInterface(ent, IID_ResourceGatherer);
if (cmpResourceGatherer)
ret.resourceGatherRates = cmpResourceGatherer.GetGatherRates();
let cmpResourceDropsite = Engine.QueryInterface(ent, IID_ResourceDropsite);
if (cmpResourceDropsite)
ret.resourceDropsite = {
@ -581,27 +550,17 @@ GuiInterface.prototype.GetExtendedEntityState = function(player, ent)
let cmpLoot = Engine.QueryInterface(ent, IID_Loot);
if (cmpLoot)
{
let resources = cmpLoot.GetResources();
ret.loot = {
"xp": cmpLoot.GetXp()
};
for (let res of Resources.GetCodes())
ret.loot[res] = resources[res];
ret.loot = cmpLoot.GetResources();
ret.loot.xp = cmpLoot.GetXp();
}
let cmpResourceTrickle = Engine.QueryInterface(ent, IID_ResourceTrickle);
if (cmpResourceTrickle)
{
ret.resourceTrickle = {
"interval": cmpResourceTrickle.GetTimer(),
"rates": {}
"rates": cmpResourceTrickle.GetRates()
};
let rates = cmpResourceTrickle.GetRates();
for (let res in rates)
ret.resourceTrickle.rates[res] = rates[res];
}
let cmpUnitMotion = Engine.QueryInterface(ent, IID_UnitMotion);
if (cmpUnitMotion)
ret.speed = {
@ -612,6 +571,11 @@ GuiInterface.prototype.GetExtendedEntityState = function(player, ent)
return ret;
};
GuiInterface.prototype.GetMultipleEntityStates = function(player, ents)
{
return ents.map(ent => ({ "entId": ent, "state": this.GetEntityState(player, ent) }));
};
GuiInterface.prototype.GetAverageRangeForBuildings = function(player, cmd)
{
let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
@ -630,10 +594,10 @@ GuiInterface.prototype.GetAverageRangeForBuildings = function(player, cmd)
return cmpRangeManager.GetElevationAdaptedRange(pos, rot, range, elevationBonus, 2*Math.PI);
};
GuiInterface.prototype.GetTemplateData = function(player, name)
GuiInterface.prototype.GetTemplateData = function(player, templateName)
{
let cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager);
let template = cmpTemplateManager.GetTemplate(name);
let template = cmpTemplateManager.GetTemplate(templateName);
if (!template)
return null;
@ -1222,42 +1186,40 @@ GuiInterface.prototype.SetWallPlacementPreview = function(player, cmd)
return false;
}
else
{
// Move all existing cached entities outside of the world and reset their use count
for (let tpl in this.placementWallEntities)
{
for (let ent of this.placementWallEntities[tpl].entities)
{
let pos = Engine.QueryInterface(ent, IID_Position);
if (pos)
pos.MoveOutOfWorld();
}
this.placementWallEntities[tpl].numUsed = 0;
// Move all existing cached entities outside of the world and reset their use count
for (let tpl in this.placementWallEntities)
{
for (let ent of this.placementWallEntities[tpl].entities)
{
let pos = Engine.QueryInterface(ent, IID_Position);
if (pos)
pos.MoveOutOfWorld();
}
// Create cache entries for templates we haven't seen before
for (let type in wallSet.templates)
this.placementWallEntities[tpl].numUsed = 0;
}
// Create cache entries for templates we haven't seen before
for (let type in wallSet.templates)
{
if (type == "curves")
continue;
let tpl = wallSet.templates[type];
if (!(tpl in this.placementWallEntities))
{
if (type == "curves")
continue;
this.placementWallEntities[tpl] = {
"numUsed": 0,
"entities": [],
"templateData": this.GetTemplateData(player, tpl),
};
let tpl = wallSet.templates[type];
if (!(tpl in this.placementWallEntities))
// ensure that the loaded template data contains a wallPiece component
if (!this.placementWallEntities[tpl].templateData.wallPiece)
{
this.placementWallEntities[tpl] = {
"numUsed": 0,
"entities": [],
"templateData": this.GetTemplateData(player, tpl),
};
// ensure that the loaded template data contains a wallPiece component
if (!this.placementWallEntities[tpl].templateData.wallPiece)
{
error("[SetWallPlacementPreview] No WallPiece component found for wall set template '" + tpl + "'");
return false;
}
error("[SetWallPlacementPreview] No WallPiece component found for wall set template '" + tpl + "'");
return false;
}
}
}
@ -1365,7 +1327,7 @@ GuiInterface.prototype.SetWallPlacementPreview = function(player, cmd)
"template": wallSet.templates.tower,
"pos": start.pos,
"angle": cmpPosition.GetRotation().y,
"controlGroups": [(startEntObstruction ? startEntObstruction.GetControlGroup() : undefined)],
"controlGroups": [startEntObstruction ? startEntObstruction.GetControlGroup() : undefined],
"excludeFromResult": true, // preview only, must not appear in the result
});
}
@ -1390,7 +1352,7 @@ GuiInterface.prototype.SetWallPlacementPreview = function(player, cmd)
previewEntities.unshift({
"template": wallSet.templates.tower,
"pos": start.pos,
"angle": (previewEntities.length > 0 ? previewEntities[0].angle : this.placementWallLastAngle)
"angle": previewEntities.length > 0 ? previewEntities[0].angle : this.placementWallLastAngle
});
}
@ -1408,7 +1370,7 @@ GuiInterface.prototype.SetWallPlacementPreview = function(player, cmd)
// '.controlGroup' property. Note that this array can only ever have 0, 1 or 2 elements (checked at a later time).
if (previewEntities.length > 0 && endEntObstruction)
{
previewEntities[previewEntities.length-1].controlGroups = (previewEntities[previewEntities.length-1].controlGroups || []);
previewEntities[previewEntities.length-1].controlGroups = previewEntities[previewEntities.length-1].controlGroups || [];
previewEntities[previewEntities.length-1].controlGroups.push(endEntObstruction.GetControlGroup());
}
@ -1422,7 +1384,7 @@ GuiInterface.prototype.SetWallPlacementPreview = function(player, cmd)
"template": wallSet.templates.tower,
"pos": end.pos,
"angle": cmpPosition.GetRotation().y,
"controlGroups": [(endEntObstruction ? endEntObstruction.GetControlGroup() : undefined)],
"controlGroups": [endEntObstruction ? endEntObstruction.GetControlGroup() : undefined],
"excludeFromResult": true
});
}
@ -1431,7 +1393,7 @@ GuiInterface.prototype.SetWallPlacementPreview = function(player, cmd)
previewEntities.push({
"template": wallSet.templates.tower,
"pos": end.pos,
"angle": (previewEntities.length > 0 ? previewEntities[previewEntities.length-1].angle : this.placementWallLastAngle)
"angle": previewEntities.length > 0 ? previewEntities[previewEntities.length-1].angle : this.placementWallLastAngle
});
}
@ -1553,7 +1515,7 @@ GuiInterface.prototype.SetWallPlacementPreview = function(player, cmd)
// Check whether it's in a visible or fogged region
// TODO: should definitely reuse SetBuildingPlacementPreview, this is just straight up copy/pasta
let visible = (cmpRangeManager.GetLosVisibility(ent, player) != "hidden");
let visible = cmpRangeManager.GetLosVisibility(ent, player) != "hidden";
if (visible)
{
let cmpBuildRestrictions = Engine.QueryInterface(ent, IID_BuildRestrictions);
@ -1564,7 +1526,7 @@ GuiInterface.prototype.SetWallPlacementPreview = function(player, cmd)
}
// TODO: Handle results of CheckPlacement
validPlacement = (cmpBuildRestrictions && cmpBuildRestrictions.CheckPlacement().success);
validPlacement = cmpBuildRestrictions && cmpBuildRestrictions.CheckPlacement().success;
// If a wall piece has two control groups, it's likely a segment that spans
// between two existing towers. To avoid placing a duplicate wall segment,
@ -1972,7 +1934,7 @@ let exposedFunctions = {
"GetRenamedEntities": 1,
"ClearRenamedEntities": 1,
"GetEntityState": 1,
"GetExtendedEntityState": 1,
"GetMultipleEntityStates": 1,
"GetAverageRangeForBuildings": 1,
"GetTemplateData": 1,
"IsTechnologyResearched": 1,
@ -2027,8 +1989,8 @@ GuiInterface.prototype.ScriptCall = function(player, name, args)
{
if (exposedFunctions[name])
return this[name](player, args);
else
throw new Error("Invalid GuiInterface Call name \""+name+"\"");
throw new Error("Invalid GuiInterface Call name \""+name+"\"");
};
Engine.RegisterSystemComponentType(IID_GuiInterface, "GuiInterface", GuiInterface);

View file

@ -561,79 +561,65 @@ AddMock(10, IID_Position, {
AddMock(10, IID_ResourceTrickle, {
"GetTimer": () => 1250,
"GetRates": () => ({
"food": 2,
"wood": 3,
"stone": 5,
"metal": 9
})
"GetRates": () => ({ "food": 2, "wood": 3, "stone": 5, "metal": 9 })
});
// Note: property order matters when using TS_ASSERT_UNEVAL_EQUALS,
// because uneval preserves property order. So make sure this object
// matches the ordering in GuiInterface.
TS_ASSERT_UNEVAL_EQUALS(cmp.GetEntityState(-1, 10), {
id: 10,
template: "example",
alertRaiser: null,
builder: true,
canGarrison: false,
identity: {
rank: "foo",
classes: ["class1", "class2"],
visibleClasses: ["class3", "class4"],
selectionGroupName: "Selection Group Name",
canDelete: true
"id": 10,
"template": "example",
"alertRaiser": null,
"armour": null,
"attack": null,
"builder": true,
"buildingAI": null,
"buildRate": null,
"buildTime": null,
"canGarrison": false,
"deathDamage": null,
"heal": null,
"identity": {
"rank": "foo",
"classes": ["class1", "class2"],
"visibleClasses": ["class3", "class4"],
"selectionGroupName": "Selection Group Name",
"canDelete": true
},
fogging: null,
foundation: null,
garrisonHolder: null,
gate: null,
guard: null,
market: null,
mirage: null,
pack: null,
upgrade: null,
player: -1,
position: {x:1, y:2, z:3},
production: null,
rallyPoint: null,
resourceCarrying: null,
rotation: {x:4, y:5, z:6},
trader: null,
unitAI: null,
visibility: "visible",
hitpoints: 50,
maxHitpoints: 60,
needsRepair: false,
needsHeal: true
});
TS_ASSERT_UNEVAL_EQUALS(cmp.GetExtendedEntityState(-1, 10), {
armour: null,
attack: null,
buildingAI: null,
deathDamage:null,
heal: null,
isBarterMarket: true,
loot: null,
obstruction: null,
turretParent: null,
promotion: null,
repairRate: null,
buildRate: null,
buildTime: null,
resourceDropsite: null,
resourceGatherRates: null,
resourceSupply: null,
resourceTrickle: {
"isBarterMarket": true,
"fogging": null,
"foundation": null,
"garrisonHolder": null,
"gate": null,
"guard": null,
"loot": null,
"market": null,
"mirage": null,
"pack": null,
"promotion": null,
"upgrade" : null,
"player": -1,
"position": {x:1, y:2, z:3},
"production": null,
"rallyPoint": null,
"repairRate": null,
"resourceCarrying": null,
"resourceDropsite": null,
"resourceGatherRates": null,
"resourceSupply": null,
"resourceTrickle": {
"interval": 1250,
"rates": {
"food": 2,
"wood": 3,
"stone": 5,
"metal": 9
}
"rates": { "food": 2, "wood": 3, "stone": 5, "metal": 9 }
},
speed: null
"rotation": {x:4, y:5, z:6},
"speed": null,
"trader": null,
"turretParent":null,
"unitAI": null,
"visibility": "visible",
"hitpoints": 50,
"maxHitpoints": 60,
"needsRepair": false,
"needsHeal": true
});