[Grids] Convert Grid/Grid Entries to Repositories (#4011)

* [Grids] Convert Grid/Grid Entries to Repositories

- Convert `AddWaypoint()`, `AddWaypointForSpawn()`, `DeleteWaypoint()`, `GetHighestWaypoint()`, `GetRandomWaypointFromGrid()`, `GridExistsInZone()`, and `ModifyGrid()` to repositories.

* Update grid.cpp

* Update questmgr.cpp

* Update waypoints.cpp

* Update waypoints.cpp
This commit is contained in:
Alex King 2024-01-29 00:37:34 -05:00 committed by GitHub
parent 8e3218aaf7
commit 2e0ed82986
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 418 additions and 327 deletions

View File

@ -76,6 +76,48 @@ public:
return grid_entries; return grid_entries;
} }
static int GetHighestWaypoint(Database& db, uint32 zone_id, uint32 grid_id)
{
auto results = db.QueryDatabase(
fmt::format(
SQL(
SELECT COALESCE(MAX(`number`), 0) FROM `{}`
WHERE `zoneid` = {} AND `gridid` = {}
),
TableName(),
zone_id,
grid_id
)
);
if (!results.Success() || !results.RowCount()) {
return 0;
}
auto row = results.begin();
return Strings::ToInt(row[0]);
}
static int GetNextWaypoint(Database& db, uint32 zone_id, uint32 grid_id)
{
auto results = db.QueryDatabase(
fmt::format(
"SELECT MAX(`number`) FROM `{}` WHERE `zoneid` = {} AND `gridid` = {}",
TableName(),
zone_id,
grid_id
)
);
if (!results.Success() || !results.RowCount()) {
return 1;
}
auto row = results.begin();
return Strings::ToInt(row[0]) + 1;
}
}; };
#endif //EQEMU_GRID_ENTRIES_REPOSITORY_H #endif //EQEMU_GRID_ENTRIES_REPOSITORY_H

View File

@ -71,6 +71,27 @@ public:
return grids; return grids;
} }
static int GetHighestGrid(Database& db, uint32 zone_id)
{
auto results = db.QueryDatabase(
fmt::format(
SQL(
SELECT COALESCE(MAX(`id`), 0) FROM `{}`
WHERE `zoneid` = {}
),
TableName(),
zone_id
)
);
if (!results.Success() || !results.RowCount()) {
return 0;
}
auto row = results.begin();
return Strings::ToInt(row[0]);
}
}; };
#endif //EQEMU_GRID_REPOSITORY_H #endif //EQEMU_GRID_REPOSITORY_H

View File

@ -44,7 +44,35 @@ public:
*/ */
// Custom extended repository methods here // Custom extended repository methods here
static uint32 GetPathGridBySpawn2ID(Database& db, uint32 spawn2_id)
{
auto results = db.QueryDatabase(
fmt::format(
"SELECT `pathgrid` FROM `{}` WHERE `id` = {}",
TableName(),
spawn2_id
)
);
if (!results.Success() || !results.RowCount()) {
return 0;
}
auto row = results.begin();
return Strings::ToUnsignedInt(row[0]);
}
static void SetPathGridBySpawn2ID(Database& db, uint32 spawn2_id, uint32 grid_id)
{
auto results = db.QueryDatabase(
fmt::format(
"UPDATE `spawn2` SET `pathgrid` = {} WHERE `id` = {}",
grid_id,
spawn2_id
)
);
}
}; };
#endif //EQEMU_SPAWN2_REPOSITORY_H #endif //EQEMU_SPAWN2_REPOSITORY_H

View File

