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:
parent
70290e8a22
commit
dde855f7d5
@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -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");
|
||||
|
@ -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)
|
||||
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user