2020-11-11 00:43:13 -08:00
|
|
|
/* Copyright (C) 2020 Wildfire Games.
|
2011-01-12 04:29:00 -08:00
|
|
|
* 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 "precompiled.h"
|
|
|
|
|
|
|
|
|
|
#include "simulation2/system/Component.h"
|
|
|
|
|
#include "ICmpAIManager.h"
|
|
|
|
|
|
2011-03-04 17:56:59 -08:00
|
|
|
#include "simulation2/MessageTypes.h"
|
|
|
|
|
|
2011-02-10 08:06:28 -08:00
|
|
|
#include "graphics/Terrain.h"
|
2011-01-12 04:29:00 -08:00
|
|
|
#include "lib/timer.h"
|
2011-02-10 08:06:28 -08:00
|
|
|
#include "lib/tex/tex.h"
|
2011-04-29 12:10:34 -07:00
|
|
|
#include "lib/allocators/shared_ptr.h"
|
2011-01-12 04:29:00 -08:00
|
|
|
#include "ps/CLogger.h"
|
|
|
|
|
#include "ps/Filesystem.h"
|
2016-06-21 03:33:11 -07:00
|
|
|
#include "ps/Profile.h"
|
2017-12-06 12:26:01 -08:00
|
|
|
#include "ps/scripting/JSInterface_VFS.h"
|
2017-08-07 12:35:43 -07:00
|
|
|
#include "ps/TemplateLoader.h"
|
2011-02-10 08:06:28 -08:00
|
|
|
#include "ps/Util.h"
|
2021-03-02 12:01:14 -08:00
|
|
|
#include "scriptinterface/FunctionWrapper.h"
|
2020-11-14 02:57:50 -08:00
|
|
|
#include "scriptinterface/ScriptContext.h"
|
2011-01-12 04:29:00 -08:00
|
|
|
#include "simulation2/components/ICmpAIInterface.h"
|
|
|
|
|
#include "simulation2/components/ICmpCommandQueue.h"
|
2011-02-10 08:06:28 -08:00
|
|
|
#include "simulation2/components/ICmpObstructionManager.h"
|
2011-06-28 16:24:42 -07:00
|
|
|
#include "simulation2/components/ICmpRangeManager.h"
|
2011-01-12 04:29:00 -08:00
|
|
|
#include "simulation2/components/ICmpTemplateManager.h"
|
2011-10-15 19:55:58 -07:00
|
|
|
#include "simulation2/components/ICmpTerritoryManager.h"
|
2019-05-13 09:58:00 -07:00
|
|
|
#include "simulation2/helpers/HierarchicalPathfinder.h"
|
New long-range pathfinder.
Based on Philip's work located at
http://git.wildfiregames.com/gitweb/?p=0ad.git;a=shortlog;h=refs/heads/projects/philip/pathfinder
Includes code by wraitii, sanderd17 and kanetaka.
An updated version of docs/pathfinder.pdf describing the changes in
detail will be committed ASAP.
Running update-workspaces is needed after this change.
Fixes #1756.
Fixes #930, #1259, #2908, #2960, #3097
Refs #1200, #1914, #1942, #2568, #2132, #2563
This was SVN commit r16751.
2015-06-12 11:58:24 -07:00
|
|
|
#include "simulation2/helpers/LongPathfinder.h"
|
2011-01-12 04:29:00 -08:00
|
|
|
#include "simulation2/serialization/DebugSerializer.h"
|
2020-12-19 01:10:37 -08:00
|
|
|
#include "simulation2/serialization/SerializedTypes.h"
|
2011-01-12 04:29:00 -08:00
|
|
|
#include "simulation2/serialization/StdDeserializer.h"
|
|
|
|
|
#include "simulation2/serialization/StdSerializer.h"
|
|
|
|
|
|
2018-05-08 02:45:54 -07:00
|
|
|
extern void QuitEngine();
|
2017-01-19 06:45:32 -08:00
|
|
|
|
2011-01-12 04:29:00 -08:00
|
|
|
/**
|
2012-02-29 19:55:05 -08:00
|
|
|
* @file
|
|
|
|
|
* Player AI interface.
|
2011-01-12 04:29:00 -08:00
|
|
|
* AI is primarily scripted, and the CCmpAIManager component defined here
|
|
|
|
|
* takes care of managing all the scripts.
|
|
|
|
|
*
|
|
|
|
|
* To avoid slow AI scripts causing jerky rendering, they are run in a background
|
|
|
|
|
* thread (maintained by CAIWorker) so that it's okay if they take a whole simulation
|
|
|
|
|
* turn before returning their results (though preferably they shouldn't use nearly
|
|
|
|
|
* that much CPU).
|
|
|
|
|
*
|
|
|
|
|
* CCmpAIManager grabs the world state after each turn (making use of AIInterface.js
|
|
|
|
|
* and AIProxy.js to decide what data to include) then passes it to CAIWorker.
|
|
|
|
|
* The AI scripts will then run asynchronously and return a list of commands to execute.
|
|
|
|
|
* Any attempts to read the command list (including indirectly via serialization)
|
|
|
|
|
* will block until it's actually completed, so the rest of the engine should avoid
|
|
|
|
|
* reading it for as long as possible.
|
|
|
|
|
*
|
2017-08-28 03:27:36 -07:00
|
|
|
* JS::Values are passed between the game and AI threads using ScriptInterface::StructuredClone.
|
2011-01-15 15:35:20 -08:00
|
|
|
*
|
2011-01-12 04:29:00 -08:00
|
|
|
* TODO: actually the thread isn't implemented yet, because performance hasn't been
|
|
|
|
|
* sufficiently problematic to justify the complexity yet, but the CAIWorker interface
|
|
|
|
|
* is designed to hopefully support threading when we want it.
|
|
|
|
|
*/
|
|
|
|
|
|
2012-02-29 19:55:05 -08:00
|
|
|
/**
|
|
|
|
|
* Implements worker thread for CCmpAIManager.
|
|
|
|
|
*/
|
2011-01-12 04:29:00 -08:00
|
|
|
class CAIWorker
|
|
|
|
|
{
|
|
|
|
|
private:
|
2011-01-15 15:35:20 -08:00
|
|
|
class CAIPlayer
|
2011-01-12 04:29:00 -08:00
|
|
|
{
|
2011-01-15 15:35:20 -08:00
|
|
|
NONCOPYABLE(CAIPlayer);
|
|
|
|
|
public:
|
2017-12-20 14:02:15 -08:00
|
|
|
CAIPlayer(CAIWorker& worker, const std::wstring& aiName, player_id_t player, u8 difficulty, const std::wstring& behavior,
|
2013-12-30 02:04:59 -08:00
|
|
|
shared_ptr<ScriptInterface> scriptInterface) :
|
2017-12-20 14:02:15 -08:00
|
|
|
m_Worker(worker), m_AIName(aiName), m_Player(player), m_Difficulty(difficulty), m_Behavior(behavior),
|
2020-11-18 06:39:04 -08:00
|
|
|
m_ScriptInterface(scriptInterface), m_Obj(scriptInterface->GetGeneralJSContext())
|
2011-01-15 15:35:20 -08:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2014-08-02 06:22:02 -07:00
|
|
|
bool Initialise()
|
2011-01-15 15:35:20 -08:00
|
|
|
{
|
2013-12-30 02:04:59 -08:00
|
|
|
// LoadScripts will only load each script once even though we call it for each player
|
|
|
|
|
if (!m_Worker.LoadScripts(m_AIName))
|
2011-01-15 15:35:20 -08:00
|
|
|
return false;
|
2015-06-17 13:35:23 -07:00
|
|
|
|
Improve JS Exception handling.
- Check for pending exceptions after function calls and script
executions.
- Call LOGERROR instead of JS_ReportError when there is a conversion
error in FromJSVal, since that can only be called from C++ (where JS
errors don't really make sense). Instead, C++ callers of FromJSVal
should handle the failure and, themselves, either report an error or
simply do something else.
- Wrap JS_ReportError since that makes updating it later easier.
This isn't a systematical fix since ToJSVal also ought return a boolean
for failures, and we probably should trigger errors instead of warnings
on 'implicit' conversions, rather a preparation diff.
Part of the SM52 migration, stage: SM45 compatible (actually SM52
incompatible, too).
Based on a patch by: Itms
Comments by: Vladislavbelov, Stan`
Refs #742, #4893
Differential Revision: https://code.wildfiregames.com/D3093
This was SVN commit r24187.
2020-11-15 10:29:17 -08:00
|
|
|
ScriptRequest rq(m_ScriptInterface);
|
2011-01-15 15:35:20 -08:00
|
|
|
|
2011-03-23 06:36:20 -07:00
|
|
|
OsPath path = L"simulation/ai/" + m_AIName + L"/data.json";
|
2020-11-13 05:18:22 -08:00
|
|
|
JS::RootedValue metadata(rq.cx);
|
2014-08-02 15:21:50 -07:00
|
|
|
m_Worker.LoadMetadata(path, &metadata);
|
2014-07-26 15:33:16 -07:00
|
|
|
if (metadata.isUndefined())
|
2011-01-15 15:35:20 -08:00
|
|
|
{
|
2015-01-22 12:36:24 -08:00
|
|
|
LOGERROR("Failed to create AI player: can't find %s", path.string8());
|
2011-01-15 15:35:20 -08:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get the constructor name from the metadata
|
2013-12-30 02:04:59 -08:00
|
|
|
std::string moduleName;
|
2011-01-15 15:35:20 -08:00
|
|
|
std::string constructor;
|
2020-11-13 05:18:22 -08:00
|
|
|
JS::RootedValue objectWithConstructor(rq.cx); // object that should contain the constructor function
|
2020-11-14 00:46:32 -08:00
|
|
|
JS::RootedValue global(rq.cx, rq.globalValue());
|
2020-11-13 05:18:22 -08:00
|
|
|
JS::RootedValue ctor(rq.cx);
|
2014-07-26 15:33:16 -07:00
|
|
|
if (!m_ScriptInterface->HasProperty(metadata, "moduleName"))
|
2013-12-30 02:04:59 -08:00
|
|
|
{
|
2015-01-22 12:36:24 -08:00
|
|
|
LOGERROR("Failed to create AI player: %s: missing 'moduleName'", path.string8());
|
2014-12-22 17:20:50 -08:00
|
|
|
return false;
|
2013-12-30 02:04:59 -08:00
|
|
|
}
|
2014-12-22 17:20:50 -08:00
|
|
|
|
|
|
|
|
m_ScriptInterface->GetProperty(metadata, "moduleName", moduleName);
|
|
|
|
|
if (!m_ScriptInterface->GetProperty(global, moduleName.c_str(), &objectWithConstructor)
|
|
|
|
|
|| objectWithConstructor.isUndefined())
|
2013-12-30 02:04:59 -08:00
|
|
|
{
|
2015-01-22 12:37:38 -08:00
|
|
|
LOGERROR("Failed to create AI player: %s: can't find the module that should contain the constructor: '%s'", path.string8(), moduleName);
|
2014-12-22 17:20:50 -08:00
|
|
|
return false;
|
2013-12-30 02:04:59 -08:00
|
|
|
}
|
2014-12-22 17:20:50 -08:00
|
|
|
|
2014-07-26 15:33:16 -07:00
|
|
|
if (!m_ScriptInterface->GetProperty(metadata, "constructor", constructor))
|
2011-01-15 15:35:20 -08:00
|
|
|
{
|
2015-01-22 12:36:24 -08:00
|
|
|
LOGERROR("Failed to create AI player: %s: missing 'constructor'", path.string8());
|
2011-01-15 15:35:20 -08:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get the constructor function from the loaded scripts
|
2014-08-02 09:30:15 -07:00
|
|
|
if (!m_ScriptInterface->GetProperty(objectWithConstructor, constructor.c_str(), &ctor)
|
2014-12-22 17:20:50 -08:00
|
|
|
|| ctor.isNull())
|
2011-01-15 15:35:20 -08:00
|
|
|
{
|
2015-01-22 12:37:38 -08:00
|
|
|
LOGERROR("Failed to create AI player: %s: can't find constructor '%s'", path.string8(), constructor);
|
2011-01-15 15:35:20 -08:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-26 15:33:16 -07:00
|
|
|
m_ScriptInterface->GetProperty(metadata, "useShared", m_UseSharedComponent);
|
2014-08-02 06:22:02 -07:00
|
|
|
|
|
|
|
|
// Set up the data to pass as the constructor argument
|
2020-11-13 05:18:22 -08:00
|
|
|
JS::RootedValue settings(rq.cx);
|
2019-09-12 17:56:51 -07:00
|
|
|
ScriptInterface::CreateObject(
|
2020-11-13 05:18:22 -08:00
|
|
|
rq,
|
2019-09-07 09:51:44 -07:00
|
|
|
&settings,
|
|
|
|
|
"player", m_Player,
|
|
|
|
|
"difficulty", m_Difficulty,
|
|
|
|
|
"behavior", m_Behavior);
|
2017-12-20 14:02:15 -08:00
|
|
|
|
2017-11-24 11:13:28 -08:00
|
|
|
if (!m_UseSharedComponent)
|
|
|
|
|
{
|
|
|
|
|
ENSURE(m_Worker.m_HasLoadedEntityTemplates);
|
|
|
|
|
m_ScriptInterface->SetProperty(settings, "templates", m_Worker.m_EntityTemplates, false);
|
|
|
|
|
}
|
2014-08-02 06:22:02 -07:00
|
|
|
|
2020-11-30 01:03:20 -08:00
|
|
|
JS::RootedValueVector argv(rq.cx);
|
2020-12-15 01:03:44 -08:00
|
|
|
ignore_result(argv.append(settings.get()));
|
2015-01-24 06:46:52 -08:00
|
|
|
m_ScriptInterface->CallConstructor(ctor, argv, &m_Obj);
|
2011-01-15 15:35:20 -08:00
|
|
|
|
2015-01-24 06:46:52 -08:00
|
|
|
if (m_Obj.get().isNull())
|
2011-01-15 15:35:20 -08:00
|
|
|
{
|
2015-01-22 12:37:38 -08:00
|
|
|
LOGERROR("Failed to create AI player: %s: error calling constructor '%s'", path.string8(), constructor);
|
2011-01-15 15:35:20 -08:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-26 15:33:16 -07:00
|
|
|
void Run(JS::HandleValue state, int playerID)
|
2011-01-15 15:35:20 -08:00
|
|
|
{
|
|
|
|
|
m_Commands.clear();
|
2015-01-24 06:46:52 -08:00
|
|
|
m_ScriptInterface->CallFunctionVoid(m_Obj, "HandleMessage", state, playerID);
|
2011-01-15 15:35:20 -08:00
|
|
|
}
|
2013-03-05 14:52:48 -08:00
|
|
|
// overloaded with a sharedAI part.
|
|
|
|
|
// javascript can handle both natively on the same function.
|
2015-01-24 06:46:52 -08:00
|
|
|
void Run(JS::HandleValue state, int playerID, JS::HandleValue SharedAI)
|
2013-03-05 14:52:48 -08:00
|
|
|
{
|
|
|
|
|
m_Commands.clear();
|
2015-01-24 06:46:52 -08:00
|
|
|
m_ScriptInterface->CallFunctionVoid(m_Obj, "HandleMessage", state, playerID, SharedAI);
|
2013-03-05 14:52:48 -08:00
|
|
|
}
|
2015-01-24 06:46:52 -08:00
|
|
|
void InitAI(JS::HandleValue state, JS::HandleValue SharedAI)
|
2013-03-05 14:52:48 -08:00
|
|
|
{
|
|
|
|
|
m_Commands.clear();
|
2015-01-24 06:46:52 -08:00
|
|
|
m_ScriptInterface->CallFunctionVoid(m_Obj, "Init", state, m_Player, SharedAI);
|
2013-03-05 14:52:48 -08:00
|
|
|
}
|
2011-01-15 15:35:20 -08:00
|
|
|
|
|
|
|
|
CAIWorker& m_Worker;
|
|
|
|
|
std::wstring m_AIName;
|
|
|
|
|
player_id_t m_Player;
|
2015-05-07 12:09:39 -07:00
|
|
|
u8 m_Difficulty;
|
2017-12-20 14:02:15 -08:00
|
|
|
std::wstring m_Behavior;
|
2013-03-05 14:52:48 -08:00
|
|
|
bool m_UseSharedComponent;
|
2015-06-17 13:35:23 -07:00
|
|
|
|
2015-01-24 06:46:52 -08:00
|
|
|
// Take care to keep this declaration before heap rooted members. Destructors of heap rooted
|
2020-11-14 02:57:50 -08:00
|
|
|
// members have to be called before the context destructor.
|
2013-12-30 02:04:59 -08:00
|
|
|
shared_ptr<ScriptInterface> m_ScriptInterface;
|
2015-06-17 13:35:23 -07:00
|
|
|
|
2015-01-24 06:46:52 -08:00
|
|
|
JS::PersistentRootedValue m_Obj;
|
2020-11-18 06:39:04 -08:00
|
|
|
std::vector<ScriptInterface::StructuredClone > m_Commands;
|
2011-01-12 04:29:00 -08:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
public:
|
2011-01-15 15:35:20 -08:00
|
|
|
struct SCommandSets
|
2011-01-12 04:29:00 -08:00
|
|
|
{
|
|
|
|
|
player_id_t player;
|
2020-11-18 06:39:04 -08:00
|
|
|
std::vector<ScriptInterface::StructuredClone > commands;
|
2011-01-12 04:29:00 -08:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
CAIWorker() :
|
2020-11-14 02:57:50 -08:00
|
|
|
m_ScriptInterface(new ScriptInterface("Engine", "AI", g_ScriptContext)),
|
2011-03-02 16:16:14 -08:00
|
|
|
m_TurnNum(0),
|
2011-12-22 06:04:32 -08:00
|
|
|
m_CommandsComputed(true),
|
2013-03-05 14:52:48 -08:00
|
|
|
m_HasLoadedEntityTemplates(false),
|
2015-01-24 06:46:52 -08:00
|
|
|
m_HasSharedComponent(false),
|
2020-11-18 06:39:04 -08:00
|
|
|
m_EntityTemplates(g_ScriptContext->GetGeneralJSContext()),
|
|
|
|
|
m_SharedAIObj(g_ScriptContext->GetGeneralJSContext()),
|
|
|
|
|
m_PassabilityMapVal(g_ScriptContext->GetGeneralJSContext()),
|
|
|
|
|
m_TerritoryMapVal(g_ScriptContext->GetGeneralJSContext())
|
2011-01-12 04:29:00 -08:00
|
|
|
{
|
|
|
|
|
|
2013-12-30 02:04:59 -08:00
|
|
|
m_ScriptInterface->ReplaceNondeterministicRNG(m_RNG);
|
2013-03-05 14:52:48 -08:00
|
|
|
|
2013-12-30 02:04:59 -08:00
|
|
|
m_ScriptInterface->SetCallbackData(static_cast<void*> (this));
|
2013-03-05 14:52:48 -08:00
|
|
|
|
2020-11-18 06:39:04 -08:00
|
|
|
JS_AddExtraGCRootsTracer(m_ScriptInterface->GetGeneralJSContext(), Trace, this);
|
2015-01-24 06:46:52 -08:00
|
|
|
|
2021-03-02 12:01:14 -08:00
|
|
|
ScriptRequest rq(m_ScriptInterface);
|
|
|
|
|
#define REGISTER_FUNC_NAME(func, name) \
|
|
|
|
|
ScriptFunction::Register<&CAIWorker::func, ScriptFunction::ObjectFromCBData<CAIWorker>>(rq, name);
|
New long-range pathfinder.
Based on Philip's work located at
http://git.wildfiregames.com/gitweb/?p=0ad.git;a=shortlog;h=refs/heads/projects/philip/pathfinder
Includes code by wraitii, sanderd17 and kanetaka.
An updated version of docs/pathfinder.pdf describing the changes in
detail will be committed ASAP.
Running update-workspaces is needed after this change.
Fixes #1756.
Fixes #930, #1259, #2908, #2960, #3097
Refs #1200, #1914, #1942, #2568, #2132, #2563
This was SVN commit r16751.
2015-06-12 11:58:24 -07:00
|
|
|
|
2021-03-02 12:01:14 -08:00
|
|
|
REGISTER_FUNC_NAME(PostCommand, "PostCommand");
|
|
|
|
|
REGISTER_FUNC_NAME(LoadScripts, "IncludeModule");
|
|
|
|
|
ScriptFunction::Register<QuitEngine>(rq, "Exit");
|
2015-06-17 13:35:23 -07:00
|
|
|
|
2021-03-02 12:01:14 -08:00
|
|
|
REGISTER_FUNC_NAME(ComputePathScript, "ComputePath");
|
2017-12-06 12:26:01 -08:00
|
|
|
|
2021-03-02 12:01:14 -08:00
|
|
|
REGISTER_FUNC_NAME(DumpImage, "DumpImage");
|
|
|
|
|
REGISTER_FUNC_NAME(GetTemplate, "GetTemplate");
|
|
|
|
|
|
|
|
|
|
#undef REGISTER_FUNC_NAME
|
|
|
|
|
|
|
|
|
|
JSI_VFS::RegisterScriptFunctions_Simulation(rq);
|
2017-12-30 17:02:21 -08:00
|
|
|
|
|
|
|
|
// Globalscripts may use VFS script functions
|
|
|
|
|
m_ScriptInterface->LoadGlobalScripts();
|
2011-01-12 04:29:00 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
~CAIWorker()
|
|
|
|
|
{
|
2020-11-18 06:39:04 -08:00
|
|
|
JS_RemoveExtraGCRootsTracer(m_ScriptInterface->GetGeneralJSContext(), Trace, this);
|
2011-01-12 04:29:00 -08:00
|
|
|
}
|
2015-06-17 13:35:23 -07:00
|
|
|
|
2017-11-24 11:13:28 -08:00
|
|
|
bool HasLoadedEntityTemplates() const { return m_HasLoadedEntityTemplates; }
|
|
|
|
|
|
2013-12-30 02:04:59 -08:00
|
|
|
bool LoadScripts(const std::wstring& moduleName)
|
|
|
|
|
{
|
|
|
|
|
// Ignore modules that are already loaded
|
|
|
|
|
if (m_LoadedModules.find(moduleName) != m_LoadedModules.end())
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
// Mark this as loaded, to prevent it recursively loading itself
|
|
|
|
|
m_LoadedModules.insert(moduleName);
|
|
|
|
|
|
|
|
|
|
// Load and execute *.js
|
|
|
|
|
VfsPaths pathnames;
|
2014-05-31 07:55:09 -07:00
|
|
|
if (vfs::GetPathnames(g_VFS, L"simulation/ai/" + moduleName + L"/", L"*.js", pathnames) < 0)
|
|
|
|
|
{
|
2015-01-22 12:37:38 -08:00
|
|
|
LOGERROR("Failed to load AI scripts for module %s", utf8_from_wstring(moduleName));
|
2014-05-31 07:55:09 -07:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-29 16:44:12 -07:00
|
|
|
for (const VfsPath& path : pathnames)
|
2013-12-30 02:04:59 -08:00
|
|
|
{
|
2015-07-29 16:44:12 -07:00
|
|
|
if (!m_ScriptInterface->LoadGlobalScriptFile(path))
|
2013-12-30 02:04:59 -08:00
|
|
|
{
|
2015-07-29 16:44:12 -07:00
|
|
|
LOGERROR("Failed to load script %s", path.string8());
|
2013-12-30 02:04:59 -08:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2015-06-17 13:35:23 -07:00
|
|
|
|
2014-08-03 12:32:39 -07:00
|
|
|
void PostCommand(int playerid, JS::HandleValue cmd)
|
2013-12-30 02:04:59 -08:00
|
|
|
{
|
|
|
|
|
for (size_t i=0; i<m_Players.size(); i++)
|
|
|
|
|
{
|
2016-11-23 06:09:58 -08:00
|
|
|
if (m_Players[i]->m_Player == playerid)
|
2013-12-30 02:04:59 -08:00
|
|
|
{
|
2020-12-06 06:03:02 -08:00
|
|
|
m_Players[i]->m_Commands.push_back(m_ScriptInterface->WriteStructuredClone(cmd));
|
2013-12-30 02:04:59 -08:00
|
|
|
return;
|
|
|
|
|
}
|
2013-03-05 14:52:48 -08:00
|
|
|
}
|
2015-06-17 13:35:23 -07:00
|
|
|
|
2016-11-23 06:09:58 -08:00
|
|
|
LOGERROR("Invalid playerid in PostCommand!");
|
2013-03-05 14:52:48 -08:00
|
|
|
}
|
New long-range pathfinder.
Based on Philip's work located at
http://git.wildfiregames.com/gitweb/?p=0ad.git;a=shortlog;h=refs/heads/projects/philip/pathfinder
Includes code by wraitii, sanderd17 and kanetaka.
An updated version of docs/pathfinder.pdf describing the changes in
detail will be committed ASAP.
Running update-workspaces is needed after this change.
Fixes #1756.
Fixes #930, #1259, #2908, #2960, #3097
Refs #1200, #1914, #1942, #2568, #2132, #2563
This was SVN commit r16751.
2015-06-12 11:58:24 -07:00
|
|
|
|
2021-03-02 12:01:14 -08:00
|
|
|
JS::Value ComputePathScript(JS::HandleValue position, JS::HandleValue goal, pass_class_t passClass)
|
New long-range pathfinder.
Based on Philip's work located at
http://git.wildfiregames.com/gitweb/?p=0ad.git;a=shortlog;h=refs/heads/projects/philip/pathfinder
Includes code by wraitii, sanderd17 and kanetaka.
An updated version of docs/pathfinder.pdf describing the changes in
detail will be committed ASAP.
Running update-workspaces is needed after this change.
Fixes #1756.
Fixes #930, #1259, #2908, #2960, #3097
Refs #1200, #1914, #1942, #2568, #2132, #2563
This was SVN commit r16751.
2015-06-12 11:58:24 -07:00
|
|
|
{
|
2021-03-02 12:01:14 -08:00
|
|
|
ScriptRequest rq(m_ScriptInterface);
|
New long-range pathfinder.
Based on Philip's work located at
http://git.wildfiregames.com/gitweb/?p=0ad.git;a=shortlog;h=refs/heads/projects/philip/pathfinder
Includes code by wraitii, sanderd17 and kanetaka.
An updated version of docs/pathfinder.pdf describing the changes in
detail will be committed ASAP.
Running update-workspaces is needed after this change.
Fixes #1756.
Fixes #930, #1259, #2908, #2960, #3097
Refs #1200, #1914, #1942, #2568, #2132, #2563
This was SVN commit r16751.
2015-06-12 11:58:24 -07:00
|
|
|
|
|
|
|
|
CFixedVector2D pos, goalPos;
|
|
|
|
|
std::vector<CFixedVector2D> waypoints;
|
2020-11-13 05:18:22 -08:00
|
|
|
JS::RootedValue retVal(rq.cx);
|
New long-range pathfinder.
Based on Philip's work located at
http://git.wildfiregames.com/gitweb/?p=0ad.git;a=shortlog;h=refs/heads/projects/philip/pathfinder
Includes code by wraitii, sanderd17 and kanetaka.
An updated version of docs/pathfinder.pdf describing the changes in
detail will be committed ASAP.
Running update-workspaces is needed after this change.
Fixes #1756.
Fixes #930, #1259, #2908, #2960, #3097
Refs #1200, #1914, #1942, #2568, #2132, #2563
This was SVN commit r16751.
2015-06-12 11:58:24 -07:00
|
|
|
|
2021-03-02 12:01:14 -08:00
|
|
|
m_ScriptInterface->FromJSVal<CFixedVector2D>(rq, position, pos);
|
|
|
|
|
m_ScriptInterface->FromJSVal<CFixedVector2D>(rq, goal, goalPos);
|
New long-range pathfinder.
Based on Philip's work located at
http://git.wildfiregames.com/gitweb/?p=0ad.git;a=shortlog;h=refs/heads/projects/philip/pathfinder
Includes code by wraitii, sanderd17 and kanetaka.
An updated version of docs/pathfinder.pdf describing the changes in
detail will be committed ASAP.
Running update-workspaces is needed after this change.
Fixes #1756.
Fixes #930, #1259, #2908, #2960, #3097
Refs #1200, #1914, #1942, #2568, #2132, #2563
This was SVN commit r16751.
2015-06-12 11:58:24 -07:00
|
|
|
|
2021-03-02 12:01:14 -08:00
|
|
|
ComputePath(pos, goalPos, passClass, waypoints);
|
|
|
|
|
m_ScriptInterface->ToJSVal<std::vector<CFixedVector2D> >(rq, &retVal, waypoints);
|
New long-range pathfinder.
Based on Philip's work located at
http://git.wildfiregames.com/gitweb/?p=0ad.git;a=shortlog;h=refs/heads/projects/philip/pathfinder
Includes code by wraitii, sanderd17 and kanetaka.
An updated version of docs/pathfinder.pdf describing the changes in
detail will be committed ASAP.
Running update-workspaces is needed after this change.
Fixes #1756.
Fixes #930, #1259, #2908, #2960, #3097
Refs #1200, #1914, #1942, #2568, #2132, #2563
This was SVN commit r16751.
2015-06-12 11:58:24 -07:00
|
|
|
|
|
|
|
|
return retVal;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ComputePath(const CFixedVector2D& pos, const CFixedVector2D& goal, pass_class_t passClass, std::vector<CFixedVector2D>& waypoints)
|
|
|
|
|
{
|
|
|
|
|
WaypointPath ret;
|
|
|
|
|
PathGoal pathGoal = { PathGoal::POINT, goal.X, goal.Y };
|
2019-05-13 09:58:00 -07:00
|
|
|
m_LongPathfinder.ComputePath(m_HierarchicalPathfinder, pos.X, pos.Y, pathGoal, passClass, ret);
|
New long-range pathfinder.
Based on Philip's work located at
http://git.wildfiregames.com/gitweb/?p=0ad.git;a=shortlog;h=refs/heads/projects/philip/pathfinder
Includes code by wraitii, sanderd17 and kanetaka.
An updated version of docs/pathfinder.pdf describing the changes in
detail will be committed ASAP.
Running update-workspaces is needed after this change.
Fixes #1756.
Fixes #930, #1259, #2908, #2960, #3097
Refs #1200, #1914, #1942, #2568, #2132, #2563
This was SVN commit r16751.
2015-06-12 11:58:24 -07:00
|
|
|
|
|
|
|
|
for (Waypoint& wp : ret.m_Waypoints)
|
|
|
|
|
waypoints.emplace_back(wp.x, wp.z);
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-07 12:35:43 -07:00
|
|
|
CParamNode GetTemplate(const std::string& name)
|
|
|
|
|
{
|
2017-11-19 11:05:54 -08:00
|
|
|
if (!m_TemplateLoader.TemplateExists(name))
|
2017-11-20 10:30:21 -08:00
|
|
|
return CParamNode(false);
|
2017-08-07 12:35:43 -07:00
|
|
|
return m_TemplateLoader.GetTemplateFileData(name).GetChild("Entity");
|
|
|
|
|
}
|
|
|
|
|
|
2013-07-25 01:57:07 -07:00
|
|
|
/**
|
|
|
|
|
* Debug function for AI scripts to dump 2D array data (e.g. terrain tile weights).
|
|
|
|
|
*/
|
2021-03-02 12:01:14 -08:00
|
|
|
void DumpImage(ScriptInterface::CmptPrivate* UNUSED(pCmptPrivate), const std::wstring& name, const std::vector<u32>& data, u32 w, u32 h, u32 max)
|
2013-07-25 01:57:07 -07:00
|
|
|
{
|
|
|
|
|
// TODO: this is totally not threadsafe.
|
|
|
|
|
VfsPath filename = L"screenshots/aidump/" + name;
|
2015-06-17 13:35:23 -07:00
|
|
|
|
2013-07-25 01:57:07 -07:00
|
|
|
if (data.size() != w*h)
|
|
|
|
|
{
|
|
|
|
|
debug_warn(L"DumpImage: data size doesn't match w*h");
|
|
|
|
|
return;
|
|
|
|
|
}
|
2015-06-17 13:35:23 -07:00
|
|
|
|
2013-07-25 01:57:07 -07:00
|
|
|
if (max == 0)
|
|
|
|
|
{
|
|
|
|
|
debug_warn(L"DumpImage: max must not be 0");
|
|
|
|
|
return;
|
|
|
|
|
}
|
2015-06-17 13:35:23 -07:00
|
|
|
|
2013-07-25 01:57:07 -07:00
|
|
|
const size_t bpp = 8;
|
|
|
|
|
int flags = TEX_BOTTOM_UP|TEX_GREY;
|
2015-06-17 13:35:23 -07:00
|
|
|
|
2013-07-25 01:57:07 -07:00
|
|
|
const size_t img_size = w * h * bpp/8;
|
|
|
|
|
const size_t hdr_size = tex_hdr_size(filename);
|
|
|
|
|
shared_ptr<u8> buf;
|
|
|
|
|
AllocateAligned(buf, hdr_size+img_size, maxSectorSize);
|
|
|
|
|
Tex t;
|
2014-03-12 19:37:05 -07:00
|
|
|
if (t.wrap(w, h, bpp, flags, buf, hdr_size) < 0)
|
2013-07-25 01:57:07 -07:00
|
|
|
return;
|
2015-06-17 13:35:23 -07:00
|
|
|
|
2013-07-25 01:57:07 -07:00
|
|
|
u8* img = buf.get() + hdr_size;
|
|
|
|
|
for (size_t i = 0; i < data.size(); ++i)
|
|
|
|
|
img[i] = (u8)((data[i] * 255) / max);
|
2015-06-17 13:35:23 -07:00
|
|
|
|
2013-07-25 01:57:07 -07:00
|
|
|
tex_write(&t, filename);
|
|
|
|
|
}
|
2013-03-05 14:52:48 -08:00
|
|
|
|
2015-05-07 12:09:39 -07:00
|
|
|
void SetRNGSeed(u32 seed)
|
2014-11-16 11:53:29 -08:00
|
|
|
{
|
|
|
|
|
m_RNG.seed(seed);
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-30 17:02:21 -08:00
|
|
|
bool TryLoadSharedComponent()
|
2013-03-05 14:52:48 -08:00
|
|
|
{
|
Improve JS Exception handling.
- Check for pending exceptions after function calls and script
executions.
- Call LOGERROR instead of JS_ReportError when there is a conversion
error in FromJSVal, since that can only be called from C++ (where JS
errors don't really make sense). Instead, C++ callers of FromJSVal
should handle the failure and, themselves, either report an error or
simply do something else.
- Wrap JS_ReportError since that makes updating it later easier.
This isn't a systematical fix since ToJSVal also ought return a boolean
for failures, and we probably should trigger errors instead of warnings
on 'implicit' conversions, rather a preparation diff.
Part of the SM52 migration, stage: SM45 compatible (actually SM52
incompatible, too).
Based on a patch by: Itms
Comments by: Vladislavbelov, Stan`
Refs #742, #4893
Differential Revision: https://code.wildfiregames.com/D3093
This was SVN commit r24187.
2020-11-15 10:29:17 -08:00
|
|
|
ScriptRequest rq(m_ScriptInterface);
|
2014-07-14 12:52:35 -07:00
|
|
|
|
2013-03-05 14:52:48 -08:00
|
|
|
// we don't need to load it.
|
|
|
|
|
if (!m_HasSharedComponent)
|
|
|
|
|
return false;
|
2015-06-17 13:35:23 -07:00
|
|
|
|
2013-03-05 14:52:48 -08:00
|
|
|
// reset the value so it can be used to determine if we actually initialized it.
|
|
|
|
|
m_HasSharedComponent = false;
|
2015-06-17 13:35:23 -07:00
|
|
|
|
2014-01-10 09:46:48 -08:00
|
|
|
if (LoadScripts(L"common-api"))
|
2013-03-05 14:52:48 -08:00
|
|
|
m_HasSharedComponent = true;
|
2013-12-30 02:04:59 -08:00
|
|
|
else
|
2013-03-05 14:52:48 -08:00
|
|
|
return false;
|
2013-12-30 02:04:59 -08:00
|
|
|
|
2013-03-05 14:52:48 -08:00
|
|
|
// mainly here for the error messages
|
2014-11-08 11:23:29 -08:00
|
|
|
OsPath path = L"simulation/ai/common-api/";
|
2015-06-17 13:35:23 -07:00
|
|
|
|
2013-12-30 02:04:59 -08:00
|
|
|
// Constructor name is SharedScript, it's in the module API3
|
2016-11-23 05:02:58 -08:00
|
|
|
// TODO: Hardcoding this is bad, we need a smarter way.
|
2020-11-13 05:18:22 -08:00
|
|
|
JS::RootedValue AIModule(rq.cx);
|
2020-11-14 00:46:32 -08:00
|
|
|
JS::RootedValue global(rq.cx, rq.globalValue());
|
2020-11-13 05:18:22 -08:00
|
|
|
JS::RootedValue ctor(rq.cx);
|
2014-07-26 15:33:16 -07:00
|
|
|
if (!m_ScriptInterface->GetProperty(global, "API3", &AIModule) || AIModule.isUndefined())
|
2013-12-30 02:04:59 -08:00
|
|
|
{
|
2015-01-22 12:36:24 -08:00
|
|
|
LOGERROR("Failed to create shared AI component: %s: can't find module '%s'", path.string8(), "API3");
|
2013-12-30 02:04:59 -08:00
|
|
|
return false;
|
|
|
|
|
}
|
2015-06-17 13:35:23 -07:00
|
|
|
|
2014-07-26 15:33:16 -07:00
|
|
|
if (!m_ScriptInterface->GetProperty(AIModule, "SharedScript", &ctor)
|
2014-12-22 17:20:50 -08:00
|
|
|
|| ctor.isUndefined())
|
2013-03-05 14:52:48 -08:00
|
|
|
{
|
2015-01-22 12:36:24 -08:00
|
|
|
LOGERROR("Failed to create shared AI component: %s: can't find constructor '%s'", path.string8(), "SharedScript");
|
2013-03-05 14:52:48 -08:00
|
|
|
return false;
|
|
|
|
|
}
|
2015-06-17 13:35:23 -07:00
|
|
|
|
2013-12-08 11:23:09 -08:00
|
|
|
// Set up the data to pass as the constructor argument
|
2020-11-13 05:18:22 -08:00
|
|
|
JS::RootedValue playersID(rq.cx);
|
|
|
|
|
ScriptInterface::CreateObject(rq, &playersID);
|
2015-06-17 13:35:23 -07:00
|
|
|
|
2013-12-08 11:23:09 -08:00
|
|
|
for (size_t i = 0; i < m_Players.size(); ++i)
|
2013-03-05 14:52:48 -08:00
|
|
|
{
|
2020-11-13 05:18:22 -08:00
|
|
|
JS::RootedValue val(rq.cx);
|
|
|
|
|
m_ScriptInterface->ToJSVal(rq, &val, m_Players[i]->m_Player);
|
2014-07-26 15:33:16 -07:00
|
|
|
m_ScriptInterface->SetPropertyInt(playersID, i, val, true);
|
2013-12-08 11:23:09 -08:00
|
|
|
}
|
2015-06-17 13:35:23 -07:00
|
|
|
|
2013-12-08 11:23:09 -08:00
|
|
|
ENSURE(m_HasLoadedEntityTemplates);
|
2019-09-07 09:51:44 -07:00
|
|
|
|
2020-11-13 05:18:22 -08:00
|
|
|
JS::RootedValue settings(rq.cx);
|
2019-09-12 17:56:51 -07:00
|
|
|
ScriptInterface::CreateObject(
|
2020-11-13 05:18:22 -08:00
|
|
|
rq,
|
2019-09-07 09:51:44 -07:00
|
|
|
&settings,
|
|
|
|
|
"players", playersID,
|
|
|
|
|
"templates", m_EntityTemplates);
|
2015-06-17 13:35:23 -07:00
|
|
|
|
2020-11-30 01:03:20 -08:00
|
|
|
JS::RootedValueVector argv(rq.cx);
|
2020-12-15 01:03:44 -08:00
|
|
|
ignore_result(argv.append(settings));
|
2015-01-24 06:46:52 -08:00
|
|
|
m_ScriptInterface->CallConstructor(ctor, argv, &m_SharedAIObj);
|
2015-06-17 13:35:23 -07:00
|
|
|
|
2015-01-24 06:46:52 -08:00
|
|
|
if (m_SharedAIObj.get().isNull())
|
2013-03-05 14:52:48 -08:00
|
|
|
{
|
2015-01-22 12:36:24 -08:00
|
|
|
LOGERROR("Failed to create shared AI component: %s: error calling constructor '%s'", path.string8(), "SharedScript");
|
2013-03-05 14:52:48 -08:00
|
|
|
return false;
|
|
|
|
|
}
|
2015-06-17 13:35:23 -07:00
|
|
|
|
2013-03-05 14:52:48 -08:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-20 14:02:15 -08:00
|
|
|
bool AddPlayer(const std::wstring& aiName, player_id_t player, u8 difficulty, const std::wstring& behavior)
|
2011-01-12 04:29:00 -08:00
|
|
|
{
|
2021-02-13 15:53:40 -08:00
|
|
|
shared_ptr<CAIPlayer> ai = std::make_shared<CAIPlayer>(*this, aiName, player, difficulty, behavior, m_ScriptInterface);
|
2014-08-02 06:22:02 -07:00
|
|
|
if (!ai->Initialise())
|
2011-01-12 04:29:00 -08:00
|
|
|
return false;
|
2015-06-17 13:35:23 -07:00
|
|
|
|
2013-03-05 14:52:48 -08:00
|
|
|
// this will be set to true if we need to load the shared Component.
|
|
|
|
|
if (!m_HasSharedComponent)
|
|
|
|
|
m_HasSharedComponent = ai->m_UseSharedComponent;
|
|
|
|
|
|
2011-01-12 04:29:00 -08:00
|
|
|
m_Players.push_back(ai);
|
2011-01-15 15:35:20 -08:00
|
|
|
|
2011-01-12 04:29:00 -08:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-18 06:39:04 -08:00
|
|
|
bool RunGamestateInit(const ScriptInterface::StructuredClone& gameState, const Grid<NavcellData>& passabilityMap, const Grid<u8>& territoryMap,
|
2015-07-05 12:14:52 -07:00
|
|
|
const std::map<std::string, pass_class_t>& nonPathfindingPassClassMasks, const std::map<std::string, pass_class_t>& pathfindingPassClassMasks)
|
2013-03-05 14:52:48 -08:00
|
|
|
{
|
2017-12-20 14:02:15 -08:00
|
|
|
// this will be run last by InitGame.js, passing the full game representation.
|
2013-03-05 14:52:48 -08:00
|
|
|
// For now it will run for the shared Component.
|
2013-07-25 01:57:07 -07:00
|
|
|
// This is NOT run during deserialization.
|
Improve JS Exception handling.
- Check for pending exceptions after function calls and script
executions.
- Call LOGERROR instead of JS_ReportError when there is a conversion
error in FromJSVal, since that can only be called from C++ (where JS
errors don't really make sense). Instead, C++ callers of FromJSVal
should handle the failure and, themselves, either report an error or
simply do something else.
- Wrap JS_ReportError since that makes updating it later easier.
This isn't a systematical fix since ToJSVal also ought return a boolean
for failures, and we probably should trigger errors instead of warnings
on 'implicit' conversions, rather a preparation diff.
Part of the SM52 migration, stage: SM45 compatible (actually SM52
incompatible, too).
Based on a patch by: Itms
Comments by: Vladislavbelov, Stan`
Refs #742, #4893
Differential Revision: https://code.wildfiregames.com/D3093
This was SVN commit r24187.
2020-11-15 10:29:17 -08:00
|
|
|
ScriptRequest rq(m_ScriptInterface);
|
2015-06-17 13:35:23 -07:00
|
|
|
|
2020-11-13 05:18:22 -08:00
|
|
|
JS::RootedValue state(rq.cx);
|
2014-08-01 13:55:16 -07:00
|
|
|
m_ScriptInterface->ReadStructuredClone(gameState, &state);
|
2020-11-13 05:18:22 -08:00
|
|
|
ScriptInterface::ToJSVal(rq, &m_PassabilityMapVal, passabilityMap);
|
|
|
|
|
ScriptInterface::ToJSVal(rq, &m_TerritoryMapVal, territoryMap);
|
2015-06-17 13:35:23 -07:00
|
|
|
|
|
|
|
|
m_PassabilityMap = passabilityMap;
|
2015-07-05 12:14:52 -07:00
|
|
|
m_NonPathfindingPassClasses = nonPathfindingPassClassMasks;
|
|
|
|
|
m_PathfindingPassClasses = pathfindingPassClassMasks;
|
|
|
|
|
|
2019-05-13 09:58:00 -07:00
|
|
|
m_LongPathfinder.Reload(&m_PassabilityMap);
|
|
|
|
|
m_HierarchicalPathfinder.Recompute(&m_PassabilityMap, nonPathfindingPassClassMasks, pathfindingPassClassMasks);
|
2015-06-17 13:35:23 -07:00
|
|
|
|
2013-03-05 14:52:48 -08:00
|
|
|
if (m_HasSharedComponent)
|
|
|
|
|
{
|
2014-07-26 15:33:16 -07:00
|
|
|
m_ScriptInterface->SetProperty(state, "passabilityMap", m_PassabilityMapVal, true);
|
|
|
|
|
m_ScriptInterface->SetProperty(state, "territoryMap", m_TerritoryMapVal, true);
|
2015-01-24 06:46:52 -08:00
|
|
|
m_ScriptInterface->CallFunctionVoid(m_SharedAIObj, "init", state);
|
2015-06-17 13:35:23 -07:00
|
|
|
|
2013-03-05 14:52:48 -08:00
|
|
|
for (size_t i = 0; i < m_Players.size(); ++i)
|
|
|
|
|
{
|
|
|
|
|
if (m_HasSharedComponent && m_Players[i]->m_UseSharedComponent)
|
2014-07-26 15:33:16 -07:00
|
|
|
m_Players[i]->InitAI(state, m_SharedAIObj);
|
2013-03-05 14:52:48 -08:00
|
|
|
}
|
|
|
|
|
}
|
2015-06-17 13:35:23 -07:00
|
|
|
|
2013-03-05 14:52:48 -08:00
|
|
|
return true;
|
|
|
|
|
}
|
2016-09-24 08:16:55 -07:00
|
|
|
|
2020-11-18 06:39:04 -08:00
|
|
|
void UpdateGameState(const ScriptInterface::StructuredClone& gameState)
|
2016-09-24 08:16:55 -07:00
|
|
|
{
|
|
|
|
|
ENSURE(m_CommandsComputed);
|
|
|
|
|
m_GameState = gameState;
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-01 05:29:44 -07:00
|
|
|
void UpdatePathfinder(const Grid<NavcellData>& passabilityMap, bool globallyDirty, const Grid<u8>& dirtinessGrid, bool justDeserialized,
|
2015-07-05 12:14:52 -07:00
|
|
|
const std::map<std::string, pass_class_t>& nonPathfindingPassClassMasks, const std::map<std::string, pass_class_t>& pathfindingPassClassMasks)
|
2011-01-12 04:29:00 -08:00
|
|
|
{
|
2011-04-30 06:01:45 -07:00
|
|
|
ENSURE(m_CommandsComputed);
|
2016-09-24 08:16:55 -07:00
|
|
|
bool dimensionChange = m_PassabilityMap.m_W != passabilityMap.m_W || m_PassabilityMap.m_H != passabilityMap.m_H;
|
2011-01-12 04:29:00 -08:00
|
|
|
|
2016-09-24 08:16:55 -07:00
|
|
|
m_PassabilityMap = passabilityMap;
|
|
|
|
|
if (globallyDirty)
|
2019-05-13 09:58:00 -07:00
|
|
|
{
|
|
|
|
|
m_LongPathfinder.Reload(&m_PassabilityMap);
|
|
|
|
|
m_HierarchicalPathfinder.Recompute(&m_PassabilityMap, nonPathfindingPassClassMasks, pathfindingPassClassMasks);
|
|
|
|
|
}
|
2016-09-24 08:16:55 -07:00
|
|
|
else
|
2019-05-13 09:58:00 -07:00
|
|
|
{
|
|
|
|
|
m_LongPathfinder.Update(&m_PassabilityMap);
|
|
|
|
|
m_HierarchicalPathfinder.Update(&m_PassabilityMap, dirtinessGrid);
|
|
|
|
|
}
|
2011-01-12 04:29:00 -08:00
|
|
|
|
Improve JS Exception handling.
- Check for pending exceptions after function calls and script
executions.
- Call LOGERROR instead of JS_ReportError when there is a conversion
error in FromJSVal, since that can only be called from C++ (where JS
errors don't really make sense). Instead, C++ callers of FromJSVal
should handle the failure and, themselves, either report an error or
simply do something else.
- Wrap JS_ReportError since that makes updating it later easier.
This isn't a systematical fix since ToJSVal also ought return a boolean
for failures, and we probably should trigger errors instead of warnings
on 'implicit' conversions, rather a preparation diff.
Part of the SM52 migration, stage: SM45 compatible (actually SM52
incompatible, too).
Based on a patch by: Itms
Comments by: Vladislavbelov, Stan`
Refs #742, #4893
Differential Revision: https://code.wildfiregames.com/D3093
This was SVN commit r24187.
2020-11-15 10:29:17 -08:00
|
|
|
ScriptRequest rq(m_ScriptInterface);
|
2016-10-01 05:29:44 -07:00
|
|
|
if (dimensionChange || justDeserialized)
|
2020-11-13 05:18:22 -08:00
|
|
|
ScriptInterface::ToJSVal(rq, &m_PassabilityMapVal, m_PassabilityMap);
|
2016-09-24 08:16:55 -07:00
|
|
|
else
|
2011-10-15 19:55:58 -07:00
|
|
|
{
|
2016-09-24 08:16:55 -07:00
|
|
|
// Avoid a useless memory reallocation followed by a garbage collection.
|
2020-11-13 05:18:22 -08:00
|
|
|
JS::RootedObject mapObj(rq.cx, &m_PassabilityMapVal.toObject());
|
|
|
|
|
JS::RootedValue mapData(rq.cx);
|
|
|
|
|
ENSURE(JS_GetProperty(rq.cx, mapObj, "data", &mapData));
|
|
|
|
|
JS::RootedObject dataObj(rq.cx, &mapData.toObject());
|
2016-09-24 08:16:55 -07:00
|
|
|
|
|
|
|
|
u32 length = 0;
|
2020-12-06 06:03:02 -08:00
|
|
|
ENSURE(JS::GetArrayLength(rq.cx, dataObj, &length));
|
2016-09-24 08:16:55 -07:00
|
|
|
u32 nbytes = (u32)(length * sizeof(NavcellData));
|
|
|
|
|
|
Upgrade SpiderMonkey to version 45.0.2, refs #4893.
- Various build changes, in particular NSPR is not needed on Unix
anymore
- Add js/Initialization.h to source/scriptinterface/ScriptEngine.h
- Use nullptr instead of JS::NullPtr(), see
https://bugzilla.mozilla.org/show_bug.cgi?id=1164602
- Remove `JS::RuntimeOptionsRef.varObjFix`, see
https://bugzilla.mozilla.org/show_bug.cgi?id=1171177
- Remove uses of `AutoIdArray`, see
https://bugzilla.mozilla.org/show_bug.cgi?id=1191529
- `JS_InternUCStringN` has been renamed, see
https://bugzilla.mozilla.org/show_bug.cgi?id=1178581
- `JS::Evaluate` now takes scope chains explicitly, see
https://bugzilla.mozilla.org/show_bug.cgi?id=1097987
- Array functions (such as `JS_IsArrayObject`) are fallible and output
to params, see https://bugzilla.mozilla.org/show_bug.cgi?id=f3d35d8
- Remove `JSCLASS_CACHED_PROTO_WIDTH` workaround in our code, see
https://bugzilla.mozilla.org/show_bug.cgi?id=1236373
- Remove compile'n go (`setCompileAndGo`) and replace it by
`setIsRunOnce` which will become the default in the future, see
https://bugzilla.mozilla.org/show_bug.cgi?id=679939
- Mark shared memory in direct access operations
(`JS_GetUint16ArrayData` and `JS_GetUint8ArrayData`), see
https://bugzilla.mozilla.org/show_bug.cgi?id=1176214
- Use new `JS::ObjectOpResult`, see
https://bugzilla.mozilla.org/show_bug.cgi?id=1113369
Thanks to wraitii, elexis, Krinkle and historic_bruno for contributions
and comments, and to gentz, madpilot, s0600204 and Stan for testing and
indirect contributions.
Differential Revision: https://code.wildfiregames.com/D1510
This was SVN commit r22627.
2019-08-07 15:37:43 -07:00
|
|
|
bool sharedMemory;
|
2016-09-24 08:16:55 -07:00
|
|
|
JS::AutoCheckCannotGC nogc;
|
Upgrade SpiderMonkey to version 45.0.2, refs #4893.
- Various build changes, in particular NSPR is not needed on Unix
anymore
- Add js/Initialization.h to source/scriptinterface/ScriptEngine.h
- Use nullptr instead of JS::NullPtr(), see
https://bugzilla.mozilla.org/show_bug.cgi?id=1164602
- Remove `JS::RuntimeOptionsRef.varObjFix`, see
https://bugzilla.mozilla.org/show_bug.cgi?id=1171177
- Remove uses of `AutoIdArray`, see
https://bugzilla.mozilla.org/show_bug.cgi?id=1191529
- `JS_InternUCStringN` has been renamed, see
https://bugzilla.mozilla.org/show_bug.cgi?id=1178581
- `JS::Evaluate` now takes scope chains explicitly, see
https://bugzilla.mozilla.org/show_bug.cgi?id=1097987
- Array functions (such as `JS_IsArrayObject`) are fallible and output
to params, see https://bugzilla.mozilla.org/show_bug.cgi?id=f3d35d8
- Remove `JSCLASS_CACHED_PROTO_WIDTH` workaround in our code, see
https://bugzilla.mozilla.org/show_bug.cgi?id=1236373
- Remove compile'n go (`setCompileAndGo`) and replace it by
`setIsRunOnce` which will become the default in the future, see
https://bugzilla.mozilla.org/show_bug.cgi?id=679939
- Mark shared memory in direct access operations
(`JS_GetUint16ArrayData` and `JS_GetUint8ArrayData`), see
https://bugzilla.mozilla.org/show_bug.cgi?id=1176214
- Use new `JS::ObjectOpResult`, see
https://bugzilla.mozilla.org/show_bug.cgi?id=1113369
Thanks to wraitii, elexis, Krinkle and historic_bruno for contributions
and comments, and to gentz, madpilot, s0600204 and Stan for testing and
indirect contributions.
Differential Revision: https://code.wildfiregames.com/D1510
This was SVN commit r22627.
2019-08-07 15:37:43 -07:00
|
|
|
memcpy((void*)JS_GetUint16ArrayData(dataObj, &sharedMemory, nogc), m_PassabilityMap.m_Data, nbytes);
|
2016-11-23 06:09:58 -08:00
|
|
|
}
|
2016-09-24 08:16:55 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UpdateTerritoryMap(const Grid<u8>& territoryMap)
|
|
|
|
|
{
|
|
|
|
|
ENSURE(m_CommandsComputed);
|
|
|
|
|
bool dimensionChange = m_TerritoryMap.m_W != territoryMap.m_W || m_TerritoryMap.m_H != territoryMap.m_H;
|
|
|
|
|
|
|
|
|
|
m_TerritoryMap = territoryMap;
|
2016-11-23 06:09:58 -08:00
|
|
|
|
Improve JS Exception handling.
- Check for pending exceptions after function calls and script
executions.
- Call LOGERROR instead of JS_ReportError when there is a conversion
error in FromJSVal, since that can only be called from C++ (where JS
errors don't really make sense). Instead, C++ callers of FromJSVal
should handle the failure and, themselves, either report an error or
simply do something else.
- Wrap JS_ReportError since that makes updating it later easier.
This isn't a systematical fix since ToJSVal also ought return a boolean
for failures, and we probably should trigger errors instead of warnings
on 'implicit' conversions, rather a preparation diff.
Part of the SM52 migration, stage: SM45 compatible (actually SM52
incompatible, too).
Based on a patch by: Itms
Comments by: Vladislavbelov, Stan`
Refs #742, #4893
Differential Revision: https://code.wildfiregames.com/D3093
This was SVN commit r24187.
2020-11-15 10:29:17 -08:00
|
|
|
ScriptRequest rq(m_ScriptInterface);
|
2016-09-24 08:16:55 -07:00
|
|
|
if (dimensionChange)
|
2020-11-13 05:18:22 -08:00
|
|
|
ScriptInterface::ToJSVal(rq, &m_TerritoryMapVal, m_TerritoryMap);
|
2016-09-24 08:16:55 -07:00
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Avoid a useless memory reallocation followed by a garbage collection.
|
2020-11-13 05:18:22 -08:00
|
|
|
JS::RootedObject mapObj(rq.cx, &m_TerritoryMapVal.toObject());
|
|
|
|
|
JS::RootedValue mapData(rq.cx);
|
|
|
|
|
ENSURE(JS_GetProperty(rq.cx, mapObj, "data", &mapData));
|
|
|
|
|
JS::RootedObject dataObj(rq.cx, &mapData.toObject());
|
2016-09-24 08:16:55 -07:00
|
|
|
|
|
|
|
|
u32 length = 0;
|
2020-12-06 06:03:02 -08:00
|
|
|
ENSURE(JS::GetArrayLength(rq.cx, dataObj, &length));
|
2016-09-24 08:16:55 -07:00
|
|
|
u32 nbytes = (u32)(length * sizeof(u8));
|
|
|
|
|
|
Upgrade SpiderMonkey to version 45.0.2, refs #4893.
- Various build changes, in particular NSPR is not needed on Unix
anymore
- Add js/Initialization.h to source/scriptinterface/ScriptEngine.h
- Use nullptr instead of JS::NullPtr(), see
https://bugzilla.mozilla.org/show_bug.cgi?id=1164602
- Remove `JS::RuntimeOptionsRef.varObjFix`, see
https://bugzilla.mozilla.org/show_bug.cgi?id=1171177
- Remove uses of `AutoIdArray`, see
https://bugzilla.mozilla.org/show_bug.cgi?id=1191529
- `JS_InternUCStringN` has been renamed, see
https://bugzilla.mozilla.org/show_bug.cgi?id=1178581
- `JS::Evaluate` now takes scope chains explicitly, see
https://bugzilla.mozilla.org/show_bug.cgi?id=1097987
- Array functions (such as `JS_IsArrayObject`) are fallible and output
to params, see https://bugzilla.mozilla.org/show_bug.cgi?id=f3d35d8
- Remove `JSCLASS_CACHED_PROTO_WIDTH` workaround in our code, see
https://bugzilla.mozilla.org/show_bug.cgi?id=1236373
- Remove compile'n go (`setCompileAndGo`) and replace it by
`setIsRunOnce` which will become the default in the future, see
https://bugzilla.mozilla.org/show_bug.cgi?id=679939
- Mark shared memory in direct access operations
(`JS_GetUint16ArrayData` and `JS_GetUint8ArrayData`), see
https://bugzilla.mozilla.org/show_bug.cgi?id=1176214
- Use new `JS::ObjectOpResult`, see
https://bugzilla.mozilla.org/show_bug.cgi?id=1113369
Thanks to wraitii, elexis, Krinkle and historic_bruno for contributions
and comments, and to gentz, madpilot, s0600204 and Stan for testing and
indirect contributions.
Differential Revision: https://code.wildfiregames.com/D1510
This was SVN commit r22627.
2019-08-07 15:37:43 -07:00
|
|
|
bool sharedMemory;
|
2016-09-24 08:16:55 -07:00
|
|
|
JS::AutoCheckCannotGC nogc;
|
Upgrade SpiderMonkey to version 45.0.2, refs #4893.
- Various build changes, in particular NSPR is not needed on Unix
anymore
- Add js/Initialization.h to source/scriptinterface/ScriptEngine.h
- Use nullptr instead of JS::NullPtr(), see
https://bugzilla.mozilla.org/show_bug.cgi?id=1164602
- Remove `JS::RuntimeOptionsRef.varObjFix`, see
https://bugzilla.mozilla.org/show_bug.cgi?id=1171177
- Remove uses of `AutoIdArray`, see
https://bugzilla.mozilla.org/show_bug.cgi?id=1191529
- `JS_InternUCStringN` has been renamed, see
https://bugzilla.mozilla.org/show_bug.cgi?id=1178581
- `JS::Evaluate` now takes scope chains explicitly, see
https://bugzilla.mozilla.org/show_bug.cgi?id=1097987
- Array functions (such as `JS_IsArrayObject`) are fallible and output
to params, see https://bugzilla.mozilla.org/show_bug.cgi?id=f3d35d8
- Remove `JSCLASS_CACHED_PROTO_WIDTH` workaround in our code, see
https://bugzilla.mozilla.org/show_bug.cgi?id=1236373
- Remove compile'n go (`setCompileAndGo`) and replace it by
`setIsRunOnce` which will become the default in the future, see
https://bugzilla.mozilla.org/show_bug.cgi?id=679939
- Mark shared memory in direct access operations
(`JS_GetUint16ArrayData` and `JS_GetUint8ArrayData`), see
https://bugzilla.mozilla.org/show_bug.cgi?id=1176214
- Use new `JS::ObjectOpResult`, see
https://bugzilla.mozilla.org/show_bug.cgi?id=1113369
Thanks to wraitii, elexis, Krinkle and historic_bruno for contributions
and comments, and to gentz, madpilot, s0600204 and Stan for testing and
indirect contributions.
Differential Revision: https://code.wildfiregames.com/D1510
This was SVN commit r22627.
2019-08-07 15:37:43 -07:00
|
|
|
memcpy((void*)JS_GetUint8ArrayData(dataObj, &sharedMemory, nogc), m_TerritoryMap.m_Data, nbytes);
|
2011-03-02 16:16:14 -08:00
|
|
|
}
|
2016-09-24 08:16:55 -07:00
|
|
|
}
|
2011-03-02 16:16:14 -08:00
|
|
|
|
2016-09-24 08:16:55 -07:00
|
|
|
void StartComputation()
|
|
|
|
|
{
|
2011-01-12 04:29:00 -08:00
|
|
|
m_CommandsComputed = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void WaitToFinishComputation()
|
|
|
|
|
{
|
|
|
|
|
if (!m_CommandsComputed)
|
|
|
|
|
{
|
|
|
|
|
PerformComputation();
|
|
|
|
|
m_CommandsComputed = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-01-15 15:35:20 -08:00
|
|
|
void GetCommands(std::vector<SCommandSets>& commands)
|
2011-01-12 04:29:00 -08:00
|
|
|
{
|
2015-06-17 13:35:23 -07:00
|
|
|
WaitToFinishComputation();
|
|
|
|
|
|
2011-01-12 04:29:00 -08:00
|
|
|
commands.clear();
|
2011-01-15 15:35:20 -08:00
|
|
|
commands.resize(m_Players.size());
|
|
|
|
|
for (size_t i = 0; i < m_Players.size(); ++i)
|
2011-01-12 04:29:00 -08:00
|
|
|
{
|
2011-01-15 15:35:20 -08:00
|
|
|
commands[i].player = m_Players[i]->m_Player;
|
|
|
|
|
commands[i].commands = m_Players[i]->m_Commands;
|
2011-01-12 04:29:00 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LoadEntityTemplates(const std::vector<std::pair<std::string, const CParamNode*> >& templates)
|
|
|
|
|
{
|
Improve JS Exception handling.
- Check for pending exceptions after function calls and script
executions.
- Call LOGERROR instead of JS_ReportError when there is a conversion
error in FromJSVal, since that can only be called from C++ (where JS
errors don't really make sense). Instead, C++ callers of FromJSVal
should handle the failure and, themselves, either report an error or
simply do something else.
- Wrap JS_ReportError since that makes updating it later easier.
This isn't a systematical fix since ToJSVal also ought return a boolean
for failures, and we probably should trigger errors instead of warnings
on 'implicit' conversions, rather a preparation diff.
Part of the SM52 migration, stage: SM45 compatible (actually SM52
incompatible, too).
Based on a patch by: Itms
Comments by: Vladislavbelov, Stan`
Refs #742, #4893
Differential Revision: https://code.wildfiregames.com/D3093
This was SVN commit r24187.
2020-11-15 10:29:17 -08:00
|
|
|
ScriptRequest rq(m_ScriptInterface);
|
2014-07-26 15:33:16 -07:00
|
|
|
|
2011-12-22 06:04:32 -08:00
|
|
|
m_HasLoadedEntityTemplates = true;
|
|
|
|
|
|
2020-11-13 05:18:22 -08:00
|
|
|
ScriptInterface::CreateObject(rq, &m_EntityTemplates);
|
2011-01-12 04:29:00 -08:00
|
|
|
|
2020-11-13 05:18:22 -08:00
|
|
|
JS::RootedValue val(rq.cx);
|
2011-01-12 04:29:00 -08:00
|
|
|
for (size_t i = 0; i < templates.size(); ++i)
|
|
|
|
|
{
|
2020-11-13 05:18:22 -08:00
|
|
|
templates[i].second->ToJSVal(rq, false, &val);
|
2015-01-24 06:46:52 -08:00
|
|
|
m_ScriptInterface->SetProperty(m_EntityTemplates, templates[i].first.c_str(), val, true);
|
2011-01-12 04:29:00 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Serialize(std::ostream& stream, bool isDebug)
|
|
|
|
|
{
|
|
|
|
|
WaitToFinishComputation();
|
|
|
|
|
|
|
|
|
|
if (isDebug)
|
|
|
|
|
{
|
2013-12-30 02:04:59 -08:00
|
|
|
CDebugSerializer serializer(*m_ScriptInterface, stream);
|
2011-01-12 04:29:00 -08:00
|
|
|
serializer.Indent(4);
|
|
|
|
|
SerializeState(serializer);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2013-12-30 02:04:59 -08:00
|
|
|
CStdSerializer serializer(*m_ScriptInterface, stream);
|
2011-01-12 04:29:00 -08:00
|
|
|
SerializeState(serializer);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SerializeState(ISerializer& serializer)
|
|
|
|
|
{
|
2016-05-02 02:26:07 -07:00
|
|
|
if (m_Players.empty())
|
|
|
|
|
return;
|
|
|
|
|
|
Improve JS Exception handling.
- Check for pending exceptions after function calls and script
executions.
- Call LOGERROR instead of JS_ReportError when there is a conversion
error in FromJSVal, since that can only be called from C++ (where JS
errors don't really make sense). Instead, C++ callers of FromJSVal
should handle the failure and, themselves, either report an error or
simply do something else.
- Wrap JS_ReportError since that makes updating it later easier.
This isn't a systematical fix since ToJSVal also ought return a boolean
for failures, and we probably should trigger errors instead of warnings
on 'implicit' conversions, rather a preparation diff.
Part of the SM52 migration, stage: SM45 compatible (actually SM52
incompatible, too).
Based on a patch by: Itms
Comments by: Vladislavbelov, Stan`
Refs #742, #4893
Differential Revision: https://code.wildfiregames.com/D3093
This was SVN commit r24187.
2020-11-15 10:29:17 -08:00
|
|
|
ScriptRequest rq(m_ScriptInterface);
|
2015-05-07 12:09:39 -07:00
|
|
|
|
2011-12-22 06:04:32 -08:00
|
|
|
std::stringstream rngStream;
|
|
|
|
|
rngStream << m_RNG;
|
|
|
|
|
serializer.StringASCII("rng", rngStream.str(), 0, 32);
|
|
|
|
|
|
|
|
|
|
serializer.NumberU32_Unbounded("turn", m_TurnNum);
|
|
|
|
|
|
2013-03-24 02:10:32 -07:00
|
|
|
serializer.Bool("useSharedScript", m_HasSharedComponent);
|
|
|
|
|
if (m_HasSharedComponent)
|
2020-12-27 09:18:13 -08:00
|
|
|
serializer.ScriptVal("sharedData", &m_SharedAIObj);
|
2011-01-12 04:29:00 -08:00
|
|
|
for (size_t i = 0; i < m_Players.size(); ++i)
|
|
|
|
|
{
|
2011-12-22 06:04:32 -08:00
|
|
|
serializer.String("name", m_Players[i]->m_AIName, 1, 256);
|
2011-01-15 15:35:20 -08:00
|
|
|
serializer.NumberI32_Unbounded("player", m_Players[i]->m_Player);
|
2013-03-13 13:44:48 -07:00
|
|
|
serializer.NumberU8_Unbounded("difficulty", m_Players[i]->m_Difficulty);
|
2017-12-20 14:02:15 -08:00
|
|
|
serializer.String("behavior", m_Players[i]->m_Behavior, 1, 256);
|
2015-06-17 13:35:23 -07:00
|
|
|
|
2011-08-16 04:18:32 -07:00
|
|
|
serializer.NumberU32_Unbounded("num commands", (u32)m_Players[i]->m_Commands.size());
|
2011-01-15 15:35:20 -08:00
|
|
|
for (size_t j = 0; j < m_Players[i]->m_Commands.size(); ++j)
|
|
|
|
|
{
|
2020-11-13 05:18:22 -08:00
|
|
|
JS::RootedValue val(rq.cx);
|
2014-08-01 13:55:16 -07:00
|
|
|
m_ScriptInterface->ReadStructuredClone(m_Players[i]->m_Commands[j], &val);
|
2014-08-03 10:29:49 -07:00
|
|
|
serializer.ScriptVal("command", &val);
|
2011-01-15 15:35:20 -08:00
|
|
|
}
|
2011-12-22 06:04:32 -08:00
|
|
|
|
2020-12-27 09:18:13 -08:00
|
|
|
serializer.ScriptVal("data", &m_Players[i]->m_Obj);
|
2013-03-11 12:58:29 -07:00
|
|
|
}
|
2015-06-24 13:24:58 -07:00
|
|
|
|
|
|
|
|
// AI pathfinder
|
2020-12-19 01:10:37 -08:00
|
|
|
Serializer(serializer, "non pathfinding pass classes", m_NonPathfindingPassClasses);
|
|
|
|
|
Serializer(serializer, "pathfinding pass classes", m_PathfindingPassClasses);
|
2015-06-24 13:24:58 -07:00
|
|
|
serializer.NumberU16_Unbounded("pathfinder grid w", m_PassabilityMap.m_W);
|
|
|
|
|
serializer.NumberU16_Unbounded("pathfinder grid h", m_PassabilityMap.m_H);
|
2016-11-23 05:02:58 -08:00
|
|
|
serializer.RawBytes("pathfinder grid data", (const u8*)m_PassabilityMap.m_Data,
|
2015-06-24 13:24:58 -07:00
|
|
|
m_PassabilityMap.m_W*m_PassabilityMap.m_H*sizeof(NavcellData));
|
2011-01-12 04:29:00 -08:00
|
|
|
}
|
|
|
|
|
|
2015-05-07 12:09:39 -07:00
|
|
|
void Deserialize(std::istream& stream, u32 numAis)
|
2011-01-12 04:29:00 -08:00
|
|
|
{
|
2016-05-02 02:26:07 -07:00
|
|
|
m_PlayerMetadata.clear();
|
|
|
|
|
m_Players.clear();
|
|
|
|
|
|
|
|
|
|
if (numAis == 0)
|
|
|
|
|
return;
|
|
|
|
|
|
Improve JS Exception handling.
- Check for pending exceptions after function calls and script
executions.
- Call LOGERROR instead of JS_ReportError when there is a conversion
error in FromJSVal, since that can only be called from C++ (where JS
errors don't really make sense). Instead, C++ callers of FromJSVal
should handle the failure and, themselves, either report an error or
simply do something else.
- Wrap JS_ReportError since that makes updating it later easier.
This isn't a systematical fix since ToJSVal also ought return a boolean
for failures, and we probably should trigger errors instead of warnings
on 'implicit' conversions, rather a preparation diff.
Part of the SM52 migration, stage: SM45 compatible (actually SM52
incompatible, too).
Based on a patch by: Itms
Comments by: Vladislavbelov, Stan`
Refs #742, #4893
Differential Revision: https://code.wildfiregames.com/D3093
This was SVN commit r24187.
2020-11-15 10:29:17 -08:00
|
|
|
ScriptRequest rq(m_ScriptInterface);
|
2015-05-07 12:09:39 -07:00
|
|
|
|
2011-04-30 06:01:45 -07:00
|
|
|
ENSURE(m_CommandsComputed); // deserializing while we're still actively computing would be bad
|
2011-01-12 04:29:00 -08:00
|
|
|
|
2013-12-30 02:04:59 -08:00
|
|
|
CStdDeserializer deserializer(*m_ScriptInterface, stream);
|
2011-01-12 04:29:00 -08:00
|
|
|
|
2011-12-22 06:04:32 -08:00
|
|
|
std::string rngString;
|
|
|
|
|
std::stringstream rngStream;
|
|
|
|
|
deserializer.StringASCII("rng", rngString, 0, 32);
|
|
|
|
|
rngStream << rngString;
|
|
|
|
|
rngStream >> m_RNG;
|
|
|
|
|
|
|
|
|
|
deserializer.NumberU32_Unbounded("turn", m_TurnNum);
|
|
|
|
|
|
2013-03-24 02:10:32 -07:00
|
|
|
deserializer.Bool("useSharedScript", m_HasSharedComponent);
|
|
|
|
|
if (m_HasSharedComponent)
|
|
|
|
|
{
|
2017-12-30 17:02:21 -08:00
|
|
|
TryLoadSharedComponent();
|
2020-12-27 09:18:13 -08:00
|
|
|
deserializer.ScriptObjectAssign("sharedData", m_SharedAIObj);
|
2013-03-24 02:10:32 -07:00
|
|
|
}
|
|
|
|
|
|
2011-01-12 04:29:00 -08:00
|
|
|
for (size_t i = 0; i < numAis; ++i)
|
|
|
|
|
{
|
|
|
|
|
std::wstring name;
|
|
|
|
|
player_id_t player;
|
2015-05-07 12:09:39 -07:00
|
|
|
u8 difficulty;
|
2017-12-20 14:02:15 -08:00
|
|
|
std::wstring behavior;
|
2011-12-22 06:04:32 -08:00
|
|
|
deserializer.String("name", name, 1, 256);
|
2011-01-12 04:29:00 -08:00
|
|
|
deserializer.NumberI32_Unbounded("player", player);
|
2013-03-13 13:44:48 -07:00
|
|
|
deserializer.NumberU8_Unbounded("difficulty",difficulty);
|
2017-12-20 14:02:15 -08:00
|
|
|
deserializer.String("behavior", behavior, 1, 256);
|
|
|
|
|
if (!AddPlayer(name, player, difficulty, behavior))
|
2011-01-12 04:29:00 -08:00
|
|
|
throw PSERROR_Deserialize_ScriptError();
|
|
|
|
|
|
2015-05-07 12:09:39 -07:00
|
|
|
u32 numCommands;
|
2011-01-15 15:35:20 -08:00
|
|
|
deserializer.NumberU32_Unbounded("num commands", numCommands);
|
|
|
|
|
m_Players.back()->m_Commands.reserve(numCommands);
|
|
|
|
|
for (size_t j = 0; j < numCommands; ++j)
|
|
|
|
|
{
|
2020-11-13 05:18:22 -08:00
|
|
|
JS::RootedValue val(rq.cx);
|
2014-07-31 12:18:40 -07:00
|
|
|
deserializer.ScriptVal("command", &val);
|
2020-12-06 06:03:02 -08:00
|
|
|
m_Players.back()->m_Commands.push_back(m_ScriptInterface->WriteStructuredClone(val));
|
2011-01-15 15:35:20 -08:00
|
|
|
}
|
2015-06-17 13:35:23 -07:00
|
|
|
|
2020-12-27 09:18:13 -08:00
|
|
|
deserializer.ScriptObjectAssign("data", m_Players.back()->m_Obj);
|
2013-03-11 12:58:29 -07:00
|
|
|
}
|
2015-06-24 13:24:58 -07:00
|
|
|
|
|
|
|
|
// AI pathfinder
|
2020-12-19 01:10:37 -08:00
|
|
|
Serializer(deserializer, "non pathfinding pass classes", m_NonPathfindingPassClasses);
|
|
|
|
|
Serializer(deserializer, "pathfinding pass classes", m_PathfindingPassClasses);
|
2015-06-24 13:24:58 -07:00
|
|
|
u16 mapW, mapH;
|
|
|
|
|
deserializer.NumberU16_Unbounded("pathfinder grid w", mapW);
|
|
|
|
|
deserializer.NumberU16_Unbounded("pathfinder grid h", mapH);
|
|
|
|
|
m_PassabilityMap = Grid<NavcellData>(mapW, mapH);
|
|
|
|
|
deserializer.RawBytes("pathfinder grid data", (u8*)m_PassabilityMap.m_Data, mapW*mapH*sizeof(NavcellData));
|
2019-05-13 09:58:00 -07:00
|
|
|
m_LongPathfinder.Reload(&m_PassabilityMap);
|
|
|
|
|
m_HierarchicalPathfinder.Recompute(&m_PassabilityMap, m_NonPathfindingPassClasses, m_PathfindingPassClasses);
|
2011-01-12 04:29:00 -08:00
|
|
|
}
|
2015-06-17 13:35:23 -07:00
|
|
|
|
2013-03-05 14:52:48 -08:00
|
|
|
int getPlayerSize()
|
|
|
|
|
{
|
|
|
|
|
return m_Players.size();
|
|
|
|
|
}
|
2011-01-12 04:29:00 -08:00
|
|
|
|
|
|
|
|
private:
|
2015-01-24 06:46:52 -08:00
|
|
|
static void Trace(JSTracer *trc, void *data)
|
|
|
|
|
{
|
|
|
|
|
reinterpret_cast<CAIWorker*>(data)->TraceMember(trc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TraceMember(JSTracer *trc)
|
|
|
|
|
{
|
2016-01-12 16:42:55 -08:00
|
|
|
for (std::pair<const VfsPath, JS::Heap<JS::Value>>& metadata : m_PlayerMetadata)
|
2020-11-12 00:04:24 -08:00
|
|
|
JS::TraceEdge(trc, &metadata.second, "CAIWorker::m_PlayerMetadata");
|
2015-01-24 06:46:52 -08:00
|
|
|
}
|
|
|
|
|
|
2014-08-02 15:21:50 -07:00
|
|
|
void LoadMetadata(const VfsPath& path, JS::MutableHandleValue out)
|
2011-01-12 04:29:00 -08:00
|
|
|
{
|
|
|
|
|
if (m_PlayerMetadata.find(path) == m_PlayerMetadata.end())
|
|
|
|
|
{
|
|
|
|
|
// Load and cache the AI player metadata
|
2014-08-02 15:21:50 -07:00
|
|
|
m_ScriptInterface->ReadJSONFile(path, out);
|
2015-01-24 06:46:52 -08:00
|
|
|
m_PlayerMetadata[path] = JS::Heap<JS::Value>(out);
|
|
|
|
|
return;
|
2011-01-12 04:29:00 -08:00
|
|
|
}
|
2014-08-02 15:21:50 -07:00
|
|
|
out.set(m_PlayerMetadata[path].get());
|
2011-01-12 04:29:00 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PerformComputation()
|
2015-06-17 13:35:23 -07:00
|
|
|
{
|
2011-01-12 04:29:00 -08:00
|
|
|
// Deserialize the game state, to pass to the AI's HandleMessage
|
Improve JS Exception handling.
- Check for pending exceptions after function calls and script
executions.
- Call LOGERROR instead of JS_ReportError when there is a conversion
error in FromJSVal, since that can only be called from C++ (where JS
errors don't really make sense). Instead, C++ callers of FromJSVal
should handle the failure and, themselves, either report an error or
simply do something else.
- Wrap JS_ReportError since that makes updating it later easier.
This isn't a systematical fix since ToJSVal also ought return a boolean
for failures, and we probably should trigger errors instead of warnings
on 'implicit' conversions, rather a preparation diff.
Part of the SM52 migration, stage: SM45 compatible (actually SM52
incompatible, too).
Based on a patch by: Itms
Comments by: Vladislavbelov, Stan`
Refs #742, #4893
Differential Revision: https://code.wildfiregames.com/D3093
This was SVN commit r24187.
2020-11-15 10:29:17 -08:00
|
|
|
ScriptRequest rq(m_ScriptInterface);
|
2020-11-13 05:18:22 -08:00
|
|
|
JS::RootedValue state(rq.cx);
|
2011-03-02 16:16:14 -08:00
|
|
|
{
|
2011-11-03 18:35:50 -07:00
|
|
|
PROFILE3("AI compute read state");
|
2014-08-01 13:55:16 -07:00
|
|
|
m_ScriptInterface->ReadStructuredClone(m_GameState, &state);
|
2014-07-26 15:33:16 -07:00
|
|
|
m_ScriptInterface->SetProperty(state, "passabilityMap", m_PassabilityMapVal, true);
|
|
|
|
|
m_ScriptInterface->SetProperty(state, "territoryMap", m_TerritoryMapVal, true);
|
2011-03-02 16:16:14 -08:00
|
|
|
}
|
2011-01-12 04:29:00 -08:00
|
|
|
|
2011-01-15 15:35:20 -08:00
|
|
|
// It would be nice to do
|
2013-12-30 02:04:59 -08:00
|
|
|
// m_ScriptInterface->FreezeObject(state.get(), true);
|
2011-01-15 15:35:20 -08:00
|
|
|
// to prevent AI scripts accidentally modifying the state and
|
|
|
|
|
// affecting other AI scripts they share it with. But the performance
|
|
|
|
|
// cost is far too high, so we won't do that.
|
2013-03-05 14:52:48 -08:00
|
|
|
// If there is a shared component, run it
|
2011-01-12 04:29:00 -08:00
|
|
|
|
2013-03-05 14:52:48 -08:00
|
|
|
if (m_HasSharedComponent)
|
|
|
|
|
{
|
|
|
|
|
PROFILE3("AI run shared component");
|
2015-05-10 02:01:39 -07:00
|
|
|
m_ScriptInterface->CallFunctionVoid(m_SharedAIObj, "onUpdate", state);
|
2013-03-05 14:52:48 -08:00
|
|
|
}
|
2015-06-17 13:35:23 -07:00
|
|
|
|
2011-11-03 18:35:50 -07:00
|
|
|
for (size_t i = 0; i < m_Players.size(); ++i)
|
2011-03-02 16:16:14 -08:00
|
|
|
{
|
2011-11-03 18:35:50 -07:00
|
|
|
PROFILE3("AI script");
|
|
|
|
|
PROFILE2_ATTR("player: %d", m_Players[i]->m_Player);
|
|
|
|
|
PROFILE2_ATTR("script: %ls", m_Players[i]->m_AIName.c_str());
|
2013-12-30 02:04:59 -08:00
|
|
|
|
2013-03-05 14:52:48 -08:00
|
|
|
if (m_HasSharedComponent && m_Players[i]->m_UseSharedComponent)
|
2013-12-30 02:04:59 -08:00
|
|
|
m_Players[i]->Run(state, m_Players[i]->m_Player, m_SharedAIObj);
|
2013-03-05 14:52:48 -08:00
|
|
|
else
|
2013-12-30 02:04:59 -08:00
|
|
|
m_Players[i]->Run(state, m_Players[i]->m_Player);
|
2011-03-02 16:16:14 -08:00
|
|
|
}
|
2011-01-12 04:29:00 -08:00
|
|
|
}
|
|
|
|
|
|
2015-01-24 06:46:52 -08:00
|
|
|
// Take care to keep this declaration before heap rooted members. Destructors of heap rooted
|
2020-11-14 02:57:50 -08:00
|
|
|
// members have to be called before the context destructor.
|
|
|
|
|
shared_ptr<ScriptContext> m_ScriptContext;
|
2015-06-17 13:35:23 -07:00
|
|
|
|
2013-12-30 02:04:59 -08:00
|
|
|
shared_ptr<ScriptInterface> m_ScriptInterface;
|
2011-01-12 04:29:00 -08:00
|
|
|
boost::rand48 m_RNG;
|
2011-12-22 06:04:32 -08:00
|
|
|
u32 m_TurnNum;
|
2011-01-12 04:29:00 -08:00
|
|
|
|
2015-01-24 06:46:52 -08:00
|
|
|
JS::PersistentRootedValue m_EntityTemplates;
|
2011-12-22 06:04:32 -08:00
|
|
|
bool m_HasLoadedEntityTemplates;
|
|
|
|
|
|
2015-01-24 06:46:52 -08:00
|
|
|
std::map<VfsPath, JS::Heap<JS::Value> > m_PlayerMetadata;
|
2011-01-15 15:35:20 -08:00
|
|
|
std::vector<shared_ptr<CAIPlayer> > m_Players; // use shared_ptr just to avoid copying
|
2011-01-12 04:29:00 -08:00
|
|
|
|
2013-03-05 14:52:48 -08:00
|
|
|
bool m_HasSharedComponent;
|
2015-01-24 06:46:52 -08:00
|
|
|
JS::PersistentRootedValue m_SharedAIObj;
|
2013-03-05 14:52:48 -08:00
|
|
|
std::vector<SCommandSets> m_Commands;
|
2015-06-17 13:35:23 -07:00
|
|
|
|
2013-12-30 02:04:59 -08:00
|
|
|
std::set<std::wstring> m_LoadedModules;
|
2015-06-17 13:35:23 -07:00
|
|
|
|
2020-11-18 06:39:04 -08:00
|
|
|
ScriptInterface::StructuredClone m_GameState;
|
2015-10-03 01:27:19 -07:00
|
|
|
Grid<NavcellData> m_PassabilityMap;
|
2015-01-24 06:46:52 -08:00
|
|
|
JS::PersistentRootedValue m_PassabilityMapVal;
|
2011-10-15 19:55:58 -07:00
|
|
|
Grid<u8> m_TerritoryMap;
|
2015-01-24 06:46:52 -08:00
|
|
|
JS::PersistentRootedValue m_TerritoryMapVal;
|
2011-01-12 04:29:00 -08:00
|
|
|
|
2015-07-05 12:14:52 -07:00
|
|
|
std::map<std::string, pass_class_t> m_NonPathfindingPassClasses;
|
|
|
|
|
std::map<std::string, pass_class_t> m_PathfindingPassClasses;
|
2019-05-13 09:58:00 -07:00
|
|
|
HierarchicalPathfinder m_HierarchicalPathfinder;
|
New long-range pathfinder.
Based on Philip's work located at
http://git.wildfiregames.com/gitweb/?p=0ad.git;a=shortlog;h=refs/heads/projects/philip/pathfinder
Includes code by wraitii, sanderd17 and kanetaka.
An updated version of docs/pathfinder.pdf describing the changes in
detail will be committed ASAP.
Running update-workspaces is needed after this change.
Fixes #1756.
Fixes #930, #1259, #2908, #2960, #3097
Refs #1200, #1914, #1942, #2568, #2132, #2563
This was SVN commit r16751.
2015-06-12 11:58:24 -07:00
|
|
|
LongPathfinder m_LongPathfinder;
|
|
|
|
|
|
2011-01-12 04:29:00 -08:00
|
|
|
bool m_CommandsComputed;
|
2013-05-26 14:57:24 -07:00
|
|
|
|
2017-08-07 12:35:43 -07:00
|
|
|
CTemplateLoader m_TemplateLoader;
|
2011-01-12 04:29:00 -08:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2012-02-29 19:55:05 -08:00
|
|
|
/**
|
|
|
|
|
* Implementation of ICmpAIManager.
|
|
|
|
|
*/
|
2011-01-12 04:29:00 -08:00
|
|
|
class CCmpAIManager : public ICmpAIManager
|
|
|
|
|
{
|
|
|
|
|
public:
|
2017-11-24 11:13:28 -08:00
|
|
|
static void ClassInit(CComponentManager& UNUSED(componentManager))
|
2011-01-12 04:29:00 -08:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DEFAULT_COMPONENT_ALLOCATOR(AIManager)
|
|
|
|
|
|
|
|
|
|
static std::string GetSchema()
|
|
|
|
|
{
|
|
|
|
|
return "<a:component type='system'/><empty/>";
|
|
|
|
|
}
|
|
|
|
|
|
2011-01-16 06:08:38 -08:00
|
|
|
virtual void Init(const CParamNode& UNUSED(paramNode))
|
2011-01-12 04:29:00 -08:00
|
|
|
{
|
2011-11-23 13:24:41 -08:00
|
|
|
m_TerritoriesDirtyID = 0;
|
2017-10-07 01:42:39 -07:00
|
|
|
m_TerritoriesDirtyBlinkingID = 0;
|
2013-12-11 09:10:14 -08:00
|
|
|
m_JustDeserialized = false;
|
2011-01-12 04:29:00 -08:00
|
|
|
}
|
|
|
|
|
|
2011-01-16 06:08:38 -08:00
|
|
|
virtual void Deinit()
|
2011-01-12 04:29:00 -08:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual void Serialize(ISerializer& serialize)
|
|
|
|
|
{
|
2015-05-07 12:09:39 -07:00
|
|
|
serialize.NumberU32_Unbounded("num ais", m_Worker.getPlayerSize());
|
|
|
|
|
|
2011-01-12 04:29:00 -08:00
|
|
|
// Because the AI worker uses its own ScriptInterface, we can't use the
|
|
|
|
|
// ISerializer (which was initialised with the simulation ScriptInterface)
|
|
|
|
|
// directly. So we'll just grab the ISerializer's stream and write to it
|
|
|
|
|
// with an independent serializer.
|
|
|
|
|
|
2011-12-22 06:04:32 -08:00
|
|
|
m_Worker.Serialize(serialize.GetStream(), serialize.IsDebug());
|
2011-01-12 04:29:00 -08:00
|
|
|
}
|
|
|
|
|
|
2011-01-16 06:08:38 -08:00
|
|
|
virtual void Deserialize(const CParamNode& paramNode, IDeserializer& deserialize)
|
2011-01-12 04:29:00 -08:00
|
|
|
{
|
2011-01-16 06:08:38 -08:00
|
|
|
Init(paramNode);
|
2011-01-12 04:29:00 -08:00
|
|
|
|
2015-05-07 12:09:39 -07:00
|
|
|
u32 numAis;
|
|
|
|
|
deserialize.NumberU32_Unbounded("num ais", numAis);
|
|
|
|
|
if (numAis > 0)
|
2017-11-24 11:13:28 -08:00
|
|
|
LoadUsedEntityTemplates();
|
2011-12-22 06:04:32 -08:00
|
|
|
|
2015-05-07 12:09:39 -07:00
|
|
|
m_Worker.Deserialize(deserialize.GetStream(), numAis);
|
2015-06-17 13:35:23 -07:00
|
|
|
|
2013-12-11 09:10:14 -08:00
|
|
|
m_JustDeserialized = true;
|
2011-01-12 04:29:00 -08:00
|
|
|
}
|
|
|
|
|
|
2017-12-20 14:02:15 -08:00
|
|
|
virtual void AddPlayer(const std::wstring& id, player_id_t player, u8 difficulty, const std::wstring& behavior)
|
2011-01-12 04:29:00 -08:00
|
|
|
{
|
2017-11-24 11:13:28 -08:00
|
|
|
LoadUsedEntityTemplates();
|
|
|
|
|
|
2017-12-20 14:02:15 -08:00
|
|
|
m_Worker.AddPlayer(id, player, difficulty, behavior);
|
2011-06-28 16:24:42 -07:00
|
|
|
|
|
|
|
|
// AI players can cheat and see through FoW/SoD, since that greatly simplifies
|
|
|
|
|
// their implementation.
|
|
|
|
|
// (TODO: maybe cleverer AIs should be able to optionally retain FoW/SoD)
|
2013-09-11 13:41:53 -07:00
|
|
|
CmpPtr<ICmpRangeManager> cmpRangeManager(GetSystemEntity());
|
2012-02-07 18:46:15 -08:00
|
|
|
if (cmpRangeManager)
|
2011-06-28 16:24:42 -07:00
|
|
|
cmpRangeManager->SetLosRevealAll(player, true);
|
2011-01-12 04:29:00 -08:00
|
|
|
}
|
2015-06-17 13:35:23 -07:00
|
|
|
|
2015-05-07 12:09:39 -07:00
|
|
|
virtual void SetRNGSeed(u32 seed)
|
2014-11-16 11:53:29 -08:00
|
|
|
{
|
|
|
|
|
m_Worker.SetRNGSeed(seed);
|
|
|
|
|
}
|
|
|
|
|
|
2013-03-05 14:52:48 -08:00
|
|
|
virtual void TryLoadSharedComponent()
|
|
|
|
|
{
|
2017-12-30 17:02:21 -08:00
|
|
|
m_Worker.TryLoadSharedComponent();
|
2013-03-05 14:52:48 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual void RunGamestateInit()
|
|
|
|
|
{
|
2017-11-24 22:49:58 -08:00
|
|
|
const ScriptInterface& scriptInterface = GetSimContext().GetScriptInterface();
|
Improve JS Exception handling.
- Check for pending exceptions after function calls and script
executions.
- Call LOGERROR instead of JS_ReportError when there is a conversion
error in FromJSVal, since that can only be called from C++ (where JS
errors don't really make sense). Instead, C++ callers of FromJSVal
should handle the failure and, themselves, either report an error or
simply do something else.
- Wrap JS_ReportError since that makes updating it later easier.
This isn't a systematical fix since ToJSVal also ought return a boolean
for failures, and we probably should trigger errors instead of warnings
on 'implicit' conversions, rather a preparation diff.
Part of the SM52 migration, stage: SM45 compatible (actually SM52
incompatible, too).
Based on a patch by: Itms
Comments by: Vladislavbelov, Stan`
Refs #742, #4893
Differential Revision: https://code.wildfiregames.com/D3093
This was SVN commit r24187.
2020-11-15 10:29:17 -08:00
|
|
|
ScriptRequest rq(scriptInterface);
|
2015-06-17 13:35:23 -07:00
|
|
|
|
2013-09-11 13:41:53 -07:00
|
|
|
CmpPtr<ICmpAIInterface> cmpAIInterface(GetSystemEntity());
|
2013-03-05 14:52:48 -08:00
|
|
|
ENSURE(cmpAIInterface);
|
2015-06-17 13:35:23 -07:00
|
|
|
|
2013-03-05 14:52:48 -08:00
|
|
|
// Get the game state from AIInterface
|
2013-12-04 08:52:44 -08:00
|
|
|
// We flush events from the initialization so we get a clean state now.
|
2020-11-13 05:18:22 -08:00
|
|
|
JS::RootedValue state(rq.cx);
|
2015-01-24 06:46:52 -08:00
|
|
|
cmpAIInterface->GetFullRepresentation(&state, true);
|
2013-03-05 14:52:48 -08:00
|
|
|
|
|
|
|
|
// Get the passability data
|
2015-10-03 01:27:19 -07:00
|
|
|
Grid<NavcellData> dummyGrid;
|
|
|
|
|
const Grid<NavcellData>* passabilityMap = &dummyGrid;
|
2013-09-11 13:41:53 -07:00
|
|
|
CmpPtr<ICmpPathfinder> cmpPathfinder(GetSystemEntity());
|
2013-03-05 14:52:48 -08:00
|
|
|
if (cmpPathfinder)
|
|
|
|
|
passabilityMap = &cmpPathfinder->GetPassabilityGrid();
|
2015-06-17 13:35:23 -07:00
|
|
|
|
2013-03-05 14:52:48 -08:00
|
|
|
// Get the territory data
|
2018-02-03 06:17:31 -08:00
|
|
|
// Since getting the territory grid can trigger a recalculation, we check NeedUpdateAI first
|
2013-03-05 14:52:48 -08:00
|
|
|
Grid<u8> dummyGrid2;
|
|
|
|
|
const Grid<u8>* territoryMap = &dummyGrid2;
|
2013-09-11 13:41:53 -07:00
|
|
|
CmpPtr<ICmpTerritoryManager> cmpTerritoryManager(GetSystemEntity());
|
2018-02-03 06:17:31 -08:00
|
|
|
if (cmpTerritoryManager && cmpTerritoryManager->NeedUpdateAI(&m_TerritoriesDirtyID, &m_TerritoriesDirtyBlinkingID))
|
2013-03-05 14:52:48 -08:00
|
|
|
territoryMap = &cmpTerritoryManager->GetTerritoryGrid();
|
2015-06-17 13:35:23 -07:00
|
|
|
|
2013-03-05 14:52:48 -08:00
|
|
|
LoadPathfinderClasses(state);
|
2015-07-05 12:14:52 -07:00
|
|
|
std::map<std::string, pass_class_t> nonPathfindingPassClassMasks, pathfindingPassClassMasks;
|
2015-06-17 13:35:23 -07:00
|
|
|
if (cmpPathfinder)
|
2015-07-05 12:14:52 -07:00
|
|
|
cmpPathfinder->GetPassabilityClasses(nonPathfindingPassClassMasks, pathfindingPassClassMasks);
|
2013-03-05 14:52:48 -08:00
|
|
|
|
2020-12-06 06:03:02 -08:00
|
|
|
m_Worker.RunGamestateInit(scriptInterface.WriteStructuredClone(state),
|
2020-11-18 06:39:04 -08:00
|
|
|
*passabilityMap, *territoryMap, nonPathfindingPassClassMasks, pathfindingPassClassMasks);
|
2013-03-05 14:52:48 -08:00
|
|
|
}
|
2011-01-12 04:29:00 -08:00
|
|
|
|
|
|
|
|
virtual void StartComputation()
|
|
|
|
|
{
|
|
|
|
|
PROFILE("AI setup");
|
|
|
|
|
|
2017-11-24 22:49:58 -08:00
|
|
|
const ScriptInterface& scriptInterface = GetSimContext().GetScriptInterface();
|
Improve JS Exception handling.
- Check for pending exceptions after function calls and script
executions.
- Call LOGERROR instead of JS_ReportError when there is a conversion
error in FromJSVal, since that can only be called from C++ (where JS
errors don't really make sense). Instead, C++ callers of FromJSVal
should handle the failure and, themselves, either report an error or
simply do something else.
- Wrap JS_ReportError since that makes updating it later easier.
This isn't a systematical fix since ToJSVal also ought return a boolean
for failures, and we probably should trigger errors instead of warnings
on 'implicit' conversions, rather a preparation diff.
Part of the SM52 migration, stage: SM45 compatible (actually SM52
incompatible, too).
Based on a patch by: Itms
Comments by: Vladislavbelov, Stan`
Refs #742, #4893
Differential Revision: https://code.wildfiregames.com/D3093
This was SVN commit r24187.
2020-11-15 10:29:17 -08:00
|
|
|
ScriptRequest rq(scriptInterface);
|
2011-01-12 04:29:00 -08:00
|
|
|
|
2013-03-05 14:52:48 -08:00
|
|
|
if (m_Worker.getPlayerSize() == 0)
|
|
|
|
|
return;
|
2015-06-17 13:35:23 -07:00
|
|
|
|
2013-09-11 13:41:53 -07:00
|
|
|
CmpPtr<ICmpAIInterface> cmpAIInterface(GetSystemEntity());
|
2012-02-07 18:46:15 -08:00
|
|
|
ENSURE(cmpAIInterface);
|
2011-01-12 04:29:00 -08:00
|
|
|
|
2011-01-15 15:35:20 -08:00
|
|
|
// Get the game state from AIInterface
|
2020-11-13 05:18:22 -08:00
|
|
|
JS::RootedValue state(rq.cx);
|
2013-12-11 09:10:14 -08:00
|
|
|
if (m_JustDeserialized)
|
2015-01-24 06:46:52 -08:00
|
|
|
cmpAIInterface->GetFullRepresentation(&state, false);
|
2013-12-11 09:10:14 -08:00
|
|
|
else
|
2015-01-24 06:46:52 -08:00
|
|
|
cmpAIInterface->GetRepresentation(&state);
|
2016-09-24 08:16:55 -07:00
|
|
|
LoadPathfinderClasses(state); // add the pathfinding classes to it
|
2011-01-12 04:29:00 -08:00
|
|
|
|
2016-09-24 08:16:55 -07:00
|
|
|
// Update the game state
|
2020-12-06 06:03:02 -08:00
|
|
|
m_Worker.UpdateGameState(scriptInterface.WriteStructuredClone(state));
|
2016-09-24 08:16:55 -07:00
|
|
|
|
|
|
|
|
// Update the pathfinding data
|
2013-09-11 13:41:53 -07:00
|
|
|
CmpPtr<ICmpPathfinder> cmpPathfinder(GetSystemEntity());
|
2012-02-07 18:46:15 -08:00
|
|
|
if (cmpPathfinder)
|
2016-09-24 08:16:55 -07:00
|
|
|
{
|
2017-07-14 03:09:32 -07:00
|
|
|
const GridUpdateInformation& dirtinessInformations = cmpPathfinder->GetAIPathfinderDirtinessInformation();
|
2011-10-15 19:55:58 -07:00
|
|
|
|
2016-10-01 05:29:44 -07:00
|
|
|
if (dirtinessInformations.dirty || m_JustDeserialized)
|
2016-09-24 08:16:55 -07:00
|
|
|
{
|
|
|
|
|
const Grid<NavcellData>& passabilityMap = cmpPathfinder->GetPassabilityGrid();
|
New long-range pathfinder.
Based on Philip's work located at
http://git.wildfiregames.com/gitweb/?p=0ad.git;a=shortlog;h=refs/heads/projects/philip/pathfinder
Includes code by wraitii, sanderd17 and kanetaka.
An updated version of docs/pathfinder.pdf describing the changes in
detail will be committed ASAP.
Running update-workspaces is needed after this change.
Fixes #1756.
Fixes #930, #1259, #2908, #2960, #3097
Refs #1200, #1914, #1942, #2568, #2132, #2563
This was SVN commit r16751.
2015-06-12 11:58:24 -07:00
|
|
|
|
2016-09-24 08:16:55 -07:00
|
|
|
std::map<std::string, pass_class_t> nonPathfindingPassClassMasks, pathfindingPassClassMasks;
|
|
|
|
|
cmpPathfinder->GetPassabilityClasses(nonPathfindingPassClassMasks, pathfindingPassClassMasks);
|
|
|
|
|
|
2016-10-01 05:29:44 -07:00
|
|
|
m_Worker.UpdatePathfinder(passabilityMap,
|
|
|
|
|
dirtinessInformations.globallyDirty, dirtinessInformations.dirtinessGrid, m_JustDeserialized,
|
2016-09-24 08:16:55 -07:00
|
|
|
nonPathfindingPassClassMasks, pathfindingPassClassMasks);
|
|
|
|
|
}
|
2017-07-14 03:09:32 -07:00
|
|
|
|
|
|
|
|
cmpPathfinder->FlushAIPathfinderDirtinessInformation();
|
2016-09-24 08:16:55 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Update the territory data
|
2018-02-03 06:17:31 -08:00
|
|
|
// Since getting the territory grid can trigger a recalculation, we check NeedUpdateAI first
|
2013-09-11 13:41:53 -07:00
|
|
|
CmpPtr<ICmpTerritoryManager> cmpTerritoryManager(GetSystemEntity());
|
2018-02-03 06:17:31 -08:00
|
|
|
if (cmpTerritoryManager && (cmpTerritoryManager->NeedUpdateAI(&m_TerritoriesDirtyID, &m_TerritoriesDirtyBlinkingID) || m_JustDeserialized))
|
2011-10-15 19:55:58 -07:00
|
|
|
{
|
2016-09-24 08:16:55 -07:00
|
|
|
const Grid<u8>& territoryMap = cmpTerritoryManager->GetTerritoryGrid();
|
|
|
|
|
m_Worker.UpdateTerritoryMap(territoryMap);
|
2011-10-15 19:55:58 -07:00
|
|
|
}
|
2011-02-10 08:06:28 -08:00
|
|
|
|
2016-09-24 08:16:55 -07:00
|
|
|
m_Worker.StartComputation();
|
2015-06-17 13:35:23 -07:00
|
|
|
|
2013-12-11 09:10:14 -08:00
|
|
|
m_JustDeserialized = false;
|
2011-01-12 04:29:00 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual void PushCommands()
|
|
|
|
|
{
|
2011-01-15 15:35:20 -08:00
|
|
|
std::vector<CAIWorker::SCommandSets> commands;
|
2011-01-12 04:29:00 -08:00
|
|
|
m_Worker.GetCommands(commands);
|
|
|
|
|
|
2013-09-11 13:41:53 -07:00
|
|
|
CmpPtr<ICmpCommandQueue> cmpCommandQueue(GetSystemEntity());
|
2012-02-07 18:46:15 -08:00
|
|
|
if (!cmpCommandQueue)
|
2011-01-12 04:29:00 -08:00
|
|
|
return;
|
2015-06-17 13:35:23 -07:00
|
|
|
|
2017-11-24 22:49:58 -08:00
|
|
|
const ScriptInterface& scriptInterface = GetSimContext().GetScriptInterface();
|
Improve JS Exception handling.
- Check for pending exceptions after function calls and script
executions.
- Call LOGERROR instead of JS_ReportError when there is a conversion
error in FromJSVal, since that can only be called from C++ (where JS
errors don't really make sense). Instead, C++ callers of FromJSVal
should handle the failure and, themselves, either report an error or
simply do something else.
- Wrap JS_ReportError since that makes updating it later easier.
This isn't a systematical fix since ToJSVal also ought return a boolean
for failures, and we probably should trigger errors instead of warnings
on 'implicit' conversions, rather a preparation diff.
Part of the SM52 migration, stage: SM45 compatible (actually SM52
incompatible, too).
Based on a patch by: Itms
Comments by: Vladislavbelov, Stan`
Refs #742, #4893
Differential Revision: https://code.wildfiregames.com/D3093
This was SVN commit r24187.
2020-11-15 10:29:17 -08:00
|
|
|
ScriptRequest rq(scriptInterface);
|
2020-11-13 05:18:22 -08:00
|
|
|
JS::RootedValue clonedCommandVal(rq.cx);
|
2015-06-17 13:35:23 -07:00
|
|
|
|
2011-01-12 04:29:00 -08:00
|
|
|
for (size_t i = 0; i < commands.size(); ++i)
|
|
|
|
|
{
|
|
|
|
|
for (size_t j = 0; j < commands[i].commands.size(); ++j)
|
|
|
|
|
{
|
2014-08-01 13:55:16 -07:00
|
|
|
scriptInterface.ReadStructuredClone(commands[i].commands[j], &clonedCommandVal);
|
2015-01-24 06:46:52 -08:00
|
|
|
cmpCommandQueue->PushLocalCommand(commands[i].player, clonedCommandVal);
|
2011-01-12 04:29:00 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
2011-10-15 19:55:58 -07:00
|
|
|
size_t m_TerritoriesDirtyID;
|
2017-10-07 01:42:39 -07:00
|
|
|
size_t m_TerritoriesDirtyBlinkingID;
|
2011-03-04 17:56:59 -08:00
|
|
|
|
2013-12-11 09:10:14 -08:00
|
|
|
bool m_JustDeserialized;
|
|
|
|
|
|
2017-11-24 11:13:28 -08:00
|
|
|
/**
|
|
|
|
|
* Load the templates of all entities on the map (called when adding a new AI player for a new game
|
|
|
|
|
* or when deserializing)
|
|
|
|
|
*/
|
|
|
|
|
void LoadUsedEntityTemplates()
|
2011-03-04 17:56:59 -08:00
|
|
|
{
|
2017-11-24 11:13:28 -08:00
|
|
|
if (m_Worker.HasLoadedEntityTemplates())
|
|
|
|
|
return;
|
2011-01-12 04:29:00 -08:00
|
|
|
|
2013-09-11 13:41:53 -07:00
|
|
|
CmpPtr<ICmpTemplateManager> cmpTemplateManager(GetSystemEntity());
|
2012-02-07 18:46:15 -08:00
|
|
|
ENSURE(cmpTemplateManager);
|
2011-01-12 04:29:00 -08:00
|
|
|
|
2017-11-24 11:13:28 -08:00
|
|
|
std::vector<std::string> templateNames = cmpTemplateManager->FindUsedTemplates();
|
|
|
|
|
std::vector<std::pair<std::string, const CParamNode*> > usedTemplates;
|
|
|
|
|
usedTemplates.reserve(templateNames.size());
|
|
|
|
|
for (const std::string& name : templateNames)
|
2011-01-12 04:29:00 -08:00
|
|
|
{
|
2017-11-24 11:13:28 -08:00
|
|
|
const CParamNode* node = cmpTemplateManager->GetTemplateWithoutValidation(name);
|
|
|
|
|
if (node)
|
|
|
|
|
usedTemplates.emplace_back(name, node);
|
2011-01-12 04:29:00 -08:00
|
|
|
}
|
2017-11-24 11:13:28 -08:00
|
|
|
// Send the data to the worker
|
|
|
|
|
m_Worker.LoadEntityTemplates(usedTemplates);
|
2011-01-12 04:29:00 -08:00
|
|
|
}
|
|
|
|
|
|
2014-07-26 15:33:16 -07:00
|
|
|
void LoadPathfinderClasses(JS::HandleValue state)
|
2011-02-10 08:06:28 -08:00
|
|
|
{
|
2013-09-11 13:41:53 -07:00
|
|
|
CmpPtr<ICmpPathfinder> cmpPathfinder(GetSystemEntity());
|
2012-02-07 18:46:15 -08:00
|
|
|
if (!cmpPathfinder)
|
2011-02-10 08:06:28 -08:00
|
|
|
return;
|
|
|
|
|
|
2017-11-24 22:49:58 -08:00
|
|
|
const ScriptInterface& scriptInterface = GetSimContext().GetScriptInterface();
|
Improve JS Exception handling.
- Check for pending exceptions after function calls and script
executions.
- Call LOGERROR instead of JS_ReportError when there is a conversion
error in FromJSVal, since that can only be called from C++ (where JS
errors don't really make sense). Instead, C++ callers of FromJSVal
should handle the failure and, themselves, either report an error or
simply do something else.
- Wrap JS_ReportError since that makes updating it later easier.
This isn't a systematical fix since ToJSVal also ought return a boolean
for failures, and we probably should trigger errors instead of warnings
on 'implicit' conversions, rather a preparation diff.
Part of the SM52 migration, stage: SM45 compatible (actually SM52
incompatible, too).
Based on a patch by: Itms
Comments by: Vladislavbelov, Stan`
Refs #742, #4893
Differential Revision: https://code.wildfiregames.com/D3093
This was SVN commit r24187.
2020-11-15 10:29:17 -08:00
|
|
|
ScriptRequest rq(scriptInterface);
|
2011-02-10 08:06:28 -08:00
|
|
|
|
2020-11-13 05:18:22 -08:00
|
|
|
JS::RootedValue classesVal(rq.cx);
|
|
|
|
|
ScriptInterface::CreateObject(rq, &classesVal);
|
2011-02-10 08:06:28 -08:00
|
|
|
|
2015-07-05 12:14:52 -07:00
|
|
|
std::map<std::string, pass_class_t> classes;
|
|
|
|
|
cmpPathfinder->GetPassabilityClasses(classes);
|
New long-range pathfinder.
Based on Philip's work located at
http://git.wildfiregames.com/gitweb/?p=0ad.git;a=shortlog;h=refs/heads/projects/philip/pathfinder
Includes code by wraitii, sanderd17 and kanetaka.
An updated version of docs/pathfinder.pdf describing the changes in
detail will be committed ASAP.
Running update-workspaces is needed after this change.
Fixes #1756.
Fixes #930, #1259, #2908, #2960, #3097
Refs #1200, #1914, #1942, #2568, #2132, #2563
This was SVN commit r16751.
2015-06-12 11:58:24 -07:00
|
|
|
for (std::map<std::string, pass_class_t>::iterator it = classes.begin(); it != classes.end(); ++it)
|
2014-07-26 15:33:16 -07:00
|
|
|
scriptInterface.SetProperty(classesVal, it->first.c_str(), it->second, true);
|
2011-02-10 08:06:28 -08:00
|
|
|
|
2014-07-26 15:33:16 -07:00
|
|
|
scriptInterface.SetProperty(state, "passabilityClasses", classesVal, true);
|
2011-02-10 08:06:28 -08:00
|
|
|
}
|
|
|
|
|
|
2011-01-12 04:29:00 -08:00
|
|
|
CAIWorker m_Worker;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
REGISTER_COMPONENT_TYPE(AIManager)
|