Files
ogre-prototype/src/gamedata/CharacterManagerModule.cpp
2026-01-29 15:28:50 +03:00

242 lines
9.0 KiB
C++

#include <Ogre.h>
#include <OgreConfigFile.h>
#include "GameData.h"
#include "Components.h"
#include "CharacterModule.h"
#include "CharacterAnimationModule.h"
#include "StaticGeometryModule.h"
#include "PhysicsModule.h"
#include "PlayerActionModule.h"
#include "items.h"
#include "CharacterManagerModule.h"
namespace ECS
{
void createNPCActionNodes(flecs::entity town, int index)
{
TownNPCs &npcs = town.get_mut<TownNPCs>();
TownNPCs::NPCData &npc = npcs.npcs.at(index);
flecs::entity e = npc.e;
nlohmann::json npcprops = npc.props;
const CharacterBase &ch = e.get<CharacterBase>();
Ogre::Vector3 characterPos = ch.mBodyNode->_getDerivedPosition();
Ogre::Quaternion characterRot = ch.mBodyNode->_getDerivedOrientation();
if (npc.actionNodes.size() > 0) {
int i;
for (i = 0; i < npc.actionNodes.size(); i++) {
auto &anode = npc.actionNodes[i];
Ogre::Vector3 offset = Ogre::Vector3::UNIT_Z * 0.3f +
Ogre::Vector3::UNIT_Y;
if (i == 1)
offset = Ogre::Vector3::NEGATIVE_UNIT_Z * 0.3f +
Ogre::Vector3::UNIT_Y;
anode.position = characterPos + characterRot * offset;
anode.rotation = characterRot;
to_json(anode.props["position"], anode.position);
to_json(anode.props["rotation"], anode.rotation);
}
return;
}
{
ActionNodeList::ActionNode anode;
anode.props["action"] = "talk";
anode.props["action_text"] = "Talk";
anode.action = "talk";
anode.action_text = "Talk";
Ogre::Vector3 offset = Ogre::Vector3::UNIT_Z * 0.25f +
Ogre::Vector3::UNIT_Y * 1.5f;
anode.position = characterPos + characterRot * offset;
anode.rotation = characterRot;
anode.radius = 0.6f;
anode.height = 1.0f;
to_json(anode.props["position"], anode.position);
to_json(anode.props["rotation"], anode.rotation);
anode.props["radius"] = anode.radius;
anode.props["height"] = anode.height;
anode.props["town"] = town.id();
anode.props["index"] = index;
anode.props["npc"] = npcprops;
npc.actionNodes.push_back(anode);
}
{
ActionNodeList::ActionNode anode;
anode.props["action"] = "action";
anode.props["action_text"] = "Action";
anode.action = "action";
anode.action_text = "Action";
Ogre::Vector3 offset = Ogre::Vector3::NEGATIVE_UNIT_Z * 0.2f +
Ogre::Vector3::UNIT_Y;
anode.position = characterPos + characterRot * offset;
anode.rotation = characterRot;
anode.radius = 0.3f;
anode.height = 1.0f;
to_json(anode.props["position"], anode.position);
to_json(anode.props["rotation"], anode.rotation);
anode.props["radius"] = anode.radius;
anode.props["height"] = anode.height;
anode.props["town"] = town.id();
anode.props["index"] = index;
anode.props["npc"] = npcprops;
npc.actionNodes.push_back(anode);
}
}
CharacterManagerModule::CharacterManagerModule(flecs::world &ecs)
{
ecs.module<CharacterManagerModule>();
ecs.import <CharacterModule>();
ecs.import <CharacterAnimationModule>();
ecs.import <PhysicsModule>();
ecs.import <PlayerActionModule>();
ecs.component<TownCharacterHolder>();
ecs.component<TownNPCs>();
ecs.component<LivesIn>();
ecs.system<TerrainItem, TownNPCs>("UpdateCharacters")
.kind(flecs::OnUpdate)
.interval(1.0f)
.write<CharacterBase>()
.write<CharacterLocation>()
.write<CharacterConf>()
.write<Character>()
.write<LivesIn>()
.each([this](flecs::entity town, TerrainItem &item,
TownNPCs &npcs) {
if (!player.is_valid())
return;
if (!player.has<CharacterBase>())
return;
Ogre::Root::getSingleton().getWorkQueue()->addMainThreadTask([this,
town]() {
flecs::entity player =
ECS::get<CharacterManagerModule>()
.getPlayer();
if (!player.is_valid())
return;
if (!player.has<CharacterBase>())
return;
TownNPCs &npcs = town.get_mut<TownNPCs>();
Ogre::Vector3 cameraPos =
player.get<CharacterBase>()
.mBodyNode
->_getDerivedPosition();
for (auto &npc : npcs.npcs) {
int index = npc.first;
TownNPCs::NPCData &data = npc.second;
Ogre::Vector3 npcPosition =
data.position;
Ogre::Quaternion npcOrientation =
data.orientation;
if (cameraPos.squaredDistance(
npcPosition) < 10000.0f) {
if (!data.e.is_valid()) {
data.e = createCharacterData(
data.model,
data.position,
data.orientation);
data.e.add<LivesIn>(
town);
break;
}
}
if (cameraPos.squaredDistance(
npcPosition) > 22500.0f) {
if (data.e.is_valid()) {
data.e.destruct();
data.e =
flecs::entity();
break;
}
}
}
for (auto &npc : npcs.npcs) {
int index = npc.first;
TownNPCs::NPCData &data = npc.second;
Ogre::Vector3 npcPosition =
data.position;
Ogre::Quaternion npcOrientation =
data.orientation;
if (cameraPos.squaredDistance(
npcPosition) < 10000.0f) {
if (data.e.is_valid()) {
if (data.e.has<
CharacterBase>() &&
data.e.has<LivesIn>(
town))
createNPCActionNodes(
town,
index);
}
}
}
town.modified<TownNPCs>();
});
});
}
flecs::entity
CharacterManagerModule::createPlayer(const Ogre::Vector3 &position,
const Ogre::Quaternion &rotation)
{
static int count = 0;
OgreAssert(count == 0, "overspawn");
OgreAssert(!player.is_valid(), "Player already created");
player = ECS::get().entity("player");
OgreAssert(player.is_valid(), "Can't create player");
std::cout << "Begin player create" << std::endl;
player.add<Player>();
ECS::get_mut<CharacterModule>().createCharacter(
player, position, rotation, "normal-male.glb");
ECS::modified<CharacterModule>();
std::cout << "End player create" << std::endl;
count++;
return player;
}
flecs::entity
CharacterManagerModule::createCharacterData(const Ogre::String model,
const Ogre::Vector3 &position,
const Ogre::Quaternion &rotation)
{
flecs::entity e = ECS::get().entity();
ECS::get_mut<CharacterModule>().createCharacter(e, position, rotation,
model);
ECS::modified<CharacterModule>();
return e;
}
void CharacterManagerModule::registerTownCharacters(flecs::entity town)
{
Ogre::MeshManager::getSingleton().load("normal-male.glb", "General");
Ogre::MeshManager::getSingleton().load("normal-female.glb", "General");
Ogre::String props = StaticGeometryModule::getItemProperties(town);
nlohmann::json j = nlohmann::json::parse(props);
nlohmann::json npcs = nlohmann::json::array();
if (town.has<TownNPCs>())
return;
if (j.find("npcs") != j.end())
npcs = j["npcs"];
std::cout << npcs.dump(4) << std::endl;
int index = 0;
std::map<int, TownNPCs::NPCData> npcMap;
for (auto &npc : npcs) {
const char *models[] = { "normal-male.glb",
"normal-female.glb" };
int sex = npc["sex"].get<int>();
Ogre::Vector3 npcPosition;
Ogre::Quaternion npcOrientation;
from_json(npc["position"], npcPosition);
from_json(npc["orientation"], npcOrientation);
Ogre::String model = models[sex];
TownNPCs::NPCData npcData;
npcData.e = flecs::entity();
npcData.model = model;
npcData.orientation = npcOrientation;
npcData.position = npcPosition;
npcData.props = npc;
npcMap[index] = npcData;
index++;
}
town.set<TownNPCs>({ npcMap });
}
}