1
0
forked from 0ad/0ad

Use correct distance for determining nearest dropsite

Use the distance to the nearest point on the dropsite's obstruction
rather than the center of the dropsite.

Differential Revision: https://code.wildfiregames.com/D1160
Reviewed by: wraitii
Comments by: bb, elexis
Fixes: #4592

This was SVN commit r20950.
This commit is contained in:
temple 2018-01-21 21:21:21 +00:00
parent 70290e8a22
commit dde855f7d5
4 changed files with 65 additions and 19 deletions

View File

@ -4146,32 +4146,55 @@ UnitAI.prototype.FindNearbyResource = function(filter, target)
*/
UnitAI.prototype.FindNearestDropsite = function(genericType)
{
var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
let cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
if (!cmpOwnership || cmpOwnership.GetOwner() == -1)
return undefined;
// Find dropsites owned by this unit's player or allied ones if allowed
var owner = cmpOwnership.GetOwner();
var players = [owner];
var cmpPlayer = QueryOwnerInterface(this.entity);
if (cmpPlayer && cmpPlayer.HasSharedDropsites())
players = cmpPlayer.GetMutualAllies();
let cmpPosition = Engine.QueryInterface(this.entity, IID_Position)
if (!cmpPosition)
return undefined;
var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
var nearby = cmpRangeManager.ExecuteQuery(this.entity, 0, -1, players, IID_ResourceDropsite);
let pos = cmpPosition.GetPosition2D();
let bestDropsite;
let bestDist = Infinity;
// Maximum distance a point on an obstruction can be from the center of the obstruction.
let maxDifference = 40;
// Ships are unable to reach land dropsites and shouldn't attempt to do so.
var excludeLand = Engine.QueryInterface(this.entity, IID_Identity).HasClass("Ship");
if (excludeLand)
nearby = nearby.filter(e => Engine.QueryInterface(e, IID_Identity).HasClass("Naval"));
// Find dropsites owned by this unit's player or allied ones if allowed.
let owner = cmpOwnership.GetOwner();
let cmpPlayer = QueryOwnerInterface(this.entity);
let players = cmpPlayer && cmpPlayer.HasSharedDropsites() ? cmpPlayer.GetMutualAllies() : [owner];
let nearbyDropsites = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager).ExecuteQuery(this.entity, 0, -1, players, IID_ResourceDropsite);
return nearby.find(ent => {
let cmpResourceDropsite = Engine.QueryInterface(ent, IID_ResourceDropsite);
let isShip = Engine.QueryInterface(this.entity, IID_Identity).HasClass("Ship");
let cmpObstructionManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_ObstructionManager);
for (let dropsite of nearbyDropsites)
{
// Ships are unable to reach land dropsites and shouldn't attempt to do so.
if (isShip && !Engine.QueryInterface(dropsite, IID_Identity).HasClass("Naval"))
continue;
let cmpResourceDropsite = Engine.QueryInterface(dropsite, IID_ResourceDropsite);
if (!cmpResourceDropsite.AcceptsType(genericType))
return false;
let cmpOwnership = Engine.QueryInterface(ent, IID_Ownership);
return cmpOwnership.GetOwner() == owner || cmpResourceDropsite.IsShared();
});
continue;
if (Engine.QueryInterface(dropsite, IID_Ownership).GetOwner() != owner && !cmpResourceDropsite.IsShared())
continue;
// The range manager sorts entities by the distance to their center,
// but we want the distance to the point where resources will be dropped off.
let dist = cmpObstructionManager.DistanceToPoint(dropsite, pos.x, pos.y);
if (dist == -1)
continue;
if (dist < bestDist)
{
bestDropsite = dropsite;
bestDist = dist;
}
else if (dist > bestDist + maxDifference)
break;
}
return bestDropsite;
};
/**

View File

@ -21,6 +21,7 @@
#include "ICmpObstructionManager.h"
#include "ICmpTerrain.h"
#include "ICmpPosition.h"
#include "simulation2/MessageTypes.h"
#include "simulation2/helpers/Geometry.h"
@ -464,6 +465,8 @@ public:
}
}
virtual fixed DistanceToPoint(entity_id_t ent, entity_pos_t px, entity_pos_t pz) const;
virtual bool TestLine(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1, entity_pos_t r, bool relaxClearanceForUnits = false) const;
virtual bool TestStaticShape(const IObstructionTestFilter& filter, entity_pos_t x, entity_pos_t z, entity_pos_t a, entity_pos_t w, entity_pos_t h, std::vector<entity_id_t>* out) const;
virtual bool TestUnitShape(const IObstructionTestFilter& filter, entity_pos_t x, entity_pos_t z, entity_pos_t r, std::vector<entity_id_t>* out) const;
@ -653,6 +656,20 @@ private:
REGISTER_COMPONENT_TYPE(ObstructionManager)
fixed CCmpObstructionManager::DistanceToPoint(entity_id_t ent, entity_pos_t px, entity_pos_t pz) const
{
CmpPtr<ICmpPosition> cmpPosition(GetSimContext(), ent);
if (!cmpPosition || !cmpPosition->IsInWorld())
return fixed::FromInt(-1);
ObstructionSquare s;
CmpPtr<ICmpObstruction> cmpObstruction(GetSimContext(), ent);
if (!cmpObstruction || !cmpObstruction->GetObstructionSquare(s))
return (CFixedVector2D(px, pz) - cmpPosition->GetPosition2D()).Length();
return Geometry::DistanceToSquare(CFixedVector2D(px - s.x, pz - s.z), s.u, s.v, CFixedVector2D(s.hw, s.hh));
}
bool CCmpObstructionManager::TestLine(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1, entity_pos_t r, bool relaxClearanceForUnits) const
{
PROFILE("TestLine");

View File

@ -23,5 +23,6 @@
BEGIN_INTERFACE_WRAPPER(ObstructionManager)
DEFINE_INTERFACE_METHOD_1("SetPassabilityCircular", void, ICmpObstructionManager, SetPassabilityCircular, bool)
DEFINE_INTERFACE_METHOD_CONST_3("DistanceToPoint", fixed, ICmpObstructionManager, DistanceToPoint, entity_id_t, entity_pos_t, entity_pos_t)
DEFINE_INTERFACE_METHOD_1("SetDebugOverlay", void, ICmpObstructionManager, SetDebugOverlay, bool)
END_INTERFACE_WRAPPER(ObstructionManager)

View File

@ -158,6 +158,11 @@ public:
*/
virtual void RemoveShape(tag_t tag) = 0;
/**
* Returns the distance from the obstruction to the point (px, pz), or -1 if the entity is out of the world.
*/
virtual fixed DistanceToPoint(entity_id_t ent, entity_pos_t px, entity_pos_t pz) const = 0;
/**
* Collision test a flat-ended thick line against the current set of shapes.
* The line caps extend by @p r beyond the end points.