@ -1,82 +1,138 @@
#include "../client.h" #include "../client.h"
#include "../../common/repositories/grid_entries_repository.h"
void command_grid(Client *c, const Seperator *sep) void command_grid(Client *c, const Seperator *sep)
{ {
auto command_type = sep->arg[1]; const uint16 arguments = sep->argnum;
auto zone_id = zone->GetZoneID();
if (strcasecmp("max", command_type) == 0) { if (!arguments) {
c->Message( c->Message(Chat::White, "Usage: #grid add [Grid ID] [Wander Type] [Pause Type] - Add a grid with the specified wander and pause type");
Chat::White, c->Message(Chat::White, "Usage: #grid delete [Grid ID] - Delete a grid");
fmt::format( c->Message(Chat::White, "Usage: #grid hide - Hides waypoint nodes from targeted NPC's grid");
"Highest grid ID in this zone is {}.", c->Message(Chat::White, "Usage: #grid max - Displays the highest grid ID used in this zone (for add)");
content_db.GetHighestGrid(zone_id) c->Message(Chat::White, "Usage: #grid show - Displays waypoint nodes for targeted NPC's grid");
).c_str() return;
);
} }
else if (strcasecmp("add", command_type) == 0) {
auto grid_id = Strings::ToInt(sep->arg[2]); const bool is_add = !strcasecmp(sep->arg[1], "add");
auto wander_type = Strings::ToInt(sep->arg[3]); const bool is_delete = !strcasecmp(sep->arg[1], "delete");
auto pause_type = Strings::ToInt(sep->arg[4]); const bool is_hide = !strcasecmp(sep->arg[1], "hide");
if (!content_db.GridExistsInZone(zone_id, grid_id)) { const bool is_max = !strcasecmp(sep->arg[1], "max");
content_db.ModifyGrid(c, false, grid_id, wander_type, pause_type, zone_id); const bool is_show = !strcasecmp(sep->arg[1], "show");
if (!is_add && !is_delete && !is_hide && !is_max && !is_show) {
c->Message(Chat::White, "Usage: #grid add [Grid ID] [Wander Type] [Pause Type] - Add a grid with the specified wander and pause type");
c->Message(Chat::White, "Usage: #grid delete [Grid ID] - Delete a grid");
c->Message(Chat::White, "Usage: #grid hide - Hides waypoint nodes from targeted NPC's grid");
c->Message(Chat::White, "Usage: #grid max - Displays the highest grid ID used in this zone (for add)");
c->Message(Chat::White, "Usage: #grid show - Displays waypoint nodes for targeted NPC's grid");
return;
}
if (is_add) {
const uint32 grid_id = Strings::ToUnsignedInt(sep->arg[2]);
const uint8 wander_type = static_cast<uint8>(Strings::ToUnsignedInt(sep->arg[3]));
const uint8 pause_type = static_cast<uint8>(Strings::ToUnsignedInt(sep->arg[4]));
if (!grid_id) {
c->Message(Chat::White, "You must specify a valid grid ID.");
return;
}
if (!content_db.GridExistsInZone(zone->GetZoneID(), grid_id)) {
content_db.ModifyGrid(c, false, grid_id, wander_type, pause_type, zone->GetZoneID());
c->Message( c->Message(
Chat::White, Chat::White,
fmt::format( fmt::format(
"Grid {} added to zone ID {} with wander type {} and pause type {}.", "Grid {} added to zone ID {} with wander type {} and pause type {}.",
grid_id, grid_id,
zone_id, zone->GetZoneID(),
wander_type, wander_type,
pause_type pause_type
).c_str() ).c_str()
); );
} } else {
else {
c->Message( c->Message(
Chat::White, Chat::White,
fmt::format( fmt::format(
"Grid {} already exists in zone ID {}.", "Grid {} already exists in zone ID {}.",
grid_id, grid_id,
zone_id zone->GetZoneID()
).c_str() ).c_str()
); );
return;
} }
} } else if (is_delete) {
else if (strcasecmp("show", command_type) == 0) { const uint32 grid_id = Strings::ToUnsignedInt(sep->arg[2]);
Mob *target = c->GetTarget();
if (!target || !target->IsNPC()) { content_db.ModifyGrid(c, true, grid_id, 0, 0, zone->GetZoneID());
c->Message(Chat::White, "You need to target an NPC!");
c->Message(
Chat::White,
fmt::format(
"Grid {} deleted from zone ID {}.",
grid_id,
zone->GetZoneID()
).c_str()
);
} else if (is_hide) {
Mob* t = c->GetTarget();
if (!t || !t->IsNPC()) {
c->Message(Chat::White, "You must target an NPC to use this command.");
return; return;
} }
auto grid_id = target->CastToNPC()->GetGrid(); const uint32 grid_id = t->CastToNPC()->GetGrid();
std::string query = fmt::format(
"SELECT `x`, `y`, `z`, `heading`, `number` " entity_list.DespawnGridNodes(grid_id);
"FROM `grid_entries` "
"WHERE `zoneid` = {} AND `gridid` = {} " c->Message(
"ORDER BY `number`", Chat::White,
zone_id, fmt::format(
"Depawning nodes for grid {}.",
grid_id grid_id
).c_str()
);
} else if (is_max) {
c->Message(
Chat::White,
fmt::format(
"Highest grid ID in this zone is {}.",
content_db.GetHighestGrid(zone->GetZoneID())
).c_str()
);
} else if (is_show) {
Mob* t = c->GetTarget();
if (!t || !t->IsNPC()) {
c->Message(Chat::White, "You must target an NPC to use this command.");
return;
}
const uint32 grid_id = t->CastToNPC()->GetGrid();
const auto& l = GridEntriesRepository::GetWhere(
content_db,
fmt::format(
"`zoneid` = {} AND `gridid` = {} ORDER BY `number`",
zone->GetZoneID(),
grid_id
)
); );
auto results = content_db.QueryDatabase(query); if (l.empty()) {
if (!results.Success()) {
c->Message(Chat::White, "Error querying database.");
c->Message(Chat::White, query.c_str());
}
if (results.RowCount() == 0) {
c->Message(Chat::White, "No grid found."); c->Message(Chat::White, "No grid found.");
return; return;
} }
// Depop any node npc's already spawned // Depop any grid nodes already spawned
entity_list.DespawnGridNodes(grid_id); entity_list.DespawnGridNodes(grid_id);
// Spawn grid nodes // Spawn grid nodes
std::map<std::vector<float>, int32> zoffset; std::map<std::vector<float>, int32> zoffset;
for (auto row : results) {
glm::vec4 node_position = glm::vec4(Strings::ToFloat(row[0]), Strings::ToFloat(row[1]), Strings::ToFloat(row[2]), Strings::ToFloat(row[3])); for (const auto& e : l) {
glm::vec4 node_position = glm::vec4(e.x, e.y, e.z, e.heading);
std::vector<float> node_loc{ std::vector<float> node_loc{
node_position.x, node_position.x,
node_position.y, node_position.y,
@ -84,19 +140,20 @@ void command_grid(Client *c, const Seperator *sep)
}; };
// If we already have a node at this location, set the z offset // If we already have a node at this location, set the z offset
// higher from the existing one so we can see it. Adjust so if // higher from the existing one, so we can see it. Adjust so if
// there is another at the same spot we adjust again. // there is another at the same spot we adjust again.
auto search = zoffset.find(node_loc); auto search = zoffset.find(node_loc);
if (search != zoffset.end()) { if (search != zoffset.end()) {
search->second = search->second + 3; search->second += 3;
} } else {
else {
zoffset[node_loc] = 0.0; zoffset[node_loc] = 0.0;
} }
node_position.z += zoffset[node_loc]; node_position.z += zoffset[node_loc];
NPC::SpawnGridNodeNPC(node_position, grid_id, Strings::ToInt(row[4]), zoffset[node_loc]);
NPC::SpawnGridNodeNPC(node_position, grid_id, e.number, zoffset[node_loc]);
} }
c->Message( c->Message(
Chat::White, Chat::White,
fmt::format( fmt::format(
@ -105,39 +162,4 @@ void command_grid(Client *c, const Seperator *sep)
).c_str() ).c_str()
); );
} }
else if (strcasecmp("hide", command_type) == 0) {
Mob *target = c->GetTarget();
if (!target || !target->IsNPC()) {
c->Message(Chat::White, "You need to target an NPC!");
return;
}
auto grid_id = target->CastToNPC()->GetGrid();
entity_list.DespawnGridNodes(grid_id);
c->Message(
Chat::White,
fmt::format(
"Depawning nodes for grid {}.",
grid_id
).c_str()
);
}
else if (strcasecmp("delete", command_type) == 0) {
auto grid_id = Strings::ToInt(sep->arg[2]);
content_db.ModifyGrid(c, true, grid_id, 0, 0, zone_id);
c->Message(
Chat::White,
fmt::format(
"Grid {} deleted from zone ID {}.",
grid_id,
zone_id
).c_str()
);
}
else {
c->Message(Chat::White, "Usage: #grid [add|delete] [grid_id] [wander_type] [pause_type]");
c->Message(Chat::White, "Usage: #grid [max] - displays the highest grid ID used in this zone (for add)");
c->Message(Chat::White, "Usage: #grid [show] - displays wp nodes as boxes");
}
} }

