Threads and tasks

This commit is contained in:
2026-01-29 15:28:50 +03:00
parent 4cf0ea5321
commit da4c1fee0e
21 changed files with 1464 additions and 558 deletions

View File

@@ -3,6 +3,7 @@
#include <iostream>
#include <flecs.h>
#include <nlohmann/json.hpp>
#include <lua.hpp>
#include "Components.h"
#include "GameData.h"
#include "CharacterManagerModule.h"
@@ -181,6 +182,33 @@ struct LuaNarrationHandler : GUI::NarrationHandler {
},
1);
lua_setfield(L, -2, "_get_properties");
lua_pushlightuserdata(L, this);
lua_pushcclosure(
L,
[](lua_State *L) {
LuaNarrationHandler *handler =
static_cast<LuaNarrationHandler *>(
lua_touserdata(
L,
lua_upvalueindex(1)));
lua_pushstring(
L, handler->getProperties().c_str());
const std::vector<ActionNodeList::ActionNode>
&nodes = ECS::get<ActionNodeList>()
.dynamicNodes;
lua_newtable(L);
int i;
for (i = 0; i < nodes.size(); i++) {
lua_pushinteger(L, i + 1);
lua_pushstring(
L,
nodes[i].props.dump().c_str());
lua_settable(L, -3);
}
return 1;
},
1);
lua_setfield(L, -2, "_get_goals");
lua_pop(L, 1);
}
void finish() override
@@ -231,7 +259,7 @@ struct SimpleWordHandler : PlayerActionModule::ActionWordHandler {
const TownNPCs::NPCData &npc =
town.get<TownNPCs>().npcs.at(index);
flecs::entity e = npc.e;
for (const auto &anode : e.get<NPCActionNodes>().anodes) {
for (const auto &anode : npc.actionNodes) {
if (anode.action == word) {
nlohmann::json props = anode.props;
props["initiator"] =
@@ -254,17 +282,18 @@ PlayerActionModule::PlayerActionModule(flecs::world &ecs)
ecs.import <CharacterManagerModule>();
ecs.component<ActionNodeList>()
.on_add([](flecs::entity e, ActionNodeList &alist) {
alist.dirty = true;
alist.nodeMutex = std::make_shared<std::mutex>();
alist.setDirty();
alist.nodes.reserve(1000);
alist.dynamicNodes.reserve(1000);
alist.selected = -1;
alist.busy = false;
alist.setUISelected(-1);
alist.setReady();
})
.add(flecs::Singleton);
ecs.system<ActionNodeList>("updateNodeList")
.kind(flecs::OnUpdate)
.each([](ActionNodeList &list) {
if (list.busy)
if (list.isBusy())
return;
if (list.nodes.size() > 0) {
Ogre::SceneNode *cameraNode =
@@ -279,49 +308,55 @@ PlayerActionModule::PlayerActionModule(flecs::world &ecs)
player.get<CharacterBase>()
.mBodyNode
->_getDerivedPosition();
list.query(playerPos, list.points,
list.distances);
list.UIquery(playerPos);
} else {
list.query(cameraPos, list.points,
list.distances);
list.UIquery(cameraPos);
}
}
});
ecs.system<ActionNodeList, const Input>("ActivateActionNode")
.kind(flecs::OnUpdate)
.each([this](ActionNodeList &list, const Input &input) {
std::lock_guard<std::mutex> lock(*list.nodeMutex);
if (input.control & 32)
std::cout << "act pressed" << std::endl;
if (list.busy)
if (list.isBusy())
return;
if (input.act_pressed && list.selected >= 0) {
std::cout << list.dynamicNodes[list.selected]
.props.dump(4)
<< std::endl;
if (input.act_pressed &&
list.getUIData().selected >= 0) {
std::cout
<< list.dynamicNodes[list.getUIData()
.selected]
.props.dump(4)
<< std::endl;
flecs::entity_t townid =
list.dynamicNodes[list.selected]
list.dynamicNodes[list.getUIData()
.selected]
.props["town"]
.get<flecs::entity_t>();
flecs::entity town = ECS::get().entity(townid);
int index = list.dynamicNodes[list.selected]
int index = list.dynamicNodes[list.getUIData()
.selected]
.props["index"]
.get<int>();
for (auto it = actionWords.begin();
it != actionWords.end(); it++) {
if (it->first ==
list.dynamicNodes[list.selected]
list.dynamicNodes[list.getUIData()
.selected]
.action) {
(*it->second)(
town, index,
list.dynamicNodes
[list.selected]
[list.getUIData()
.selected]
.action);
list.busy = true;
list.setBusy();
}
}
}
if (!ECS::get<GUI>().enabled)
list.busy = false;
list.setReady();
});
}
@@ -367,8 +402,7 @@ struct LuaWordHandler : PlayerActionModule::ActionWordHandler {
const TownNPCs::NPCData &npc =
town.get<TownNPCs>().npcs.at(index);
flecs::entity e = npc.e;
for (const auto &anode :
e.get<NPCActionNodes>().anodes) {
for (const auto &anode : npc.actionNodes) {
if (anode.action == word) {
nlohmann::json props = anode.props;
props["initiator"] =
@@ -426,27 +460,41 @@ int PlayerActionModule::setupLuaActionHandler(lua_State *L)
return 0;
}
void ActionNodeList::updateDynamicNodes()
{
std::lock_guard<std::mutex> lock(*nodeMutex);
if (dynamicNodes.size() > nodes.size())
dynamicNodes.resize(nodes.size());
else {
dynamicNodes.clear();
dynamicNodes.insert(dynamicNodes.end(), nodes.begin(),
nodes.end());
}
ECS::get().query_builder<const TownNPCs>().each(
[this](flecs::entity town, const TownNPCs &npcs) {
for (auto it = npcs.npcs.begin(); it != npcs.npcs.end();
it++) {
dynamicNodes.insert(
dynamicNodes.end(),
it->second.actionNodes.begin(),
it->second.actionNodes.end());
}
});
dirty = true;
}
void ActionNodeList::build()
{
dynamicNodes.clear();
dynamicNodes.insert(dynamicNodes.end(), nodes.begin(), nodes.end());
ECS::get().query_builder<const NPCActionNodes>().each(
[&](flecs::entity e, const NPCActionNodes &anodes) {
dynamicNodes.insert(dynamicNodes.end(),
anodes.anodes.begin(),
anodes.anodes.end());
});
std::lock_guard<std::mutex> lock(*nodeMutex);
indexObj = std::make_shared<ActionNodeList::indexObject>(dynamicNodes);
indexObj->index.buildIndex();
dirty = false;
}
bool ActionNodeList::query(const Ogre::Vector3 &position,
std::vector<size_t> &points,
std::vector<float> &distances)
bool ActionNodeList::_query(const Ogre::Vector3 &position,
std::vector<size_t> &points,
std::vector<float> &distances)
{
build();
std::vector<size_t> tmppoints;
std::vector<float> tmpdistances;
points.clear();
@@ -455,6 +503,10 @@ bool ActionNodeList::query(const Ogre::Vector3 &position,
distances.reserve(4);
tmppoints.resize(4);
tmpdistances.resize(4);
if (!indexObj) {
dirty = true;
return false;
}
nanoflann::KNNResultSet<float> resultSet(4);
resultSet.init(tmppoints.data(), tmpdistances.data());
bool ret = indexObj->index.findNeighbors(resultSet, &position.x,
@@ -467,4 +519,108 @@ bool ActionNodeList::query(const Ogre::Vector3 &position,
}
return ret;
}
bool ActionNodeList::query_ai(const Ogre::Vector3 &position, float distance,
std::vector<size_t> &points,
std::vector<float> &distances)
{
std::lock_guard<std::mutex> lock(*nodeMutex);
std::vector<size_t> tmppoints;
std::vector<float> tmpdistances;
points.clear();
points.reserve(100);
distances.clear();
distances.reserve(100);
tmppoints.resize(100);
tmpdistances.resize(100);
if (!indexObj) {
dirty = true;
return false;
}
nanoflann::KNNResultSet<float> resultSet(100);
resultSet.init(tmppoints.data(), tmpdistances.data());
bool ret = indexObj->index.findNeighbors(resultSet, &position.x,
nanoflann::SearchParameters());
int i;
for (i = 0; i < resultSet.size(); i++)
if (tmpdistances[i] < distance) {
points.push_back(tmppoints[i]);
distances.push_back(tmpdistances[i]);
}
return ret;
}
int ActionNodeList::addNode(ActionNode &node)
{
std::lock_guard<std::mutex> lock(*nodeMutex);
int index = nodes.size();
nodes.push_back(node);
dirty = true;
return index;
}
void ActionNodeList::removeNode(int index)
{
std::lock_guard<std::mutex> lock(*nodeMutex);
nodes.erase(nodes.begin() + index);
dirty = true;
}
const ActionNodeList::UIData &ActionNodeList::getUIData()
{
std::lock_guard<std::mutex> lock(*uidata.mutex);
return uidata;
}
void ActionNodeList::setUISelected(int selected)
{
std::lock_guard<std::mutex> lock(*uidata.mutex);
uidata.selected = selected;
}
void ActionNodeList::setUIPoints(const std::vector<size_t> &points,
const std::vector<float> &distances)
{
std::lock_guard<std::mutex> lock(*uidata.mutex);
uidata.points = points;
uidata.distances = distances;
}
void ActionNodeList::UIquery(const Ogre::Vector3 &position)
{
bool needBuild = false;
{
std::lock_guard<std::mutex> lock(*nodeMutex);
if (dirty || !indexObj)
needBuild = true;
}
if (needBuild)
build();
{
std::lock_guard<std::mutex> lock(*uidata.mutex);
_query(position, uidata.points, uidata.distances);
}
}
void ActionNodeList::setDirty()
{
dirty = true;
}
void ActionNodeList::setReady()
{
busy = false;
}
void ActionNodeList::setBusy()
{
busy = true;
}
bool ActionNodeList::isBusy()
{
return busy;
}
}