From 4873eba16072cfc939d44f9c9e1aabb6006b1487 Mon Sep 17 00:00:00 2001 From: Gent Date: Tue, 6 Oct 2020 17:57:46 -0400 Subject: [PATCH 1/5] Add overload to updateNPCPosition with rotation arg --- src/NPCManager.cpp | 5 +++++ src/NPCManager.hpp | 1 + 2 files changed, 6 insertions(+) diff --git a/src/NPCManager.cpp b/src/NPCManager.cpp index 781f06c..64f9918 100644 --- a/src/NPCManager.cpp +++ b/src/NPCManager.cpp @@ -134,6 +134,11 @@ void NPCManager::destroyNPC(int32_t id) { std::cout << "npc removed!" << std::endl; } +void NPCManager::updateNPCPosition(int32_t id, int X, int Y, int Z, int angle) { + NPCs[id]->appearanceData.iAngle = angle; + updateNPCPosition(id, X, Y, Z); +} + void NPCManager::updateNPCPosition(int32_t id, int X, int Y, int Z) { BaseNPC* npc = NPCs[id]; diff --git a/src/NPCManager.hpp b/src/NPCManager.hpp index 73b8d0f..abf0712 100644 --- a/src/NPCManager.hpp +++ b/src/NPCManager.hpp @@ -27,6 +27,7 @@ namespace NPCManager { void addNPC(std::vector viewableChunks, int32_t id); void removeNPC(std::vector viewableChunks, int32_t id); void destroyNPC(int32_t); + void updateNPCPosition(int32_t, int X, int Y, int Z, int angle); void updateNPCPosition(int32_t, int X, int Y, int Z); void sendToViewable(BaseNPC* npc, void* buf, uint32_t type, size_t size); From 5009fe1994aeaf7651388424c93f76dbff432df4 Mon Sep 17 00:00:00 2001 From: Gent Date: Tue, 6 Oct 2020 17:59:12 -0400 Subject: [PATCH 2/5] Implement temporary NPC rotations --- src/TableData.cpp | 21 +++++++++++++++++++++ src/TableData.hpp | 1 + 2 files changed, 22 insertions(+) diff --git a/src/TableData.cpp b/src/TableData.cpp index 0a8b1d3..5139404 100644 --- a/src/TableData.cpp +++ b/src/TableData.cpp @@ -13,6 +13,7 @@ #include std::map> TableData::RunningSkywayRoutes; +std::map TableData::RunningNPCRotations; void TableData::init() { int32_t nextId = 0; @@ -364,6 +365,17 @@ void TableData::loadGruntwork() { RunningSkywayRoutes[(int)route["iRouteID"]] = points; } + // npc rotations + auto npcRot = gruntwork["rotations"]; + for (auto _rot = npcRot.begin(); _rot != npcRot.end(); _rot++) { + int32_t npcID = _rot.value()["iNPCID"]; + int angle = _rot.value()["iAngle"]; + if (NPCManager::NPCs.find(npcID) == NPCManager::NPCs.end()) + continue; // NPC not found + BaseNPC* npc = NPCManager::NPCs[npcID]; + npc->appearanceData.iAngle = angle; + } + std::cout << "[INFO] Loaded gruntwork.json" << std::endl; } catch (const std::exception& err) { @@ -396,5 +408,14 @@ void TableData::flush() { gruntwork["skyway"].push_back(route); } + for (auto& pair : RunningNPCRotations) { + nlohmann::json rotation; + + rotation["iNPCID"] = (int)pair.first; + rotation["iAngle"] = pair.second; + + gruntwork["rotations"].push_back(rotation); + } + file << gruntwork << std::endl; } diff --git a/src/TableData.hpp b/src/TableData.hpp index 2913f87..09f2ccf 100644 --- a/src/TableData.hpp +++ b/src/TableData.hpp @@ -6,6 +6,7 @@ namespace TableData { extern std::map> RunningSkywayRoutes; + extern std::map RunningNPCRotations; void init(); void cleanup(); From 1b68b5e2e284aeddfcc3b0848bc64ee3e0559d4f Mon Sep 17 00:00:00 2001 From: Gent Date: Tue, 6 Oct 2020 17:59:33 -0400 Subject: [PATCH 3/5] Add NPC rotation command /npcr --- src/ChatManager.cpp | 43 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/src/ChatManager.cpp b/src/ChatManager.cpp index 59dae23..6359563 100644 --- a/src/ChatManager.cpp +++ b/src/ChatManager.cpp @@ -160,7 +160,7 @@ void mssCommand(std::string full, std::vector& args, CNSocket* sock return; } - // mss reload + // mss test if (args[2] == "test") { if (route->empty()) { ChatManager::sendServerMessage(sock, "[MSS] Route " + std::to_string(routeNum) + " is empty"); @@ -175,7 +175,7 @@ void mssCommand(std::string full, std::vector& args, CNSocket* sock // for compatibility: mss export if (args[2] == "export") { - ChatManager::sendServerMessage(sock, "[MSS] export on " + std::to_string(routeNum)); + ChatManager::sendServerMessage(sock, "Wrote gruntwork to " + settings::GRUNTWORKJSON); TableData::flush(); return; } @@ -185,6 +185,44 @@ void mssCommand(std::string full, std::vector& args, CNSocket* sock } +void npcRotateCommand(std::string full, std::vector& args, CNSocket* sock) { + + if (args.size() < 2) { + ChatManager::sendServerMessage(sock, "[NPCR] Too few arguments"); + ChatManager::sendServerMessage(sock, "[NPCR] Usage: /npcr "); + return; + } + + // Validate NPC ID number + char* npcIDC; + int npcID = std::strtol(args[1].c_str(), &npcIDC, 10); + if (*npcIDC) { + // not an integer + ChatManager::sendServerMessage(sock, "[NPCR] Invalid NPC ID '" + args[1] + "'"); + return; + } + + // Ensure NPC exists + if (NPCManager::NPCs.find(npcID) == NPCManager::NPCs.end()) { + // doesn't exist + ChatManager::sendServerMessage(sock, "[NPCR] Can't find NPC with ID " + args[1]); + return; + } + + Player* plr = PlayerManager::getPlayer(sock); + BaseNPC* npc = NPCManager::NPCs[npcID]; + int angle = plr->angle + 180; + // normalize angle + while (angle >= 360) + angle -= 360; + while (angle < 0) + angle += 360; + NPCManager::updateNPCPosition(npcID, npc->appearanceData.iX, npc->appearanceData.iY, npc->appearanceData.iZ, angle); + TableData::RunningNPCRotations[npcID] = angle; + PlayerManager::sendPlayerTo(sock, plr->x, plr->y, plr->z); + ChatManager::sendServerMessage(sock, "[NPCR] Successfully set angle to " + std::to_string(angle) + " for NPC " + args[1]); +} + void flushCommand(std::string full, std::vector& args, CNSocket* sock) { ChatManager::sendServerMessage(sock, "Wrote gruntwork to " + settings::GRUNTWORKJSON); TableData::flush(); @@ -199,6 +237,7 @@ void ChatManager::init() { registerCommand("access", 100, accessCommand); // TODO: add help command registerCommand("mss", 30, mssCommand); + registerCommand("npcr", 30, npcRotateCommand); registerCommand("flush", 30, flushCommand); registerCommand("level", 50, levelCommand); registerCommand("population", 100, populationCommand); From 42fc018097faab481f57e7c7fe980f9a03f2525d Mon Sep 17 00:00:00 2001 From: Gent Date: Tue, 6 Oct 2020 18:00:17 -0400 Subject: [PATCH 4/5] Add chunk reload command /refresh --- src/ChatManager.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/ChatManager.cpp b/src/ChatManager.cpp index 6359563..bccc350 100644 --- a/src/ChatManager.cpp +++ b/src/ChatManager.cpp @@ -223,6 +223,11 @@ void npcRotateCommand(std::string full, std::vector& args, CNSocket ChatManager::sendServerMessage(sock, "[NPCR] Successfully set angle to " + std::to_string(angle) + " for NPC " + args[1]); } +void refreshCommand(std::string full, std::vector& args, CNSocket* sock) { + Player* plr = PlayerManager::getPlayer(sock); + PlayerManager::sendPlayerTo(sock, plr->x, plr->y, plr->z); +} + void flushCommand(std::string full, std::vector& args, CNSocket* sock) { ChatManager::sendServerMessage(sock, "Wrote gruntwork to " + settings::GRUNTWORKJSON); TableData::flush(); @@ -241,6 +246,7 @@ void ChatManager::init() { registerCommand("flush", 30, flushCommand); registerCommand("level", 50, levelCommand); registerCommand("population", 100, populationCommand); + registerCommand("refresh", 100, refreshCommand); } void ChatManager::registerCommand(std::string cmd, int requiredLevel, CommandHandler handlr) { From 5ed332d836684529312da65a9bc11efcde700c2e Mon Sep 17 00:00:00 2001 From: Gent Date: Tue, 6 Oct 2020 18:34:11 -0400 Subject: [PATCH 5/5] Make /npcr use the nearest NPC --- src/ChatManager.cpp | 61 +++++++++++++++++++++++---------------------- 1 file changed, 31 insertions(+), 30 deletions(-) diff --git a/src/ChatManager.cpp b/src/ChatManager.cpp index bccc350..fd902d4 100644 --- a/src/ChatManager.cpp +++ b/src/ChatManager.cpp @@ -4,9 +4,11 @@ #include "PlayerManager.hpp" #include "TransportManager.hpp" #include "TableData.hpp" +#include "limits.h" #include #include +#include std::map ChatManager::commands; @@ -186,41 +188,40 @@ void mssCommand(std::string full, std::vector& args, CNSocket* sock } void npcRotateCommand(std::string full, std::vector& args, CNSocket* sock) { + + PlayerView& plrv = PlayerManager::players[sock]; + Player* plr = plrv.plr; - if (args.size() < 2) { - ChatManager::sendServerMessage(sock, "[NPCR] Too few arguments"); - ChatManager::sendServerMessage(sock, "[NPCR] Usage: /npcr "); + BaseNPC* npc = nullptr; + int lastDist = INT_MAX; + for (auto c = plrv.currentChunks.begin(); c != plrv.currentChunks.end(); c++) { // haha get it + Chunk* chunk = *c; + for (auto _npc = chunk->NPCs.begin(); _npc != chunk->NPCs.end(); _npc++) { + BaseNPC* npcTemp = NPCManager::NPCs[*_npc]; + int distXY = std::hypot(plr->x - npcTemp->appearanceData.iX, plr->y - npcTemp->appearanceData.iY); + int dist = std::hypot(distXY, plr->z - npcTemp->appearanceData.iZ); + if (dist < lastDist) { + npc = npcTemp; + lastDist = dist; + } + } + } + + if (npc == nullptr) { + ChatManager::sendServerMessage(sock, "[NPCR] No NPCs found nearby"); return; } - // Validate NPC ID number - char* npcIDC; - int npcID = std::strtol(args[1].c_str(), &npcIDC, 10); - if (*npcIDC) { - // not an integer - ChatManager::sendServerMessage(sock, "[NPCR] Invalid NPC ID '" + args[1] + "'"); - return; - } + int angle = (plr->angle + 180) % 360; + NPCManager::updateNPCPosition(npc->appearanceData.iNPC_ID, npc->appearanceData.iX, npc->appearanceData.iY, npc->appearanceData.iZ, angle); + TableData::RunningNPCRotations[npc->appearanceData.iNPC_ID] = angle; + + // update rotation clientside + INITSTRUCT(sP_FE2CL_NPC_ENTER, pkt); + pkt.NPCAppearanceData = npc->appearanceData; + sock->sendPacket((void*)&pkt, P_FE2CL_NPC_ENTER, sizeof(sP_FE2CL_NPC_ENTER)); - // Ensure NPC exists - if (NPCManager::NPCs.find(npcID) == NPCManager::NPCs.end()) { - // doesn't exist - ChatManager::sendServerMessage(sock, "[NPCR] Can't find NPC with ID " + args[1]); - return; - } - - Player* plr = PlayerManager::getPlayer(sock); - BaseNPC* npc = NPCManager::NPCs[npcID]; - int angle = plr->angle + 180; - // normalize angle - while (angle >= 360) - angle -= 360; - while (angle < 0) - angle += 360; - NPCManager::updateNPCPosition(npcID, npc->appearanceData.iX, npc->appearanceData.iY, npc->appearanceData.iZ, angle); - TableData::RunningNPCRotations[npcID] = angle; - PlayerManager::sendPlayerTo(sock, plr->x, plr->y, plr->z); - ChatManager::sendServerMessage(sock, "[NPCR] Successfully set angle to " + std::to_string(angle) + " for NPC " + args[1]); + ChatManager::sendServerMessage(sock, "[NPCR] Successfully set angle to " + std::to_string(angle) + " for NPC " + std::to_string(npc->appearanceData.iNPC_ID)); } void refreshCommand(std::string full, std::vector& args, CNSocket* sock) {