View File

@ -14,12 +14,12 @@ void command_wp(Client *c, const Seperator *sep)
} }
if (strcasecmp("-h", sep->arg[5]) == 0) { if (strcasecmp("-h", sep->arg[5]) == 0) {
content_db.AddWP(c, grid_id, waypoint, c->GetPosition(), pause, zone_id); content_db.AddWaypoint(c, grid_id, waypoint, c->GetPosition(), pause, zone_id);
} }
else { else {
auto position = c->GetPosition(); auto position = c->GetPosition();
position.w = -1; position.w = -1;
content_db.AddWP(c, grid_id, waypoint, position, pause, zone_id); content_db.AddWaypoint(c, grid_id, waypoint, position, pause, zone_id);
} }
c->Message( c->Message(
Chat::White, Chat::White,

View File

@ -29,7 +29,7 @@ void command_wpadd(Client *c, const Seperator *sep)
} }
auto zone_id = zone->GetZoneID(); auto zone_id = zone->GetZoneID();
uint32 tmp_grid = content_db.AddWPForSpawn(c, s2info->GetID(), position, pause, type1, type2, zone_id); uint32 tmp_grid = content_db.AddWaypointForSpawn(c, s2info->GetID(), position, pause, type1, type2, zone_id);
if (tmp_grid) { if (tmp_grid) {
target->CastToNPC()->SetGrid(tmp_grid); target->CastToNPC()->SetGrid(tmp_grid);
} }

