Ticket #3215: t3215_fix_observer_statusbars_v4.patch

File t3215_fix_observer_statusbars_v4.patch, 21.1 KB (added by elexis, 9 years ago)
  • binaries/data/mods/public/gui/session/input.js

     
    156156            return true;
    157157        }
    158158    }
    159159    else if (placementSupport.mode === "wall")
    160160    {
    161161        if (placementSupport.wallSet && placementSupport.position)
    162162        {
    163163            // Fetch an updated list of snapping candidate entities
    164             placementSupport.wallSnapEntities = Engine.PickSimilarFriendlyEntities(
     164            placementSupport.wallSnapEntities = Engine.PickSimilarPlayerEntities(
    165165                placementSupport.wallSet.templates.tower,
    166166                placementSupport.wallSnapEntitiesIncludeOffscreen,
    167167                true, // require exact template match
    168168                true  // include foundations
    169169            );
    170170           
    171171            return Engine.GuiInterfaceCall("SetWallPlacementPreview", {
    172172                "wallSet": placementSupport.wallSet,
     
    546546    {
    547547    case INPUT_BANDBOXING:
    548548        var bandbox = Engine.GetGUIObjectByName("bandbox");
    549549        switch (ev.type)
    550550        {
    551551        case "mousemotion":
    552552            var rect = updateBandbox(bandbox, ev, false);
    553553
    554             var ents = Engine.PickFriendlyEntitiesInRect(rect[0], rect[1], rect[2], rect[3], Engine.GetPlayerID());
     554            var ents = Engine.PickPlayerEntitiesInRect(rect[0], rect[1], rect[2], rect[3], Engine.GetPlayerID());
    555555            var preferredEntities = getPreferredEntities(ents);
    556556            g_Selection.setHighlightList(preferredEntities);
    557557
    558558            return false;
    559559
    560560        case "mousebuttonup":
    561561            if (ev.button == SDL_BUTTON_LEFT)
    562562            {
    563563                var rect = updateBandbox(bandbox, ev, true);
    564564
    565565                // Get list of entities limited to preferred entities
    566                 var ents = getPreferredEntities(Engine.PickFriendlyEntitiesInRect(rect[0], rect[1], rect[2], rect[3], Engine.GetPlayerID()));
     566                var ents = getPreferredEntities(Engine.PickPlayerEntitiesInRect(rect[0], rect[1], rect[2], rect[3], Engine.GetPlayerID()));
    567567
    568568                // Remove the bandbox hover highlighting
    569569                g_Selection.setHighlightList([]);
    570570
    571571                // Update the list of selected units
    572572                if (Engine.HotkeyIsPressed("selection.add"))
    573573                {
    574574                    g_Selection.addList(ents);
     
    10401040                    else
    10411041                    {
    10421042                        // Double click has already occurred, so this is a triple click.
    10431043                        // Select units matching exact template name (same rank)
    10441044                        templateToMatch = GetEntityState(selectedEntity).template;
    10451045                    }
    10461046
    10471047                    // TODO: Should we handle "control all units" here as well?
    1048                     ents = Engine.PickSimilarFriendlyEntities(templateToMatch, showOffscreen, matchRank, false);
     1048                    ents = Engine.PickSimilarPlayerEntities(templateToMatch, showOffscreen, matchRank, false);
    10491049                }
    10501050                else
    10511051                {
    10521052                    // It's single click right now but it may become double or triple click
    10531053                    doubleClicked = false;
    10541054                    doubleClickTimer = now.getTime();
    10551055                    prevClickedEntity = selectedEntity;
    10561056
  • binaries/data/mods/public/gui/session/session.js

     
    792792    for (var i = numButtons; i < 10; ++i)
    793793        Engine.GetGUIObjectByName("researchStartedButton[" + i + "]").hidden = true;
    794794}
    795795
    796796// Toggles the display of status bars for all of the player's entities.
    797797function recalculateStatusBarDisplay()
    798798{
    799799    if (g_ShowAllStatusBars)
    800         var entities = Engine.PickFriendlyEntitiesOnScreen(Engine.GetPlayerID());
     800        var entities = g_IsObserver ? Engine.PickNonGaiaEntitiesOnScreen() : Engine.PickPlayerEntitiesOnScreen(Engine.GetPlayerID());
    801801    else
    802802    {
    803803        var selected = g_Selection.toList();
    804804        for each (var ent in g_Selection.highlighted)
    805805            selected.push(ent);
    806806
    807807        // Remove selected entities from the 'all entities' array, to avoid disabling their status bars.
    808         var entities = Engine.GuiInterfaceCall("GetPlayerEntities").filter(
    809                 function(idx) { return (selected.indexOf(idx) == -1); }
    810         );
     808        var entities = Engine.GuiInterfaceCall(g_IsObserver ? "GetNonGaiaEntities" : "GetPlayerEntities").filter(idx => selected.indexOf(idx) == -1);
    811809    }
    812810
    813811    Engine.GuiInterfaceCall("SetStatusBars", { "entities": entities, "enabled": g_ShowAllStatusBars });
    814812}
    815 
    816813// Update the additional list of entities to be highlighted.
    817814function updateAdditionalHighlight()
    818815{
    819816    var entsAdd = [];    // list of entities units to be highlighted
    820817    var entsRemove = [];
    821818    var highlighted = g_Selection.toList();
    822819    for each (var ent in g_Selection.highlighted)
    823820        highlighted.push(ent);
  • binaries/data/mods/public/simulation/components/GuiInterface.js

     
    896896};
    897897
    898898GuiInterface.prototype.GetPlayerEntities = function(player)
    899899{
    900900    var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
    901901    return cmpRangeManager.GetEntitiesByPlayer(player);
    902902};
    903903
     904GuiInterface.prototype.GetNonGaiaEntities = function()
     905{
     906    var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
     907    return cmpRangeManager.GetNonGaiaEntities();
     908};
     909
    904910/**
    905911 * Displays the rally points of a given list of entities (carried in cmd.entities).
    906912 *
    907913 * The 'cmd' object may carry its own x/z coordinate pair indicating the location where the rally point should
    908914 * be rendered, in order to support instantaneously rendering a rally point marker at a specified location
    909915 * instead of incurring a delay while PostNetworkCommand processes the set-rallypoint command (see input.js).
    910916 * If cmd doesn't carry a custom location, then the position to render the marker at will be read from the
    911917 * RallyPoint component.
     
    18941900    "IsFormationSelected": 1,
    18951901    "GetFormationInfoFromTemplate": 1,
    18961902    "IsStanceSelected": 1,
    18971903
    18981904    "SetSelectionHighlight": 1,
    18991905    "GetAllBuildableEntities": 1,
    19001906    "SetStatusBars": 1,
    19011907    "GetPlayerEntities": 1,
     1908    "GetNonGaiaEntities": 1,
    19021909    "DisplayRallyPoint": 1,
    19031910    "SetBuildingPlacementPreview": 1,
    19041911    "SetWallPlacementPreview": 1,
    19051912    "GetFoundationSnapData": 1,
    19061913    "PlaySound": 1,
    19071914    "FindIdleUnits": 1,
    19081915    "GetTradingRouteGain": 1,
    19091916    "GetTradingDetails": 1,
  • source/gui/scripting/ScriptFunctions.cpp

     
    5656#include "ps/scripting/JSInterface_Console.h"
    5757#include "ps/scripting/JSInterface_Mod.h"
    5858#include "ps/scripting/JSInterface_VFS.h"
    5959#include "renderer/scripting/JSInterface_Renderer.h"
    6060#include "simulation2/Simulation2.h"
    6161#include "simulation2/components/ICmpAIManager.h"
    6262#include "simulation2/components/ICmpCommandQueue.h"
    6363#include "simulation2/components/ICmpGuiInterface.h"
     64#include "simulation2/components/ICmpPlayerManager.h"
    6465#include "simulation2/components/ICmpRangeManager.h"
    6566#include "simulation2/components/ICmpSelectable.h"
    6667#include "simulation2/components/ICmpTemplateManager.h"
    6768#include "simulation2/helpers/Selection.h"
    6869#include "soundmanager/SoundManager.h"
    6970#include "soundmanager/scripting/JSInterface_Sound.h"
    7071#include "tools/atlas/GameInterface/GameLoop.h"
    7172
     
    148149    cmpCommandQueue->PostNetworkCommand(cmd2);
    149150}
    150151
    151152entity_id_t PickEntityAtPoint(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), int x, int y)
    152153{
    153154    return EntitySelection::PickEntityAtPoint(*g_Game->GetSimulation2(), *g_Game->GetView()->GetCamera(), x, y, g_Game->GetPlayerID(), false);
    154155}
    155156
    156 std::vector<entity_id_t> PickFriendlyEntitiesInRect(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), int x0, int y0, int x1, int y1, int player)
     157std::vector<entity_id_t> PickPlayerEntitiesInRect(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), int x0, int y0, int x1, int y1, int player)
    157158{
    158159    return EntitySelection::PickEntitiesInRect(*g_Game->GetSimulation2(), *g_Game->GetView()->GetCamera(), x0, y0, x1, y1, player, false);
    159160}
    160161
    161 std::vector<entity_id_t> PickFriendlyEntitiesOnScreen(ScriptInterface::CxPrivate* pCxPrivate, int player)
     162std::vector<entity_id_t> PickPlayerEntitiesOnScreen(ScriptInterface::CxPrivate* pCxPrivate, int player)
    162163{
    163     return PickFriendlyEntitiesInRect(pCxPrivate, 0, 0, g_xres, g_yres, player);
     164    return PickPlayerEntitiesInRect(pCxPrivate, 0, 0, g_xres, g_yres, player);
    164165}
    165166
    166 std::vector<entity_id_t> PickSimilarFriendlyEntities(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), std::string templateName, bool includeOffScreen, bool matchRank, bool allowFoundations)
     167std::vector<entity_id_t> PickNonGaiaEntitiesOnScreen(ScriptInterface::CxPrivate* pCxPrivate)
     168{
     169    return PickPlayerEntitiesInRect(pCxPrivate, 0, 0, g_xres, g_yres, NON_GAIA_PLAYERS);
     170}
     171
     172std::vector<entity_id_t> PickSimilarPlayerEntities(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), CStr templateName, bool includeOffScreen, bool matchRank, bool allowFoundations)
    167173{
    168174    return EntitySelection::PickSimilarEntities(*g_Game->GetSimulation2(), *g_Game->GetView()->GetCamera(), templateName, g_Game->GetPlayerID(), includeOffScreen, matchRank, false, allowFoundations);
    169175}
    170176
    171177CFixedVector3D GetTerrainAtScreenPoint(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), int x, int y)
    172178{
    173179    CVector3D pos = g_Game->GetView()->GetCamera()->GetWorldCoordinates(x, y, true);
    174180    return CFixedVector3D(fixed::FromFloat(pos.X), fixed::FromFloat(pos.Y), fixed::FromFloat(pos.Z));
     
    939945    scriptInterface.RegisterFunction<JS::Value, CStr, &GetGUIObjectByName>("GetGUIObjectByName");
    940946
    941947    // Simulation<->GUI interface functions:
    942948    scriptInterface.RegisterFunction<JS::Value, std::wstring, JS::HandleValue, &GuiInterfaceCall>("GuiInterfaceCall");
    943949    scriptInterface.RegisterFunction<void, JS::HandleValue, &PostNetworkCommand>("PostNetworkCommand");
    944950
    945951    // Entity picking
    946952    scriptInterface.RegisterFunction<entity_id_t, int, int, &PickEntityAtPoint>("PickEntityAtPoint");
    947     scriptInterface.RegisterFunction<std::vector<entity_id_t>, int, int, int, int, int, &PickFriendlyEntitiesInRect>("PickFriendlyEntitiesInRect");
    948     scriptInterface.RegisterFunction<std::vector<entity_id_t>, int, &PickFriendlyEntitiesOnScreen>("PickFriendlyEntitiesOnScreen");
    949     scriptInterface.RegisterFunction<std::vector<entity_id_t>, std::string, bool, bool, bool, &PickSimilarFriendlyEntities>("PickSimilarFriendlyEntities");
     953    scriptInterface.RegisterFunction<std::vector<entity_id_t>, int, int, int, int, int, &PickPlayerEntitiesInRect>("PickPlayerEntitiesInRect");
     954    scriptInterface.RegisterFunction<std::vector<entity_id_t>, int, &PickPlayerEntitiesOnScreen>("PickPlayerEntitiesOnScreen");
     955    scriptInterface.RegisterFunction<std::vector<entity_id_t>, &PickNonGaiaEntitiesOnScreen>("PickNonGaiaEntitiesOnScreen");
     956    scriptInterface.RegisterFunction<std::vector<entity_id_t>, CStr, bool, bool, bool, &PickSimilarPlayerEntities>("PickSimilarPlayerEntities");
    950957    scriptInterface.RegisterFunction<CFixedVector3D, int, int, &GetTerrainAtScreenPoint>("GetTerrainAtScreenPoint");
    951958
    952959    // Network / game setup functions
    953960    scriptInterface.RegisterFunction<void, &StartNetworkGame>("StartNetworkGame");
    954961    scriptInterface.RegisterFunction<void, JS::HandleValue, int, &StartGame>("StartGame");
    955962    scriptInterface.RegisterFunction<void, &Script_EndGame>("EndGame");
    956963    scriptInterface.RegisterFunction<void, std::wstring, &StartNetworkHost>("StartNetworkHost");
    957964    scriptInterface.RegisterFunction<void, std::wstring, std::string, &StartNetworkJoin>("StartNetworkJoin");
  • source/simulation2/components/CCmpRangeManager.cpp

     
    889889
    890890        return r;
    891891    }
    892892
    893893    virtual std::vector<entity_id_t> GetEntitiesByPlayer(player_id_t player)
    894894    {
    895895        std::vector<entity_id_t> entities;
    896896
    897         u32 ownerMask = CalcOwnerMask(player);
    898 
    899         for (EntityMap<EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it)
    900         {
    901             // Check owner and add to list if it matches
    902             if (CalcOwnerMask(it->second.owner) & ownerMask)
    903                 entities.push_back(it->first);
    904         }
     897        for (const EntityMap<EntityData>::key_val<unsigned int, EntityData>& entityData : m_EntityData)
     898            if ((player == NON_GAIA_PLAYERS && entityData.second.owner != 0) || entityData.second.owner == player)
     899                entities.emplace_back(entityData.first);
    905900
    906901        return entities;
    907902    }
    908903
     904    virtual std::vector<entity_id_t> GetNonGaiaEntities()
     905    {
     906        return GetEntitiesByPlayer(NON_GAIA_PLAYERS);
     907    }
     908
    909909    virtual void SetDebugOverlay(bool enabled)
    910910    {
    911911        m_DebugOverlayEnabled = enabled;
    912912        m_DebugOverlayDirty = true;
    913913        if (!enabled)
    914914            m_DebugOverlayLines.clear();
    915915    }
    916916
  • source/simulation2/components/ICmpRangeManager.cpp

     
    4040DEFINE_INTERFACE_METHOD_7("CreateActiveParabolicQuery", ICmpRangeManager::tag_t, ICmpRangeManager, CreateActiveParabolicQuery, entity_id_t, entity_pos_t, entity_pos_t, entity_pos_t, std::vector<int>, int, u8)
    4141DEFINE_INTERFACE_METHOD_1("DestroyActiveQuery", void, ICmpRangeManager, DestroyActiveQuery, ICmpRangeManager::tag_t)
    4242DEFINE_INTERFACE_METHOD_1("EnableActiveQuery", void, ICmpRangeManager, EnableActiveQuery, ICmpRangeManager::tag_t)
    4343DEFINE_INTERFACE_METHOD_1("DisableActiveQuery", void, ICmpRangeManager, DisableActiveQuery, ICmpRangeManager::tag_t)
    4444DEFINE_INTERFACE_METHOD_1("ResetActiveQuery", std::vector<entity_id_t>, ICmpRangeManager, ResetActiveQuery, ICmpRangeManager::tag_t)
    4545DEFINE_INTERFACE_METHOD_3("SetEntityFlag", void, ICmpRangeManager, SetEntityFlag, entity_id_t, std::string, bool)
    4646DEFINE_INTERFACE_METHOD_1("GetEntityFlagMask", u8, ICmpRangeManager, GetEntityFlagMask, std::string)
    4747DEFINE_INTERFACE_METHOD_1("GetEntitiesByPlayer", std::vector<entity_id_t>, ICmpRangeManager, GetEntitiesByPlayer, player_id_t)
     48DEFINE_INTERFACE_METHOD_0("GetNonGaiaEntities", std::vector<entity_id_t>, ICmpRangeManager, GetNonGaiaEntities)
    4849DEFINE_INTERFACE_METHOD_1("SetDebugOverlay", void, ICmpRangeManager, SetDebugOverlay, bool)
    4950DEFINE_INTERFACE_METHOD_1("ExploreAllTiles", void, ICmpRangeManager, ExploreAllTiles, player_id_t)
    5051DEFINE_INTERFACE_METHOD_0("ExploreTerritories", void, ICmpRangeManager, ExploreTerritories)
    5152DEFINE_INTERFACE_METHOD_2("SetLosRevealAll", void, ICmpRangeManager, SetLosRevealAll, player_id_t, bool)
    5253DEFINE_INTERFACE_METHOD_1("GetLosRevealAll", bool, ICmpRangeManager, GetLosRevealAll, player_id_t)
    5354DEFINE_INTERFACE_METHOD_5("GetElevationAdaptedRange", entity_pos_t, ICmpRangeManager, GetElevationAdaptedRange, CFixedVector3D, CFixedVector3D, entity_pos_t, entity_pos_t, entity_pos_t)
    5455DEFINE_INTERFACE_METHOD_2("ActivateScriptedVisibility", void, ICmpRangeManager, ActivateScriptedVisibility, entity_id_t, bool)
    5556DEFINE_INTERFACE_METHOD_2("GetLosVisibility", std::string, ICmpRangeManager, GetLosVisibility_wrapper, entity_id_t, player_id_t)
  • source/simulation2/components/ICmpRangeManager.h

     
    174174     * The next RangeUpdate message will say who has entered/left since this call,
    175175     * so you won't miss any notifications.
    176176     * @param tag identifier of query.
    177177     * @return list of entities matching the query, ordered by increasing distance from the source entity.
    178178     */
    179179    virtual std::vector<entity_id_t> ResetActiveQuery(tag_t tag) = 0;
    180180
    181181    /**
    182      * Returns list of all entities for specific player.
     182     * Returns a list of all entities for specific player.
    183183     * (This is on this interface because it shares a lot of the implementation.
    184184     * Maybe it should be extended to be more like ExecuteQuery without
    185185     * the range parameter.)
    186186     */
    187187    virtual std::vector<entity_id_t> GetEntitiesByPlayer(player_id_t player) = 0;
    188188
    189189    /**
     190     * Returns a list of all entities of all players except gaia. Also see GetEntitiesByPlayer.
     191     */
     192    virtual std::vector<entity_id_t> GetNonGaiaEntities() = 0;
     193
     194    /**
    190195     * Toggle the rendering of debug info.
    191196     */
    192197    virtual void SetDebugOverlay(bool enabled) = 0;
    193198
    194199    /**
    195200     * Returns the mask for the specified identifier.
    196201     */
    197202    virtual u8 GetEntityFlagMask(std::string identifier) = 0;
  • source/simulation2/helpers/Player.h

     
    1919#define INCLUDED_PLAYER
    2020
    2121/**
    2222 * valid player IDs are non-negative (see ICmpOwnership)
    2323 */
    2424typedef int32_t player_id_t;
    2525
    2626static const player_id_t INVALID_PLAYER = -1;
     27static const player_id_t NON_GAIA_PLAYERS = -2;
    2728
    2829#endif // INCLUDED_PLAYER
  • source/simulation2/helpers/Selection.cpp

     
    9393static bool CheckEntityVisibleAndInRect(CEntityHandle handle, CmpPtr<ICmpRangeManager> cmpRangeManager, const CCamera& camera, int sx0, int sy0, int sx1, int sy1, player_id_t owner, bool allowEditorSelectables)
    9494{
    9595    // Check if this entity is only selectable in Atlas
    9696    CmpPtr<ICmpSelectable> cmpSelectable(handle);
    9797    if (!cmpSelectable || (!allowEditorSelectables && cmpSelectable->IsEditorOnly()))
    9898        return false;
    9999
    100100    // Ignore entities hidden by LOS (or otherwise hidden, e.g. when not IsInWorld)
    101     if (cmpRangeManager->GetLosVisibility(handle, owner) == ICmpRangeManager::VIS_HIDDEN)
     101    if (owner != NON_GAIA_PLAYERS && cmpRangeManager->GetLosVisibility(handle, owner) == ICmpRangeManager::VIS_HIDDEN)
    102102        return false;
    103103
    104104    // Find the current interpolated model position.
    105105    // (We just use the centre position and not the whole bounding box, because maybe
    106106    // that's better for users trying to select objects in busy areas)
    107107
    108108    CmpPtr<ICmpVisual> cmpVisual(handle);
    109109    if (!cmpVisual)
     
    118118    // Compare screen-space coordinates
    119119    float x, y;
    120120    camera.GetScreenCoordinates(position, x, y);
    121121    int ix = (int)x;
    122122    int iy = (int)y;
    123123    return sx0 <= ix && ix <= sx1 && sy0 <= iy && iy <= sy1;
    124124}
    125125
     126/**
     127 * Returns all entities visible in the given screen area and owned by the given player.
     128 * If allowEditorSelectables is true, then all selectable entities, including decoratives will be returned.
     129 */
    126130std::vector<entity_id_t> EntitySelection::PickEntitiesInRect(CSimulation2& simulation, const CCamera& camera, int sx0, int sy0, int sx1, int sy1, player_id_t owner, bool allowEditorSelectables)
    127131{
    128132    PROFILE2("PickEntitiesInRect");
     133
    129134    // Make sure sx0 <= sx1, and sy0 <= sy1
    130135    if (sx0 > sx1)
    131136        std::swap(sx0, sx1);
    132137    if (sy0 > sy1)
    133138        std::swap(sy0, sy1);
    134139
    135140    CmpPtr<ICmpRangeManager> cmpRangeManager(simulation, SYSTEM_ENTITY);
    136141    ENSURE(cmpRangeManager);
    137142
    138143    std::vector<entity_id_t> hitEnts;
    139 
    140     if (owner != INVALID_PLAYER)
    141     {
    142         CComponentManager& componentManager = simulation.GetSimContext().GetComponentManager();
    143         std::vector<entity_id_t> ents = cmpRangeManager->GetEntitiesByPlayer(owner);
    144         for (std::vector<entity_id_t>::iterator it = ents.begin(); it != ents.end(); ++it)
    145         {
    146             if (CheckEntityVisibleAndInRect(componentManager.LookupEntityHandle(*it), cmpRangeManager, camera, sx0, sy0, sx1, sy1, owner, allowEditorSelectables))
    147                 hitEnts.push_back(*it);
    148         }
    149     }
    150     else // owner == INVALID_PLAYER; Used when selecting units in Atlas or other mods that allow all kinds of selectables to be selected.
    151     {
    152         const CSimulation2::InterfaceListUnordered& selectableEnts = simulation.GetEntitiesWithInterfaceUnordered(IID_Selectable);
    153         for (CSimulation2::InterfaceListUnordered::const_iterator it = selectableEnts.begin(); it != selectableEnts.end(); ++it)
    154         {
    155             if (CheckEntityVisibleAndInRect(it->second->GetEntityHandle(), cmpRangeManager, camera, sx0, sy0, sx1, sy1, owner, allowEditorSelectables))
    156                 hitEnts.push_back(it->first);
    157         }
    158     }
     144    if (owner == INVALID_PLAYER)
     145        // Get all selectable entities (including decoratives), used by Atlas
     146        for (const std::pair<const unsigned int, IComponent*>& component : simulation.GetEntitiesWithInterfaceUnordered(IID_Selectable))
     147            hitEnts.emplace_back(component.first);
     148    else
     149        hitEnts = (owner == NON_GAIA_PLAYERS) ? cmpRangeManager->GetNonGaiaEntities() : cmpRangeManager->GetEntitiesByPlayer(owner);
     150
     151    // Remove all entities invisible or not in the given rectangle
     152    CComponentManager& componentManager = simulation.GetSimContext().GetComponentManager();
     153    hitEnts.erase(std::remove_if(hitEnts.begin(), hitEnts.end(),
     154        [&](const entity_id_t& ent)
     155            { return !CheckEntityVisibleAndInRect(componentManager.LookupEntityHandle(ent), cmpRangeManager, camera, sx0, sy0, sx1, sy1, owner, allowEditorSelectables); }
     156    ), hitEnts.end());
    159157
    160158    return hitEnts;
    161159}
    162160
    163161std::vector<entity_id_t> EntitySelection::PickSimilarEntities(CSimulation2& simulation, const CCamera& camera,
    164162    const std::string& templateName, player_id_t owner, bool includeOffScreen, bool matchRank,
    165163    bool allowEditorSelectables, bool allowFoundations)
    166164{