diff --git a/rts/Game/Camera.cpp b/rts/Game/Camera.cpp index cb5cc0f4d8..b01bc62f89 100644 --- a/rts/Game/Camera.cpp +++ b/rts/Game/Camera.cpp @@ -13,6 +13,8 @@ #include "System/float3.h" #include "System/Matrix44f.h" #include "System/Config/ConfigHandler.h" +#include "Sim/Features/FeatureHandler.h" +#include "Sim/Units/UnitHandler.h" #include "System/Misc/TracyDefs.h" @@ -773,6 +775,62 @@ float3 CCamera::GetMoveVectorFromState(bool fromKeyState) const return v; } +std::optional CCamera::TracePointToMaxAltitude(const float3& point, const float rayLength, const float maxAltitude) const +{ + // ray from camera position to point, intersecting with the maxAltitude horizontal plane. + const float3 dir = (point-pos).Normalize(); + const float dist = CGround::LinePlaneCol(pos, dir, rayLength, maxAltitude); + if (dist > 0.0) { + return pos + dir*dist; + } + return std::nullopt; +} + +float3 CCamera::NearTheaterIntersection(const float3& dir, const float rayLength) const +{ + // intersect the frustum with max altitude to get the optimal ray start. + + // max unit and feature altitudes are always at least map MaxHeight. + const float maxAltitude = std::max (unitHandler.MaxUnitAltitude(), featureHandler.MaxFeatureAltitude()); + if (pos.y < maxAltitude) + return pos; + + const auto fbl = GetFrustumVert(CCamera::FRUSTUM_POINT_FBL); + const auto fbr = GetFrustumVert(CCamera::FRUSTUM_POINT_FBR); + const auto ftl = GetFrustumVert(CCamera::FRUSTUM_POINT_FTL); + + // check the bottom frustum is parallel to ground and lower than the top frustum + if ((std::abs(fbl.y-fbr.y) > std::abs(fbl.y/100000.0)) || (fbl.y >= ftl.y)) + return pos; + + const auto fv1 = TracePointToMaxAltitude(fbl, rayLength, maxAltitude); + const auto fv2 = TracePointToMaxAltitude(fbr, rayLength, maxAltitude); + if (!fv1 || !fv2) + return pos; + + float3 midFv = (fv1.value()+fv2.value())/2.0; + midFv.y = pos.y; + + // vertical plane from frustum intersection to max height + const float3 p = fv1.value(); + const float3 norm = midFv-pos; + const auto d = -norm.dot(p); + const float4 nearTheaterPlane = float4(norm.x, norm.y, norm.z, d); + + // intersection + float3 rayIntersection; + float3 topFrustumIntersection; + + // both the ray and cam to ftl need to intersect the plane to make sure we're not looking down, in that + // case results wouldn't be correct and also we wouldn't gain anything. + const bool rayRes = RayAndPlaneIntersection(pos, pos+dir*rayLength, nearTheaterPlane, false, rayIntersection); + const bool tfRes = RayAndPlaneIntersection(pos, ftl, nearTheaterPlane, false, topFrustumIntersection); + if (rayRes && tfRes) { + return rayIntersection; + } + return pos; +} + // http://www.lighthouse3d.com/tutorials/view-frustum-culling/geometric-approach-testing-points-and-spheres/ bool CCamera::Frustum::IntersectSphere(float3 p, float radius, uint8_t testMask) const { diff --git a/rts/Game/Camera.h b/rts/Game/Camera.h index 7901f2218e..163f059c89 100644 --- a/rts/Game/Camera.h +++ b/rts/Game/Camera.h @@ -221,6 +221,9 @@ class CCamera { return (forward.dot(objPos - pos)); } + std::optional TracePointToMaxAltitude(const float3& point, const float rayLength, const float maxAltitude) const; + float3 NearTheaterIntersection(const float3& dir, const float rayLength) const; + /* float ProjectedDistanceShadow(const float3& objPos, const float3& sunDir) const { // FIXME: fix it, cap it for shallow shadows? diff --git a/rts/Game/UI/GuiHandler.cpp b/rts/Game/UI/GuiHandler.cpp index acf36c3a86..ab2ec5c5dd 100644 --- a/rts/Game/UI/GuiHandler.cpp +++ b/rts/Game/UI/GuiHandler.cpp @@ -1155,8 +1155,9 @@ bool CGuiHandler::TryTarget(const SCommandDescription& cmdDesc) const const CFeature* targetFeature = nullptr; const float viewRange = camera->GetFarPlaneDist() * 1.4f; - const float dist = TraceRay::GuiTraceRay(camera->GetPos(), mouse->dir, viewRange, NULL, targetUnit, targetFeature, true); - const float3 groundPos = camera->GetPos() + mouse->dir * dist; + const float3 rayOrigin = camera->NearTheaterIntersection(mouse->dir, viewRange); + const float dist = TraceRay::GuiTraceRay(rayOrigin, mouse->dir, viewRange, nullptr, targetUnit, targetFeature, true); + const float3 groundPos = rayOrigin + mouse->dir * dist; if (dist <= 0.0f) return false; @@ -1685,8 +1686,11 @@ int CGuiHandler::GetDefaultCommand(int x, int y, const float3& cameraPos, const unit = minimap->GetSelectUnit(minimap->GetMapPosition(x, y)); } else { const float viewRange = camera->GetFarPlaneDist() * 1.4f; - const float dist = TraceRay::GuiTraceRay(cameraPos, mouseDir, viewRange, nullptr, unit, feature, true); - const float3 hit = cameraPos + mouseDir * dist; + + const float3 rayOrigin = camera->NearTheaterIntersection(mouseDir, viewRange); + const float dist = TraceRay::GuiTraceRay(rayOrigin, mouseDir, viewRange, nullptr, unit, feature, true); + + const float3 hit = rayOrigin + mouseDir * dist; // make sure the ray hit in the map if (unit == nullptr && feature == nullptr && !hit.IsInBounds()) @@ -2265,7 +2269,9 @@ Command CGuiHandler::GetCommand(int mouseX, int mouseY, int buttonHint, bool pre const CUnit* unit = nullptr; const CFeature* feature = nullptr; - TraceRay::GuiTraceRay(cameraPos, mouseDir, camera->GetFarPlaneDist() * 1.4f, nullptr, unit, feature, true); + const float viewRange = camera->GetFarPlaneDist() * 1.4f; + const float3 rayOrigin = camera->NearTheaterIntersection(mouseDir, viewRange); + TraceRay::GuiTraceRay(rayOrigin, mouseDir, viewRange, nullptr, unit, feature, true); if (unit == nullptr) return defaultRet; @@ -2282,7 +2288,8 @@ Command CGuiHandler::GetCommand(int mouseX, int mouseY, int buttonHint, bool pre const CFeature* feature = nullptr; const float traceDist = camera->GetFarPlaneDist() * 1.4f; - const float isectDist = TraceRay::GuiTraceRay(cameraPos, mouseDir, traceDist, nullptr, unit, feature, true); + const float3 rayOrigin = camera->NearTheaterIntersection(mouseDir, traceDist); + const float isectDist = TraceRay::GuiTraceRay(rayOrigin, mouseDir, traceDist, nullptr, unit, feature, true); if (isectDist > (traceDist - 300.0f)) return defaultRet; @@ -2292,7 +2299,7 @@ Command CGuiHandler::GetCommand(int mouseX, int mouseY, int buttonHint, bool pre c.PushParam(unit->id); } else { // clicked in map - c.PushPos(cameraPos + (mouseDir * isectDist)); + c.PushPos(rayOrigin + (mouseDir * isectDist)); } return CheckCommand(c); } @@ -2345,7 +2352,9 @@ Command CGuiHandler::GetCommand(int mouseX, int mouseY, int buttonHint, bool pre if (mouse->buttons[button].movement <= mouse->dragCircleCommandThreshold) { const CUnit* unit = nullptr; const CFeature* feature = nullptr; - const float dist2 = TraceRay::GuiTraceRay(cameraPos, mouseDir, camera->GetFarPlaneDist() * 1.4f, NULL, unit, feature, true); + const float viewRange = camera->GetFarPlaneDist() * 1.4f; + const float3 rayOrigin = camera->NearTheaterIntersection(mouseDir, viewRange); + const float dist2 = TraceRay::GuiTraceRay(rayOrigin, mouseDir, viewRange, nullptr, unit, feature, true); if (dist2 > (camera->GetFarPlaneDist() * 1.4f - 300) && (commands[tempInCommand].type != CMDTYPE_ICON_UNIT_FEATURE_OR_AREA)) return defaultRet; @@ -2362,7 +2371,7 @@ Command CGuiHandler::GetCommand(int mouseX, int mouseY, int buttonHint, bool pre if (explicitCommand < 0 || !ZeroRadiusAllowed(c)) return defaultRet; - c.PushPos(cameraPos + (mouseDir * dist2)); + c.PushPos(rayOrigin + (mouseDir * dist2)); c.PushParam(0); // zero radius if (c.GetID() == CMD_UNLOAD_UNITS) @@ -2408,7 +2417,8 @@ Command CGuiHandler::GetCommand(int mouseX, int mouseY, int buttonHint, bool pre const CFeature* feature = nullptr; const float traceDist = camera->GetFarPlaneDist() * 1.4f; - const float outerDist = TraceRay::GuiTraceRay(cameraPos, mouseDir, traceDist, nullptr, unit, feature, true); + const float3 rayOrigin = camera->NearTheaterIntersection(mouseDir, traceDist); + const float outerDist = TraceRay::GuiTraceRay(rayOrigin, mouseDir, traceDist, nullptr, unit, feature, true); if (outerDist > (traceDist - 300.0f)) return defaultRet; @@ -2421,7 +2431,7 @@ Command CGuiHandler::GetCommand(int mouseX, int mouseY, int buttonHint, bool pre if (explicitCommand < 0) return defaultRet; - c.PushPos(cameraPos + (mouseDir * outerDist)); + c.PushPos(rayOrigin + (mouseDir * outerDist)); } } else { // create rectangular area-command @@ -2503,7 +2513,9 @@ size_t CGuiHandler::GetBuildPositions(const BuildInfo& startInfo, const BuildInf const CUnit* unit = nullptr; const CFeature* feature = nullptr; - TraceRay::GuiTraceRay(cameraPos, mouseDir, camera->GetFarPlaneDist() * 1.4f, nullptr, unit, feature, startInfo.def->floatOnWater); + const float viewRange = camera->GetFarPlaneDist() * 1.4f; + const float3 rayOrigin = camera->NearTheaterIntersection(mouseDir, viewRange); + TraceRay::GuiTraceRay(rayOrigin, mouseDir, viewRange, nullptr, unit, feature, startInfo.def->floatOnWater); if (unit != nullptr) { other.def = unit->unitDef; @@ -3710,7 +3722,8 @@ void CGuiHandler::DrawMapStuff(bool onMiniMap) unit = minimap->GetSelectUnit(tracePos); } else { // ignore the returned distance, we don't care about it here - TraceRay::GuiTraceRay(tracePos, traceDir, maxTraceDist, nullptr, unit, feature, false); + const float3 rayOrigin = camera->NearTheaterIntersection(traceDir, maxTraceDist); + TraceRay::GuiTraceRay(rayOrigin, traceDir, maxTraceDist, nullptr, unit, feature, false); } if (unit != nullptr && (gu->spectatingFullView || unit->IsInLosForAllyTeam(gu->myAllyTeam))) { diff --git a/rts/Game/UI/MouseHandler.cpp b/rts/Game/UI/MouseHandler.cpp index 54a2841622..3969a6a2d1 100644 --- a/rts/Game/UI/MouseHandler.cpp +++ b/rts/Game/UI/MouseHandler.cpp @@ -569,7 +569,9 @@ void CMouseHandler::MouseRelease(int x, int y, int button) const CUnit* unit = nullptr; const CFeature* feature = nullptr; - TraceRay::GuiTraceRay(camera->GetPos(), dir, camera->GetFarPlaneDist() * 1.4f, nullptr, unit, feature, false); + const float viewRange = camera->GetFarPlaneDist() * 1.4f; + const float3 rayOrigin = camera->NearTheaterIntersection(dir, viewRange); + TraceRay::GuiTraceRay(rayOrigin, dir, viewRange, nullptr, unit, feature, false); lastClicked = unit; const bool selectType = (bp.lastRelease >= (gu->gameTime - doubleClickTime) && unit == _lastClicked); @@ -701,8 +703,9 @@ std::string CMouseHandler::GetCurrentTooltip() const const CUnit* unit = nullptr; const CFeature* feature = nullptr; + const float3 rayOrigin = camera->NearTheaterIntersection(dir, range); { - dist = TraceRay::GuiTraceRay(camera->GetPos(), dir, range, nullptr, unit, feature, true, false, true); + dist = TraceRay::GuiTraceRay(rayOrigin, dir, range, nullptr, unit, feature, true, false, true); if (unit != nullptr) return CTooltipConsole::MakeUnitString(unit); if (feature != nullptr) return CTooltipConsole::MakeFeatureString(feature); @@ -714,7 +717,7 @@ std::string CMouseHandler::GetCurrentTooltip() const return selTip; if (dist <= range) - return CTooltipConsole::MakeGroundString(camera->GetPos() + (dir * dist)); + return CTooltipConsole::MakeGroundString(rayOrigin + (dir * dist)); return ""; } diff --git a/rts/Lua/LuaSyncedCtrl.cpp b/rts/Lua/LuaSyncedCtrl.cpp index 4f255f396c..0f09a65641 100644 --- a/rts/Lua/LuaSyncedCtrl.cpp +++ b/rts/Lua/LuaSyncedCtrl.cpp @@ -3261,6 +3261,7 @@ int LuaSyncedCtrl::SetUnitMidAndAimPos(lua_State* L) if (updateQuads) { quadField.MovedUnit(unit); + unitHandler.MovedUnit(unit); } lua_pushboolean(L, true); @@ -3296,6 +3297,7 @@ int LuaSyncedCtrl::SetUnitRadiusAndHeight(lua_State* L) if (updateQuads) { quadField.MovedUnit(unit); + unitHandler.MovedUnit(unit); } lua_pushboolean(L, true); diff --git a/rts/Lua/LuaUnsyncedRead.cpp b/rts/Lua/LuaUnsyncedRead.cpp index 8ce2e17e85..ec0febe4bb 100644 --- a/rts/Lua/LuaUnsyncedRead.cpp +++ b/rts/Lua/LuaUnsyncedRead.cpp @@ -2952,10 +2952,15 @@ int LuaUnsyncedRead::TraceScreenRay(lua_State* L) const float3 pxlDir = camera->CalcPixelDir(wx, wy); // trace for player's allyteam - const float traceDist = TraceRay::GuiTraceRay(camPos, pxlDir, rawRange, nullptr, unit, feature, true, onlyCoords, ignoreWater); + float3 rayOrigin; + if (onlyCoords) + rayOrigin = camPos; + else + rayOrigin = camera->NearTheaterIntersection(pxlDir, rawRange); + const float traceDist = TraceRay::GuiTraceRay(rayOrigin, pxlDir, rawRange, nullptr, unit, feature, true, onlyCoords, ignoreWater); const float planeDist = CGround::LinePlaneCol(camPos, pxlDir, rawRange, luaL_optnumber(L, newArgIdx, 0.0f)); - const float3 tracePos = camPos + (pxlDir * traceDist); + const float3 tracePos = rayOrigin + (pxlDir * traceDist); const float3 planePos = camPos + (pxlDir * planeDist); // backup (for includeSky and onlyCoords) if ((traceDist < 0.0f || traceDist > badRange) && unit == nullptr && feature == nullptr) { @@ -4890,4 +4895,4 @@ int LuaUnsyncedRead::SolveNURBSCurve(lua_State* L) lua_rawseti(L, -2, ++i); } return 1; -} \ No newline at end of file +} diff --git a/rts/Rendering/UniformConstants.cpp b/rts/Rendering/UniformConstants.cpp index 218a404065..9a077e0720 100644 --- a/rts/Rendering/UniformConstants.cpp +++ b/rts/Rendering/UniformConstants.cpp @@ -275,9 +275,10 @@ void UniformConstants::UpdateParamsImpl(UniformParamsBuffer* updateBuffer) const float3 pxlDir = camPlayer->CalcPixelDir(wx, wy); // trace for player's allyteam - const float traceDist = TraceRay::GuiTraceRay(camPos, pxlDir, rawRange, nullptr, unit, feature, true, false, true); + const float3 rayOrigin = camPlayer->NearTheaterIntersection(pxlDir, rawRange); + const float traceDist = TraceRay::GuiTraceRay(rayOrigin, pxlDir, rawRange, nullptr, unit, feature, true, false, true); - const float3 tracePos = camPos + (pxlDir * traceDist); + const float3 tracePos = rayOrigin + (pxlDir * traceDist); if (unit) updateBuffer->mouseWorldPos = float4{ unit->drawPos, 1.0f }; diff --git a/rts/Sim/Features/Feature.cpp b/rts/Sim/Features/Feature.cpp index 34c2e9811c..dd0764496c 100644 --- a/rts/Sim/Features/Feature.cpp +++ b/rts/Sim/Features/Feature.cpp @@ -481,6 +481,7 @@ void CFeature::ForcedMove(const float3& newPos) UpdateTransformAndPhysState(); eventHandler.FeatureMoved(this, oldPos); + featureHandler.MovedFeature(this); // insert into managers quadField.AddFeature(this); @@ -596,6 +597,7 @@ bool CFeature::UpdatePosition() // use an exact comparison for the y-component (gravity is small) if (!pos.equals(oldPos, float3(float3::cmp_eps(), 0.0f, float3::cmp_eps()))) { eventHandler.FeatureMoved(this, oldPos); + featureHandler.MovedFeature(this); return true; } diff --git a/rts/Sim/Features/FeatureHandler.cpp b/rts/Sim/Features/FeatureHandler.cpp index b76dcf8bba..ef4a051a36 100644 --- a/rts/Sim/Features/FeatureHandler.cpp +++ b/rts/Sim/Features/FeatureHandler.cpp @@ -10,6 +10,7 @@ #include "Sim/Ecs/Registry.h" #include "Sim/Misc/QuadField.h" #include "Sim/Units/CommandAI/BuilderCAI.h" +#include "Sim/Units/UnitHandler.h" #include "System/creg/STL_Set.h" #include "System/EventHandler.h" #include "System/TimeProfiler.h" @@ -39,6 +40,7 @@ void CFeatureHandler::Init() { features.resize(MAX_FEATURES, nullptr); activeFeatureIDs.reserve(MAX_FEATURES); // internal table size must be constant featureMemPool.reserve(128); + maxFeatureAltitude = readMap->GetCurrMaxHeight(); idPool.Clear(); idPool.Expand(0, MAX_FEATURES); @@ -58,6 +60,7 @@ void CFeatureHandler::Kill() { deletedFeatureIDs.clear(); features.clear(); updateFeatures.clear(); + maxFeatureAltitude = std::numeric_limits::lowest(); } @@ -141,6 +144,7 @@ bool CFeatureHandler::AddFeature(CFeature* feature) InsertActiveFeature(feature); SetFeatureUpdateable(feature); + MovedFeature(feature); return true; } @@ -186,6 +190,19 @@ CFeature* CFeatureHandler::CreateWreckage(const FeatureLoadParams& cparams) } +void CFeatureHandler::RecalculateMaxAltitude() +{ + if (maxFeatureAltitude < std::max(readMap->GetCurrMaxHeight(), unitHandler.MaxUnitAltitude())) + return; + + maxFeatureAltitude = readMap->GetCurrMaxHeight(); + + for (const int featureID: activeFeatureIDs) { + CFeature* f = features[featureID]; + MovedFeature(f); + } +} + void CFeatureHandler::Update() { @@ -203,6 +220,9 @@ void CFeatureHandler::Update() updateFeatures.erase(iter, updateFeatures.end()); } + if ((gs->frameNum & 63) == 0) { + RecalculateMaxAltitude(); + } } @@ -287,3 +307,9 @@ void CFeatureHandler::TerrainChanged(int x1, int y1, int x2, int y2) } } +void CFeatureHandler::MovedFeature(const CFeature* feature) +{ + const CollisionVolume& cv = feature->selectionVolume; + const float top = cv.GetWorldSpacePos(feature).y + cv.GetBoundingRadius(); + maxFeatureAltitude = std::max(top, maxFeatureAltitude); +} diff --git a/rts/Sim/Features/FeatureHandler.h b/rts/Sim/Features/FeatureHandler.h index 740575a3fa..c57333c15a 100644 --- a/rts/Sim/Features/FeatureHandler.h +++ b/rts/Sim/Features/FeatureHandler.h @@ -59,12 +59,15 @@ class CFeatureHandler : public spring::noncopyable bool TryFreeFeatureID(int id); bool AddFeature(CFeature* feature); void DeleteFeature(CFeature* feature); + void MovedFeature(const CFeature* feature); void LoadFeaturesFromMap(); void SetFeatureUpdateable(CFeature* feature); void TerrainChanged(int x1, int y1, int x2, int y2); + float MaxFeatureAltitude() const { return maxFeatureAltitude; } + const spring::unordered_set& GetActiveFeatureIDs() const { return activeFeatureIDs; } private: @@ -88,6 +91,12 @@ class CFeatureHandler : public spring::noncopyable std::vector deletedFeatureIDs; std::vector features; std::vector updateFeatures; + + ///< highest altitude of any feature added so far + ///< (ray tracing uses this in some cases) + float maxFeatureAltitude = 0.0f; + + void RecalculateMaxAltitude(); }; extern CFeatureHandler featureHandler; diff --git a/rts/Sim/Units/Unit.cpp b/rts/Sim/Units/Unit.cpp index 50172ecc80..17963b92d5 100644 --- a/rts/Sim/Units/Unit.cpp +++ b/rts/Sim/Units/Unit.cpp @@ -531,6 +531,7 @@ void CUnit::ForcedMove(const float3& newPos) eventHandler.UnitMoved(this); quadField.MovedUnit(this); + unitHandler.MovedUnit(this); } @@ -741,6 +742,7 @@ void CUnit::UpdateTransportees() // see ::AttachUnit if (transportee->IsStunned()) { quadField.MovedUnit(transportee); + unitHandler.MovedUnit(transportee); } } } diff --git a/rts/Sim/Units/UnitHandler.cpp b/rts/Sim/Units/UnitHandler.cpp index 1f649d1025..151238fee8 100644 --- a/rts/Sim/Units/UnitHandler.cpp +++ b/rts/Sim/Units/UnitHandler.cpp @@ -11,6 +11,7 @@ #include "UnitTypes/Factory.h" #include "CommandAI/BuilderCAI.h" +#include "Map/ReadMap.h" #include "Sim/Ecs/Registry.h" #include "Sim/Misc/GlobalSynced.h" #include "Sim/Misc/ModInfo.h" @@ -55,6 +56,7 @@ CR_REG_METADATA(CUnitHandler, ( CR_MEMBER(maxUnits), CR_MEMBER(maxUnitRadius), + CR_MEMBER_UN(maxUnitAltitude), CR_MEMBER(inUpdateCall) )) @@ -115,6 +117,7 @@ void CUnitHandler::Init() { // other team in the respective allyteam maxUnits = CalcMaxUnits(); maxUnitRadius = 0.0f; + maxUnitAltitude = readMap->GetCurrMaxHeight(); } { activeSlowUpdateUnit = 0; @@ -170,6 +173,7 @@ void CUnitHandler::Kill() { maxUnits = 0; maxUnitRadius = 0.0f; + maxUnitAltitude = std::numeric_limits::lowest(); } } @@ -236,6 +240,7 @@ bool CUnitHandler::AddUnit(CUnit* unit) spring::VectorInsertUnique(GetUnitsByTeamAndDef(unit->team, unit->unitDef->id), unit, false); maxUnitRadius = std::max(unit->radius, maxUnitRadius); + MovedUnit(unit); return true; } @@ -408,6 +413,7 @@ void CUnitHandler::UpdateUnits() { SCOPED_TIMER("Sim::Unit::Update"); + maxUnitAltitude = readMap->GetCurrMaxHeight(); size_t activeUnitCount = activeUnits.size(); for (size_t i = 0; i < activeUnitCount; ++i) { CUnit* unit = activeUnits[i]; @@ -415,6 +421,7 @@ void CUnitHandler::UpdateUnits() unit->SanityCheck(); unit->Update(); unit->moveType->UpdateCollisionMap(); + MovedUnit(unit); // unsynced; done on-demand when drawing unit // unit->UpdateLocalModel(); unit->SanityCheck(); @@ -514,3 +521,9 @@ unsigned int CUnitHandler::CalcMaxUnits() const return n; } +void CUnitHandler::MovedUnit(const CUnit* unit) +{ + const CollisionVolume& cv = unit->selectionVolume; + const float top = cv.GetWorldSpacePos(unit).y + cv.GetBoundingRadius(); + maxUnitAltitude = std::max(top, maxUnitAltitude); +} diff --git a/rts/Sim/Units/UnitHandler.h b/rts/Sim/Units/UnitHandler.h index 76525f2e0a..eb7803b0e6 100644 --- a/rts/Sim/Units/UnitHandler.h +++ b/rts/Sim/Units/UnitHandler.h @@ -28,6 +28,7 @@ class CUnitHandler void Update(); bool AddUnit(CUnit* unit); + void MovedUnit(const CUnit* unit); bool CanAddUnit(int id) const { // do we want to be assigned a random ID and are any left in pool? @@ -46,6 +47,7 @@ class CUnitHandler unsigned int CalcMaxUnits() const; float MaxUnitRadius() const { return maxUnitRadius; } + float MaxUnitAltitude() const { return maxUnitAltitude; } /// Returns true if a unit of type unitID can be built, false otherwise bool CanBuildUnit(const UnitDef* unitdef, int team) const; @@ -115,6 +117,10 @@ class CUnitHandler ///< spatial query filters in GameHelper use this) float maxUnitRadius = 0.0f; + ///< highest altitude of any unit added so far + ///< (ray tracing uses this in some cases) + float maxUnitAltitude = 0.0f; + bool inUpdateCall = false; };