View File

@ -41,6 +41,7 @@
#include "../common/repositories/tradeskill_recipe_repository.h" #include "../common/repositories/tradeskill_recipe_repository.h"
#include "../common/repositories/instance_list_repository.h" #include "../common/repositories/instance_list_repository.h"
#include "../common/repositories/grid_entries_repository.h"
#include <iostream> #include <iostream>
#include <limits.h> #include <limits.h>
@ -1988,38 +1989,48 @@ void QuestManager::setanim(int npc_type, int animnum) {
} }
//displays an in game path based on a waypoint grid //displays an in game path based on a waypoint grid
void QuestManager::showgrid(int grid) { void QuestManager::showgrid(int grid_id)
{
QuestManagerCurrentQuestVars(); QuestManagerCurrentQuestVars();
if(initiator == nullptr)
return;
FindPerson_Point pt; if (!initiator) {
std::vector<FindPerson_Point> pts;
pt.x = initiator->GetX();
pt.y = initiator->GetY();
pt.z = initiator->GetZ();
pts.push_back(pt);
// Retrieve all waypoints for this grid
std::string query = StringFormat("SELECT `x`,`y`,`z` FROM grid_entries "
"WHERE `gridid` = %i AND `zoneid` = %i "
"ORDER BY `number`", grid, zone->GetZoneID());
auto results = content_db.QueryDatabase(query);
if (!results.Success()) {
LogQuests("Error loading grid [{}] for showgrid(): [{}]", grid, results.ErrorMessage().c_str());
return; return;
} }
for(auto row = results.begin(); row != results.end(); ++row) { std::vector<FindPerson_Point> v;
pt.x = Strings::ToFloat(row[0]);
pt.y = Strings::ToFloat(row[1]);
pt.z = Strings::ToFloat(row[2]);
pts.push_back(pt); v.push_back(
FindPerson_Point{
.y = initiator->GetY(),
.x = initiator->GetX(),
.z = initiator->GetZ()
}
);
const auto& l = GridEntriesRepository::GetWhere(
content_db,
fmt::format(
"`gridid` = {} AND `zoneid` = {} ORDER BY `number`",
grid_id,
zone->GetZoneID()
)
);
if (l.empty()) {
return;
} }
initiator->SendPathPacket(pts); for (const auto& e : l) {
v.push_back(
FindPerson_Point{
.y = e.y,
.x = e.x,
.z = e.z
}
);
}
initiator->SendPathPacket(v);
} }

View File

