Merge branch 'feature/peq-expansions' of https://github.com/EQEmu/Server into feature/generated-repositories

This commit is contained in:
Akkadius 2020-04-05 23:21:21 -05:00
commit a19bb7b544
21 changed files with 639 additions and 325 deletions

View File

@ -26,8 +26,10 @@
#include "../../common/crash.h" #include "../../common/crash.h"
#include "../../common/rulesys.h" #include "../../common/rulesys.h"
#include "../../common/string_util.h" #include "../../common/string_util.h"
#include "../../common/content/world_content_service.h"
EQEmuLogSys LogSys; EQEmuLogSys LogSys;
WorldContentService content_service;
void ExportSpells(SharedDatabase *db); void ExportSpells(SharedDatabase *db);
void ExportSkillCaps(SharedDatabase *db); void ExportSkillCaps(SharedDatabase *db);

View File

@ -24,8 +24,10 @@
#include "../../common/crash.h" #include "../../common/crash.h"
#include "../../common/rulesys.h" #include "../../common/rulesys.h"
#include "../../common/string_util.h" #include "../../common/string_util.h"
#include "../../common/content/world_content_service.h"
EQEmuLogSys LogSys; EQEmuLogSys LogSys;
WorldContentService content_service;
void ImportSpells(SharedDatabase *db); void ImportSpells(SharedDatabase *db);
void ImportSkillCaps(SharedDatabase *db); void ImportSkillCaps(SharedDatabase *db);

View File

