Changeset View
Changeset View
Standalone View
Standalone View
source/simulation2/components/tests/test_Pathfinder.h
Show All 11 Lines | |||||
* GNU General Public License for more details. | * GNU General Public License for more details. | ||||
* | * | ||||
* You should have received a copy of the GNU General Public License | * You should have received a copy of the GNU General Public License | ||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>. | * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>. | ||||
*/ | */ | ||||
#include "simulation2/system/ComponentTest.h" | #include "simulation2/system/ComponentTest.h" | ||||
#define TEST | |||||
#include "simulation2/components/ICmpObstructionManager.h" | #include "simulation2/components/ICmpObstructionManager.h" | ||||
#include "simulation2/components/ICmpPathfinder.h" | #include "simulation2/components/ICmpPathfinder.h" | ||||
#include "simulation2/components/CCmpPathfinder_Common.h" | |||||
#include "graphics/MapReader.h" | #include "graphics/MapReader.h" | ||||
#include "graphics/Terrain.h" | #include "graphics/Terrain.h" | ||||
#include "graphics/TerrainTextureManager.h" | #include "graphics/TerrainTextureManager.h" | ||||
#include "lib/timer.h" | #include "lib/timer.h" | ||||
#include "lib/tex/tex.h" | #include "lib/tex/tex.h" | ||||
#include "ps/Loader.h" | #include "ps/Loader.h" | ||||
#include "ps/Pyrogenesis.h" | #include "ps/Pyrogenesis.h" | ||||
▲ Show 20 Lines • Show All 76 Lines • ▼ Show 20 Lines | CFixedVector2D v(i*0, i*1); | ||||
PathGoal goal = { PathGoal::INVERTED_SQUARE, i*8, i*6, i*4, i*3, u, v }; | PathGoal goal = { PathGoal::INVERTED_SQUARE, i*8, i*6, i*4, i*3, u, v }; | ||||
TS_ASSERT_EQUALS(goal.NearestPointOnGoal(u*8 + v*4), u*8 + v*3); | TS_ASSERT_EQUALS(goal.NearestPointOnGoal(u*8 + v*4), u*8 + v*3); | ||||
TS_ASSERT_EQUALS(goal.DistanceToPoint(u*8 + v*4), i*1); | TS_ASSERT_EQUALS(goal.DistanceToPoint(u*8 + v*4), i*1); | ||||
TS_ASSERT_EQUALS(goal.NearestPointOnGoal(u*0 + v*0), u*0 + v*0); | TS_ASSERT_EQUALS(goal.NearestPointOnGoal(u*0 + v*0), u*0 + v*0); | ||||
TS_ASSERT_EQUALS(goal.DistanceToPoint(u*0 + v*0), i*0); | TS_ASSERT_EQUALS(goal.DistanceToPoint(u*0 + v*0), i*0); | ||||
} | } | ||||
} | } | ||||
void hierarchical_globalRegions_testmap(std::wstring map) | |||||
{ | |||||
CTerrain terrain; | |||||
CSimulation2 sim2(NULL, g_ScriptRuntime, &terrain); | |||||
sim2.LoadDefaultScripts(); | |||||
sim2.ResetState(); | |||||
CMapReader* mapReader = new CMapReader(); // it'll call "delete this" itself | |||||
LDR_BeginRegistering(); | |||||
mapReader->LoadMap(map, | |||||
sim2.GetScriptInterface().GetJSRuntime(), JS::UndefinedHandleValue, | |||||
&terrain, NULL, NULL, NULL, NULL, NULL, NULL, NULL, | |||||
&sim2, &sim2.GetSimContext(), -1, false); | |||||
LDR_EndRegistering(); | |||||
TS_ASSERT_OK(LDR_NonprogressiveLoad()); | |||||
sim2.PreInitGame(); | |||||
sim2.InitGame(); | |||||
sim2.Update(0); | |||||
CmpPtr<ICmpPathfinder> cmpPathfinder(sim2, SYSTEM_ENTITY); | |||||
pass_class_t obstructionsMask = cmpPathfinder->GetPassabilityClass("default"); | |||||
HierarchicalPathfinder& hier = ((CCmpPathfinder*)cmpPathfinder.operator->())->m_LongPathfinder.GetHierarchicalPathfinder(); | |||||
std::map<HierarchicalPathfinder::RegionID, HierarchicalPathfinder::GlobalRegionID> globalRegions = hier.m_GlobalRegions[obstructionsMask]; | |||||
for (u8 cj = 0; cj < hier.m_ChunksH; cj += 2) | |||||
for (u8 ci = 0; ci < hier.m_ChunksW; ci += 2) | |||||
for(u16 i : hier.GetChunk(ci, cj, obstructionsMask).m_RegionsID) | |||||
{ | |||||
// Assert that all reachable regions are indeed the same region ID | |||||
// This does not highlight that unreachable regions might (wrongly) have the same ID). | |||||
std::set<HierarchicalPathfinder::RegionID> reachables; | |||||
hier.FindReachableRegions(HierarchicalPathfinder::RegionID{ci, cj, i}, reachables, obstructionsMask); | |||||
HierarchicalPathfinder::GlobalRegionID ID = globalRegions[HierarchicalPathfinder::RegionID{ci, cj, i}]; | |||||
for (HierarchicalPathfinder::RegionID region : reachables) | |||||
TS_ASSERT_EQUALS(ID, globalRegions[region]); | |||||
} | |||||
} | |||||
void test_hierarchical_globalRegions() | |||||
{ | |||||
// This test validates that the hierarchical's pathfinder global regions are in accordance with its regions | |||||
// IE it asserts that, for any two regions A and B of the hierarchical pathfinder, if one can find a path from A to B | |||||
// then A and B have the same global region. | |||||
std::vector<std::wstring> maps = { L"maps/scenarios/Peloponnese.pmp", L"maps/skirmishes/Corinthian Isthmus (2).pmp", L"maps/skirmishes/Greek Acropolis (2).pmp" }; | |||||
// disable in debug mode, creating the simulation and running the initial turn is too slow and tends to OOM in debug mode. | |||||
#ifndef DEBUG | |||||
for (std::wstring t : maps) | |||||
hierarchical_globalRegions_testmap(t); | |||||
#endif | |||||
} | |||||
void hierarchical_update_testmap(std::wstring map) | |||||
{ | |||||
CTerrain terrain; | |||||
CSimulation2 sim2(NULL, g_ScriptRuntime, &terrain); | |||||
sim2.LoadDefaultScripts(); | |||||
sim2.ResetState(); | |||||
CMapReader* mapReader = new CMapReader(); // it'll call "delete this" itself | |||||
LDR_BeginRegistering(); | |||||
mapReader->LoadMap(map, | |||||
sim2.GetScriptInterface().GetJSRuntime(), JS::UndefinedHandleValue, | |||||
&terrain, NULL, NULL, NULL, NULL, NULL, NULL, NULL, | |||||
&sim2, &sim2.GetSimContext(), -1, false); | |||||
LDR_EndRegistering(); | |||||
TS_ASSERT_OK(LDR_NonprogressiveLoad()); | |||||
sim2.PreInitGame(); | |||||
sim2.InitGame(); | |||||
sim2.Update(0); | |||||
CmpPtr<ICmpPathfinder> cmpPathfinder(sim2, SYSTEM_ENTITY); | |||||
pass_class_t obstructionsMask = cmpPathfinder->GetPassabilityClass("default"); | |||||
HierarchicalPathfinder& hier = ((CCmpPathfinder*)cmpPathfinder.operator->())->m_LongPathfinder.GetHierarchicalPathfinder(); | |||||
// make copies | |||||
const auto pristine_GR = hier.m_GlobalRegions; | |||||
const auto pristine_Chunks = hier.m_Chunks; | |||||
const HierarchicalPathfinder::EdgesMap pristine_Edges = hier.m_Edges.at(obstructionsMask); | |||||
Grid<NavcellData>* pathfinderGrid = ((CCmpPathfinder*)cmpPathfinder.operator->())->m_LongPathfinder.m_Grid; | |||||
Grid<u8> dirtyGrid(hier.m_ChunksW * HierarchicalPathfinder::CHUNK_SIZE,hier.m_ChunksH * HierarchicalPathfinder::CHUNK_SIZE); | |||||
srand(1234); | |||||
size_t tries = 20; | |||||
for (size_t i = 0; i < tries; ++i) | |||||
{ | |||||
// Dirty a random one | |||||
dirtyGrid.reset(); | |||||
u8 ci = rand() % (hier.m_ChunksW-10) + 8; | |||||
u8 cj = rand() % (hier.m_ChunksH-10) + 8; | |||||
dirtyGrid.set(ci * HierarchicalPathfinder::CHUNK_SIZE + 4, cj * HierarchicalPathfinder::CHUNK_SIZE + 4, 1); | |||||
hier.Update(pathfinderGrid, dirtyGrid); | |||||
// Formally speaking we should rather validate that regions exist with the same pixels, but so far | |||||
// re-initing regions will keep the same IDs for the same pixels so this is OK. | |||||
TS_ASSERT_EQUALS(hier.m_Chunks.at(obstructionsMask), pristine_Chunks.at(obstructionsMask)); | |||||
// same here | |||||
TS_ASSERT_EQUALS(pristine_Edges, hier.m_Edges.at(obstructionsMask)); | |||||
} | |||||
} | |||||
void test_hierarchical_update() | |||||
{ | |||||
// This test validates that the "Update" function of the hierarchical pathfinder | |||||
// ends up in a correct state (by comparing it with the clean, "Recompute"-d state). | |||||
std::vector<std::wstring> maps = { L"maps/scenarios/Peloponnese.pmp", L"maps/skirmishes/Corinthian Isthmus (2).pmp", L"maps/skirmishes/Greek Acropolis (2).pmp" }; | |||||
// disable in debug mode, creating the simulation and running the initial turn is too slow and tends to OOM in debug mode. | |||||
#ifndef DEBUG | |||||
for (std::wstring t : maps) | |||||
hierarchical_update_testmap(t); | |||||
#endif | |||||
} | |||||
void test_performance_DISABLED() | void test_performance_DISABLED() | ||||
{ | { | ||||
CTerrain terrain; | CTerrain terrain; | ||||
CSimulation2 sim2(NULL, g_ScriptRuntime, &terrain); | CSimulation2 sim2(NULL, g_ScriptRuntime, &terrain); | ||||
sim2.LoadDefaultScripts(); | sim2.LoadDefaultScripts(); | ||||
sim2.ResetState(); | sim2.ResetState(); | ||||
std::unique_ptr<CMapReader> mapReader(new CMapReader()); | std::unique_ptr<CMapReader> mapReader(new CMapReader()); | ||||
LDR_BeginRegistering(); | LDR_BeginRegistering(); | ||||
mapReader->LoadMap(L"maps/skirmishes/Median Oasis (2).pmp", | mapReader->LoadMap(L"maps/skirmishes/Median Oasis (2).pmp", | ||||
sim2.GetScriptInterface().GetJSRuntime(), JS::UndefinedHandleValue, | sim2.GetScriptInterface().GetJSRuntime(), JS::UndefinedHandleValue, | ||||
&terrain, NULL, NULL, NULL, NULL, NULL, NULL, NULL, | &terrain, NULL, NULL, NULL, NULL, NULL, NULL, NULL, | ||||
&sim2, &sim2.GetSimContext(), -1, false); | &sim2, &sim2.GetSimContext(), -1, false); | ||||
LDR_EndRegistering(); | LDR_EndRegistering(); | ||||
TS_ASSERT_OK(LDR_NonprogressiveLoad()); | TS_ASSERT_OK(LDR_NonprogressiveLoad()); | ||||
sim2.PreInitGame(); | |||||
sim2.InitGame(); | |||||
sim2.Update(0); | sim2.Update(0); | ||||
CmpPtr<ICmpPathfinder> cmp(sim2, SYSTEM_ENTITY); | CmpPtr<ICmpPathfinder> cmp(sim2, SYSTEM_ENTITY); | ||||
#if 0 | #if 0 | ||||
entity_pos_t x0 = entity_pos_t::FromInt(10); | entity_pos_t x0 = entity_pos_t::FromInt(10); | ||||
entity_pos_t z0 = entity_pos_t::FromInt(495); | entity_pos_t z0 = entity_pos_t::FromInt(495); | ||||
entity_pos_t x1 = entity_pos_t::FromInt(500); | entity_pos_t x1 = entity_pos_t::FromInt(500); | ||||
▲ Show 20 Lines • Show All 95 Lines • ▼ Show 20 Lines | void test_perf2_DISABLED() | ||||
LDR_BeginRegistering(); | LDR_BeginRegistering(); | ||||
mapReader->LoadMap(L"maps/scenarios/Peloponnese.pmp", | mapReader->LoadMap(L"maps/scenarios/Peloponnese.pmp", | ||||
sim2.GetScriptInterface().GetJSRuntime(), JS::UndefinedHandleValue, | sim2.GetScriptInterface().GetJSRuntime(), JS::UndefinedHandleValue, | ||||
&terrain, NULL, NULL, NULL, NULL, NULL, NULL, NULL, | &terrain, NULL, NULL, NULL, NULL, NULL, NULL, NULL, | ||||
&sim2, &sim2.GetSimContext(), -1, false); | &sim2, &sim2.GetSimContext(), -1, false); | ||||
LDR_EndRegistering(); | LDR_EndRegistering(); | ||||
TS_ASSERT_OK(LDR_NonprogressiveLoad()); | TS_ASSERT_OK(LDR_NonprogressiveLoad()); | ||||
sim2.PreInitGame(); | |||||
sim2.InitGame(); | |||||
sim2.Update(0); | sim2.Update(0); | ||||
std::ofstream stream(OsString("perf2.html").c_str(), std::ofstream::out | std::ofstream::trunc); | std::ofstream stream(OsString("perf2.html").c_str(), std::ofstream::out | std::ofstream::trunc); | ||||
CmpPtr<ICmpObstructionManager> cmpObstructionManager(sim2, SYSTEM_ENTITY); | CmpPtr<ICmpObstructionManager> cmpObstructionManager(sim2, SYSTEM_ENTITY); | ||||
CmpPtr<ICmpPathfinder> cmpPathfinder(sim2, SYSTEM_ENTITY); | CmpPtr<ICmpPathfinder> cmpPathfinder(sim2, SYSTEM_ENTITY); | ||||
pass_class_t obstructionsMask = cmpPathfinder->GetPassabilityClass("default"); | pass_class_t obstructionsMask = cmpPathfinder->GetPassabilityClass("default"); | ||||
Show All 39 Lines | void test_perf3_DISABLED() | ||||
LDR_BeginRegistering(); | LDR_BeginRegistering(); | ||||
mapReader->LoadMap(L"maps/scenarios/Peloponnese.pmp", | mapReader->LoadMap(L"maps/scenarios/Peloponnese.pmp", | ||||
sim2.GetScriptInterface().GetJSRuntime(), JS::UndefinedHandleValue, | sim2.GetScriptInterface().GetJSRuntime(), JS::UndefinedHandleValue, | ||||
&terrain, NULL, NULL, NULL, NULL, NULL, NULL, NULL, | &terrain, NULL, NULL, NULL, NULL, NULL, NULL, NULL, | ||||
&sim2, &sim2.GetSimContext(), -1, false); | &sim2, &sim2.GetSimContext(), -1, false); | ||||
LDR_EndRegistering(); | LDR_EndRegistering(); | ||||
TS_ASSERT_OK(LDR_NonprogressiveLoad()); | TS_ASSERT_OK(LDR_NonprogressiveLoad()); | ||||
sim2.PreInitGame(); | |||||
sim2.InitGame(); | |||||
sim2.Update(0); | sim2.Update(0); | ||||
std::ofstream stream(OsString("perf3.html").c_str(), std::ofstream::out | std::ofstream::trunc); | std::ofstream stream(OsString("perf3.html").c_str(), std::ofstream::out | std::ofstream::trunc); | ||||
CmpPtr<ICmpObstructionManager> cmpObstructionManager(sim2, SYSTEM_ENTITY); | CmpPtr<ICmpObstructionManager> cmpObstructionManager(sim2, SYSTEM_ENTITY); | ||||
CmpPtr<ICmpPathfinder> cmpPathfinder(sim2, SYSTEM_ENTITY); | CmpPtr<ICmpPathfinder> cmpPathfinder(sim2, SYSTEM_ENTITY); | ||||
pass_class_t obstructionsMask = cmpPathfinder->GetPassabilityClass("default"); | pass_class_t obstructionsMask = cmpPathfinder->GetPassabilityClass("default"); | ||||
▲ Show 20 Lines • Show All 86 Lines • ▼ Show 20 Lines | void RepeatPath(int n, int i0, int j0, int i1, int j1, CmpPtr<ICmpPathfinder>& cmpPathfinder) | ||||
{ | { | ||||
WaypointPath path; | WaypointPath path; | ||||
cmpPathfinder->ComputePath(x0, z0, goal, cmpPathfinder->GetPassabilityClass("default"), path); | cmpPathfinder->ComputePath(x0, z0, goal, cmpPathfinder->GetPassabilityClass("default"), path); | ||||
} | } | ||||
t = timer_Time() - t; | t = timer_Time() - t; | ||||
debug_printf("### RepeatPath %fms each (%fs total)\n", 1000*t / n, t); | debug_printf("### RepeatPath %fms each (%fs total)\n", 1000*t / n, t); | ||||
} | } | ||||
}; | }; | ||||
elexis: :s | |||||
Done Inline ActionsDeleted this horrible test hack. wraitii: Deleted this horrible test hack. |
Wildfire Games · Phabricator
:s