Better narration processing

This commit is contained in:
2026-01-22 17:15:19 +03:00
parent 4b24d85123
commit cd91174f5d
23 changed files with 1301 additions and 367 deletions

View File

@@ -1,8 +1,16 @@
#include <nanoflann.hpp>
#include <vector>
#include <iostream>
#include <flecs.h>
#include <nlohmann/json.hpp>
#include "Components.h"
#include "GameData.h"
#include "CharacterManagerModule.h"
#include "CharacterModule.h"
#include "items.h"
#include "GUIModule.h"
#include "GUIModuleCommon.h"
#include "LuaData.h"
#include "PlayerActionModule.h"
namespace ECS
@@ -51,13 +59,69 @@ struct ActionNodeList::indexObject {
}
};
struct TestNarrativeHandler : GUI::NarrationHandler {
int count;
TestNarrativeHandler()
: GUI::NarrationHandler()
, count(0)
{
}
void finish() override
{
_clear_narration();
}
void activate() override
{
_narration("Dialogue...", {});
count = 0;
}
void event(const Ogre::String &evt) override
{
if (evt == "narration_progress" ||
evt == "narration_answered") {
count++;
if (count == 1) {
_narration(
"Question..." +
Ogre::StringConverter::toString(
count),
{ "Answer1", "Answer2" });
} else {
_narration(
"Whatever..." +
Ogre::StringConverter::toString(
count),
{});
}
if (count > 5)
_finish();
}
if (evt == "narration_answered")
std::cout << "answer: " << getNarrationAnswer()
<< std::endl;
}
};
struct SimpleWordHandler : PlayerActionModule::ActionWordHandler {
void operator()(flecs::entity town, int index,
const Ogre::String &word) override
{
TestNarrativeHandler *handle = OGRE_NEW TestNarrativeHandler();
ECS::get_mut<GUI>().addNarrationHandler(handle);
ECS::modified<GUI>();
}
};
PlayerActionModule::PlayerActionModule(flecs::world &ecs)
{
ecs.module<PlayerActionModule>();
ecs.import <CharacterManagerModule>();
ecs.component<ActionNodeList>()
.on_add([](flecs::entity e, ActionNodeList &alist) {
alist.dirty = true;
alist.nodes.reserve(1000);
alist.dynamicNodes.reserve(1000);
alist.selected = -1;
alist.busy = false;
})
.add(flecs::Singleton);
#if 0
@@ -79,25 +143,166 @@ PlayerActionModule::PlayerActionModule(flecs::world &ecs)
}
});
#endif
ecs.system<ActionNodeList>("updateNodeList")
.kind(flecs::OnUpdate)
.each([](ActionNodeList &list) {
if (list.busy)
return;
if (list.nodes.size() > 0) {
Ogre::SceneNode *cameraNode =
ECS::get<Camera>().mCameraNode;
Ogre::Vector3 cameraPos =
cameraNode->_getDerivedPosition();
flecs::entity player =
ECS::get<CharacterManagerModule>()
.getPlayer();
if (player.is_valid()) {
Ogre::Vector3 playerPos =
player.get<CharacterBase>()
.mBodyNode
->_getDerivedPosition();
list.query(playerPos, list.points,
list.distances);
} else {
list.query(cameraPos, list.points,
list.distances);
}
}
});
ecs.system<ActionNodeList, const Input>("ActivateActionNode")
.kind(flecs::OnUpdate)
.each([this](ActionNodeList &list, const Input &input) {
if (input.control & 32)
std::cout << "act pressed" << std::endl;
if (list.busy)
return;
if (input.act_pressed && list.selected >= 0) {
std::cout << list.dynamicNodes[list.selected]
.props.dump(4)
<< std::endl;
flecs::entity_t townid =
list.dynamicNodes[list.selected]
.props["town"]
.get<flecs::entity_t>();
flecs::entity town = ECS::get().entity(townid);
int index = list.dynamicNodes[list.selected]
.props["index"]
.get<int>();
for (auto it = actionWords.begin();
it != actionWords.end(); it++) {
if (it->first ==
list.dynamicNodes[list.selected]
.action) {
(*it->second)(
town, index,
list.dynamicNodes
[list.selected]
.action);
list.busy = true;
}
}
}
if (!ECS::get<GUI>().enabled)
list.busy = false;
});
SimpleWordHandler *handler = OGRE_NEW SimpleWordHandler;
addWordHandler("talk", handler);
}
void PlayerActionModule::addWordHandler(const Ogre::String &word,
ActionWordHandler *handler)
{
actionWords.insert({ word, handler });
}
void PlayerActionModule::removeWordHandler(const Ogre::String &word,
ActionWordHandler *handler)
{
for (auto it = actionWords.begin(); it != actionWords.end();) {
if (it->first == word && it->second == handler)
it = actionWords.erase(it);
else
it++;
}
}
struct LuaWordHandler : PlayerActionModule::ActionWordHandler {
lua_State *L;
int ref;
void operator()(flecs::entity town, int index,
const Ogre::String &word) override
{
lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
lua_pushinteger(L, town.id());
lua_pushinteger(L, index);
lua_pushstring(L, word.c_str());
if (lua_pcall(L, 3, 0, 0)) {
Ogre::LogManager::getSingleton().stream()
<< lua_tostring(L, -1);
OgreAssert(false, "Lua error");
}
}
};
void PlayerActionModule::addLuaWordHandler(const Ogre::String &word,
lua_State *L, int ref)
{
struct LuaWordHandler *handler = OGRE_NEW LuaWordHandler;
handler->L = L;
handler->ref = ref;
addWordHandler(word, handler);
}
void PlayerActionModule::removeLuaWordHandler(const Ogre::String &word,
lua_State *L, int ref)
{
for (auto it = actionWords.begin(); it != actionWords.end();) {
LuaWordHandler *handler =
static_cast<LuaWordHandler *>(it->second);
if (it->first == word && handler->L == L && handler->ref == ref)
it = actionWords.erase(it);
else
it++;
}
}
int PlayerActionModule::setupLuaActionHandler(lua_State *L)
{
luaL_checktype(L, 1, LUA_TSTRING);
luaL_checktype(L, 2, LUA_TFUNCTION);
Ogre::String word = lua_tostring(L, 1);
lua_pushvalue(L, 2);
int ref = luaL_ref(L, LUA_REGISTRYINDEX);
addLuaWordHandler(word, L, ref);
return 0;
}
void ActionNodeList::build()
{
indexObj = std::make_shared<ActionNodeList::indexObject>(nodes);
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());
});
indexObj = std::make_shared<ActionNodeList::indexObject>(dynamicNodes);
indexObj->index.buildIndex();
dirty = false;
std::cout << "index built" << std::endl;
}
bool ActionNodeList::query(const Ogre::Vector3 &position,
std::vector<size_t> &points)
std::vector<size_t> &points,
std::vector<float> &distances)
{
if (dirty)
build();
build();
std::vector<size_t> tmppoints;
std::vector<float> tmpdistances;
points.clear();
points.reserve(4);
distances.clear();
distances.reserve(4);
tmppoints.resize(4);
tmpdistances.resize(4);
nanoflann::KNNResultSet<float> resultSet(4);
@@ -106,9 +311,10 @@ bool ActionNodeList::query(const Ogre::Vector3 &position,
nanoflann::SearchParameters());
int i;
for (i = 0; i < resultSet.size(); i++)
if (tmpdistances[i] < 25.0f)
if (tmpdistances[i] < 25.0f) {
points.push_back(tmppoints[i]);
distances.push_back(tmpdistances[i]);
}
return ret;
}
}