@ -28,7 +28,7 @@ namespace Expansion {
enum ExpansionNumber { enum ExpansionNumber {
Classic = 0, Classic = 0,
TheRuinsOfKunark, TheRuinsOfKunark,
TheShardsOfVelious, TheScarsOfVelious,
TheShadowsOfLuclin, TheShadowsOfLuclin,
ThePlanesOfPower, ThePlanesOfPower,
TheLegacyOfYkesha, TheLegacyOfYkesha,
@ -62,8 +62,10 @@ namespace Expansion {
static const char *ExpansionName[ExpansionNumber::MaxId] = { static const char *ExpansionName[ExpansionNumber::MaxId] = {
"Classic", "Classic",
"The Ruins of Kunark", "The Ruins of Kunark",
"The Scars of Velious",
"The Shadows of Luclin", "The Shadows of Luclin",
"The Planes of Power", "The Planes of Power",
"The Legacy of Ykesha",
"Lost Dungeons of Norrath", "Lost Dungeons of Norrath",
"Gates of Discord", "Gates of Discord",
"Omens of War", "Omens of War",
@ -96,7 +98,7 @@ public:
bool IsClassicEnabled() { return GetCurrentExpansion() >= Expansion::ExpansionNumber::Classic; } bool IsClassicEnabled() { return GetCurrentExpansion() >= Expansion::ExpansionNumber::Classic; }
bool IsTheRuinsOfKunarkEnabled() { return GetCurrentExpansion() >= Expansion::ExpansionNumber::TheRuinsOfKunark; } bool IsTheRuinsOfKunarkEnabled() { return GetCurrentExpansion() >= Expansion::ExpansionNumber::TheRuinsOfKunark; }
bool IsTheShardsOfVeliousEnabled() { return GetCurrentExpansion() >= Expansion::ExpansionNumber::TheShardsOfVelious; } bool IsTheScarsOfVeliousEnabled() { return GetCurrentExpansion() >= Expansion::ExpansionNumber::TheScarsOfVelious; }
bool IsTheShadowsOfLuclinEnabled() { return GetCurrentExpansion() >= Expansion::ExpansionNumber::TheShadowsOfLuclin; } bool IsTheShadowsOfLuclinEnabled() { return GetCurrentExpansion() >= Expansion::ExpansionNumber::TheShadowsOfLuclin; }
bool IsThePlanesOfPowerEnabled() { return GetCurrentExpansion() >= Expansion::ExpansionNumber::ThePlanesOfPower; } bool IsThePlanesOfPowerEnabled() { return GetCurrentExpansion() >= Expansion::ExpansionNumber::ThePlanesOfPower; }
bool IsTheLegacyOfYkeshaEnabled() { return GetCurrentExpansion() >= Expansion::ExpansionNumber::TheLegacyOfYkesha; } bool IsTheLegacyOfYkeshaEnabled() { return GetCurrentExpansion() >= Expansion::ExpansionNumber::TheLegacyOfYkesha; }
@ -124,7 +126,7 @@ public:
bool IsCurrentExpansionClassic() { return current_expansion == Expansion::ExpansionNumber::Classic; } bool IsCurrentExpansionClassic() { return current_expansion == Expansion::ExpansionNumber::Classic; }
bool IsCurrentExpansionTheRuinsOfKunark() { return current_expansion == Expansion::ExpansionNumber::TheRuinsOfKunark; } bool IsCurrentExpansionTheRuinsOfKunark() { return current_expansion == Expansion::ExpansionNumber::TheRuinsOfKunark; }
bool IsCurrentExpansionTheShardsOfVelious() { return current_expansion == Expansion::ExpansionNumber::TheShardsOfVelious; } bool IsCurrentExpansionTheScarsOfVelious() { return current_expansion == Expansion::ExpansionNumber::TheScarsOfVelious; }
bool IsCurrentExpansionTheShadowsOfLuclin() { return current_expansion == Expansion::ExpansionNumber::TheShadowsOfLuclin; } bool IsCurrentExpansionTheShadowsOfLuclin() { return current_expansion == Expansion::ExpansionNumber::TheShadowsOfLuclin; }
bool IsCurrentExpansionThePlanesOfPower() { return current_expansion == Expansion::ExpansionNumber::ThePlanesOfPower; } bool IsCurrentExpansionThePlanesOfPower() { return current_expansion == Expansion::ExpansionNumber::ThePlanesOfPower; }
bool IsCurrentExpansionTheLegacyOfYkesha() { return current_expansion == Expansion::ExpansionNumber::TheLegacyOfYkesha; } bool IsCurrentExpansionTheLegacyOfYkesha() { return current_expansion == Expansion::ExpansionNumber::TheLegacyOfYkesha; }

View File

@ -26,29 +26,48 @@
#include "../../string_util.h" #include "../../string_util.h"
namespace ContentFilterCriteria { namespace ContentFilterCriteria {
static std::string apply() static std::string apply(std::string table_prefix = "")
{ {
std::string criteria; std::string criteria;
if (!table_prefix.empty()) {
table_prefix = table_prefix + ".";
}
criteria += fmt::format( criteria += fmt::format(
" AND (min_expansion >= {} OR min_expansion = 0)", " AND ({}min_expansion <= {} OR {}min_expansion = 0)",
content_service.GetCurrentExpansion() table_prefix,
content_service.GetCurrentExpansion(),
table_prefix
); );
criteria += fmt::format( criteria += fmt::format(
" AND (max_expansion <= {} OR max_expansion = 0)", " AND ({}max_expansion >= {} OR {}max_expansion = 0)",
content_service.GetCurrentExpansion() table_prefix,
content_service.GetCurrentExpansion(),
table_prefix
); );
std::vector<std::string> flags = content_service.GetContentFlags(); std::vector<std::string> flags = content_service.GetContentFlags();
for (auto &flag: flags) { for (auto &flag: flags) {
flag = "'" + flag + "'"; flag = "'" + flag + "'";
} }
criteria += fmt::format( std::string flags_in_filter;
" AND (content_flags IS NULL OR content_flags IN ({}))", if (!flags.empty()) {
flags_in_filter = fmt::format(
" OR {}content_flags IN ({})",
table_prefix,
implode(", ", flags) implode(", ", flags)
); );
}
criteria += fmt::format(
" AND ({}content_flags IS NULL{})",
table_prefix,
flags_in_filter
);
return std::string(criteria); return std::string(criteria);
}; };

View File

@ -38,6 +38,7 @@
#include "shareddb.h" #include "shareddb.h"
#include "string_util.h" #include "string_util.h"
#include "eqemu_config.h" #include "eqemu_config.h"
#include "repositories/criteria/content_filter_criteria.h"
namespace ItemField namespace ItemField
{ {
@ -431,16 +432,25 @@ bool SharedDatabase::SetSharedPlatinum(uint32 account_id, int32 amount_to_add) {
bool SharedDatabase::SetStartingItems(PlayerProfile_Struct* pp, EQEmu::InventoryProfile* inv, uint32 si_race, uint32 si_class, uint32 si_deity, uint32 si_current_zone, char* si_name, int admin_level) { bool SharedDatabase::SetStartingItems(PlayerProfile_Struct* pp, EQEmu::InventoryProfile* inv, uint32 si_race, uint32 si_class, uint32 si_deity, uint32 si_current_zone, char* si_name, int admin_level) {
const EQEmu::ItemData* myitem; const EQEmu::ItemData *myitem;
std::string query = StringFormat("SELECT itemid, item_charges, slot FROM starting_items " std::string query = StringFormat(
"SELECT itemid, item_charges, slot FROM starting_items "
"WHERE (race = %i or race = 0) AND (class = %i or class = 0) AND " "WHERE (race = %i or race = 0) AND (class = %i or class = 0) AND "
"(deityid = %i or deityid = 0) AND (zoneid = %i or zoneid = 0) AND " "(deityid = %i or deityid = 0) AND (zoneid = %i or zoneid = 0) AND "
"gm <= %i ORDER BY id", "gm <= %i %s ORDER BY id",
si_race, si_class, si_deity, si_current_zone, admin_level); si_race,
si_class,
si_deity,
si_current_zone,
admin_level,
ContentFilterCriteria::apply().c_str()
);
auto results = QueryDatabase(query); auto results = QueryDatabase(query);
if (!results.Success()) if (!results.Success()) {
return false; return false;
}
for (auto row = results.begin(); row != results.end(); ++row) { for (auto row = results.begin(); row != results.end(); ++row) {
@ -1996,7 +2006,11 @@ void SharedDatabase::GetLootTableInfo(uint32 &loot_table_count, uint32 &max_loot
loot_table_count = 0; loot_table_count = 0;
max_loot_table = 0; max_loot_table = 0;
loot_table_entries = 0; loot_table_entries = 0;
const std::string query = "SELECT COUNT(*), MAX(id), (SELECT COUNT(*) FROM loottable_entries) FROM loottable"; const std::string query =
fmt::format(
"SELECT COUNT(*), MAX(id), (SELECT COUNT(*) FROM loottable_entries) FROM loottable WHERE TRUE {}",
ContentFilterCriteria::apply()
);
auto results = QueryDatabase(query); auto results = QueryDatabase(query);
if (!results.Success()) { if (!results.Success()) {
return; return;
@ -2017,7 +2031,11 @@ void SharedDatabase::GetLootDropInfo(uint32 &loot_drop_count, uint32 &max_loot_d
max_loot_drop = 0; max_loot_drop = 0;
loot_drop_entries = 0; loot_drop_entries = 0;
const std::string query = "SELECT COUNT(*), MAX(id), (SELECT COUNT(*) FROM lootdrop_entries) FROM lootdrop"; const std::string query = fmt::format(
"SELECT COUNT(*), MAX(id), (SELECT COUNT(*) FROM lootdrop_entries) FROM lootdrop WHERE TRUE {}",
ContentFilterCriteria::apply()
);
auto results = QueryDatabase(query); auto results = QueryDatabase(query);
if (!results.Success()) { if (!results.Success()) {
return; return;
@ -2039,10 +2057,28 @@ void SharedDatabase::LoadLootTables(void *data, uint32 size) {
uint8 loot_table[sizeof(LootTable_Struct) + (sizeof(LootTableEntries_Struct) * 128)]; uint8 loot_table[sizeof(LootTable_Struct) + (sizeof(LootTableEntries_Struct) * 128)];
LootTable_Struct *lt = reinterpret_cast<LootTable_Struct*>(loot_table); LootTable_Struct *lt = reinterpret_cast<LootTable_Struct*>(loot_table);
const std::string query = "SELECT loottable.id, loottable.mincash, loottable.maxcash, loottable.avgcoin, " const std::string query = fmt::format(
"loottable_entries.lootdrop_id, loottable_entries.multiplier, loottable_entries.droplimit, " SQL(
"loottable_entries.mindrop, loottable_entries.probability FROM loottable LEFT JOIN loottable_entries " SELECT
"ON loottable.id = loottable_entries.loottable_id ORDER BY id"; loottable.id,
loottable.mincash,
loottable.maxcash,
loottable.avgcoin,
loottable_entries.lootdrop_id,
loottable_entries.multiplier,
loottable_entries.droplimit,
loottable_entries.mindrop,
loottable_entries.probability
FROM
loottable
LEFT JOIN loottable_entries ON loottable.id = loottable_entries.loottable_id
WHERE TRUE {}
ORDER BY
id
),
ContentFilterCriteria::apply()
);
auto results = QueryDatabase(query); auto results = QueryDatabase(query);
if (!results.Success()) { if (!results.Success()) {
return; return;
@ -2053,9 +2089,13 @@ void SharedDatabase::LoadLootTables(void *data, uint32 size) {
for (auto row = results.begin(); row != results.end(); ++row) { for (auto row = results.begin(); row != results.end(); ++row) {
uint32 id = static_cast<uint32>(atoul(row[0])); uint32 id = static_cast<uint32>(atoul(row[0]));
if(id != current_id) { if (id != current_id) {
if(current_id != 0) if (current_id != 0) {
hash.insert(current_id, loot_table, (sizeof(LootTable_Struct) + (sizeof(LootTableEntries_Struct) * lt->NumEntries))); hash.insert(
current_id,
loot_table,
(sizeof(LootTable_Struct) + (sizeof(LootTableEntries_Struct) * lt->NumEntries)));
}
memset(loot_table, 0, sizeof(LootTable_Struct) + (sizeof(LootTableEntries_Struct) * 128)); memset(loot_table, 0, sizeof(LootTable_Struct) + (sizeof(LootTableEntries_Struct) * 128));
current_entry = 0; current_entry = 0;
@ -2065,11 +2105,13 @@ void SharedDatabase::LoadLootTables(void *data, uint32 size) {
lt->avgcoin = static_cast<uint32>(atoul(row[3])); lt->avgcoin = static_cast<uint32>(atoul(row[3]));
} }
if(current_entry > 128) if (current_entry > 128) {
continue; continue;
}
if(!row[4]) if (!row[4]) {
continue; continue;
}
lt->Entries[current_entry].lootdrop_id = static_cast<uint32>(atoul(row[4])); lt->Entries[current_entry].lootdrop_id = static_cast<uint32>(atoul(row[4]));
lt->Entries[current_entry].multiplier = static_cast<uint8>(atoi(row[5])); lt->Entries[current_entry].multiplier = static_cast<uint8>(atoi(row[5]));
@ -2081,8 +2123,13 @@ void SharedDatabase::LoadLootTables(void *data, uint32 size) {
++current_entry; ++current_entry;
} }
if(current_id != 0) if (current_id != 0) {
hash.insert(current_id, loot_table, (sizeof(LootTable_Struct) + (sizeof(LootTableEntries_Struct) * lt->NumEntries))); hash.insert(
current_id,
loot_table,
(sizeof(LootTable_Struct) + (sizeof(LootTableEntries_Struct) * lt->NumEntries))
);
}
} }
@ -2092,10 +2139,28 @@ void SharedDatabase::LoadLootDrops(void *data, uint32 size) {
uint8 loot_drop[sizeof(LootDrop_Struct) + (sizeof(LootDropEntries_Struct) * 1260)]; uint8 loot_drop[sizeof(LootDrop_Struct) + (sizeof(LootDropEntries_Struct) * 1260)];
LootDrop_Struct *ld = reinterpret_cast<LootDrop_Struct*>(loot_drop); LootDrop_Struct *ld = reinterpret_cast<LootDrop_Struct*>(loot_drop);
const std::string query = "SELECT lootdrop.id, lootdrop_entries.item_id, lootdrop_entries.item_charges, " const std::string query = fmt::format(
"lootdrop_entries.equip_item, lootdrop_entries.chance, lootdrop_entries.minlevel, " SQL(
"lootdrop_entries.maxlevel, lootdrop_entries.multiplier FROM lootdrop JOIN lootdrop_entries " SELECT
"ON lootdrop.id = lootdrop_entries.lootdrop_id ORDER BY lootdrop_id"; lootdrop.id,
lootdrop_entries.item_id,
lootdrop_entries.item_charges,
lootdrop_entries.equip_item,
lootdrop_entries.chance,
lootdrop_entries.minlevel,
lootdrop_entries.maxlevel,
lootdrop_entries.multiplier
FROM
lootdrop
JOIN lootdrop_entries ON lootdrop.id = lootdrop_entries.lootdrop_id
WHERE
TRUE {}
ORDER BY
lootdrop_id
),
ContentFilterCriteria::apply()
);
auto results = QueryDatabase(query); auto results = QueryDatabase(query);
if (!results.Success()) { if (!results.Success()) {
return; return;

View File

@ -33,8 +33,10 @@
#include "skill_caps.h" #include "skill_caps.h"
#include "spells.h" #include "spells.h"
#include "base_data.h" #include "base_data.h"
#include "../common/content/world_content_service.h"
EQEmuLogSys LogSys; EQEmuLogSys LogSys;
WorldContentService content_service;
#ifdef _WINDOWS #ifdef _WINDOWS
#include <direct.h> #include <direct.h>
@ -139,6 +141,39 @@ int main(int argc, char **argv)
} }
} }
/**
* Rules: TODO: Remove later
*/
{
std::string tmp;
if (database.GetVariable("RuleSet", tmp)) {
LogInfo("Loading rule set [{}]", tmp.c_str());
if (!RuleManager::Instance()->LoadRules(&database, tmp.c_str(), false)) {
LogError("Failed to load ruleset [{}], falling back to defaults", tmp.c_str());
}
}
else {
if (!RuleManager::Instance()->LoadRules(&database, "default", false)) {
LogInfo("No rule set configured, using default rules");
}
else {
LogInfo("Loaded default rule set 'default'");
}
}
EQEmu::InitializeDynamicLookups();
LogInfo("Initialized dynamic dictionary entries");
}
content_service.SetCurrentExpansion(RuleI(Expansion, CurrentExpansion));
LogInfo(
"Current expansion is [{}] ({})",
content_service.GetCurrentExpansion(),
Expansion::ExpansionName[content_service.GetCurrentExpansion()]
);
std::string hotfix_name = ""; std::string hotfix_name = "";
bool load_all = true; bool load_all = true;

View File

@ -59,6 +59,7 @@ namespace WorldserverCommandHandler {
function_map["database:schema"] = &WorldserverCommandHandler::DatabaseGetSchema; function_map["database:schema"] = &WorldserverCommandHandler::DatabaseGetSchema;
function_map["database:dump"] = &WorldserverCommandHandler::DatabaseDump; function_map["database:dump"] = &WorldserverCommandHandler::DatabaseDump;
function_map["test:test"] = &WorldserverCommandHandler::TestCommand; function_map["test:test"] = &WorldserverCommandHandler::TestCommand;
function_map["test:expansion"] = &WorldserverCommandHandler::ExpansionTestCommand;
function_map["test:repository"] = &WorldserverCommandHandler::TestRepository; function_map["test:repository"] = &WorldserverCommandHandler::TestRepository;
function_map["test:repository2"] = &WorldserverCommandHandler::TestRepository2; function_map["test:repository2"] = &WorldserverCommandHandler::TestRepository2;
@ -293,6 +294,22 @@ namespace WorldserverCommandHandler {
return; return;
} }
}
/**
* @param argc
* @param argv
* @param cmd
* @param description
*/
void ExpansionTestCommand(int argc, char **argv, argh::parser &cmd, std::string &description)
{
description = "Expansion test command";
if (cmd[{"-h", "--help"}]) {
return;
}
if (!RuleManager::Instance()->LoadRules(&database, "default", false)) { if (!RuleManager::Instance()->LoadRules(&database, "default", false)) {
LogInfo("No rule set configured, using default rules"); LogInfo("No rule set configured, using default rules");
} }
@ -310,7 +327,7 @@ namespace WorldserverCommandHandler {
"Current expansion is [{}] ({}) is Velious Enabled [{}] Criteria [{}]", "Current expansion is [{}] ({}) is Velious Enabled [{}] Criteria [{}]",
content_service.GetCurrentExpansion(), content_service.GetCurrentExpansion(),
Expansion::ExpansionName[content_service.GetCurrentExpansion()], Expansion::ExpansionName[content_service.GetCurrentExpansion()],
content_service.IsTheShardsOfVeliousEnabled() ? "true" : "false", content_service.IsTheScarsOfVeliousEnabled() ? "true" : "false",
ContentFilterCriteria::apply() ContentFilterCriteria::apply()
); );
} }

View File

@ -32,6 +32,7 @@ namespace WorldserverCommandHandler {
void DatabaseGetSchema(int argc, char **argv, argh::parser &cmd, std::string &description); void DatabaseGetSchema(int argc, char **argv, argh::parser &cmd, std::string &description);
void DatabaseDump(int argc, char **argv, argh::parser &cmd, std::string &description); void DatabaseDump(int argc, char **argv, argh::parser &cmd, std::string &description);
void TestCommand(int argc, char **argv, argh::parser &cmd, std::string &description); void TestCommand(int argc, char **argv, argh::parser &cmd, std::string &description);
void ExpansionTestCommand(int argc, char **argv, argh::parser &cmd, std::string &description);
void TestRepository(int argc, char **argv, argh::parser &cmd, std::string &description); void TestRepository(int argc, char **argv, argh::parser &cmd, std::string &description);
void TestRepository2(int argc, char **argv, argh::parser &cmd, std::string &description); void TestRepository2(int argc, char **argv, argh::parser &cmd, std::string &description);
}; };

View File

@ -25,6 +25,7 @@
#include <cstdlib> #include <cstdlib>
#include <vector> #include <vector>
#include "sof_char_create_data.h" #include "sof_char_create_data.h"
#include "../common/repositories/criteria/content_filter_criteria.h"
WorldDatabase database; WorldDatabase database;
WorldDatabase content_db; WorldDatabase content_db;
@ -197,10 +198,11 @@ void WorldDatabase::GetCharSelectInfo(uint32 account_id, EQApplicationPacket **o
if (has_home == 0 || has_bind == 0) { if (has_home == 0 || has_bind == 0) {
character_list_query = StringFormat( character_list_query = StringFormat(
"SELECT `zone_id`, `bind_id`, `x`, `y`, `z` FROM `start_zones` WHERE `player_class` = %i AND `player_deity` = %i AND `player_race` = %i", "SELECT `zone_id`, `bind_id`, `x`, `y`, `z` FROM `start_zones` WHERE `player_class` = %i AND `player_deity` = %i AND `player_race` = %i %s",
p_character_select_entry_struct->Class, p_character_select_entry_struct->Class,
p_character_select_entry_struct->Deity, p_character_select_entry_struct->Deity,
p_character_select_entry_struct->Race p_character_select_entry_struct->Race,
ContentFilterCriteria::apply().c_str()
); );
auto results_bind = content_db.QueryDatabase(character_list_query); auto results_bind = content_db.QueryDatabase(character_list_query);
for (auto row_d = results_bind.begin(); row_d != results_bind.end(); ++row_d) { for (auto row_d = results_bind.begin(); row_d != results_bind.end(); ++row_d) {
@ -423,11 +425,12 @@ bool WorldDatabase::GetStartZone(
// see if we have an entry for start_zone. We can support both titanium & SOF+ by having two entries per class/race/deity combo with different zone_ids // see if we have an entry for start_zone. We can support both titanium & SOF+ by having two entries per class/race/deity combo with different zone_ids
std::string query = StringFormat( std::string query = StringFormat(
"SELECT x, y, z, heading, start_zone, bind_id, bind_x, bind_y, bind_z FROM start_zones WHERE zone_id = %i " "SELECT x, y, z, heading, start_zone, bind_id, bind_x, bind_y, bind_z FROM start_zones WHERE zone_id = %i "
"AND player_class = %i AND player_deity = %i AND player_race = %i", "AND player_class = %i AND player_deity = %i AND player_race = %i %s",
p_char_create_struct->start_zone, p_char_create_struct->start_zone,
p_char_create_struct->class_, p_char_create_struct->class_,
p_char_create_struct->deity, p_char_create_struct->deity,
p_char_create_struct->race p_char_create_struct->race,
ContentFilterCriteria::apply().c_str()
); );
auto results = QueryDatabase(query); auto results = QueryDatabase(query);

View File

@ -61,6 +61,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "worldserver.h" #include "worldserver.h"
#include "zone.h" #include "zone.h"
#include "mob_movement_manager.h" #include "mob_movement_manager.h"
#include "../common/repositories/criteria/content_filter_criteria.h"
#ifdef BOTS #ifdef BOTS
#include "bot.h" #include "bot.h"
@ -11828,6 +11829,7 @@ void Client::Handle_OP_RecipesFavorite(const EQApplicationPacket *app)
if (first) //no favorites.... if (first) //no favorites....
return; return;
// TODO: Clean this up
const std::string query = StringFormat( const std::string query = StringFormat(
SQL ( SQL (
SELECT SELECT
@ -11849,6 +11851,7 @@ void Client::Handle_OP_RecipesFavorite(const EQApplicationPacket *app)
) )
OR (tr.must_learn & 0x3 = 0) OR (tr.must_learn & 0x3 = 0)
) )
%s
GROUP BY GROUP BY
tr.id tr.id
HAVING HAVING
@ -11861,10 +11864,12 @@ void Client::Handle_OP_RecipesFavorite(const EQApplicationPacket *app)
) )
) > 0 ) > 0
AND SUM(tre.componentcount) <= %u AND SUM(tre.componentcount) <= %u
LIMIT LIMIT
100 100
), ),
favoriteIDs.c_str(), favoriteIDs.c_str(),
ContentFilterCriteria::apply().c_str(),
containers.c_str(), containers.c_str(),
combineObjectSlots combineObjectSlots
); );
@ -11924,6 +11929,7 @@ void Client::Handle_OP_RecipesSearch(const EQApplicationPacket *app)
} }
//arbitrary limit of 200 recipes, makes sense to me. //arbitrary limit of 200 recipes, makes sense to me.
// TODO: Clean this up
std::string query = fmt::format( std::string query = fmt::format(
SQL( SQL(
SELECT SELECT
@ -11931,27 +11937,10 @@ void Client::Handle_OP_RecipesSearch(const EQApplicationPacket *app)
tr.name, tr.name,
tr.trivial, tr.trivial,
SUM(tre.componentcount), SUM(tre.componentcount),
crl.madecount,
tr.tradeskill tr.tradeskill
FROM FROM
tradeskill_recipe tradeskill_recipe AS tr
AS tr LEFT JOIN tradeskill_recipe_entries AS tre ON tr.id = tre.recipe_id
LEFT
JOIN
tradeskill_recipe_entries
AS
tre
ON
tr.id = tre.recipe_id
LEFT JOIN(
SELECT
recipe_id,
madecount
FROM
char_recipe_list
WHERE
char_id = {}
) AS crl ON tr.id = crl.recipe_id
WHERE WHERE
{} tr.trivial >= {} {} tr.trivial >= {}
AND tr.trivial <= {} AND tr.trivial <= {}
@ -11960,10 +11949,10 @@ void Client::Handle_OP_RecipesSearch(const EQApplicationPacket *app)
AND ( AND (
( (
tr.must_learn & 0x3 <> 0 tr.must_learn & 0x3 <> 0
AND crl.madecount IS NOT NULL
) )
OR (tr.must_learn & 0x3 = 0) OR (tr.must_learn & 0x3 = 0)
) )
{}
GROUP BY GROUP BY
tr.id tr.id
HAVING HAVING
@ -11976,13 +11965,14 @@ void Client::Handle_OP_RecipesSearch(const EQApplicationPacket *app)
) )
) > 0 ) > 0
AND SUM(tre.componentcount) <= {} AND SUM(tre.componentcount) <= {}
LIMIT LIMIT
200 200
), ),
CharacterID(),
search_clause, search_clause,
p_recipes_search_struct->mintrivial, p_recipes_search_struct->mintrivial,
p_recipes_search_struct->maxtrivial, p_recipes_search_struct->maxtrivial,
ContentFilterCriteria::apply(),
containers_where_clause, containers_where_clause,
combine_object_slots combine_object_slots
); );
@ -12447,9 +12437,14 @@ void Client::Handle_OP_SetStartCity(const EQApplicationPacket *app)
uint32 zoneid = 0; uint32 zoneid = 0;
uint32 startCity = (uint32)strtol((const char*)app->pBuffer, nullptr, 10); uint32 startCity = (uint32)strtol((const char*)app->pBuffer, nullptr, 10);
std::string query = StringFormat("SELECT zone_id, bind_id, x, y, z FROM start_zones " std::string query = StringFormat(
"WHERE player_class=%i AND player_deity=%i AND player_race=%i", "SELECT zone_id, bind_id, x, y, z FROM start_zones "
m_pp.class_, m_pp.deity, m_pp.race); "WHERE player_class=%i AND player_deity=%i AND player_race=%i %s",
m_pp.class_,
m_pp.deity,
m_pp.race,
ContentFilterCriteria::apply().c_str()
);
auto results = content_db.QueryDatabase(query); auto results = content_db.QueryDatabase(query);
if (!results.Success()) { if (!results.Success()) {
LogError("No valid start zones found for /setstartcity"); LogError("No valid start zones found for /setstartcity");

View File

@ -28,6 +28,7 @@
#include "string_ids.h" #include "string_ids.h"
#include "worldserver.h" #include "worldserver.h"
#include "zonedb.h" #include "zonedb.h"
#include "../common/repositories/criteria/content_filter_criteria.h"
#include <iostream> #include <iostream>
#include <string.h> #include <string.h>
@ -716,10 +717,12 @@ bool ZoneDatabase::LoadDoors(int32 door_count, Door *into, const char *zone_name
" WHERE " " WHERE "
" zone = '%s' " " zone = '%s' "
" AND ( version = % u OR version = - 1 ) " " AND ( version = % u OR version = - 1 ) "
" %s "
" ORDER BY " " ORDER BY "
" doorid ASC ", " doorid ASC ",
zone_name, zone_name,
version version,
ContentFilterCriteria::apply().c_str()
); );
auto results = QueryDatabase(query); auto results = QueryDatabase(query);
if (!results.Success()) { if (!results.Success()) {

View File

@ -30,6 +30,7 @@
#include "titles.h" #include "titles.h"
#include "water_map.h" #include "water_map.h"
#include "zonedb.h" #include "zonedb.h"
#include "../common/repositories/criteria/content_filter_criteria.h"
#include <iostream> #include <iostream>
@ -54,9 +55,25 @@ uint32 ZoneDatabase::GetZoneForage(uint32 ZoneID, uint8 skill) {
} }
uint32 chancepool = 0; uint32 chancepool = 0;
std::string query = StringFormat("SELECT itemid, chance FROM " std::string query = fmt::format(
"forage WHERE zoneid = '%i' and level <= '%i' " SQL(
"LIMIT %i", ZoneID, skill, FORAGE_ITEM_LIMIT); SELECT
itemid,
chance
FROM
forage
WHERE
zoneid = '{}'
and level <= '{}'
{}
LIMIT
{}
),
ZoneID,
skill,
ContentFilterCriteria::apply(),
FORAGE_ITEM_LIMIT
);
auto results = QueryDatabase(query); auto results = QueryDatabase(query);
if (!results.Success()) { if (!results.Success()) {
return 0; return 0;
@ -109,9 +126,24 @@ uint32 ZoneDatabase::GetZoneFishing(uint32 ZoneID, uint8 skill, uint32 &npc_id,
chance[c]=0; chance[c]=0;
} }
std::string query = StringFormat("SELECT itemid, chance, npc_id, npc_chance " std::string query = fmt::format(
"FROM fishing WHERE (zoneid = '%i' || zoneid = 0) AND skill_level <= '%i'", SQL(
ZoneID, skill); SELECT
itemid,
chance,
npc_id,
npc_chance
FROM
fishing
WHERE
(zoneid = '{}' || zoneid = 0)
AND skill_level <= '{}'
{}
),
ZoneID,
skill,
ContentFilterCriteria::apply()
);
auto results = QueryDatabase(query); auto results = QueryDatabase(query);
if (!results.Success()) { if (!results.Success()) {
return 0; return 0;

View File

@ -27,6 +27,7 @@
#include "npc.h" #include "npc.h"
#include "zonedb.h" #include "zonedb.h"
#include "global_loot_manager.h" #include "global_loot_manager.h"
#include "../common/repositories/criteria/content_filter_criteria.h"
#include <iostream> #include <iostream>
#include <stdlib.h> #include <stdlib.h>
@ -463,12 +464,35 @@ void NPC::CheckGlobalLootTables()
void ZoneDatabase::LoadGlobalLoot() void ZoneDatabase::LoadGlobalLoot()
{ {
auto query = StringFormat("SELECT id, loottable_id, description, min_level, max_level, rare, raid, race, " auto query = fmt::format(
"class, bodytype, zone, hot_zone FROM global_loot WHERE enabled = 1"); SQL
(
SELECT
id,
loottable_id,
description,
min_level,
max_level,
rare,
raid,
race,
class,
bodytype,
zone,
hot_zone
FROM
global_loot
WHERE
enabled = 1
{}
),
ContentFilterCriteria::apply()
);
auto results = QueryDatabase(query); auto results = QueryDatabase(query);
if (!results.Success() || results.RowCount() == 0) if (!results.Success() || results.RowCount() == 0) {
return; return;
}
// we might need this, lets not keep doing it in a loop // we might need this, lets not keep doing it in a loop
auto zoneid = std::to_string(zone->GetZoneID()); auto zoneid = std::to_string(zone->GetZoneID());
@ -478,27 +502,32 @@ void ZoneDatabase::LoadGlobalLoot()
auto zones = SplitString(row[10], '|'); auto zones = SplitString(row[10], '|');
auto it = std::find(zones.begin(), zones.end(), zoneid); auto it = std::find(zones.begin(), zones.end(), zoneid);
if (it == zones.end()) // not in here, skip if (it == zones.end()) { // not in here, skip
continue; continue;
} }
}
GlobalLootEntry e(atoi(row[0]), atoi(row[1]), row[2] ? row[2] : ""); GlobalLootEntry e(atoi(row[0]), atoi(row[1]), row[2] ? row[2] : "");
auto min_level = atoi(row[3]); auto min_level = atoi(row[3]);
if (min_level) if (min_level) {
e.AddRule(GlobalLoot::RuleTypes::LevelMin, min_level); e.AddRule(GlobalLoot::RuleTypes::LevelMin, min_level);
}
auto max_level = atoi(row[4]); auto max_level = atoi(row[4]);
if (max_level) if (max_level) {
e.AddRule(GlobalLoot::RuleTypes::LevelMax, max_level); e.AddRule(GlobalLoot::RuleTypes::LevelMax, max_level);
}
// null is not used // null is not used
if (row[5]) if (row[5]) {
e.AddRule(GlobalLoot::RuleTypes::Rare, atoi(row[5])); e.AddRule(GlobalLoot::RuleTypes::Rare, atoi(row[5]));
}
// null is not used // null is not used
if (row[6]) if (row[6]) {
e.AddRule(GlobalLoot::RuleTypes::Raid, atoi(row[6])); e.AddRule(GlobalLoot::RuleTypes::Raid, atoi(row[6]));
}
if (row[7]) { if (row[7]) {
auto races = SplitString(row[7], '|'); auto races = SplitString(row[7], '|');
@ -522,8 +551,9 @@ void ZoneDatabase::LoadGlobalLoot()
} }
// null is not used // null is not used
if (row[11]) if (row[11]) {
e.AddRule(GlobalLoot::RuleTypes::HotZone, atoi(row[11])); e.AddRule(GlobalLoot::RuleTypes::HotZone, atoi(row[11]));
}
zone->AddGlobalLootEntry(e); zone->AddGlobalLootEntry(e);
} }

View File

@ -90,6 +90,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#else #else
#include <pthread.h> #include <pthread.h>
#include "../common/unix.h" #include "../common/unix.h"
#include "../common/content/world_content_service.h"
#endif #endif
volatile bool RunLoops = true; volatile bool RunLoops = true;
@ -107,6 +110,7 @@ TaskManager *taskmanager = 0;
NpcScaleManager *npc_scale_manager; NpcScaleManager *npc_scale_manager;
QuestParserCollection *parse = 0; QuestParserCollection *parse = 0;
EQEmuLogSys LogSys; EQEmuLogSys LogSys;
WorldContentService content_service;
const SPDat_Spell_Struct* spells; const SPDat_Spell_Struct* spells;
int32 SPDAT_RECORDS = -1; int32 SPDAT_RECORDS = -1;
const ZoneConfig *Config; const ZoneConfig *Config;
@ -392,6 +396,14 @@ int main(int argc, char** argv) {
LogInfo("Initialized dynamic dictionary entries"); LogInfo("Initialized dynamic dictionary entries");
} }
content_service.SetCurrentExpansion(RuleI(Expansion, CurrentExpansion));
LogInfo(
"Current expansion is [{}] ({})",
content_service.GetCurrentExpansion(),
Expansion::ExpansionName[content_service.GetCurrentExpansion()]
);
#ifdef BOTS #ifdef BOTS
LogInfo("Loading bot commands"); LogInfo("Loading bot commands");
int botretval = bot_command_init(); int botretval = bot_command_init();

View File

@ -26,6 +26,7 @@
#include "quest_parser_collection.h" #include "quest_parser_collection.h"
#include "zonedb.h" #include "zonedb.h"
#include "../common/repositories/criteria/content_filter_criteria.h"
#include <iostream> #include <iostream>
@ -698,12 +699,18 @@ void ZoneDatabase::UpdateObject(uint32 id, uint32 type, uint32 icon, const Objec
// //
Ground_Spawns* ZoneDatabase::LoadGroundSpawns(uint32 zone_id, int16 version, Ground_Spawns* gs) { Ground_Spawns* ZoneDatabase::LoadGroundSpawns(uint32 zone_id, int16 version, Ground_Spawns* gs) {
std::string query = StringFormat("SELECT max_x, max_y, max_z, " std::string query = StringFormat(
"SELECT max_x, max_y, max_z, "
"min_x, min_y, heading, name, " "min_x, min_y, heading, name, "
"item, max_allowed, respawn_timer " "item, max_allowed, respawn_timer "
"FROM ground_spawns " "FROM ground_spawns "
"WHERE zoneid = %i AND (version = %u OR version = -1) " "WHERE zoneid = %i AND (version = %u OR version = -1) %s "
"LIMIT 50", zone_id, version); "LIMIT 50",
zone_id,
version,
ContentFilterCriteria::apply().c_str()
);
auto results = QueryDatabase(query); auto results = QueryDatabase(query);
if (!results.Success()) { if (!results.Success()) {
return gs; return gs;

View File

@ -24,6 +24,7 @@
#include "spawngroup.h" #include "spawngroup.h"
#include "zone.h" #include "zone.h"
#include "zonedb.h" #include "zonedb.h"
#include "../common/repositories/criteria/content_filter_criteria.h"
extern EntityList entity_list; extern EntityList entity_list;
extern Zone *zone; extern Zone *zone;
@ -209,9 +210,11 @@ bool ZoneDatabase::LoadSpawnGroups(const char *zone_name, uint16 version, SpawnG
spawn2.spawngroupID = spawngroup.ID spawn2.spawngroupID = spawngroup.ID
AND AND
spawn2.version = {} and zone = '{}' spawn2.version = {} and zone = '{}'
{}
), ),
version, version,
zone_name zone_name,
ContentFilterCriteria::apply()
); );
auto results = QueryDatabase(query); auto results = QueryDatabase(query);

View File

@ -310,6 +310,7 @@
#define WHOALL_NO_RESULTS 5029 //There are no players in EverQuest that match those who filters. #define WHOALL_NO_RESULTS 5029 //There are no players in EverQuest that match those who filters.
#define TELL_QUEUED_MESSAGE 5045 //You told %1 '%T2. %3' #define TELL_QUEUED_MESSAGE 5045 //You told %1 '%T2. %3'
#define TOLD_NOT_ONLINE 5046 //%1 is not online at this time. #define TOLD_NOT_ONLINE 5046 //%1 is not online at this time.
#define ZONING_NO_EXPANSION 5052 //The zone that you are attempting to enter is part of an expansion that you do not yet own. You may need to return to the Login screen and enter an account key for that expansion. If you have received this message in error, please /petition or send an email to EQAccounts@soe.sony.com
#define PETITION_NO_DELETE 5053 //You do not have a petition in the queue. #define PETITION_NO_DELETE 5053 //You do not have a petition in the queue.
#define PETITION_DELETED 5054 //Your petition was successfully deleted. #define PETITION_DELETED 5054 //Your petition was successfully deleted.
#define ALREADY_IN_RAID 5060 //%1 is already in a raid. #define ALREADY_IN_RAID 5060 //%1 is already in a raid.

View File

@ -24,6 +24,7 @@
#include "entity.h" #include "entity.h"
#include "mob.h" #include "mob.h"
#include "trap.h" #include "trap.h"
#include "../common/repositories/criteria/content_filter_criteria.h"
/* /*
@ -399,9 +400,14 @@ void EntityList::ClearTrapPointers()
bool ZoneDatabase::LoadTraps(const char* zonename, int16 version) { bool ZoneDatabase::LoadTraps(const char* zonename, int16 version) {
std::string query = StringFormat("SELECT id, x, y, z, effect, effectvalue, effectvalue2, skill, " std::string query = StringFormat(
"SELECT id, x, y, z, effect, effectvalue, effectvalue2, skill, "
"maxzdiff, radius, chance, message, respawn_time, respawn_var, level, " "maxzdiff, radius, chance, message, respawn_time, respawn_var, level, "
"`group`, triggered_number, despawn_when_triggered, undetectable FROM traps WHERE zone='%s' AND version=%u", zonename, version); "`group`, triggered_number, despawn_when_triggered, undetectable FROM traps WHERE zone='%s' AND version=%u %s",
zonename,
version,
ContentFilterCriteria::apply().c_str()
);
auto results = QueryDatabase(query); auto results = QueryDatabase(query);
if (!results.Success()) { if (!results.Success()) {

View File

@ -56,6 +56,7 @@
#include "npc_scale_manager.h" #include "npc_scale_manager.h"
#include "../common/data_verification.h" #include "../common/data_verification.h"
#include "zone_reload.h" #include "zone_reload.h"
#include "../common/repositories/criteria/content_filter_criteria.h"
#include <time.h> #include <time.h>
#include <ctime> #include <ctime>
@ -170,11 +171,14 @@ bool Zone::Bootup(uint32 iZoneID, uint32 iInstanceID, bool iStaticZone) {
//this really loads the objects into entity_list //this really loads the objects into entity_list
bool Zone::LoadZoneObjects() bool Zone::LoadZoneObjects()
{ {
std::string query = std::string query = StringFormat(
StringFormat("SELECT id, zoneid, xpos, ypos, zpos, heading, itemid, charges, objectname, type, icon, " "SELECT id, zoneid, xpos, ypos, zpos, heading, itemid, charges, objectname, type, icon, "
"unknown08, unknown10, unknown20, unknown24, unknown76, size, tilt_x, tilt_y, display_name " "unknown08, unknown10, unknown20, unknown24, unknown76, size, tilt_x, tilt_y, display_name "
"FROM object WHERE zoneid = %i AND (version = %u OR version = -1)", "FROM object WHERE zoneid = %i AND (version = %u OR version = -1) %s",
zoneid, instanceversion); zoneid,
instanceversion,
ContentFilterCriteria::apply().c_str()
);
auto results = content_db.QueryDatabase(query); auto results = content_db.QueryDatabase(query);
if (!results.Success()) { if (!results.Success()) {
LogError("Error Loading Objects from DB: [{}]", LogError("Error Loading Objects from DB: [{}]",
@ -498,14 +502,35 @@ void Zone::LoadTempMerchantData()
void Zone::LoadNewMerchantData(uint32 merchantid) { void Zone::LoadNewMerchantData(uint32 merchantid) {
std::list<MerchantList> merlist; std::list<MerchantList> merlist;
std::string query = StringFormat("SELECT item, slot, faction_required, level_required, alt_currency_cost, "
"classes_required, probability FROM merchantlist WHERE merchantid=%d ORDER BY slot", merchantid); std::string query = fmt::format(
SQL(
SELECT
item,
slot,
faction_required,
level_required,
alt_currency_cost,
classes_required,
probability
FROM
merchantlist
WHERE
merchantid = {}
{}
ORDER BY
slot
),
merchantid,
ContentFilterCriteria::apply()
);
auto results = content_db.QueryDatabase(query); auto results = content_db.QueryDatabase(query);
if (!results.Success()) { if (!results.Success()) {
return; return;
} }
for(auto row = results.begin(); row != results.end(); ++row) { for (auto row = results.begin(); row != results.end(); ++row) {
MerchantList ml; MerchantList ml;
ml.id = merchantid; ml.id = merchantid;
ml.item = atoul(row[0]); ml.item = atoul(row[0]);
@ -523,48 +548,65 @@ void Zone::LoadNewMerchantData(uint32 merchantid) {
void Zone::GetMerchantDataForZoneLoad() { void Zone::GetMerchantDataForZoneLoad() {
LogInfo("Loading Merchant Lists"); LogInfo("Loading Merchant Lists");
std::string query = StringFormat( std::string query = fmt::format(
"SELECT " SQL (
"DISTINCT ml.merchantid, " SELECT
"ml.slot, " DISTINCT merchantlist.merchantid,
"ml.item, " merchantlist.slot,
"ml.faction_required, " merchantlist.item,
"ml.level_required, " merchantlist.faction_required,
"ml.alt_currency_cost, " merchantlist.level_required,
"ml.classes_required, " merchantlist.alt_currency_cost,
"ml.probability " merchantlist.classes_required,
"FROM " merchantlist.probability
"merchantlist AS ml, " FROM
"npc_types AS nt, " merchantlist,
"spawnentry AS se, " npc_types,
"spawn2 AS s2 " spawnentry,
"WHERE nt.merchant_id = ml.merchantid AND nt.id = se.npcid " spawn2
"AND se.spawngroupid = s2.spawngroupid AND s2.zone = '%s' AND s2.version = %i " WHERE
"ORDER BY ml.slot ", GetShortName(), GetInstanceVersion()); npc_types.merchant_id = merchantlist.merchantid
AND npc_types.id = spawnentry.npcid
AND spawnentry.spawngroupid = spawn2.spawngroupid
AND spawn2.zone = '{}'
AND spawn2.version = {}
{}
ORDER BY
merchantlist.slot
),
GetShortName(),
GetInstanceVersion(),
ContentFilterCriteria::apply("merchantlist")
);
auto results = content_db.QueryDatabase(query); auto results = content_db.QueryDatabase(query);
std::map<uint32, std::list<MerchantList> >::iterator cur;
uint32 npcid = 0; std::map<uint32, std::list<MerchantList> >::iterator merchant_list;
uint32 npc_id = 0;
if (results.RowCount() == 0) { if (results.RowCount() == 0) {
LogDebug("No Merchant Data found for [{}]", GetShortName()); LogDebug("No Merchant Data found for [{}]", GetShortName());
return; return;
} }
for (auto row = results.begin(); row != results.end(); ++row) { for (auto row = results.begin(); row != results.end(); ++row) {
MerchantList ml; MerchantList merchant_list_entry{};
ml.id = atoul(row[0]); merchant_list_entry.id = atoul(row[0]);
if (npcid != ml.id) { if (npc_id != merchant_list_entry.id) {
cur = merchanttable.find(ml.id); merchant_list = merchanttable.find(merchant_list_entry.id);
if (cur == merchanttable.end()) { if (merchant_list == merchanttable.end()) {
std::list<MerchantList> empty; std::list<MerchantList> empty;
merchanttable[ml.id] = empty; merchanttable[merchant_list_entry.id] = empty;
cur = merchanttable.find(ml.id); merchant_list = merchanttable.find(merchant_list_entry.id);
}
npcid = ml.id;
} }
auto iter = cur->second.begin(); npc_id = merchant_list_entry.id;
}
auto iter = merchant_list->second.begin();
bool found = false; bool found = false;
while (iter != cur->second.end()) { while (iter != merchant_list->second.end()) {
if ((*iter).item == ml.id) { if ((*iter).item == merchant_list_entry.id) {
found = true; found = true;
break; break;
} }
@ -575,14 +617,15 @@ void Zone::GetMerchantDataForZoneLoad() {
continue; continue;
} }
ml.slot = atoul(row[1]); merchant_list_entry.slot = atoul(row[1]);
ml.item = atoul(row[2]); merchant_list_entry.item = atoul(row[2]);
ml.faction_required = atoul(row[3]); merchant_list_entry.faction_required = atoul(row[3]);
ml.level_required = atoul(row[4]); merchant_list_entry.level_required = atoul(row[4]);
ml.alt_currency_cost = atoul(row[5]); merchant_list_entry.alt_currency_cost = atoul(row[5]);
ml.classes_required = atoul(row[6]); merchant_list_entry.classes_required = atoul(row[6]);
ml.probability = atoul(row[7]); merchant_list_entry.probability = atoul(row[7]);
cur->second.push_back(ml);
merchant_list->second.push_back(merchant_list_entry);
} }
} }
@ -1798,16 +1841,22 @@ ZonePoint* Zone::GetClosestZonePointWithoutZone(float x, float y, float z, Clien
return closest_zp; return closest_zp;
} }
bool ZoneDatabase::LoadStaticZonePoints(LinkedList<ZonePoint*>* zone_point_list, const char* zonename, uint32 version) bool ZoneDatabase::LoadStaticZonePoints(LinkedList<ZonePoint *> *zone_point_list, const char *zonename, uint32 version)
{ {
zone_point_list->Clear(); zone_point_list->Clear();
zone->numzonepoints = 0; zone->numzonepoints = 0;
std::string query = StringFormat("SELECT x, y, z, target_x, target_y, "
std::string query = StringFormat(
"SELECT x, y, z, target_x, target_y, "
"target_z, target_zone_id, heading, target_heading, " "target_z, target_zone_id, heading, target_heading, "
"number, target_instance, client_version_mask " "number, target_instance, client_version_mask "
"FROM zone_points WHERE zone='%s' AND (version=%i OR version=-1) " "FROM zone_points WHERE zone='%s' AND (version=%i OR version=-1) %s"
"ORDER BY number", "ORDER BY number",
zonename, version); zonename,
version,
ContentFilterCriteria::apply().c_str()
);
auto results = QueryDatabase(query); auto results = QueryDatabase(query);
if (!results.Success()) { if (!results.Success()) {
return false; return false;

View File

@ -12,6 +12,7 @@
#include "zone.h" #include "zone.h"
#include "zonedb.h" #include "zonedb.h"
#include "aura.h" #include "aura.h"
#include "../common/repositories/criteria/content_filter_criteria.h"
#include <ctime> #include <ctime>
#include <iostream> #include <iostream>
@ -165,8 +166,11 @@ bool ZoneDatabase::GetZoneCFG(
"fast_regen_endurance, " // 59 "fast_regen_endurance, " // 59
"npc_max_aggro_dist, " // 60 "npc_max_aggro_dist, " // 60
"max_movement_update_range " // 61 "max_movement_update_range " // 61
"FROM zone WHERE zoneidnumber = %i AND version = %i", "FROM zone WHERE zoneidnumber = %i AND version = %i %s",
zoneid, instance_id); zoneid,
instance_id,
ContentFilterCriteria::apply().c_str()
);
auto results = QueryDatabase(query); auto results = QueryDatabase(query);
if (!results.Success()) { if (!results.Success()) {
strcpy(*map_filename, "default"); strcpy(*map_filename, "default");

View File

@ -35,6 +35,9 @@ extern QueryServ* QServ;
extern WorldServer worldserver; extern WorldServer worldserver;
extern Zone* zone; extern Zone* zone;
#include "../common/repositories/zone_repository.h"
#include "../common/content/world_content_service.h"
void Client::Handle_OP_ZoneChange(const EQApplicationPacket *app) { void Client::Handle_OP_ZoneChange(const EQApplicationPacket *app) {
#ifdef BOTS #ifdef BOTS
@ -284,6 +287,29 @@ void Client::Handle_OP_ZoneChange(const EQApplicationPacket *app) {
//TODO: ADVENTURE ENTRANCE CHECK //TODO: ADVENTURE ENTRANCE CHECK
/**
* Expansion check
*/
auto zones = ZoneRepository::GetWhere(
fmt::format(
"expansion <= {} AND short_name = '{}'",
(content_service.GetCurrentExpansion() + 1),
target_zone_name
)
);
LogInfo(
"Checking zone request [{}] for expansion [{}] ({}) success [{}]",
target_zone_name,
(content_service.GetCurrentExpansion() + 1),
Expansion::ExpansionName[content_service.GetCurrentExpansion()],
!zones.empty() ? "true" : "false"
);
if (zones.empty()) {
myerror = ZONE_ERROR_NOEXPANSION;
}
if(myerror == 1) { if(myerror == 1) {
//we have successfully zoned //we have successfully zoned
DoZoneSuccess(zc, target_zone_id, target_instance_id, dest_x, dest_y, dest_z, dest_h, ignorerestrictions); DoZoneSuccess(zc, target_zone_id, target_instance_id, dest_x, dest_y, dest_z, dest_h, ignorerestrictions);