Changeset View
Changeset View
Standalone View
Standalone View
source/simulation2/components/CCmpPathfinder.cpp
/* Copyright (C) 2018 Wildfire Games. | /* Copyright (C) 2018 Wildfire Games. | ||||
Silier: 2019 :) | |||||
* This file is part of 0 A.D. | * This file is part of 0 A.D. | ||||
* | * | ||||
* 0 A.D. is free software: you can redistribute it and/or modify | * 0 A.D. is free software: you can redistribute it and/or modify | ||||
* it under the terms of the GNU General Public License as published by | * it under the terms of the GNU General Public License as published by | ||||
* the Free Software Foundation, either version 2 of the License, or | * the Free Software Foundation, either version 2 of the License, or | ||||
* (at your option) any later version. | * (at your option) any later version. | ||||
* | * | ||||
* 0 A.D. is distributed in the hope that it will be useful, | * 0 A.D. is distributed in the hope that it will be useful, | ||||
Show All 20 Lines | |||||
#include "ps/XML/Xeromyces.h" | #include "ps/XML/Xeromyces.h" | ||||
#include "renderer/Scene.h" | #include "renderer/Scene.h" | ||||
#include "simulation2/MessageTypes.h" | #include "simulation2/MessageTypes.h" | ||||
#include "simulation2/components/ICmpObstruction.h" | #include "simulation2/components/ICmpObstruction.h" | ||||
#include "simulation2/components/ICmpObstructionManager.h" | #include "simulation2/components/ICmpObstructionManager.h" | ||||
#include "simulation2/components/ICmpTerrain.h" | #include "simulation2/components/ICmpTerrain.h" | ||||
#include "simulation2/components/ICmpWaterManager.h" | #include "simulation2/components/ICmpWaterManager.h" | ||||
#include "simulation2/helpers/Rasterize.h" | #include "simulation2/helpers/Rasterize.h" | ||||
#include "simulation2/helpers/VertexPathfinder.h" | |||||
#include "simulation2/serialization/SerializeTemplates.h" | #include "simulation2/serialization/SerializeTemplates.h" | ||||
REGISTER_COMPONENT_TYPE(Pathfinder) | REGISTER_COMPONENT_TYPE(Pathfinder) | ||||
void CCmpPathfinder::Init(const CParamNode& UNUSED(paramNode)) | void CCmpPathfinder::Init(const CParamNode& UNUSED(paramNode)) | ||||
{ | { | ||||
m_MapSize = 0; | m_MapSize = 0; | ||||
m_Grid = NULL; | m_Grid = NULL; | ||||
m_TerrainOnlyGrid = NULL; | m_TerrainOnlyGrid = NULL; | ||||
FlushAIPathfinderDirtinessInformation(); | FlushAIPathfinderDirtinessInformation(); | ||||
m_NextAsyncTicket = 1; | m_NextAsyncTicket = 1; | ||||
m_DebugOverlay = false; | |||||
m_AtlasOverlay = NULL; | m_AtlasOverlay = NULL; | ||||
m_SameTurnMovesCount = 0; | m_SameTurnMovesCount = 0; | ||||
m_VertexPathfinder = std::unique_ptr<VertexPathfinder>(new VertexPathfinder(m_MapSize, m_TerrainOnlyGrid)); | |||||
// Register Relax NG validator | // Register Relax NG validator | ||||
CXeromyces::AddValidator(g_VFS, "pathfinder", "simulation/data/pathfinder.rng"); | CXeromyces::AddValidator(g_VFS, "pathfinder", "simulation/data/pathfinder.rng"); | ||||
// Since this is used as a system component (not loaded from an entity template), | // Since this is used as a system component (not loaded from an entity template), | ||||
// we can't use the real paramNode (it won't get handled properly when deserializing), | // we can't use the real paramNode (it won't get handled properly when deserializing), | ||||
// so load the data from a special XML file. | // so load the data from a special XML file. | ||||
CParamNode externalParamNode; | CParamNode externalParamNode; | ||||
CParamNode::LoadXML(externalParamNode, L"simulation/data/pathfinder.xml", "pathfinder"); | CParamNode::LoadXML(externalParamNode, L"simulation/data/pathfinder.xml", "pathfinder"); | ||||
Show All 23 Lines | for (CParamNode::ChildrenMap::const_iterator it = passClasses.begin(); it != passClasses.end(); ++it) | ||||
std::string name = it->first; | std::string name = it->first; | ||||
ENSURE((int)m_PassClasses.size() <= PASS_CLASS_BITS); | ENSURE((int)m_PassClasses.size() <= PASS_CLASS_BITS); | ||||
pass_class_t mask = PASS_CLASS_MASK_FROM_INDEX(m_PassClasses.size()); | pass_class_t mask = PASS_CLASS_MASK_FROM_INDEX(m_PassClasses.size()); | ||||
m_PassClasses.push_back(PathfinderPassability(mask, it->second)); | m_PassClasses.push_back(PathfinderPassability(mask, it->second)); | ||||
m_PassClassMasks[name] = mask; | m_PassClassMasks[name] = mask; | ||||
} | } | ||||
} | } | ||||
CCmpPathfinder::~CCmpPathfinder() {}; | |||||
void CCmpPathfinder::Deinit() | void CCmpPathfinder::Deinit() | ||||
{ | { | ||||
SetDebugOverlay(false); // cleans up memory | SetDebugOverlay(false); // cleans up memory | ||||
SAFE_DELETE(m_AtlasOverlay); | SAFE_DELETE(m_AtlasOverlay); | ||||
SAFE_DELETE(m_Grid); | SAFE_DELETE(m_Grid); | ||||
SAFE_DELETE(m_TerrainOnlyGrid); | SAFE_DELETE(m_TerrainOnlyGrid); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 74 Lines • ▼ Show 20 Lines | void CCmpPathfinder::HandleMessage(const CMessage& msg, bool UNUSED(global)) | ||||
case MT_TurnStart: | case MT_TurnStart: | ||||
m_SameTurnMovesCount = 0; | m_SameTurnMovesCount = 0; | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
void CCmpPathfinder::RenderSubmit(SceneCollector& collector) | void CCmpPathfinder::RenderSubmit(SceneCollector& collector) | ||||
{ | { | ||||
for (size_t i = 0; i < m_DebugOverlayShortPathLines.size(); ++i) | m_VertexPathfinder->RenderSubmit(collector); | ||||
collector.Submit(&m_DebugOverlayShortPathLines[i]); | |||||
m_LongPathfinder.HierarchicalRenderSubmit(collector); | m_LongPathfinder.HierarchicalRenderSubmit(collector); | ||||
} | } | ||||
void CCmpPathfinder::SetDebugPath(entity_pos_t x0, entity_pos_t z0, const PathGoal& goal, pass_class_t passClass) | |||||
{ | |||||
m_LongPathfinder.SetDebugPath(x0, z0, goal, passClass); | |||||
} | |||||
void CCmpPathfinder::SetDebugOverlay(bool enabled) | |||||
{ | |||||
m_VertexPathfinder->SetDebugOverlay(enabled); | |||||
m_LongPathfinder.SetDebugOverlay(enabled); | |||||
StanUnsubmitted Done Inline ActionsWhy not split this into two functions ? :) Stan: Why not split this into two functions ? :) | |||||
wraitiiAuthorUnsubmitted Done Inline ActionsI don't want to introduce too many changes with this diff as I have another that decouples long and hierarchical pathfinder coming up. Cleanup can be done in another diff imo. wraitii: I don't want to introduce too many changes with this diff as I have another that decouples long… | |||||
} | |||||
void CCmpPathfinder::SetHierDebugOverlay(bool enabled) | |||||
{ | |||||
m_LongPathfinder.SetHierDebugOverlay(enabled, &GetSimContext()); | |||||
} | |||||
void CCmpPathfinder::GetDebugData(u32& steps, double& time, Grid<u8>& grid) const | |||||
{ | |||||
m_LongPathfinder.GetDebugData(steps, time, grid); | |||||
} | |||||
void CCmpPathfinder::SetAtlasOverlay(bool enable, pass_class_t passClass) | void CCmpPathfinder::SetAtlasOverlay(bool enable, pass_class_t passClass) | ||||
{ | { | ||||
if (enable) | if (enable) | ||||
{ | { | ||||
if (!m_AtlasOverlay) | if (!m_AtlasOverlay) | ||||
m_AtlasOverlay = new AtlasOverlay(this, passClass); | m_AtlasOverlay = new AtlasOverlay(this, passClass); | ||||
m_AtlasOverlay->m_PassClass = passClass; | m_AtlasOverlay->m_PassClass = passClass; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 467 Lines • ▼ Show 20 Lines | for (PathfinderPassability& passability : m_PassClasses) | ||||
int clearance = (passability.m_Clearance / Pathfinding::NAVCELL_SIZE).ToInt_RoundToInfinity(); | int clearance = (passability.m_Clearance / Pathfinding::NAVCELL_SIZE).ToInt_RoundToInfinity(); | ||||
ExpandImpassableCells(*m_TerrainOnlyGrid, clearance, passability.m_Mask); | ExpandImpassableCells(*m_TerrainOnlyGrid, clearance, passability.m_Mask); | ||||
} | } | ||||
} | } | ||||
////////////////////////////////////////////////////////// | ////////////////////////////////////////////////////////// | ||||
// Async path requests: | |||||
u32 CCmpPathfinder::ComputePathAsync(entity_pos_t x0, entity_pos_t z0, const PathGoal& goal, pass_class_t passClass, entity_id_t notify) | u32 CCmpPathfinder::ComputePathAsync(entity_pos_t x0, entity_pos_t z0, const PathGoal& goal, pass_class_t passClass, entity_id_t notify) | ||||
{ | { | ||||
AsyncLongPathRequest req = { m_NextAsyncTicket++, x0, z0, goal, passClass, notify }; | AsyncLongPathRequest req = { m_NextAsyncTicket++, x0, z0, goal, passClass, notify }; | ||||
m_AsyncLongPathRequests.push_back(req); | m_AsyncLongPathRequests.push_back(req); | ||||
return req.ticket; | return req.ticket; | ||||
} | } | ||||
u32 CCmpPathfinder::ComputeShortPathAsync(entity_pos_t x0, entity_pos_t z0, entity_pos_t clearance, entity_pos_t range, const PathGoal& goal, pass_class_t passClass, bool avoidMovingUnits, entity_id_t group, entity_id_t notify) | u32 CCmpPathfinder::ComputeShortPathAsync(entity_pos_t x0, entity_pos_t z0, entity_pos_t clearance, entity_pos_t range, const PathGoal& goal, pass_class_t passClass, bool avoidMovingUnits, entity_id_t group, entity_id_t notify) | ||||
{ | { | ||||
AsyncShortPathRequest req = { m_NextAsyncTicket++, x0, z0, clearance, range, goal, passClass, avoidMovingUnits, group, notify }; | AsyncShortPathRequest req = { m_NextAsyncTicket++, x0, z0, clearance, range, goal, passClass, avoidMovingUnits, group, notify }; | ||||
m_AsyncShortPathRequests.push_back(req); | m_AsyncShortPathRequests.push_back(req); | ||||
return req.ticket; | return req.ticket; | ||||
} | } | ||||
WaypointPath CCmpPathfinder::ComputeShortPath(const AsyncShortPathRequest& request) const | |||||
{ | |||||
return m_VertexPathfinder->ComputeShortPath(request, CmpPtr<ICmpObstructionManager>(GetSystemEntity())); | |||||
} | |||||
// Async processing: | |||||
void CCmpPathfinder::FinishAsyncRequests() | void CCmpPathfinder::FinishAsyncRequests() | ||||
{ | { | ||||
PROFILE2("Finish Async Requests"); | PROFILE2("Finish Async Requests"); | ||||
// Save the request queue in case it gets modified while iterating | // Save the request queue in case it gets modified while iterating | ||||
std::vector<AsyncLongPathRequest> longRequests; | std::vector<AsyncLongPathRequest> longRequests; | ||||
m_AsyncLongPathRequests.swap(longRequests); | m_AsyncLongPathRequests.swap(longRequests); | ||||
std::vector<AsyncShortPathRequest> shortRequests; | std::vector<AsyncShortPathRequest> shortRequests; | ||||
Show All 22 Lines | |||||
} | } | ||||
void CCmpPathfinder::ProcessShortRequests(const std::vector<AsyncShortPathRequest>& shortRequests) | void CCmpPathfinder::ProcessShortRequests(const std::vector<AsyncShortPathRequest>& shortRequests) | ||||
{ | { | ||||
PROFILE2("Process Short Requests"); | PROFILE2("Process Short Requests"); | ||||
for (size_t i = 0; i < shortRequests.size(); ++i) | for (size_t i = 0; i < shortRequests.size(); ++i) | ||||
{ | { | ||||
const AsyncShortPathRequest& req = shortRequests[i]; | const AsyncShortPathRequest& req = shortRequests[i]; | ||||
WaypointPath path; | WaypointPath path = m_VertexPathfinder->ComputeShortPath(req, CmpPtr<ICmpObstructionManager>(GetSystemEntity())); | ||||
ControlGroupMovementObstructionFilter filter(req.avoidMovingUnits, req.group); | |||||
ComputeShortPath(filter, req.x0, req.z0, req.clearance, req.range, req.goal, req.passClass, path); | |||||
CMessagePathResult msg(req.ticket, path); | CMessagePathResult msg(req.ticket, path); | ||||
GetSimContext().GetComponentManager().PostMessage(req.notify, msg); | GetSimContext().GetComponentManager().PostMessage(req.notify, msg); | ||||
} | } | ||||
} | } | ||||
void CCmpPathfinder::ProcessSameTurnMoves() | void CCmpPathfinder::ProcessSameTurnMoves() | ||||
{ | { | ||||
if (!m_AsyncLongPathRequests.empty()) | if (!m_AsyncLongPathRequests.empty()) | ||||
▲ Show 20 Lines • Show All 151 Lines • Show Last 20 Lines |
Wildfire Games · Phabricator
2019 :)