Support random map script tests, fixes #4827.
Differential Revision: https://code.wildfiregames.com/D2085 Comments By: wraitii This was SVN commit r23455.
This commit is contained in:
parent
67a4c18c74
commit
0a6db43c83
@ -1,14 +1,16 @@
|
|||||||
function RandomMapLogger()
|
function RandomMapLogger()
|
||||||
{
|
{
|
||||||
this.lastTime = undefined;
|
this.lastTime = undefined;
|
||||||
this.startTime = Engine.GetMicroseconds();
|
this.startTime = Engine.GetMicroseconds ? Engine.GetMicroseconds() : 0;
|
||||||
this.prefix = ""; // seems noisy
|
this.prefix = ""; // seems noisy
|
||||||
|
|
||||||
|
// Don't print in test cases
|
||||||
|
if (g_MapSettings.Name)
|
||||||
this.printDirectly(
|
this.printDirectly(
|
||||||
this.prefix +
|
this.prefix +
|
||||||
"Generating " + g_MapSettings.Name +
|
"Generating " + g_MapSettings.Name +
|
||||||
" of size " + g_MapSettings.Size +
|
" of size " + g_MapSettings.Size +
|
||||||
" and " + getNumPlayers() + " players.\n");
|
" and " + (g_MapSettings.PlayerData.length - 1) + " players.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
RandomMapLogger.prototype.printDirectly = function(string)
|
RandomMapLogger.prototype.printDirectly = function(string)
|
||||||
|
@ -0,0 +1,91 @@
|
|||||||
|
Engine.LoadLibrary("rmgen");
|
||||||
|
|
||||||
|
var g_MapSettings = { "Size": 512 };
|
||||||
|
var g_Map = new RandomMap(0, "blackness");
|
||||||
|
|
||||||
|
// Test that that it checks by value, not by reference
|
||||||
|
{
|
||||||
|
let tileClass = new TileClass(2);
|
||||||
|
let reference1 = new Vector2D(1, 1);
|
||||||
|
let reference2 = new Vector2D(1, 1);
|
||||||
|
tileClass.add(reference1);
|
||||||
|
TS_ASSERT(tileClass.has(reference2));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test out-of-bounds
|
||||||
|
{
|
||||||
|
let tileClass = new TileClass(32);
|
||||||
|
let absentPoints = [
|
||||||
|
new Vector2D(0, 0),
|
||||||
|
new Vector2D(0, 1),
|
||||||
|
new Vector2D(1, 0),
|
||||||
|
new Vector2D(-1, -1),
|
||||||
|
new Vector2D(2048, 0),
|
||||||
|
new Vector2D(0, NaN),
|
||||||
|
new Vector2D(0, Infinity)
|
||||||
|
];
|
||||||
|
|
||||||
|
for (let point of absentPoints)
|
||||||
|
TS_ASSERT(!tileClass.has(point));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test multi-insertion
|
||||||
|
{
|
||||||
|
let tileClass = new TileClass(32);
|
||||||
|
let point = new Vector2D(1, 1);
|
||||||
|
|
||||||
|
tileClass.add(point);
|
||||||
|
tileClass.add(point);
|
||||||
|
TS_ASSERT_EQUALS(tileClass.countMembersInRadius(point, 0), 1);
|
||||||
|
|
||||||
|
// Still one point remaining
|
||||||
|
tileClass.remove(point);
|
||||||
|
tileClass.remove(point);
|
||||||
|
TS_ASSERT(!tileClass.has(point));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test multi-insertion removal
|
||||||
|
{
|
||||||
|
let tileClass = new TileClass(32);
|
||||||
|
let point = new Vector2D(2, 7);
|
||||||
|
|
||||||
|
tileClass.add(point);
|
||||||
|
tileClass.add(point);
|
||||||
|
tileClass.remove(point);
|
||||||
|
TS_ASSERT(tileClass.has(point));
|
||||||
|
|
||||||
|
tileClass.remove(point);
|
||||||
|
TS_ASSERT(!tileClass.has(point));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test multi-insertion removal
|
||||||
|
{
|
||||||
|
let tileClass = new TileClass(55);
|
||||||
|
let point = new Vector2D(5, 4);
|
||||||
|
|
||||||
|
for (let i = 0; i < 50; ++i)
|
||||||
|
tileClass.add(point);
|
||||||
|
|
||||||
|
tileClass.remove(point);
|
||||||
|
TS_ASSERT(tileClass.has(point));
|
||||||
|
|
||||||
|
tileClass.remove(point);
|
||||||
|
TS_ASSERT(tileClass.has(point));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test getters
|
||||||
|
{
|
||||||
|
let tileClass = new TileClass(88);
|
||||||
|
let point = new Vector2D(5, 1);
|
||||||
|
tileClass.add(point);
|
||||||
|
|
||||||
|
let point2 = new Vector2D(4, 9);
|
||||||
|
tileClass.add(point2);
|
||||||
|
|
||||||
|
TS_ASSERT_EQUALS(tileClass.countMembersInRadius(point, 1), 1);
|
||||||
|
TS_ASSERT_EQUALS(tileClass.countMembersInRadius(point, 100), 2);
|
||||||
|
|
||||||
|
TS_ASSERT_EQUALS(tileClass.countNonMembersInRadius(point, 1), 4);
|
||||||
|
TS_ASSERT_EQUALS(tileClass.countNonMembersInRadius(point, 2), 12);
|
||||||
|
TS_ASSERT_EQUALS(tileClass.countNonMembersInRadius(point, 3), 28);
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2019 Wildfire Games.
|
/* Copyright (C) 2020 Wildfire Games.
|
||||||
* 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
|
||||||
@ -57,7 +57,8 @@ MapGeneratorInterruptCallback(JSContext* UNUSED(cx))
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
CMapGeneratorWorker::CMapGeneratorWorker()
|
CMapGeneratorWorker::CMapGeneratorWorker(ScriptInterface* scriptInterface) :
|
||||||
|
m_ScriptInterface(scriptInterface)
|
||||||
{
|
{
|
||||||
// If something happens before we initialize, that's a failure
|
// If something happens before we initialize, that's a failure
|
||||||
m_Progress = -1;
|
m_Progress = -1;
|
||||||
@ -66,6 +67,7 @@ CMapGeneratorWorker::CMapGeneratorWorker()
|
|||||||
CMapGeneratorWorker::~CMapGeneratorWorker()
|
CMapGeneratorWorker::~CMapGeneratorWorker()
|
||||||
{
|
{
|
||||||
// Wait for thread to end
|
// Wait for thread to end
|
||||||
|
if (m_WorkerThread.joinable())
|
||||||
m_WorkerThread.join();
|
m_WorkerThread.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,13 +118,6 @@ bool CMapGeneratorWorker::Run()
|
|||||||
JSContext* cx = m_ScriptInterface->GetContext();
|
JSContext* cx = m_ScriptInterface->GetContext();
|
||||||
JSAutoRequest rq(cx);
|
JSAutoRequest rq(cx);
|
||||||
|
|
||||||
m_ScriptInterface->SetCallbackData(static_cast<void*> (this));
|
|
||||||
|
|
||||||
// Replace RNG with a seeded deterministic function
|
|
||||||
m_ScriptInterface->ReplaceNondeterministicRNG(m_MapGenRNG);
|
|
||||||
|
|
||||||
RegisterScriptFunctions();
|
|
||||||
|
|
||||||
// Parse settings
|
// Parse settings
|
||||||
JS::RootedValue settingsVal(cx);
|
JS::RootedValue settingsVal(cx);
|
||||||
if (!m_ScriptInterface->ParseJSON(m_Settings, &settingsVal) && settingsVal.isUndefined())
|
if (!m_ScriptInterface->ParseJSON(m_Settings, &settingsVal) && settingsVal.isUndefined())
|
||||||
@ -144,7 +139,9 @@ bool CMapGeneratorWorker::Run()
|
|||||||
!m_ScriptInterface->GetProperty(settingsVal, "Seed", seed))
|
!m_ScriptInterface->GetProperty(settingsVal, "Seed", seed))
|
||||||
LOGWARNING("CMapGeneratorWorker::Run: No seed value specified - using 0");
|
LOGWARNING("CMapGeneratorWorker::Run: No seed value specified - using 0");
|
||||||
|
|
||||||
m_MapGenRNG.seed(seed);
|
InitScriptInterface(seed);
|
||||||
|
|
||||||
|
RegisterScriptFunctions_MapGenerator();
|
||||||
|
|
||||||
// Copy settings to global variable
|
// Copy settings to global variable
|
||||||
JS::RootedValue global(cx, m_ScriptInterface->GetGlobalObject());
|
JS::RootedValue global(cx, m_ScriptInterface->GetGlobalObject());
|
||||||
@ -165,8 +162,13 @@ bool CMapGeneratorWorker::Run()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMapGeneratorWorker::RegisterScriptFunctions()
|
void CMapGeneratorWorker::InitScriptInterface(const u32 seed)
|
||||||
{
|
{
|
||||||
|
m_ScriptInterface->SetCallbackData(static_cast<void*>(this));
|
||||||
|
|
||||||
|
m_ScriptInterface->ReplaceNondeterministicRNG(m_MapGenRNG);
|
||||||
|
m_MapGenRNG.seed(seed);
|
||||||
|
|
||||||
// VFS
|
// VFS
|
||||||
JSI_VFS::RegisterScriptFunctions_Maps(*m_ScriptInterface);
|
JSI_VFS::RegisterScriptFunctions_Maps(*m_ScriptInterface);
|
||||||
|
|
||||||
@ -178,17 +180,6 @@ void CMapGeneratorWorker::RegisterScriptFunctions()
|
|||||||
m_ScriptInterface->RegisterFunction<JS::Value, VfsPath, CMapGeneratorWorker::LoadHeightmap>("LoadHeightmapImage");
|
m_ScriptInterface->RegisterFunction<JS::Value, VfsPath, CMapGeneratorWorker::LoadHeightmap>("LoadHeightmapImage");
|
||||||
m_ScriptInterface->RegisterFunction<JS::Value, VfsPath, CMapGeneratorWorker::LoadMapTerrain>("LoadMapTerrain");
|
m_ScriptInterface->RegisterFunction<JS::Value, VfsPath, CMapGeneratorWorker::LoadMapTerrain>("LoadMapTerrain");
|
||||||
|
|
||||||
// Progression and profiling
|
|
||||||
m_ScriptInterface->RegisterFunction<void, int, CMapGeneratorWorker::SetProgress>("SetProgress");
|
|
||||||
m_ScriptInterface->RegisterFunction<double, CMapGeneratorWorker::GetMicroseconds>("GetMicroseconds");
|
|
||||||
m_ScriptInterface->RegisterFunction<void, JS::HandleValue, CMapGeneratorWorker::ExportMap>("ExportMap");
|
|
||||||
|
|
||||||
// Template functions
|
|
||||||
m_ScriptInterface->RegisterFunction<CParamNode, std::string, CMapGeneratorWorker::GetTemplate>("GetTemplate");
|
|
||||||
m_ScriptInterface->RegisterFunction<bool, std::string, CMapGeneratorWorker::TemplateExists>("TemplateExists");
|
|
||||||
m_ScriptInterface->RegisterFunction<std::vector<std::string>, std::string, bool, CMapGeneratorWorker::FindTemplates>("FindTemplates");
|
|
||||||
m_ScriptInterface->RegisterFunction<std::vector<std::string>, std::string, bool, CMapGeneratorWorker::FindActorTemplates>("FindActorTemplates");
|
|
||||||
|
|
||||||
// Engine constants
|
// Engine constants
|
||||||
|
|
||||||
// Length of one tile of the terrain grid in metres.
|
// Length of one tile of the terrain grid in metres.
|
||||||
@ -199,6 +190,20 @@ void CMapGeneratorWorker::RegisterScriptFunctions()
|
|||||||
m_ScriptInterface->SetGlobal("MAP_BORDER_WIDTH", static_cast<int>(MAP_EDGE_TILES));
|
m_ScriptInterface->SetGlobal("MAP_BORDER_WIDTH", static_cast<int>(MAP_EDGE_TILES));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CMapGeneratorWorker::RegisterScriptFunctions_MapGenerator()
|
||||||
|
{
|
||||||
|
// Template functions
|
||||||
|
m_ScriptInterface->RegisterFunction<CParamNode, std::string, CMapGeneratorWorker::GetTemplate>("GetTemplate");
|
||||||
|
m_ScriptInterface->RegisterFunction<bool, std::string, CMapGeneratorWorker::TemplateExists>("TemplateExists");
|
||||||
|
m_ScriptInterface->RegisterFunction<std::vector<std::string>, std::string, bool, CMapGeneratorWorker::FindTemplates>("FindTemplates");
|
||||||
|
m_ScriptInterface->RegisterFunction<std::vector<std::string>, std::string, bool, CMapGeneratorWorker::FindActorTemplates>("FindActorTemplates");
|
||||||
|
|
||||||
|
// Progression and profiling
|
||||||
|
m_ScriptInterface->RegisterFunction<void, int, CMapGeneratorWorker::SetProgress>("SetProgress");
|
||||||
|
m_ScriptInterface->RegisterFunction<double, CMapGeneratorWorker::GetMicroseconds>("GetMicroseconds");
|
||||||
|
m_ScriptInterface->RegisterFunction<void, JS::HandleValue, CMapGeneratorWorker::ExportMap>("ExportMap");
|
||||||
|
}
|
||||||
|
|
||||||
int CMapGeneratorWorker::GetProgress()
|
int CMapGeneratorWorker::GetProgress()
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(m_WorkerMutex);
|
std::lock_guard<std::mutex> lock(m_WorkerMutex);
|
||||||
@ -410,7 +415,7 @@ JS::Value CMapGeneratorWorker::LoadMapTerrain(ScriptInterface::CxPrivate* pCxPri
|
|||||||
//////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////
|
||||||
//////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
CMapGenerator::CMapGenerator() : m_Worker(new CMapGeneratorWorker())
|
CMapGenerator::CMapGenerator() : m_Worker(new CMapGeneratorWorker(nullptr))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2019 Wildfire Games.
|
/* Copyright (C) 2020 Wildfire Games.
|
||||||
* 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
|
||||||
@ -86,7 +86,7 @@ private:
|
|||||||
class CMapGeneratorWorker
|
class CMapGeneratorWorker
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CMapGeneratorWorker();
|
CMapGeneratorWorker(ScriptInterface* scriptInterface);
|
||||||
~CMapGeneratorWorker();
|
~CMapGeneratorWorker();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -112,12 +112,18 @@ public:
|
|||||||
*/
|
*/
|
||||||
shared_ptr<ScriptInterface::StructuredClone> GetResults();
|
shared_ptr<ScriptInterface::StructuredClone> GetResults();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set initial seed, callback data.
|
||||||
|
* Expose functions, globals and classes defined in this class relevant to the map and test scripts.
|
||||||
|
*/
|
||||||
|
void InitScriptInterface(const u32 seed);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Expose functions defined in this class to the script.
|
* Expose functions defined in this class that are relevant to mapscripts but not the tests.
|
||||||
*/
|
*/
|
||||||
void RegisterScriptFunctions();
|
void RegisterScriptFunctions_MapGenerator();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load all scripts of the given library
|
* Load all scripts of the given library
|
||||||
|
54
source/graphics/tests/test_MapGenerator.h
Normal file
54
source/graphics/tests/test_MapGenerator.h
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
/* Copyright (C) 2020 Wildfire Games.
|
||||||
|
* This file is part of 0 A.D.
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* the Free Software Foundation, either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* 0 A.D. is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "graphics/MapGenerator.h"
|
||||||
|
#include "ps/Filesystem.h"
|
||||||
|
#include "simulation2/system/ComponentTest.h"
|
||||||
|
|
||||||
|
class TestMapGenerator : public CxxTest::TestSuite
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void setUp()
|
||||||
|
{
|
||||||
|
g_VFS = CreateVfs();
|
||||||
|
g_VFS->Mount(L"", DataDir() / "mods" / "mod", VFS_MOUNT_MUST_EXIST);
|
||||||
|
g_VFS->Mount(L"", DataDir() / "mods" / "public", VFS_MOUNT_MUST_EXIST, 1); // ignore directory-not-found errors
|
||||||
|
CXeromyces::Startup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void tearDown()
|
||||||
|
{
|
||||||
|
CXeromyces::Terminate();
|
||||||
|
g_VFS.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_mapgen_scripts()
|
||||||
|
{
|
||||||
|
VfsPaths paths;
|
||||||
|
TS_ASSERT_OK(vfs::GetPathnames(g_VFS, L"maps/random/tests/", L"test_*.js", paths));
|
||||||
|
|
||||||
|
for (const VfsPath& path : paths)
|
||||||
|
{
|
||||||
|
ScriptInterface scriptInterface("Engine", "MapGenerator", g_ScriptRuntime);
|
||||||
|
ScriptTestSetup(scriptInterface);
|
||||||
|
|
||||||
|
CMapGeneratorWorker worker(&scriptInterface);
|
||||||
|
worker.InitScriptInterface(0);
|
||||||
|
scriptInterface.LoadGlobalScriptFile(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user