mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-05-02 15:53:51 +00:00
Fix single-player NPC loading outside Goldshire
This commit is contained in:
parent
28a8e806e1
commit
b16578e2b9
3 changed files with 66 additions and 22 deletions
|
|
@ -38,6 +38,7 @@ struct NpcInstance {
|
||||||
|
|
||||||
class NpcManager {
|
class NpcManager {
|
||||||
public:
|
public:
|
||||||
|
void clear(rendering::CharacterRenderer* cr, EntityManager* em);
|
||||||
void initialize(pipeline::AssetManager* am,
|
void initialize(pipeline::AssetManager* am,
|
||||||
rendering::CharacterRenderer* cr,
|
rendering::CharacterRenderer* cr,
|
||||||
EntityManager& em,
|
EntityManager& em,
|
||||||
|
|
|
||||||
|
|
@ -859,6 +859,9 @@ void Application::spawnNpcs() {
|
||||||
if (!renderer || !renderer->getCharacterRenderer() || !renderer->getCamera()) return;
|
if (!renderer || !renderer->getCharacterRenderer() || !renderer->getCamera()) return;
|
||||||
if (!gameHandler) return;
|
if (!gameHandler) return;
|
||||||
|
|
||||||
|
if (npcManager) {
|
||||||
|
npcManager->clear(renderer->getCharacterRenderer(), &gameHandler->getEntityManager());
|
||||||
|
}
|
||||||
npcManager = std::make_unique<game::NpcManager>();
|
npcManager = std::make_unique<game::NpcManager>();
|
||||||
glm::vec3 playerSpawnGL = renderer->getCharacterPosition();
|
glm::vec3 playerSpawnGL = renderer->getCharacterPosition();
|
||||||
glm::vec3 playerCanonical = core::coords::renderToCanonical(playerSpawnGL);
|
glm::vec3 playerCanonical = core::coords::renderToCanonical(playerSpawnGL);
|
||||||
|
|
@ -1138,6 +1141,15 @@ void Application::teleportTo(int presetIndex) {
|
||||||
gameHandler->setPosition(finalCanonical.x, finalCanonical.y, finalCanonical.z);
|
gameHandler->setPosition(finalCanonical.x, finalCanonical.y, finalCanonical.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Rebuild nearby NPC set for the new location.
|
||||||
|
if (singlePlayerMode && gameHandler && renderer && renderer->getCharacterRenderer()) {
|
||||||
|
if (npcManager) {
|
||||||
|
npcManager->clear(renderer->getCharacterRenderer(), &gameHandler->getEntityManager());
|
||||||
|
}
|
||||||
|
npcsSpawned = false;
|
||||||
|
spawnNpcs();
|
||||||
|
}
|
||||||
|
|
||||||
LOG_INFO("Teleport to ", preset.label, " complete");
|
LOG_INFO("Teleport to ", preset.label, " complete");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,10 +15,24 @@
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
namespace wowee {
|
namespace wowee {
|
||||||
namespace game {
|
namespace game {
|
||||||
|
|
||||||
|
void NpcManager::clear(rendering::CharacterRenderer* cr, EntityManager* em) {
|
||||||
|
for (const auto& npc : npcs) {
|
||||||
|
if (cr) {
|
||||||
|
cr->removeInstance(npc.renderInstanceId);
|
||||||
|
}
|
||||||
|
if (em) {
|
||||||
|
em->removeEntity(npc.guid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
npcs.clear();
|
||||||
|
loadedModels.clear();
|
||||||
|
}
|
||||||
|
|
||||||
// Random emote animation IDs (humanoid only)
|
// Random emote animation IDs (humanoid only)
|
||||||
static const uint32_t EMOTE_ANIMS[] = { 60, 66, 67, 70 }; // Talk, Bow, Wave, Laugh
|
static const uint32_t EMOTE_ANIMS[] = { 60, 66, 67, 70 }; // Talk, Bow, Wave, Laugh
|
||||||
static constexpr int NUM_EMOTE_ANIMS = 4;
|
static constexpr int NUM_EMOTE_ANIMS = 4;
|
||||||
|
|
@ -504,16 +518,39 @@ std::vector<NpcSpawnDef> NpcManager::loadSpawnDefsFromAzerothCoreDb(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto processInsertStatements =
|
||||||
|
[](std::ifstream& in, const std::function<bool(const std::vector<std::string>&)>& onTuple) {
|
||||||
|
std::string line;
|
||||||
|
std::string stmt;
|
||||||
|
std::vector<std::string> tuples;
|
||||||
|
while (std::getline(in, line)) {
|
||||||
|
if (stmt.empty()) {
|
||||||
|
// Skip non-INSERT lines early.
|
||||||
|
if (line.find("INSERT INTO") == std::string::npos &&
|
||||||
|
line.find("insert into") == std::string::npos) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!stmt.empty()) stmt.push_back('\n');
|
||||||
|
stmt += line;
|
||||||
|
if (line.find(';') == std::string::npos) continue;
|
||||||
|
|
||||||
|
if (parseInsertTuples(stmt, tuples)) {
|
||||||
|
for (const auto& t : tuples) {
|
||||||
|
if (!onTuple(splitCsvTuple(t))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stmt.clear();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Parse creature_template.sql: entry, modelid1(displayId), name, minlevel.
|
// Parse creature_template.sql: entry, modelid1(displayId), name, minlevel.
|
||||||
{
|
{
|
||||||
std::ifstream in(tmplPath);
|
std::ifstream in(tmplPath);
|
||||||
std::string line;
|
processInsertStatements(in, [&](const std::vector<std::string>& cols) {
|
||||||
std::vector<std::string> tuples;
|
if (cols.size() < 16) return true;
|
||||||
while (std::getline(in, line)) {
|
|
||||||
if (!parseInsertTuples(line, tuples)) continue;
|
|
||||||
for (const auto& t : tuples) {
|
|
||||||
auto cols = splitCsvTuple(t);
|
|
||||||
if (cols.size() < 16) continue;
|
|
||||||
try {
|
try {
|
||||||
uint32_t entry = static_cast<uint32_t>(std::stoul(cols[0]));
|
uint32_t entry = static_cast<uint32_t>(std::stoul(cols[0]));
|
||||||
uint32_t displayId = static_cast<uint32_t>(std::stoul(cols[6]));
|
uint32_t displayId = static_cast<uint32_t>(std::stoul(cols[6]));
|
||||||
|
|
@ -531,25 +568,20 @@ std::vector<NpcSpawnDef> NpcManager::loadSpawnDefsFromAzerothCoreDb(
|
||||||
templates[entry] = std::move(tr);
|
templates[entry] = std::move(tr);
|
||||||
} catch (const std::exception&) {
|
} catch (const std::exception&) {
|
||||||
}
|
}
|
||||||
}
|
return true;
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
int targetMap = mapNameToId(mapName);
|
int targetMap = mapNameToId(mapName);
|
||||||
constexpr float kRadius = 2200.0f;
|
constexpr float kRadius = 2200.0f;
|
||||||
constexpr size_t kMaxSpawns = 220;
|
constexpr size_t kMaxSpawns = 220;
|
||||||
std::ifstream in(creaturePath);
|
std::ifstream in(creaturePath);
|
||||||
std::string line;
|
processInsertStatements(in, [&](const std::vector<std::string>& cols) {
|
||||||
std::vector<std::string> tuples;
|
if (cols.size() < 16) return true;
|
||||||
while (std::getline(in, line)) {
|
|
||||||
if (!parseInsertTuples(line, tuples)) continue;
|
|
||||||
for (const auto& t : tuples) {
|
|
||||||
auto cols = splitCsvTuple(t);
|
|
||||||
if (cols.size() < 16) continue;
|
|
||||||
try {
|
try {
|
||||||
uint32_t entry = static_cast<uint32_t>(std::stoul(cols[1]));
|
uint32_t entry = static_cast<uint32_t>(std::stoul(cols[1]));
|
||||||
int mapId = static_cast<int>(std::stol(cols[2]));
|
int mapId = static_cast<int>(std::stol(cols[2]));
|
||||||
if (mapId != targetMap) continue;
|
if (mapId != targetMap) return true;
|
||||||
|
|
||||||
float sx = std::stof(cols[7]);
|
float sx = std::stof(cols[7]);
|
||||||
float sy = std::stof(cols[8]);
|
float sy = std::stof(cols[8]);
|
||||||
|
|
@ -560,7 +592,7 @@ std::vector<NpcSpawnDef> NpcManager::loadSpawnDefsFromAzerothCoreDb(
|
||||||
glm::vec3 canonical = core::coords::serverToCanonical(glm::vec3(sx, sy, sz));
|
glm::vec3 canonical = core::coords::serverToCanonical(glm::vec3(sx, sy, sz));
|
||||||
float dx = canonical.x - playerCanonical.x;
|
float dx = canonical.x - playerCanonical.x;
|
||||||
float dy = canonical.y - playerCanonical.y;
|
float dy = canonical.y - playerCanonical.y;
|
||||||
if (dx * dx + dy * dy > kRadius * kRadius) continue;
|
if (dx * dx + dy * dy > kRadius * kRadius) return true;
|
||||||
|
|
||||||
NpcSpawnDef def;
|
NpcSpawnDef def;
|
||||||
def.mapName = mapName;
|
def.mapName = mapName;
|
||||||
|
|
@ -584,12 +616,11 @@ std::vector<NpcSpawnDef> NpcManager::loadSpawnDefsFromAzerothCoreDb(
|
||||||
def.scale = 1.0f;
|
def.scale = 1.0f;
|
||||||
def.isCritter = (def.level <= 1 || def.health <= 50);
|
def.isCritter = (def.level <= 1 || def.health <= 50);
|
||||||
out.push_back(std::move(def));
|
out.push_back(std::move(def));
|
||||||
if (out.size() >= kMaxSpawns) break;
|
if (out.size() >= kMaxSpawns) return false;
|
||||||
} catch (const std::exception&) {
|
} catch (const std::exception&) {
|
||||||
}
|
}
|
||||||
}
|
return true;
|
||||||
if (out.size() >= kMaxSpawns) break;
|
});
|
||||||
}
|
|
||||||
|
|
||||||
LOG_INFO("NpcManager: loaded ", out.size(), " nearby creature spawns from AzerothCore DB at ", basePath);
|
LOG_INFO("NpcManager: loaded ", out.size(), " nearby creature spawns from AzerothCore DB at ", basePath);
|
||||||
return out;
|
return out;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue