BACKEND: integrated the lua ai registry

Martin Gerhardy 2020-03-08 10:34:21 +01:00
parent 5b1ef3b6af
commit 517a9c5205
14 changed files with 81 additions and 10 deletions

View File

@ -0,0 +1,5 @@
local luanode = REGISTRY.createNode("Test")
function luanode:execute(ai, deltaMillis)
print("Node execute called with parameters: ai=["..tostring(ai).."], deltaMillis=["..tostring(deltaMillis).."]")
return FINISHED
end

View File

@ -123,12 +123,12 @@ public:
/**
* @see shutdown()
*/
bool init();
virtual bool init();
/**
* @see init()
*/
void shutdown();
virtual void shutdown();
~LUAAIRegistry();

5
src/modules/ai/README.md Normal file
View File

@ -0,0 +1,5 @@
# General
This module depends on [SimpleAI](https://github.com/mgerhardy/simpleai). A lot of its documentation is doxygen based.
See e.g. [SimpleAI.h](SimpleAI.h)

View File

@ -65,6 +65,7 @@ generate_db_models(${LIB} ${CMAKE_CURRENT_SOURCE_DIR}/tables.tbl BackendModels.h
set(TEST_FILES
tests/behaviourtrees.lua
tests/behaviourtreenodes.lua
tests/test-attributes.lua
)
set(TEST_SRCS

View File

@ -24,9 +24,23 @@
#include "attrib/ContainerProvider.h"
#include "core/io/Filesystem.h"
#include "core/App.h"
namespace backend {
void AIRegistry::init() {
bool AIRegistry::init() {
if (!Super::init()) {
Log::error("Failed to initialize the lua behaviour tree registry");
return false;
}
const core::String& script = io::filesystem()->load("behaviourtreenodes.lua");
if (!evaluate(script)) {
Log::error("Failed to load behaviour tree nodes");
return false;
}
registerNodeFactory("GoHome", GoHome::getFactory());
registerNodeFactory("AttackOnSelection", AttackOnSelection::getFactory());
registerNodeFactory("SetPointOfInterest", SetPointOfInterest::getFactory());
@ -44,6 +58,7 @@ void AIRegistry::init() {
registerFilterFactory("SelectEntitiesOfTypes", SelectEntitiesOfTypes::getFactory());
registerSteeringFactory("WanderAroundHome", WanderAroundHome::getFactory());
return true;
}
}

View File

@ -12,9 +12,11 @@ namespace backend {
/**
* @ingroup AI
*/
class AIRegistry: public ai::AIRegistry {
class AIRegistry: public ai::LUAAIRegistry {
private:
using Super = ai::LUAAIRegistry;
public:
void init();
bool init() override;
};
typedef std::shared_ptr<AIRegistry> AIRegistryPtr;

View File

@ -82,7 +82,7 @@ protected:
network = std::make_shared<network::ServerNetwork>(protocolHandlerRegistry, _testApp->eventBus(), _testApp->metric());
messageSender = std::make_shared<network::ServerMessageSender>(network, _testApp->metric());
registry = std::make_shared<AIRegistry>();
registry->init();
ASSERT_TRUE(registry->init());
loader = std::make_shared<AILoader>(registry);
containerProvider = core::make_shared<attrib::ContainerProvider>();
ASSERT_TRUE(containerProvider->init(CONTAINER));
@ -95,6 +95,7 @@ protected:
persistenceMgr = persistence::createPersistenceMgrMock();
testing::Mock::AllowLeak(persistenceMgr.get());
persistence::DBHandlerPtr dbHandler = persistence::createDbHandlerMock();
// TODO: don't use the DBChunkPersister - but a mock
core::Factory<backend::DBChunkPersister> chunkPersisterFactory;
mapProvider = std::make_shared<MapProvider>(filesystem, eventBus, timeProvider,
entityStorage, messageSender, loader, containerProvider, cooldownProvider,

View File

@ -45,7 +45,7 @@ public:
_network = std::make_shared<network::ServerNetwork>(_protocolHandlerRegistry, _testApp->eventBus(), _testApp->metric());
_messageSender = std::make_shared<network::ServerMessageSender>(_network, _testApp->metric());
const AIRegistryPtr& registry = std::make_shared<AIRegistry>();
registry->init();
ASSERT_TRUE(registry->init());
_loader = std::make_shared<AILoader>(registry);
_containerProvider = core::make_shared<attrib::ContainerProvider>();
_cooldownProvider = std::make_shared<cooldown::CooldownProvider>();

View File

@ -41,7 +41,7 @@ public:
_network = std::make_shared<network::ServerNetwork>(_protocolHandlerRegistry, _testApp->eventBus(), _testApp->metric());
_messageSender = std::make_shared<network::ServerMessageSender>(_network, _testApp->metric());
const AIRegistryPtr& registry = std::make_shared<AIRegistry>();
registry->init();
ASSERT_TRUE(registry->init());
_loader = std::make_shared<AILoader>(registry);
_containerProvider = core::make_shared<attrib::ContainerProvider>();
_cooldownProvider = std::make_shared<cooldown::CooldownProvider>();

View File

@ -45,7 +45,7 @@ public:
_network = std::make_shared<network::ServerNetwork>(_protocolHandlerRegistry, _testApp->eventBus(), _testApp->metric());
_messageSender = std::make_shared<network::ServerMessageSender>(_network, _testApp->metric());
_aiRegistry = std::make_shared<AIRegistry>();
_aiRegistry->init();
ASSERT_TRUE(_aiRegistry->init());
_loader = std::make_shared<AILoader>(_aiRegistry);
_containerProvider = core::make_shared<attrib::ContainerProvider>();
const core::String& attributes = _testApp->filesystem()->load("test-attributes.lua");

View File

@ -86,7 +86,10 @@ void World::construct() {
}
bool World::init() {
_registry->init();
if (!_registry->init()) {
Log::error("Failed to init the ai registry");
return false;
}
if (!_mapProvider->init()) {
Log::error("Failed to init the map provider");

View File

@ -16,6 +16,7 @@ set(LUA_BEHAVIOURTREES
ai/undead-male-zombie.lua
ai/shared.lua
behaviourtrees.lua
behaviourtreenodes.lua
)
set(LUA_ATTRIBUTES
attrib/animal-rabbit.lua

View File

@ -0,0 +1,34 @@
# Behaviour Trees
The behaviour trees are written in lua.
See the documentation given in the [ai module](../../../modules/ai/README.md)
# Functions
## `AI`
`createTree(name)`: Create a new behaviour tree.
## `Tree`
The object returned by `createTree` calls. The following methods are included:
* `createRoot(id, name)`: The `id` if the node factory id as given while registering nodes. The name should match the npc type as given in the [network protocol definition](../../../modules/network/definitions/Shared.fbs).
* `getName()`: Return the name of the root node
## `Node`
The object returned by `createRoot`. The following methods are included:
* `addNode(id, name)`: The `id` if the node factory id as given while registering nodes. The name can be freely chosen.
* `getName`: Return the name of the current node
* `setCondition(conditionExpression)`: See the simpleai documentation for more details about the syntax. It might also be a good idea to check the existing behaviour trees or the unit tests.
# Nodes
The behaviour tree nodes can either be implemented in C++ - see [src/modules/backend/entity/ai/action](../../../modules/backend/entity/ai/action) for examples or in lua (see [src/server/lua/behaviourtreenodes.lua](../behaviourtreenodes.lua) for examples.
## LUARegistry
The lua registry exposes functions to write lua based ai tree nodes (actions, conditions, filter, ...).
This is most likely not complete and if you write a node in lua you will probably find objects or function not yet exposed that would be needed for your script to work. In that case, just go ahead and extend the [LUARegistry.cpp](../../../modules/ai/LUARegistry.cpp).

View File

@ -0,0 +1,4 @@
local luanode = REGISTRY.createNode("Empty")
function luanode:execute(ai, deltaMillis)
return FINISHED
end