@ -183,7 +183,7 @@ public:
void enable_proximity_say(); void enable_proximity_say();
void disable_proximity_say(); void disable_proximity_say();
void setanim(int npc_type, int animnum); void setanim(int npc_type, int animnum);
void showgrid(int gridid); void showgrid(int grid_id);
void spawn_condition(const char *zone_short, uint32 instance_id, uint16 condition_id, short new_value); void spawn_condition(const char *zone_short, uint32 instance_id, uint16 condition_id, short new_value);
short get_spawn_condition(const char *zone_short, uint32 instance_id, uint16 condition_id); short get_spawn_condition(const char *zone_short, uint32 instance_id, uint16 condition_id);
void toggle_spawn_event(int event_id, bool enable, bool strict, bool reset_base); void toggle_spawn_event(int event_id, bool enable, bool strict, bool reset_base);

View File

@ -256,7 +256,7 @@ bool Spawn2::Process() {
if (spawn_group->wp_spawns && grid_ > 0) if (spawn_group->wp_spawns && grid_ > 0)
{ {
glm::vec4 wploc; glm::vec4 wploc;
starting_wp = content_db.GetRandomWaypointLocFromGrid(wploc, zone->GetZoneID(), grid_); starting_wp = content_db.GetRandomWaypointFromGrid(wploc, zone->GetZoneID(), grid_);
if (wploc.x != 0.0f || wploc.y != 0.0f || wploc.z != 0.0f) if (wploc.x != 0.0f || wploc.y != 0.0f || wploc.z != 0.0f)
{ {
loc = wploc; loc = wploc;

View File

@ -32,6 +32,10 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "fastmath.h" #include "fastmath.h"
#include "mob_movement_manager.h" #include "mob_movement_manager.h"
#include "../common/repositories/grid_repository.h"
#include "../common/repositories/grid_entries_repository.h"
#include "../common/repositories/spawn2_repository.h"
#include <math.h> #include <math.h>
extern FastMath g_Math; extern FastMath g_Math;
@ -1052,233 +1056,198 @@ glm::vec4 Mob::TryMoveAlong(const glm::vec4 &start, float distance, float angle)
return {new_pos.x, new_pos.y, new_pos.z, start.w}; return {new_pos.x, new_pos.y, new_pos.z, start.w};
} }
int ZoneDatabase::GetHighestGrid(uint32 zoneid) { int ZoneDatabase::GetHighestGrid(uint32 zone_id)
{
std::string query = StringFormat("SELECT COALESCE(MAX(id), 0) FROM grid WHERE zoneid = %i", zoneid); return GridRepository::GetHighestGrid(*this, zone_id);
auto results = QueryDatabase(query);
if (!results.Success()) {
return 0;
}
if (results.RowCount() != 1)
return 0;
auto row = results.begin();
return Strings::ToInt(row[0]);
} }
/****************** void ZoneDatabase::ModifyGrid(
* ModifyGrid - Either adds an empty grid, or removes a grid and all its waypoints, for a particular zone. Client* c,
* remove: TRUE if we are deleting the specified grid, FALSE if we are adding it bool remove,
* id: The ID# of the grid to add or delete uint32 grid_id,
* type,type2: The type and type2 values for the grid being created (ignored if grid is being deleted) uint8 type,
* zoneid: The ID number of the zone the grid is being created/deleted in uint8 type2,
*/ uint32 zone_id
void ZoneDatabase::ModifyGrid(Client *client, bool remove, uint32 id, uint8 type, uint8 type2, uint16 zoneid) { )
{
if (!remove) if (!remove) {
{ GridRepository::InsertOne(
std::string query = StringFormat("INSERT INTO grid(id, zoneid, type, type2) " *this,
"VALUES (%i, %i, %i, %i)", id, zoneid, type, type2); GridRepository::Grid{
auto results = QueryDatabase(query); .id = static_cast<int32_t>(grid_id),
if (!results.Success()) { .zoneid = static_cast<int32_t>(zone_id),
return; .type = type,
.type2 = type2
} }
);
return; return;
} }
std::string query = StringFormat("DELETE FROM grid where id=%i and zoneid=%i", id, zoneid); GridRepository::DeleteWhere(
auto results = QueryDatabase(query); *this,
fmt::format(
query = StringFormat("DELETE FROM grid_entries WHERE zoneid = %i AND gridid = %i", zoneid, id); "`id` = {} AND `zoneid` = {}",
results = QueryDatabase(query);
}
bool ZoneDatabase::GridExistsInZone(uint32 zone_id, uint32 grid_id) {
bool grid_exists = false;
std::string query = fmt::format(
"SELECT * FROM `grid` WHERE `id` = {} AND `zoneid` = {}",
grid_id, grid_id,
zone_id zone_id
)
); );
auto results = QueryDatabase(query);
if (!results.Success()) {
return grid_exists;
}
if (results.RowCount() == 1) { GridEntriesRepository::DeleteWhere(
grid_exists = true; *this,
} fmt::format(
return grid_exists; "`gridid` = {} AND `zoneid` = {}",
grid_id,
zone_id
)
);
} }
/************************************** bool ZoneDatabase::GridExistsInZone(uint32 zone_id, uint32 grid_id)
* AddWP - Adds a new waypoint to a specific grid for a specific zone.
*/
void ZoneDatabase::AddWP(Client *client, uint32 gridid, uint32 wpnum, const glm::vec4& position, uint32 pause, uint16 zoneid)
{ {
std::string query = StringFormat("INSERT INTO grid_entries (gridid, zoneid, `number`, x, y, z, pause, heading) " const auto& l = GridRepository::GetWhere(
"VALUES (%i, %i, %i, %f, %f, %f, %i, %f)", *this,
gridid, zoneid, wpnum, position.x, position.y, position.z, pause, position.w); fmt::format(
auto results = QueryDatabase(query); "`id` = {} AND `zoneid` = {}",
if (!results.Success()) { grid_id,
return; zone_id
)
);
if (l.empty()) {
return false;
} }
return true;
} }
void ZoneDatabase::AddWaypoint(
/********** Client* c,
* ModifyWP() has been obsoleted. The #wp command either uses AddWP() or DeleteWaypoint() uint32 grid_id,
***********/ uint32 number,
const glm::vec4& position,
/****************** uint32 pause,
* DeleteWaypoint - Removes a specific waypoint from the grid uint32 zone_id
* grid_id: The ID number of the grid whose wp is being deleted )
* wp_num: The number of the waypoint being deleted
* zoneid: The ID number of the zone that Contains the waypoint being deleted
*/
void ZoneDatabase::DeleteWaypoint(Client *client, uint32 grid_num, uint32 wp_num, uint16 zoneid)
{ {
std::string query = StringFormat("DELETE FROM grid_entries WHERE " GridEntriesRepository::InsertOne(
"gridid = %i AND zoneid = %i AND `number` = %i", *this,
grid_num, zoneid, wp_num); GridEntriesRepository::GridEntries{
auto results = QueryDatabase(query); .gridid = static_cast<int32_t>(grid_id),
if (!results.Success()) { .zoneid = static_cast<int32_t>(zone_id),
return; .number = static_cast<int32_t>(number),
.x = position.x,
.y = position.y,
.z = position.z,
.heading = position.w,
.pause = static_cast<int32_t>(pause)
} }
);
} }
void ZoneDatabase::DeleteWaypoint(Client* c, uint32 grid_id, uint32 number, uint32 zone_id)
/****************** {
* AddWPForSpawn - Used by the #wpadd command - for a given spawn, this will add a new waypoint to whatever grid that spawn is assigned to. GridEntriesRepository::DeleteWhere(
* If there is currently no grid assigned to the spawn, a new grid will be created using the next available Grid ID number for the zone *this,
* the spawn is in. fmt::format(
* Returns 0 if the function didn't have to create a new grid. If the function had to create a new grid for the spawn, then the ID of "`gridid` = {} AND `zoneid` = {} AND `number` = {}",
* the created grid is returned. grid_id,
*/ zone_id,
uint32 ZoneDatabase::AddWPForSpawn(Client *client, uint32 spawn2id, const glm::vec4& position, uint32 pause, int type1, int type2, uint16 zoneid) { number
)
uint32 grid_num; // The grid number the spawn is assigned to (if spawn has no grid, will be the grid number we end up creating) );
uint32 next_wp_num; // The waypoint number we should be assigning to the new waypoint
bool createdNewGrid; // Did we create a new grid in this function?
// See what grid number our spawn is assigned
std::string query = StringFormat("SELECT pathgrid FROM spawn2 WHERE id = %i", spawn2id);
auto results = QueryDatabase(query);
if (!results.Success()) {
// Query error
return 0;
}
if (results.RowCount() == 0)
return 0;
auto row = results.begin();
grid_num = Strings::ToInt(row[0]);
if (grid_num == 0)
{ // Our spawn doesn't have a grid assigned to it -- we need to create a new grid and assign it to the spawn
createdNewGrid = true;
grid_num = GetFreeGrid(zoneid);
if (grid_num == 0) // There are no grids for the current zone -- create Grid #1
grid_num = 1;
query = StringFormat("INSERT INTO grid SET id = '%i', zoneid = %i, type ='%i', type2 = '%i'",
grid_num, zoneid, type1, type2);
QueryDatabase(query);
query = StringFormat("UPDATE spawn2 SET pathgrid = '%i' WHERE id = '%i'", grid_num, spawn2id);
QueryDatabase(query);
}
else // NPC had a grid assigned to it
createdNewGrid = false;
// Find out what the next waypoint is for this grid
query = StringFormat("SELECT max(`number`) FROM grid_entries WHERE zoneid = '%i' AND gridid = '%i'", zoneid, grid_num);
results = QueryDatabase(query);
if (!results.Success()) { // Query error
return 0;
}
row = results.begin();
if (row[0] != 0)
next_wp_num = Strings::ToInt(row[0]) + 1;
else // No waypoints in this grid yet
next_wp_num = 1;
query = StringFormat("INSERT INTO grid_entries(gridid, zoneid, `number`, x, y, z, pause, heading) "
"VALUES (%i, %i, %i, %f, %f, %f, %i, %f)",
grid_num, zoneid, next_wp_num, position.x, position.y, position.z, pause, position.w);
results = QueryDatabase(query);
return createdNewGrid ? grid_num : 0;
} }
uint32 ZoneDatabase::GetFreeGrid(uint16 zoneid) { uint32 ZoneDatabase::AddWaypointForSpawn(
Client* c,
uint32 spawn2_id,
const glm::vec4& position,
uint32 pause,
int type,
int type2,
uint32 zone_id
)
{
uint32 grid_id = Spawn2Repository::GetPathGridBySpawn2ID(*this, spawn2_id); // The grid number the spawn is assigned to (if spawn has no grid, will be the grid number we end up creating)
bool created; // Did we create a new grid in this function?
std::string query = StringFormat("SELECT max(id) FROM grid WHERE zoneid = %i", zoneid); if (!grid_id) { // Our spawn doesn't have a grid assigned to it -- we need to create a new grid and assign it to the spawn
auto results = QueryDatabase(query); created = true;
if (!results.Success()) { grid_id = GetFreeGrid(zone_id);
return 0;
if (grid_id == 0) { // There are no grids for the current zone -- create Grid #1
grid_id = 1;
} }
if (results.RowCount() != 1) GridRepository::InsertOne(
return 0; *this,
GridRepository::Grid{
.id = static_cast<int32_t>(grid_id),
.zoneid = static_cast<int32_t>(zone_id),
.type = type,
.type2 = type2
}
);
auto row = results.begin(); Spawn2Repository::SetPathGridBySpawn2ID(*this, spawn2_id, grid_id);
uint32 freeGridID = row[0] ? Strings::ToInt(row[0]) + 1 : 1; } else { // NPC had a grid assigned to it
created = false;
return freeGridID;
}
int ZoneDatabase::GetHighestWaypoint(uint32 zoneid, uint32 gridid) {
std::string query = StringFormat("SELECT COALESCE(MAX(number), 0) FROM grid_entries "
"WHERE zoneid = %i AND gridid = %i", zoneid, gridid);
auto results = QueryDatabase(query);
if (!results.Success()) {
return 0;
} }
if (results.RowCount() != 1) int next_waypoint = GridEntriesRepository::GetNextWaypoint(*this, zone_id, grid_id); // The waypoint number we should be assigning to the new waypoint
return 0;
auto row = results.begin(); GridEntriesRepository::InsertOne(
return Strings::ToInt(row[0]); *this,
GridEntriesRepository::GridEntries{
.gridid = static_cast<int32_t>(grid_id),
.zoneid = static_cast<int32_t>(zone_id),
.number = next_waypoint,
.x = position.x,
.y = position.y,
.z = position.z,
.heading = position.w,
.pause = static_cast<int32_t>(pause)
}
);
return created ? grid_id : 0;
} }
int ZoneDatabase::GetRandomWaypointLocFromGrid(glm::vec4 &loc, uint16 zoneid, int grid) uint32 ZoneDatabase::GetFreeGrid(uint32 zone_id)
{
return GridRepository::GetHighestGrid(*this, zone_id) + 1;
}
int ZoneDatabase::GetHighestWaypoint(uint32 zone_id, uint32 grid_id)
{
return GridEntriesRepository::GetHighestWaypoint(*this, zone_id, grid_id);
}
int ZoneDatabase::GetRandomWaypointFromGrid(glm::vec4 &loc, uint32 zone_id, uint32 grid_id)
{ {
loc.x = loc.y = loc.z = loc.w = 0.0f; loc.x = loc.y = loc.z = loc.w = 0.0f;
std::string query = StringFormat("SELECT `x`,`y`,`z`,`heading` " const auto& l = GridEntriesRepository::GetWhere(
"FROM grid_entries WHERE `gridid` = %i AND `zoneid` = %u ORDER BY `number`", grid, zone->GetZoneID()); *this,
auto results = content_db.QueryDatabase(query); fmt::format(
if (!results.Success()) { "`zoneid` = {} AND `gridid` = {} ORDER BY RAND() LIMIT 1",
Log(Logs::General, Logs::Error, "MySQL Error while trying get random waypoint loc from grid %i in zoneid %u; %s", grid, zoneid, results.ErrorMessage().c_str()); zone_id,
grid_id
)
);
if (l.empty()) {
return 0; return 0;
} }
if (results.RowCount() > 0) auto e = l.front();
{
int roll = zone->random.Int(0, results.RowCount() - 1); loc.x = e.x;
int i = 0; loc.y = e.y;
auto row = results.begin(); loc.z = e.z;
while (i < roll) loc.w = e.heading;
{
row++; return e.number;
i++;
}
loc.x = Strings::ToFloat(row[0]);
loc.y = Strings::ToFloat(row[1]);
loc.z = Strings::ToFloat(row[2]);
loc.w = Strings::ToFloat(row[3]);
return i;
}
return 0;
} }
void NPC::SaveGuardSpotCharm() void NPC::SaveGuardSpotCharm()

View File

@ -534,17 +534,15 @@ public:
void UpdateSpawn2Status(uint32 id, uint8 new_status, uint32 instance_id); void UpdateSpawn2Status(uint32 id, uint8 new_status, uint32 instance_id);
/* Grids/Paths */ /* Grids/Paths */
uint32 GetFreeGrid(uint16 zoneid); uint32 GetFreeGrid(uint32 zone_id);
void DeleteGrid(Client *c, uint32 sg2, uint32 grid_num, bool grid_too, uint16 zoneid); void DeleteWaypoint(Client* c, uint32 grid_id, uint32 number, uint32 zone_id);
void DeleteWaypoint(Client *c, uint32 grid_num, uint32 wp_num, uint16 zoneid); void AddWaypoint(Client* c, uint32 grid_id, uint32 number, const glm::vec4 &position, uint32 pause, uint32 zone_id);
void AddWP(Client *c, uint32 gridid, uint32 wpnum, const glm::vec4& position, uint32 pause, uint16 zoneid); uint32 AddWaypointForSpawn(Client* c, uint32 spawn2_id, const glm::vec4 &position, uint32 pause, int type, int type2, uint32 zone_id);
uint32 AddWPForSpawn(Client *c, uint32 spawn2id, const glm::vec4& position, uint32 pause, int type1, int type2, uint16 zoneid); void ModifyGrid(Client* c, bool remove, uint32 grid_id, uint8 type = 0, uint8 type2 = 0, uint32 zone_id = 0);
void ModifyGrid(Client *c, bool remove, uint32 id, uint8 type = 0, uint8 type2 = 0, uint16 zoneid = 0);
bool GridExistsInZone(uint32 zone_id, uint32 grid_id); bool GridExistsInZone(uint32 zone_id, uint32 grid_id);
void ModifyWP(Client *c, uint32 grid_id, uint32 wp_num, const glm::vec3& location, uint32 script = 0, uint16 zoneid = 0); int GetHighestGrid(uint32 zone_id);
int GetHighestGrid(uint32 zoneid); int GetHighestWaypoint(uint32 zone_id, uint32 grid_id);
int GetHighestWaypoint(uint32 zoneid, uint32 gridid); int GetRandomWaypointFromGrid(glm::vec4 &loc, uint32 zone_id, uint32 grid_id);
int GetRandomWaypointLocFromGrid(glm::vec4 &loc, uint16 zoneid, int grid);
/* NPCs */ /* NPCs */