diff --git a/common/database/database_update_manifest.cpp b/common/database/database_update_manifest.cpp index a61b39489..c30cfcb90 100644 --- a/common/database/database_update_manifest.cpp +++ b/common/database/database_update_manifest.cpp @@ -5162,7 +5162,19 @@ ALTER TABLE `tasks` ADD COLUMN `enabled` smallint NULL DEFAULT 1 AFTER `faction_amount` )", .content_schema_update = true - } + }, + ManifestEntry{ + .version = 9250, + .description = "2023_01_06_task_activities_list_group.sql", + .check = "SHOW COLUMNS FROM `task_activities` LIKE 'list_group'", + .condition = "empty", + .match = "", + .sql = R"( +ALTER TABLE `task_activities` + ADD COLUMN `list_group` TINYINT UNSIGNED NOT NULL DEFAULT '0' AFTER `optional`; +)", + .content_schema_update = true + }, // -- template; copy/paste this when you need to create a new entry // ManifestEntry{ diff --git a/common/repositories/base/base_task_activities_repository.h b/common/repositories/base/base_task_activities_repository.h index e0bb196a6..798a9d5ba 100644 --- a/common/repositories/base/base_task_activities_repository.h +++ b/common/repositories/base/base_task_activities_repository.h @@ -6,7 +6,7 @@ * Any modifications to base repositories are to be made by the generator only * * @generator ./utils/scripts/generators/repository-generator.pl - * @docs https://eqemu.gitbook.io/server/in-development/developer-area/repositories + * @docs https://docs.eqemu.io/developer/repositories */ #ifndef EQEMU_BASE_TASK_ACTIVITIES_REPOSITORY_H @@ -16,6 +16,7 @@ #include "../../strings.h" #include + class BaseTaskActivitiesRepository { public: struct TaskActivities { @@ -43,6 +44,7 @@ public: std::string zones; int32_t zone_version; int8_t optional; + uint8_t list_group; }; static std::string PrimaryKey() @@ -77,6 +79,7 @@ public: "zones", "zone_version", "optional", + "list_group", }; } @@ -107,6 +110,7 @@ public: "zones", "zone_version", "optional", + "list_group", }; } @@ -171,6 +175,7 @@ public: e.zones = ""; e.zone_version = -1; e.optional = 0; + e.list_group = 0; return e; } @@ -196,8 +201,9 @@ public: { auto results = db.QueryDatabase( fmt::format( - "{} WHERE id = {} LIMIT 1", + "{} WHERE {} = {} LIMIT 1", BaseSelect(), + PrimaryKey(), task_activities_id ) ); @@ -230,6 +236,7 @@ public: e.zones = row[21] ? row[21] : ""; e.zone_version = static_cast(atoi(row[22])); e.optional = static_cast(atoi(row[23])); + e.list_group = static_cast(strtoul(row[24], nullptr, 10)); return e; } @@ -287,6 +294,7 @@ public: v.push_back(columns[21] + " = '" + Strings::Escape(e.zones) + "'"); v.push_back(columns[22] + " = " + std::to_string(e.zone_version)); v.push_back(columns[23] + " = " + std::to_string(e.optional)); + v.push_back(columns[24] + " = " + std::to_string(e.list_group)); auto results = db.QueryDatabase( fmt::format( @@ -332,6 +340,7 @@ public: v.push_back("'" + Strings::Escape(e.zones) + "'"); v.push_back(std::to_string(e.zone_version)); v.push_back(std::to_string(e.optional)); + v.push_back(std::to_string(e.list_group)); auto results = db.QueryDatabase( fmt::format( @@ -385,6 +394,7 @@ public: v.push_back("'" + Strings::Escape(e.zones) + "'"); v.push_back(std::to_string(e.zone_version)); v.push_back(std::to_string(e.optional)); + v.push_back(std::to_string(e.list_group)); insert_chunks.push_back("(" + Strings::Implode(",", v) + ")"); } @@ -442,6 +452,7 @@ public: e.zones = row[21] ? row[21] : ""; e.zone_version = static_cast(atoi(row[22])); e.optional = static_cast(atoi(row[23])); + e.list_group = static_cast(strtoul(row[24], nullptr, 10)); all_entries.push_back(e); } @@ -490,6 +501,7 @@ public: e.zones = row[21] ? row[21] : ""; e.zone_version = static_cast(atoi(row[22])); e.optional = static_cast(atoi(row[23])); + e.list_group = static_cast(strtoul(row[24], nullptr, 10)); all_entries.push_back(e); } @@ -548,6 +560,110 @@ public: return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0); } + static std::string BaseReplace() + { + return fmt::format( + "REPLACE INTO {} ({}) ", + TableName(), + ColumnsRaw() + ); + } + + static int ReplaceOne( + Database& db, + const TaskActivities &e + ) + { + std::vector v; + + v.push_back(std::to_string(e.taskid)); + v.push_back(std::to_string(e.activityid)); + v.push_back(std::to_string(e.req_activity_id)); + v.push_back(std::to_string(e.step)); + v.push_back(std::to_string(e.activitytype)); + v.push_back("'" + Strings::Escape(e.target_name) + "'"); + v.push_back(std::to_string(e.goalmethod)); + v.push_back(std::to_string(e.goalcount)); + v.push_back("'" + Strings::Escape(e.description_override) + "'"); + v.push_back("'" + Strings::Escape(e.npc_match_list) + "'"); + v.push_back("'" + Strings::Escape(e.item_id_list) + "'"); + v.push_back("'" + Strings::Escape(e.item_list) + "'"); + v.push_back(std::to_string(e.dz_switch_id)); + v.push_back(std::to_string(e.min_x)); + v.push_back(std::to_string(e.min_y)); + v.push_back(std::to_string(e.min_z)); + v.push_back(std::to_string(e.max_x)); + v.push_back(std::to_string(e.max_y)); + v.push_back(std::to_string(e.max_z)); + v.push_back("'" + Strings::Escape(e.skill_list) + "'"); + v.push_back("'" + Strings::Escape(e.spell_list) + "'"); + v.push_back("'" + Strings::Escape(e.zones) + "'"); + v.push_back(std::to_string(e.zone_version)); + v.push_back(std::to_string(e.optional)); + v.push_back(std::to_string(e.list_group)); + + auto results = db.QueryDatabase( + fmt::format( + "{} VALUES ({})", + BaseReplace(), + Strings::Implode(",", v) + ) + ); + + return (results.Success() ? results.RowsAffected() : 0); + } + + static int ReplaceMany( + Database& db, + const std::vector &entries + ) + { + std::vector insert_chunks; + + for (auto &e: entries) { + std::vector v; + + v.push_back(std::to_string(e.taskid)); + v.push_back(std::to_string(e.activityid)); + v.push_back(std::to_string(e.req_activity_id)); + v.push_back(std::to_string(e.step)); + v.push_back(std::to_string(e.activitytype)); + v.push_back("'" + Strings::Escape(e.target_name) + "'"); + v.push_back(std::to_string(e.goalmethod)); + v.push_back(std::to_string(e.goalcount)); + v.push_back("'" + Strings::Escape(e.description_override) + "'"); + v.push_back("'" + Strings::Escape(e.npc_match_list) + "'"); + v.push_back("'" + Strings::Escape(e.item_id_list) + "'"); + v.push_back("'" + Strings::Escape(e.item_list) + "'"); + v.push_back(std::to_string(e.dz_switch_id)); + v.push_back(std::to_string(e.min_x)); + v.push_back(std::to_string(e.min_y)); + v.push_back(std::to_string(e.min_z)); + v.push_back(std::to_string(e.max_x)); + v.push_back(std::to_string(e.max_y)); + v.push_back(std::to_string(e.max_z)); + v.push_back("'" + Strings::Escape(e.skill_list) + "'"); + v.push_back("'" + Strings::Escape(e.spell_list) + "'"); + v.push_back("'" + Strings::Escape(e.zones) + "'"); + v.push_back(std::to_string(e.zone_version)); + v.push_back(std::to_string(e.optional)); + v.push_back(std::to_string(e.list_group)); + + insert_chunks.push_back("(" + Strings::Implode(",", v) + ")"); + } + + std::vector v; + + auto results = db.QueryDatabase( + fmt::format( + "{} VALUES {}", + BaseReplace(), + Strings::Implode(",", insert_chunks) + ) + ); + + return (results.Success() ? results.RowsAffected() : 0); + } }; #endif //EQEMU_BASE_TASK_ACTIVITIES_REPOSITORY_H diff --git a/common/tasks.h b/common/tasks.h index fc08ff225..dab3ff328 100644 --- a/common/tasks.h +++ b/common/tasks.h @@ -75,6 +75,7 @@ struct ActivityInformation { std::string zones; // IDs ; separated, ZoneID is the first in this list for older clients -- default empty string, max length 64 int zone_version; bool optional; + uint8_t list_group; // element group in window list (groups separated by dividers), valid values are 0-19 bool has_area; // non-database field inline bool CheckZone(int zone_id, int version) const diff --git a/common/version.h b/common/version.h index 445463ddf..70ee76876 100644 --- a/common/version.h +++ b/common/version.h @@ -42,7 +42,7 @@ * Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt */ -#define CURRENT_BINARY_DATABASE_VERSION 9249 +#define CURRENT_BINARY_DATABASE_VERSION 9250 #define CURRENT_BINARY_BOTS_DATABASE_VERSION 9041 diff --git a/zone/task_manager.cpp b/zone/task_manager.cpp index 477533b4c..dc20d122f 100644 --- a/zone/task_manager.cpp +++ b/zone/task_manager.cpp @@ -214,6 +214,8 @@ bool TaskManager::LoadTasks(int single_task) ad->max_y = a.max_y; ad->max_z = a.max_z; ad->zone_version = a.zone_version >= 0 ? a.zone_version : -1; + ad->optional = a.optional; + ad->list_group = a.list_group; ad->has_area = false; if (std::abs(a.max_x - a.min_x) > 0.0f && @@ -236,8 +238,6 @@ bool TaskManager::LoadTasks(int single_task) } } - ad->optional = a.optional; - LogTasksDetail( "(Activity) task_id [{}] activity_id [{}] slot [{}] activity_type [{}] goal_method [{}] goal_count [{}] zones [{}]" " target_name [{}] item_list [{}] skill_list [{}] spell_list [{}] description_override [{}]", @@ -950,7 +950,7 @@ void TaskManager::SendTaskActivityShort(Client *client, int task_id, int activit outapp->WriteUInt32(static_cast(task_data->type)); outapp->WriteUInt32(task_id); outapp->WriteUInt32(activity_id); - outapp->WriteUInt32(0); + outapp->WriteUInt32(task_data->activity_information[activity_id].list_group); outapp->WriteUInt32(0xffffffff); outapp->WriteUInt8(task_data->activity_information[activity_id].optional ? 1 : 0); client->QueuePacket(outapp.get()); @@ -972,7 +972,7 @@ void TaskManager::SendTaskActivityLong( buf.WriteUInt32(static_cast(task_data->type)); // task type buf.WriteUInt32(task_id); buf.WriteUInt32(activity_id); - buf.WriteUInt32(0); // unknown3 + buf.WriteUInt32(task_data->activity_information[activity_id].list_group); const auto& activity = task_data->activity_information[activity_id]; int done_count = client->GetTaskActivityDoneCount(task_data->type, client_task_index, activity_id);