Index: binaries/data/mods/public/simulation/components/Foundation.js =================================================================== --- binaries/data/mods/public/simulation/components/Foundation.js +++ binaries/data/mods/public/simulation/components/Foundation.js @@ -196,7 +196,9 @@ var cmpObstruction = Engine.QueryInterface(this.entity, IID_Obstruction); if (cmpObstruction && cmpObstruction.GetBlockMovementFlag()) { - var collisions = cmpObstruction.GetUnitCollisions(); + // Remove all obstructions at the new entity, especially animal corpses + let collisions = cmpObstruction.GetEntityCollisions(); + if (collisions.length) { var cmpFoundationOwnership = Engine.QueryInterface(this.entity, IID_Ownership); Index: binaries/data/mods/public/simulation/components/tests/test_Foundation.js =================================================================== --- binaries/data/mods/public/simulation/components/tests/test_Foundation.js +++ binaries/data/mods/public/simulation/components/tests/test_Foundation.js @@ -62,7 +62,7 @@ AddMock(foundationEnt, IID_Obstruction, { "GetBlockMovementFlag": () => true, - "GetUnitCollisions": () => [], + "GetEntityCollisions": () => [], "SetDisableBlockMovementPathfinding": () => {}, }); Index: binaries/data/mods/public/simulation/helpers/Transform.js =================================================================== --- binaries/data/mods/public/simulation/helpers/Transform.js +++ binaries/data/mods/public/simulation/helpers/Transform.js @@ -190,8 +190,7 @@ var cmpNewObstruction = Engine.QueryInterface(previewEntity, IID_Obstruction); if (cmpNewObstruction && cmpNewObstruction.GetBlockMovementFlag()) { - // Check for units - var collisions = cmpNewObstruction.GetUnitCollisions(); + let collisions = cmpNewObstruction.GetEntityCollisions(); if (collisions.length) return DeleteEntityAndReturn(previewEntity, cmpPosition, pos, angle, cmpNewPosition, true); } Index: source/simulation2/components/CCmpObstruction.cpp =================================================================== --- source/simulation2/components/CCmpObstruction.cpp +++ source/simulation2/components/CCmpObstruction.cpp @@ -624,7 +624,7 @@ return ret; // error // There are four 'block' flags: construction, foundation, movement, - // and pathfinding. Structures have all of these flags, while units + // and pathfinding. Structures have all of these flags, while most units // block only movement and construction. flags_t flags = ICmpObstructionManager::FLAG_BLOCK_CONSTRUCTION; @@ -642,6 +642,27 @@ return ret; } + virtual std::vector GetEntityCollisions() const + { + std::vector ret; + + CmpPtr cmpObstructionManager(GetSystemEntity()); + if (!cmpObstructionManager) + return ret; // error + + // Ignore collisions within the same control group. + SkipControlGroupsRequireFlagObstructionFilter filter(true, m_ControlGroup, m_ControlGroup2, 0); + + ICmpObstructionManager::ObstructionSquare square; + if (!GetObstructionSquare(square)) + return ret; // error + + cmpObstructionManager->GetUnitsOnObstruction(square, ret, filter, false); + cmpObstructionManager->GetStaticObstructionsOnObstruction(square, ret, filter); + + return ret; + } + virtual void SetMovingFlag(bool enabled) { m_Moving = enabled; Index: source/simulation2/components/CCmpObstructionManager.cpp =================================================================== --- source/simulation2/components/CCmpObstructionManager.cpp +++ source/simulation2/components/CCmpObstructionManager.cpp @@ -476,6 +476,7 @@ virtual void GetUnitObstructionsInRange(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1, std::vector& squares) const; virtual void GetStaticObstructionsInRange(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1, std::vector& squares) const; virtual void GetUnitsOnObstruction(const ObstructionSquare& square, std::vector& out, const IObstructionTestFilter& filter, bool strict = false) const; + virtual void GetStaticObstructionsOnObstruction(const ObstructionSquare& square, std::vector& out, const IObstructionTestFilter& filter) const; virtual void SetPassabilityCircular(bool enabled) { @@ -890,7 +891,7 @@ { case PathfinderPassability::PATHFINDING: { - auto it = pathfindingMasks.find(passability.m_Clearance); + std::map::iterator it = pathfindingMasks.find(passability.m_Clearance); if (it == pathfindingMasks.end()) pathfindingMasks[passability.m_Clearance] = passability.m_Mask; else @@ -979,7 +980,7 @@ m_UnitSubdivision.GetInRange(unitShapes, CFixedVector2D(x0, z0), CFixedVector2D(x1, z1)); for (entity_id_t& unitShape : unitShapes) { - auto it = m_UnitShapes.find(unitShape); + std::map::const_iterator it = m_UnitShapes.find(unitShape); ENSURE(it != m_UnitShapes.end()); if (!filter.TestShape(UNIT_INDEX_TO_TAG(it->first), it->second.flags, it->second.group, INVALID_ENTITY)) @@ -1007,7 +1008,7 @@ m_StaticSubdivision.GetInRange(staticShapes, CFixedVector2D(x0, z0), CFixedVector2D(x1, z1)); for (entity_id_t& staticShape : staticShapes) { - auto it = m_StaticShapes.find(staticShape); + std::map::const_iterator it = m_StaticShapes.find(staticShape); ENSURE(it != m_StaticShapes.end()); if (!filter.TestShape(STATIC_INDEX_TO_TAG(it->first), it->second.flags, it->second.group, it->second.group2)) @@ -1030,7 +1031,7 @@ PROFILE("GetUnitsOnObstruction"); // In order to avoid getting units on impassable cells, we want to find all - // units s.t. the RasterizeRectWithClearance of the building's shape with the + // units subject to the RasterizeRectWithClearance of the building's shape with the // unit's clearance covers the navcell the unit is on. std::vector unitShapes; @@ -1044,7 +1045,7 @@ for (const u32& unitShape : unitShapes) { - auto it = m_UnitShapes.find(unitShape); + std::map::const_iterator it = m_UnitShapes.find(unitShape); ENSURE(it != m_UnitShapes.end()); const UnitShape& shape = it->second; @@ -1086,6 +1087,40 @@ } } +void CCmpObstructionManager::GetStaticObstructionsOnObstruction(const ObstructionSquare& square, std::vector& out, const IObstructionTestFilter& filter) const +{ + PROFILE("GetStaticObstructionsOnObstruction"); + + std::vector staticShapes; + CFixedVector2D center(square.x, square.z); + CFixedVector2D expandedBox = Geometry::GetHalfBoundingBox(square.u, square.v, CFixedVector2D(square.hw, square.hh)); + m_StaticSubdivision.GetInRange(staticShapes, center - expandedBox, center + expandedBox); + + for (const u32& staticShape : staticShapes) + { + std::map::const_iterator it = m_StaticShapes.find(staticShape); + ENSURE(it != m_StaticShapes.end()); + + const StaticShape& shape = it->second; + + if (!filter.TestShape(STATIC_INDEX_TO_TAG(staticShape), shape.flags, shape.group, shape.group2)) + continue; + + if (Geometry::TestSquareSquare( + center, + square.u, + square.v, + CFixedVector2D(square.hw, square.hh), + CFixedVector2D(shape.x, shape.z), + shape.u, + shape.v, + CFixedVector2D(shape.hw, shape.hh))) + { + out.push_back(shape.entity); + } + } +} + void CCmpObstructionManager::RenderSubmit(SceneCollector& collector) { if (!m_DebugOverlayEnabled) Index: source/simulation2/components/ICmpObstruction.h =================================================================== --- source/simulation2/components/ICmpObstruction.h +++ source/simulation2/components/ICmpObstruction.h @@ -89,12 +89,19 @@ virtual bool CheckDuplicateFoundation() const = 0; /** - * Returns a list of units that are colliding with this entity, + * Returns a list of units that are colliding with this entity. * @return vector of blocking units */ virtual std::vector GetUnitCollisions() const = 0; /** + * Returns a list of entities that are colliding with this entity (excluding self). + * This can be used to retrieve units with static obstructions, such as animal corpses. + * @return vector of blocking units + */ + virtual std::vector GetEntityCollisions() const = 0; + + /** * Detects collisions between foundation-blocking entities and * tries to fix them by setting control groups, if appropriate. */ Index: source/simulation2/components/ICmpObstruction.cpp =================================================================== --- source/simulation2/components/ICmpObstruction.cpp +++ source/simulation2/components/ICmpObstruction.cpp @@ -51,6 +51,7 @@ DEFINE_INTERFACE_METHOD_CONST_2("CheckFoundation", std::string, ICmpObstruction, CheckFoundation_wrapper, std::string, bool) DEFINE_INTERFACE_METHOD_CONST_0("CheckDuplicateFoundation", bool, ICmpObstruction, CheckDuplicateFoundation) DEFINE_INTERFACE_METHOD_CONST_0("GetUnitCollisions", std::vector, ICmpObstruction, GetUnitCollisions) +DEFINE_INTERFACE_METHOD_CONST_0("GetEntityCollisions", std::vector, ICmpObstruction, GetEntityCollisions) DEFINE_INTERFACE_METHOD_1("SetActive", void, ICmpObstruction, SetActive, bool) DEFINE_INTERFACE_METHOD_3("SetDisableBlockMovementPathfinding", void, ICmpObstruction, SetDisableBlockMovementPathfinding, bool, bool, int32_t) DEFINE_INTERFACE_METHOD_CONST_0("GetBlockMovementFlag", bool, ICmpObstruction, GetBlockMovementFlag) Index: source/simulation2/components/ICmpObstructionManager.h =================================================================== --- source/simulation2/components/ICmpObstructionManager.h +++ source/simulation2/components/ICmpObstructionManager.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 Wildfire Games. +/* Copyright (C) 2018 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -245,6 +245,7 @@ virtual void GetObstructionsInRange(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1, std::vector& squares) const = 0; virtual void GetStaticObstructionsInRange(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1, std::vector& squares) const = 0; virtual void GetUnitObstructionsInRange(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1, std::vector& squares) const = 0; + virtual void GetStaticObstructionsOnObstruction(const ObstructionSquare& square, std::vector& out, const IObstructionTestFilter& filter) const = 0; /** * Returns the entity IDs of all unit shapes that intersect the given