mirror of
https://github.com/EQEmu/Server.git
synced 2026-05-31 04:56:20 +00:00
Compare commits
57 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b9b2bf0477 | |||
| 0b26c80d8f | |||
| 8497042eef | |||
| 1304b9c80f | |||
| 65c9c86556 | |||
| ece9251bd6 | |||
| 3cbd0fe0f6 | |||
| 8141f831b1 | |||
| b3a3d9bec5 | |||
| fa2b5166fb | |||
| 8dc25c838b | |||
| 229de34afc | |||
| 70bdd35b69 | |||
| e99354223d | |||
| 8a8e922f46 | |||
| c1484a698c | |||
| bd96d676be | |||
| 2a637a031b | |||
| f7c7f5646e | |||
| 577e67f4ee | |||
| 1084b71d8d | |||
| c2ab2a232b | |||
| c5f739cbda | |||
| 385732f403 | |||
| b972ec581f | |||
| 32e04cd264 | |||
| b0dff0c006 | |||
| c093b3e2ab | |||
| c5bf71f221 | |||
| 977c3ca3dc | |||
| 408ce4650f | |||
| bc0f705227 | |||
| 5c1ab3b24c | |||
| 85a858fcd6 | |||
| 6ab2e46f42 | |||
| 96acb1e638 | |||
| eb98eef1b9 | |||
| e1bb3301a5 | |||
| 358ce2ca94 | |||
| 6856d1540b | |||
| cd1306d52c | |||
| 20aa1cbe77 | |||
| dfd9a3c714 | |||
| c04bf79b0f | |||
| 7286e6a37f | |||
| a244cec9e8 | |||
| 7062e2703b | |||
| 5f53856fd4 | |||
| 17d63bc3f6 | |||
| 47fda0f747 | |||
| e2c15dbc9e | |||
| c089296538 | |||
| 94f09e5287 | |||
| 93133c289e | |||
| 8934235030 | |||
| ea0a54ed60 | |||
| 39544b4723 |
+12
-2
@@ -292,16 +292,17 @@ ADD_DEFINITIONS(-DGLM_ENABLE_EXPERIMENTAL)
|
|||||||
#Find everything we need
|
#Find everything we need
|
||||||
FIND_PACKAGE(ZLIB REQUIRED)
|
FIND_PACKAGE(ZLIB REQUIRED)
|
||||||
FIND_PACKAGE(MySQL REQUIRED)
|
FIND_PACKAGE(MySQL REQUIRED)
|
||||||
|
FIND_PACKAGE(Protobuf REQUIRED)
|
||||||
IF(EQEMU_BUILD_PERL)
|
IF(EQEMU_BUILD_PERL)
|
||||||
FIND_PACKAGE(PerlLibs REQUIRED)
|
FIND_PACKAGE(PerlLibs REQUIRED)
|
||||||
INCLUDE_DIRECTORIES(SYSTEM "${PERL_INCLUDE_PATH}")
|
INCLUDE_DIRECTORIES(SYSTEM "${PERL_INCLUDE_PATH}")
|
||||||
ENDIF(EQEMU_BUILD_PERL)
|
ENDIF(EQEMU_BUILD_PERL)
|
||||||
|
|
||||||
SET(SERVER_LIBS common debug ${MySQL_LIBRARY_DEBUG} optimized ${MySQL_LIBRARY_RELEASE} ${ZLIB_LIBRARY} libuv fmt recast_navigation)
|
SET(SERVER_LIBS common debug ${MySQL_LIBRARY_DEBUG} optimized ${MySQL_LIBRARY_RELEASE} ${ZLIB_LIBRARY} protobuf::libprotoc protobuf::libprotobuf libuv fmt recast_navigation)
|
||||||
|
|
||||||
FIND_PACKAGE(Sodium REQUIRED)
|
FIND_PACKAGE(Sodium REQUIRED)
|
||||||
IF(SODIUM_FOUND)
|
IF(SODIUM_FOUND)
|
||||||
OPTION(EQEMU_ENABLE_SECURITY "Use Encryption For TCP Connections" ON)
|
OPTION(EQEMU_ENABLE_SECURITY "Use Secure Loginserver Hashes" ON)
|
||||||
IF(EQEMU_ENABLE_SECURITY)
|
IF(EQEMU_ENABLE_SECURITY)
|
||||||
INCLUDE_DIRECTORIES(SYSTEM "${SODIUM_INCLUDE_DIRS}")
|
INCLUDE_DIRECTORIES(SYSTEM "${SODIUM_INCLUDE_DIRS}")
|
||||||
ADD_DEFINITIONS(-DENABLE_SECURITY)
|
ADD_DEFINITIONS(-DENABLE_SECURITY)
|
||||||
@@ -340,6 +341,7 @@ ENDIF(EQEMU_BUILD_LUA)
|
|||||||
|
|
||||||
INCLUDE_DIRECTORIES(SYSTEM "${ZLIB_INCLUDE_DIRS}")
|
INCLUDE_DIRECTORIES(SYSTEM "${ZLIB_INCLUDE_DIRS}")
|
||||||
INCLUDE_DIRECTORIES(SYSTEM "${MySQL_INCLUDE_DIR}")
|
INCLUDE_DIRECTORIES(SYSTEM "${MySQL_INCLUDE_DIR}")
|
||||||
|
INCLUDE_DIRECTORIES(SYSTEM "${Protobuf_INCLUDE_DIRS}")
|
||||||
INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/common/glm")
|
INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/common/glm")
|
||||||
INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/libs/cereal")
|
INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/libs/cereal")
|
||||||
INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/libs/libuv/include" )
|
INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/libs/libuv/include" )
|
||||||
@@ -347,6 +349,13 @@ INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/libs/libuv/src")
|
|||||||
INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/libs/format")
|
INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/libs/format")
|
||||||
INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/libs/recast/detour/include")
|
INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/libs/recast/detour/include")
|
||||||
INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/libs/recast/recast/include")
|
INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/libs/recast/recast/include")
|
||||||
|
INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_BINARY_DIR}/common")
|
||||||
|
|
||||||
|
IF(VCPKG_TARGET_TRIPLET)
|
||||||
|
MESSAGE(STATUS "Vcpkg Detected")
|
||||||
|
MESSAGE(STATUS "Setting protobuf import dir: ${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/include")
|
||||||
|
SET(Protobuf_IMPORT_DIRS "${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/include")
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
IF(EQEMU_BUILD_SERVER OR EQEMU_BUILD_LOGIN OR EQEMU_BUILD_TESTS OR EQEMU_BUILD_HC)
|
IF(EQEMU_BUILD_SERVER OR EQEMU_BUILD_LOGIN OR EQEMU_BUILD_TESTS OR EQEMU_BUILD_HC)
|
||||||
ADD_SUBDIRECTORY(common)
|
ADD_SUBDIRECTORY(common)
|
||||||
@@ -359,6 +368,7 @@ IF(EQEMU_BUILD_SERVER)
|
|||||||
ADD_SUBDIRECTORY(ucs)
|
ADD_SUBDIRECTORY(ucs)
|
||||||
ADD_SUBDIRECTORY(queryserv)
|
ADD_SUBDIRECTORY(queryserv)
|
||||||
ADD_SUBDIRECTORY(eqlaunch)
|
ADD_SUBDIRECTORY(eqlaunch)
|
||||||
|
ADD_SUBDIRECTORY(services/tasks)
|
||||||
ENDIF(EQEMU_BUILD_SERVER)
|
ENDIF(EQEMU_BUILD_SERVER)
|
||||||
IF(EQEMU_BUILD_LOGIN)
|
IF(EQEMU_BUILD_LOGIN)
|
||||||
ADD_SUBDIRECTORY(loginserver)
|
ADD_SUBDIRECTORY(loginserver)
|
||||||
|
|||||||
+12
-2
@@ -54,6 +54,7 @@ SET(common_sources
|
|||||||
packet_functions.cpp
|
packet_functions.cpp
|
||||||
perl_eqdb.cpp
|
perl_eqdb.cpp
|
||||||
perl_eqdb_res.cpp
|
perl_eqdb_res.cpp
|
||||||
|
platform.cpp
|
||||||
proc_launcher.cpp
|
proc_launcher.cpp
|
||||||
profanity_manager.cpp
|
profanity_manager.cpp
|
||||||
ptimer.cpp
|
ptimer.cpp
|
||||||
@@ -63,6 +64,7 @@ SET(common_sources
|
|||||||
say_link.cpp
|
say_link.cpp
|
||||||
serialize_buffer.cpp
|
serialize_buffer.cpp
|
||||||
serverinfo.cpp
|
serverinfo.cpp
|
||||||
|
service.cpp
|
||||||
shareddb.cpp
|
shareddb.cpp
|
||||||
skills.cpp
|
skills.cpp
|
||||||
spdat.cpp
|
spdat.cpp
|
||||||
@@ -71,8 +73,8 @@ SET(common_sources
|
|||||||
textures.cpp
|
textures.cpp
|
||||||
timer.cpp
|
timer.cpp
|
||||||
unix.cpp
|
unix.cpp
|
||||||
|
world_connection.cpp
|
||||||
xml_parser.cpp
|
xml_parser.cpp
|
||||||
platform.cpp
|
|
||||||
json/jsoncpp.cpp
|
json/jsoncpp.cpp
|
||||||
net/console_server.cpp
|
net/console_server.cpp
|
||||||
net/console_server_connection.cpp
|
net/console_server_connection.cpp
|
||||||
@@ -151,6 +153,7 @@ SET(common_headers
|
|||||||
fixed_memory_hash_set.h
|
fixed_memory_hash_set.h
|
||||||
fixed_memory_variable_hash_set.h
|
fixed_memory_variable_hash_set.h
|
||||||
global_define.h
|
global_define.h
|
||||||
|
global_tasks.h
|
||||||
guild_base.h
|
guild_base.h
|
||||||
guilds.h
|
guilds.h
|
||||||
inventory_profile.h
|
inventory_profile.h
|
||||||
@@ -195,6 +198,7 @@ SET(common_headers
|
|||||||
serialize_buffer.h
|
serialize_buffer.h
|
||||||
serverinfo.h
|
serverinfo.h
|
||||||
servertalk.h
|
servertalk.h
|
||||||
|
service.h
|
||||||
shareddb.h
|
shareddb.h
|
||||||
skills.h
|
skills.h
|
||||||
spdat.h
|
spdat.h
|
||||||
@@ -206,6 +210,7 @@ SET(common_headers
|
|||||||
unix.h
|
unix.h
|
||||||
useperl.h
|
useperl.h
|
||||||
version.h
|
version.h
|
||||||
|
world_connection.h
|
||||||
xml_parser.h
|
xml_parser.h
|
||||||
zone_numbers.h
|
zone_numbers.h
|
||||||
event/event_loop.h
|
event/event_loop.h
|
||||||
@@ -378,7 +383,12 @@ SOURCE_GROUP(Util FILES
|
|||||||
|
|
||||||
INCLUDE_DIRECTORIES(Patches SocketLib StackWalker TinyXML)
|
INCLUDE_DIRECTORIES(Patches SocketLib StackWalker TinyXML)
|
||||||
|
|
||||||
ADD_LIBRARY(common ${common_sources} ${common_headers})
|
protobuf_generate_cpp(PROTO_TASK_SRCS PROTO_TASK_HDRS "${CMAKE_CURRENT_SOURCE_DIR}/proto/task.proto")
|
||||||
|
|
||||||
|
ADD_LIBRARY(common
|
||||||
|
${common_sources} ${common_headers}
|
||||||
|
${PROTO_TASK_SRCS} ${PROTO_TASK_HDRS}
|
||||||
|
)
|
||||||
|
|
||||||
IF(UNIX)
|
IF(UNIX)
|
||||||
SET_SOURCE_FILES_PROPERTIES("SocketLib/Mime.cpp" PROPERTY COMPILE_FLAGS -Wno-unused-result)
|
SET_SOURCE_FILES_PROPERTIES("SocketLib/Mime.cpp" PROPERTY COMPILE_FLAGS -Wno-unused-result)
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ N(OP_0x0347),
|
|||||||
N(OP_AAAction),
|
N(OP_AAAction),
|
||||||
N(OP_AAExpUpdate),
|
N(OP_AAExpUpdate),
|
||||||
N(OP_AcceptNewTask),
|
N(OP_AcceptNewTask),
|
||||||
|
N(OP_AcceptNewSharedTask),
|
||||||
N(OP_AckPacket),
|
N(OP_AckPacket),
|
||||||
N(OP_Action),
|
N(OP_Action),
|
||||||
N(OP_Action2),
|
N(OP_Action2),
|
||||||
@@ -461,6 +462,7 @@ N(OP_SetServerFilter),
|
|||||||
N(OP_SetStartCity),
|
N(OP_SetStartCity),
|
||||||
N(OP_SetTitle),
|
N(OP_SetTitle),
|
||||||
N(OP_SetTitleReply),
|
N(OP_SetTitleReply),
|
||||||
|
N(OP_SharedTaskMemberList),
|
||||||
N(OP_Shielding),
|
N(OP_Shielding),
|
||||||
N(OP_ShopDelItem),
|
N(OP_ShopDelItem),
|
||||||
N(OP_ShopEnd),
|
N(OP_ShopEnd),
|
||||||
|
|||||||
@@ -3698,6 +3698,7 @@ struct TaskMemberList_Struct {
|
|||||||
/*12*/ char list_pointer[0];
|
/*12*/ char list_pointer[0];
|
||||||
/* list is of the form:
|
/* list is of the form:
|
||||||
char member_name[1] //null terminated string
|
char member_name[1] //null terminated string
|
||||||
|
uint32 monster_mission; // class chosen
|
||||||
uint8 task_leader //boolean flag
|
uint8 task_leader //boolean flag
|
||||||
*/
|
*/
|
||||||
};
|
};
|
||||||
@@ -3799,6 +3800,14 @@ struct AcceptNewTask_Struct {
|
|||||||
uint32 task_master_id; //entity ID
|
uint32 task_master_id; //entity ID
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct AcceptNewSharedTask_Struct {
|
||||||
|
uint32 unknown00;
|
||||||
|
uint32 unknown04;
|
||||||
|
uint32 task_master_id;
|
||||||
|
uint32 task_id;
|
||||||
|
float unknown16;
|
||||||
|
};
|
||||||
|
|
||||||
//was all 0's from client, server replied with same op, all 0's
|
//was all 0's from client, server replied with same op, all 0's
|
||||||
struct CancelTask_Struct {
|
struct CancelTask_Struct {
|
||||||
uint32 SequenceNumber;
|
uint32 SequenceNumber;
|
||||||
|
|||||||
@@ -0,0 +1,170 @@
|
|||||||
|
/* EQEMu: Everquest Server Emulator
|
||||||
|
Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; version 2 of the License.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||||
|
are required to give you total support for your newly bought product;
|
||||||
|
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
#ifndef GLOBAL_TASKS_H
|
||||||
|
#define GLOBAL_TASKS_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
/* This file contains what is needed for both zone and world managers
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define MAXTASKS 10000
|
||||||
|
#define MAXTASKSETS 1000
|
||||||
|
// The Client has a hard cap of 19 active quests, 29 in SoD+
|
||||||
|
#define MAXACTIVEQUESTS 19
|
||||||
|
// The Max Chooser (Task Selector entries) is capped at 40 in the Titanium Client.
|
||||||
|
#define MAXCHOOSERENTRIES 40
|
||||||
|
// The Client has a hard cap of 20 activities per task.
|
||||||
|
#define MAXACTIVITIESPERTASK 20
|
||||||
|
// This is used to determine if a client's active task slot is empty.
|
||||||
|
#define TASKSLOTEMPTY 0
|
||||||
|
|
||||||
|
// Command Codes for worldserver ServerOP_ReloadTasks
|
||||||
|
#define RELOADTASKS 0
|
||||||
|
#define RELOADTASKGOALLISTS 1
|
||||||
|
#define RELOADTASKPROXIMITIES 2
|
||||||
|
#define RELOADTASKSETS 3
|
||||||
|
|
||||||
|
// used for timer lockouts and /tasktimers
|
||||||
|
struct TaskTimer {
|
||||||
|
int ID; // ID used in task timer (replay group)
|
||||||
|
int original_id; // original ID of the task (book keeping)
|
||||||
|
int expires; // UNIX timestamp of when it expires, what happens with DLS? Fuck it.
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef enum { METHODSINGLEID = 0, METHODLIST = 1, METHODQUEST = 2 } TaskMethodType;
|
||||||
|
|
||||||
|
struct ActivityInformation {
|
||||||
|
int StepNumber;
|
||||||
|
int Type;
|
||||||
|
std::string target_name; // name mob, location -- default empty
|
||||||
|
std::string item_list; // likely defaults to empty
|
||||||
|
std::string skill_list; // IDs ; separated -- default -1
|
||||||
|
std::string spell_list; // IDs ; separated -- default 0
|
||||||
|
std::string desc_override; // overrides auto generated description -- default empty
|
||||||
|
int skill_id; // older clients, first id from above
|
||||||
|
int spell_id; // older clients, first id from above
|
||||||
|
int GoalID;
|
||||||
|
TaskMethodType GoalMethod;
|
||||||
|
int GoalCount;
|
||||||
|
int DeliverToNPC;
|
||||||
|
std::vector<int> ZoneIDs;
|
||||||
|
std::string zones; // IDs ; searated, ZoneID is the first in this list for older clients -- default empty string
|
||||||
|
bool Optional;
|
||||||
|
|
||||||
|
inline bool CheckZone(int zone_id) {
|
||||||
|
if (ZoneIDs.empty())
|
||||||
|
return true;
|
||||||
|
return std::find(ZoneIDs.begin(), ZoneIDs.end(), zone_id) != ZoneIDs.end();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef enum { ActivitiesSequential = 0, ActivitiesStepped = 1 } SequenceType;
|
||||||
|
|
||||||
|
enum class TaskType {
|
||||||
|
Task = 0, // can have at max 1
|
||||||
|
Shared = 1, // can have at max 1
|
||||||
|
Quest = 2, // can have at max 19 or 29 depending on client
|
||||||
|
E = 3 // can have at max 19 or 29 depending on client, not present in live anymore
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class DurationCode {
|
||||||
|
None = 0,
|
||||||
|
Short = 1,
|
||||||
|
Medium = 2,
|
||||||
|
Long = 3
|
||||||
|
};
|
||||||
|
|
||||||
|
// need to capture more, shared are just Radiant/Ebon though
|
||||||
|
enum class PointType {
|
||||||
|
None = 0,
|
||||||
|
Radiant = 4,
|
||||||
|
Ebon = 5,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TaskInformation {
|
||||||
|
TaskType type;
|
||||||
|
int Duration;
|
||||||
|
DurationCode dur_code; // description for time investment for when Duration == 0
|
||||||
|
std::string Title; // max length 64
|
||||||
|
std::string Description; // max length 4000, 2048 on Tit
|
||||||
|
std::string Reward;
|
||||||
|
std::string item_link; // max length 128 older clients, item link gets own string
|
||||||
|
std::string completion_emote; // emote after completing task, yellow. Maybe should make more generic ... but yellow for now!
|
||||||
|
int RewardID;
|
||||||
|
int CashReward; // Expressed in copper
|
||||||
|
int XPReward;
|
||||||
|
int faction_reward; // just a npc_faction_id
|
||||||
|
TaskMethodType RewardMethod;
|
||||||
|
int reward_points; // DoN crystals for shared. Generic "points" for non-shared
|
||||||
|
PointType reward_type; // 4 for Radiant Crystals else Ebon crystals when shared task
|
||||||
|
int ActivityCount;
|
||||||
|
SequenceType SequenceMode;
|
||||||
|
int LastStep;
|
||||||
|
short MinLevel;
|
||||||
|
short MaxLevel;
|
||||||
|
bool Repeatable;
|
||||||
|
int replay_group; // ID of our replay timer group (0 means none)
|
||||||
|
int min_players; // shared tasks
|
||||||
|
int max_players;
|
||||||
|
int task_lock_step; // task locks after this step is completed
|
||||||
|
uint32 instance_zone_id; // instance shit
|
||||||
|
uint32 zone_version;
|
||||||
|
uint16 zone_in_zone_id;
|
||||||
|
float zone_in_x;
|
||||||
|
float zone_in_y;
|
||||||
|
uint16 zone_in_object_id;
|
||||||
|
float dest_x;
|
||||||
|
float dest_y;
|
||||||
|
float dest_z;
|
||||||
|
float dest_h;
|
||||||
|
/* int graveyard_zone_id;
|
||||||
|
float graveyard_x;
|
||||||
|
float graveyard_y;
|
||||||
|
float graveyard_z;
|
||||||
|
float graveyard_radius; */
|
||||||
|
ActivityInformation Activity[MAXACTIVITIESPERTASK];
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef enum { ActivityHidden = 0, ActivityActive = 1, ActivityCompleted = 2 } ActivityState;
|
||||||
|
|
||||||
|
typedef enum { ActivityDeliver = 1, ActivityKill = 2, ActivityLoot = 3, ActivitySpeakWith = 4, ActivityExplore = 5,
|
||||||
|
ActivityTradeSkill = 6, ActivityFish = 7, ActivityForage = 8, ActivityCastOn = 9, ActivitySkillOn = 10,
|
||||||
|
ActivityTouch = 11, ActivityCollect = 13, ActivityGiveCash = 100 } ActivityType;
|
||||||
|
|
||||||
|
struct ClientActivityInformation {
|
||||||
|
int ActivityID;
|
||||||
|
int DoneCount;
|
||||||
|
ActivityState State;
|
||||||
|
bool Updated; // Flag so we know if we need to update the database
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ClientTaskInformation {
|
||||||
|
int slot; // intrusive, but makes things easier :P
|
||||||
|
int TaskID;
|
||||||
|
int CurrentStep;
|
||||||
|
int AcceptedTime;
|
||||||
|
bool Updated;
|
||||||
|
ClientActivityInformation Activity[MAXACTIVITIESPERTASK];
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* !GLOBAL_TASKS_H */
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
#include "endian.h"
|
#include "endian.h"
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
|
#include <google/protobuf/message.h>
|
||||||
|
|
||||||
void EQ::Net::Packet::PutInt8(size_t offset, int8_t value)
|
void EQ::Net::Packet::PutInt8(size_t offset, int8_t value)
|
||||||
{
|
{
|
||||||
@@ -167,6 +168,23 @@ void EQ::Net::Packet::PutData(size_t offset, void *data, size_t length)
|
|||||||
memcpy(((char*)Data() + offset), data, length);
|
memcpy(((char*)Data() + offset), data, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EQ::Net::Packet::PutProtobuf(size_t offset, const google::protobuf::Message *msg)
|
||||||
|
{
|
||||||
|
auto length = msg->ByteSizeLong();
|
||||||
|
|
||||||
|
if (length == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Length() < offset + length) {
|
||||||
|
if (!Resize(offset + length)) {
|
||||||
|
throw std::out_of_range("Packet::PutProtobuf(), could not resize packet and would of written past the end.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
msg->SerializeToArray((void*)((char*)Data() + offset), (int)length);
|
||||||
|
}
|
||||||
|
|
||||||
int8_t EQ::Net::Packet::GetInt8(size_t offset) const
|
int8_t EQ::Net::Packet::GetInt8(size_t offset) const
|
||||||
{
|
{
|
||||||
if (Length() < offset + 1) {
|
if (Length() < offset + 1) {
|
||||||
@@ -276,6 +294,11 @@ std::string EQ::Net::Packet::GetCString(size_t offset) const
|
|||||||
return std::string(str);
|
return std::string(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EQ::Net::StaticPacket EQ::Net::Packet::GetPacket(size_t offset, size_t length) const
|
||||||
|
{
|
||||||
|
return EQ::Net::StaticPacket((char*)Data() + offset, length);
|
||||||
|
}
|
||||||
|
|
||||||
char ToSafePrint(unsigned char in) {
|
char ToSafePrint(unsigned char in) {
|
||||||
if (std::isprint(in)) {
|
if (std::isprint(in)) {
|
||||||
return in;
|
return in;
|
||||||
|
|||||||
@@ -8,8 +8,17 @@
|
|||||||
#include <cereal/cereal.hpp>
|
#include <cereal/cereal.hpp>
|
||||||
#include <cereal/archives/binary.hpp>
|
#include <cereal/archives/binary.hpp>
|
||||||
|
|
||||||
|
namespace google
|
||||||
|
{
|
||||||
|
namespace protobuf
|
||||||
|
{
|
||||||
|
class Message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace EQ {
|
namespace EQ {
|
||||||
namespace Net {
|
namespace Net {
|
||||||
|
class StaticPacket;
|
||||||
class Packet
|
class Packet
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -64,6 +73,7 @@ namespace EQ {
|
|||||||
void PutCString(size_t offset, const char *str);
|
void PutCString(size_t offset, const char *str);
|
||||||
void PutPacket(size_t offset, const Packet &p);
|
void PutPacket(size_t offset, const Packet &p);
|
||||||
void PutData(size_t offset, void *data, size_t length);
|
void PutData(size_t offset, void *data, size_t length);
|
||||||
|
void PutProtobuf(size_t offset, const google::protobuf::Message *msg);
|
||||||
|
|
||||||
int8_t GetInt8(size_t offset) const;
|
int8_t GetInt8(size_t offset) const;
|
||||||
int16_t GetInt16(size_t offset) const;
|
int16_t GetInt16(size_t offset) const;
|
||||||
@@ -77,6 +87,8 @@ namespace EQ {
|
|||||||
double GetDouble(size_t offset) const;
|
double GetDouble(size_t offset) const;
|
||||||
std::string GetString(size_t offset, size_t length) const;
|
std::string GetString(size_t offset, size_t length) const;
|
||||||
std::string GetCString(size_t offset) const;
|
std::string GetCString(size_t offset) const;
|
||||||
|
StaticPacket GetPacket(size_t offset, size_t length) const;
|
||||||
|
google::protobuf::Message* GetProtobuf(size_t offset);
|
||||||
|
|
||||||
std::string ToString() const;
|
std::string ToString() const;
|
||||||
std::string ToString(size_t line_length) const;
|
std::string ToString(size_t line_length) const;
|
||||||
|
|||||||
@@ -19,34 +19,12 @@ EQ::Net::ServertalkClient::~ServertalkClient()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void EQ::Net::ServertalkClient::Send(uint16_t opcode, EQ::Net::Packet &p)
|
void EQ::Net::ServertalkClient::Send(uint16_t opcode, const EQ::Net::Packet &p)
|
||||||
{
|
{
|
||||||
EQ::Net::DynamicPacket out;
|
EQ::Net::DynamicPacket out;
|
||||||
#ifdef ENABLE_SECURITY
|
|
||||||
if (m_encrypted) {
|
|
||||||
if (p.Length() == 0) {
|
|
||||||
p.PutUInt8(0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
out.PutUInt32(0, p.Length() + crypto_secretbox_MACBYTES);
|
|
||||||
out.PutUInt16(4, opcode);
|
|
||||||
|
|
||||||
std::unique_ptr<unsigned char[]> cipher(new unsigned char[p.Length() + crypto_secretbox_MACBYTES]);
|
|
||||||
|
|
||||||
crypto_box_easy_afternm(&cipher[0], (unsigned char*)p.Data(), p.Length(), m_nonce_ours, m_shared_key);
|
|
||||||
(*(uint64_t*)&m_nonce_ours[0])++;
|
|
||||||
out.PutData(6, &cipher[0], p.Length() + crypto_secretbox_MACBYTES);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
out.PutUInt32(0, p.Length());
|
out.PutUInt32(0, p.Length());
|
||||||
out.PutUInt16(4, opcode);
|
out.PutUInt16(4, opcode);
|
||||||
out.PutPacket(6, p);
|
out.PutPacket(6, p);
|
||||||
}
|
|
||||||
#else
|
|
||||||
out.PutUInt32(0, p.Length());
|
|
||||||
out.PutUInt16(4, opcode);
|
|
||||||
out.PutPacket(6, p);
|
|
||||||
#endif
|
|
||||||
InternalSend(ServertalkMessage, out);
|
InternalSend(ServertalkMessage, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -188,51 +166,6 @@ void EQ::Net::ServertalkClient::ProcessReadBuffer()
|
|||||||
|
|
||||||
void EQ::Net::ServertalkClient::ProcessHello(EQ::Net::Packet &p)
|
void EQ::Net::ServertalkClient::ProcessHello(EQ::Net::Packet &p)
|
||||||
{
|
{
|
||||||
#ifdef ENABLE_SECURITY
|
|
||||||
memset(m_public_key_ours, 0, crypto_box_PUBLICKEYBYTES);
|
|
||||||
memset(m_public_key_theirs, 0, crypto_box_PUBLICKEYBYTES);
|
|
||||||
memset(m_private_key_ours, 0, crypto_box_SECRETKEYBYTES);
|
|
||||||
memset(m_nonce_ours, 0, crypto_box_NONCEBYTES);
|
|
||||||
memset(m_nonce_theirs, 0, crypto_box_NONCEBYTES);
|
|
||||||
memset(m_shared_key, 0, crypto_box_BEFORENMBYTES);
|
|
||||||
m_encrypted = false;
|
|
||||||
|
|
||||||
try {
|
|
||||||
bool enc = p.GetInt8(0) == 1 ? true : false;
|
|
||||||
|
|
||||||
if (enc) {
|
|
||||||
if (p.Length() == (1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES)) {
|
|
||||||
memcpy(m_public_key_theirs, (char*)p.Data() + 1, crypto_box_PUBLICKEYBYTES);
|
|
||||||
memcpy(m_nonce_theirs, (char*)p.Data() + 1 + crypto_box_PUBLICKEYBYTES, crypto_box_NONCEBYTES);
|
|
||||||
m_encrypted = true;
|
|
||||||
|
|
||||||
SendHandshake();
|
|
||||||
|
|
||||||
if (m_on_connect_cb) {
|
|
||||||
m_on_connect_cb(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
LogF(Logs::General, Logs::Error, "Could not process hello, size != {0}", 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
SendHandshake();
|
|
||||||
|
|
||||||
if (m_on_connect_cb) {
|
|
||||||
m_on_connect_cb(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (std::exception &ex) {
|
|
||||||
LogF(Logs::General, Logs::Error, "Error parsing hello from server: {0}", ex.what());
|
|
||||||
m_connection->Disconnect();
|
|
||||||
|
|
||||||
if (m_on_connect_cb) {
|
|
||||||
m_on_connect_cb(nullptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
try {
|
try {
|
||||||
bool enc = p.GetInt8(0) == 1 ? true : false;
|
bool enc = p.GetInt8(0) == 1 ? true : false;
|
||||||
|
|
||||||
@@ -259,7 +192,6 @@ void EQ::Net::ServertalkClient::ProcessHello(EQ::Net::Packet &p)
|
|||||||
m_on_connect_cb(nullptr);
|
m_on_connect_cb(nullptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EQ::Net::ServertalkClient::ProcessMessage(EQ::Net::Packet &p)
|
void EQ::Net::ServertalkClient::ProcessMessage(EQ::Net::Packet &p)
|
||||||
@@ -269,31 +201,6 @@ void EQ::Net::ServertalkClient::ProcessMessage(EQ::Net::Packet &p)
|
|||||||
auto opcode = p.GetUInt16(4);
|
auto opcode = p.GetUInt16(4);
|
||||||
if (length > 0) {
|
if (length > 0) {
|
||||||
auto data = p.GetString(6, length);
|
auto data = p.GetString(6, length);
|
||||||
#ifdef ENABLE_SECURITY
|
|
||||||
if (m_encrypted) {
|
|
||||||
size_t message_len = length - crypto_secretbox_MACBYTES;
|
|
||||||
std::unique_ptr<unsigned char[]> decrypted_text(new unsigned char[message_len]);
|
|
||||||
if (crypto_box_open_easy_afternm(&decrypted_text[0], (unsigned char*)&data[0], length, m_nonce_theirs, m_shared_key))
|
|
||||||
{
|
|
||||||
LogF(Logs::General, Logs::Error, "Error decrypting message from server");
|
|
||||||
(*(uint64_t*)&m_nonce_theirs[0])++;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
EQ::Net::StaticPacket decrypted_packet(&decrypted_text[0], message_len);
|
|
||||||
|
|
||||||
(*(uint64_t*)&m_nonce_theirs[0])++;
|
|
||||||
|
|
||||||
auto cb = m_message_callbacks.find(opcode);
|
|
||||||
if (cb != m_message_callbacks.end()) {
|
|
||||||
cb->second(opcode, decrypted_packet);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_message_callback) {
|
|
||||||
m_message_callback(opcode, decrypted_packet);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
size_t message_len = length;
|
size_t message_len = length;
|
||||||
EQ::Net::StaticPacket packet(&data[0], message_len);
|
EQ::Net::StaticPacket packet(&data[0], message_len);
|
||||||
|
|
||||||
@@ -306,21 +213,6 @@ void EQ::Net::ServertalkClient::ProcessMessage(EQ::Net::Packet &p)
|
|||||||
m_message_callback(opcode, packet);
|
m_message_callback(opcode, packet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
|
||||||
size_t message_len = length;
|
|
||||||
EQ::Net::StaticPacket packet(&data[0], message_len);
|
|
||||||
|
|
||||||
auto cb = m_message_callbacks.find(opcode);
|
|
||||||
if (cb != m_message_callbacks.end()) {
|
|
||||||
cb->second(opcode, packet);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_message_callback) {
|
|
||||||
m_message_callback(opcode, packet);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (std::exception &ex) {
|
catch (std::exception &ex) {
|
||||||
LogF(Logs::General, Logs::Error, "Error parsing message from server: {0}", ex.what());
|
LogF(Logs::General, Logs::Error, "Error parsing message from server: {0}", ex.what());
|
||||||
@@ -330,46 +222,9 @@ void EQ::Net::ServertalkClient::ProcessMessage(EQ::Net::Packet &p)
|
|||||||
void EQ::Net::ServertalkClient::SendHandshake(bool downgrade)
|
void EQ::Net::ServertalkClient::SendHandshake(bool downgrade)
|
||||||
{
|
{
|
||||||
EQ::Net::DynamicPacket handshake;
|
EQ::Net::DynamicPacket handshake;
|
||||||
#ifdef ENABLE_SECURITY
|
|
||||||
if (m_encrypted) {
|
|
||||||
crypto_box_keypair(m_public_key_ours, m_private_key_ours);
|
|
||||||
randombytes_buf(m_nonce_ours, crypto_box_NONCEBYTES);
|
|
||||||
|
|
||||||
crypto_box_beforenm(m_shared_key, m_public_key_theirs, m_private_key_ours);
|
|
||||||
|
|
||||||
handshake.PutData(0, m_public_key_ours, crypto_box_PUBLICKEYBYTES);
|
|
||||||
handshake.PutData(crypto_box_PUBLICKEYBYTES, m_nonce_ours, crypto_box_NONCEBYTES);
|
|
||||||
|
|
||||||
memset(m_public_key_ours, 0, crypto_box_PUBLICKEYBYTES);
|
|
||||||
memset(m_public_key_theirs, 0, crypto_box_PUBLICKEYBYTES);
|
|
||||||
memset(m_private_key_ours, 0, crypto_box_SECRETKEYBYTES);
|
|
||||||
|
|
||||||
size_t cipher_length = m_identifier.length() + 1 + m_credentials.length() + 1 + crypto_secretbox_MACBYTES;
|
|
||||||
size_t data_length = m_identifier.length() + 1 + m_credentials.length() + 1;
|
|
||||||
|
|
||||||
std::unique_ptr<unsigned char[]> signed_buffer(new unsigned char[cipher_length]);
|
|
||||||
std::unique_ptr<unsigned char[]> data_buffer(new unsigned char[data_length]);
|
|
||||||
|
|
||||||
memset(&data_buffer[0], 0, data_length);
|
|
||||||
memcpy(&data_buffer[0], m_identifier.c_str(), m_identifier.length());
|
|
||||||
memcpy(&data_buffer[1 + m_identifier.length()], m_credentials.c_str(), m_credentials.length());
|
|
||||||
|
|
||||||
crypto_box_easy_afternm(&signed_buffer[0], &data_buffer[0], data_length, m_nonce_ours, m_shared_key);
|
|
||||||
|
|
||||||
(*(uint64_t*)&m_nonce_ours[0])++;
|
|
||||||
|
|
||||||
handshake.PutData(crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES, &signed_buffer[0], cipher_length);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
handshake.PutString(0, m_identifier);
|
handshake.PutString(0, m_identifier);
|
||||||
handshake.PutString(m_identifier.length() + 1, m_credentials);
|
handshake.PutString(m_identifier.length() + 1, m_credentials);
|
||||||
handshake.PutUInt8(m_identifier.length() + 1 + m_credentials.length(), 0);
|
handshake.PutUInt8(m_identifier.length() + 1 + m_credentials.length(), 0);
|
||||||
}
|
|
||||||
#else
|
|
||||||
handshake.PutString(0, m_identifier);
|
|
||||||
handshake.PutString(m_identifier.length() + 1, m_credentials);
|
|
||||||
handshake.PutUInt8(m_identifier.length() + 1 + m_credentials.length(), 0);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (downgrade) {
|
if (downgrade) {
|
||||||
InternalSend(ServertalkClientDowngradeSecurityHandshake, handshake);
|
InternalSend(ServertalkClientDowngradeSecurityHandshake, handshake);
|
||||||
|
|||||||
@@ -4,9 +4,6 @@
|
|||||||
#include "../event/timer.h"
|
#include "../event/timer.h"
|
||||||
#include "servertalk_common.h"
|
#include "servertalk_common.h"
|
||||||
#include "packet.h"
|
#include "packet.h"
|
||||||
#ifdef ENABLE_SECURITY
|
|
||||||
#include <sodium.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace EQ
|
namespace EQ
|
||||||
{
|
{
|
||||||
@@ -18,7 +15,7 @@ namespace EQ
|
|||||||
ServertalkClient(const std::string &addr, int port, bool ipv6, const std::string &identifier, const std::string &credentials);
|
ServertalkClient(const std::string &addr, int port, bool ipv6, const std::string &identifier, const std::string &credentials);
|
||||||
~ServertalkClient();
|
~ServertalkClient();
|
||||||
|
|
||||||
void Send(uint16_t opcode, EQ::Net::Packet &p);
|
void Send(uint16_t opcode, const EQ::Net::Packet &p);
|
||||||
void SendPacket(ServerPacket *p);
|
void SendPacket(ServerPacket *p);
|
||||||
void OnConnect(std::function<void(ServertalkClient*)> cb) { m_on_connect_cb = cb; }
|
void OnConnect(std::function<void(ServertalkClient*)> cb) { m_on_connect_cb = cb; }
|
||||||
void OnMessage(uint16_t opcode, std::function<void(uint16_t, EQ::Net::Packet&)> cb);
|
void OnMessage(uint16_t opcode, std::function<void(uint16_t, EQ::Net::Packet&)> cb);
|
||||||
@@ -26,6 +23,8 @@ namespace EQ
|
|||||||
bool Connected() const { return m_connecting != true; }
|
bool Connected() const { return m_connecting != true; }
|
||||||
|
|
||||||
std::shared_ptr<EQ::Net::TCPConnection> Handle() { return m_connection; }
|
std::shared_ptr<EQ::Net::TCPConnection> Handle() { return m_connection; }
|
||||||
|
|
||||||
|
std::string GetIdentifier() const { return m_identifier; }
|
||||||
private:
|
private:
|
||||||
void Connect();
|
void Connect();
|
||||||
void ProcessData(EQ::Net::TCPConnection *c, const unsigned char *data, size_t length);
|
void ProcessData(EQ::Net::TCPConnection *c, const unsigned char *data, size_t length);
|
||||||
@@ -51,17 +50,6 @@ namespace EQ
|
|||||||
std::unordered_map<uint16_t, std::function<void(uint16_t, EQ::Net::Packet&)>> m_message_callbacks;
|
std::unordered_map<uint16_t, std::function<void(uint16_t, EQ::Net::Packet&)>> m_message_callbacks;
|
||||||
std::function<void(uint16_t, EQ::Net::Packet&)> m_message_callback;
|
std::function<void(uint16_t, EQ::Net::Packet&)> m_message_callback;
|
||||||
std::function<void(ServertalkClient*)> m_on_connect_cb;
|
std::function<void(ServertalkClient*)> m_on_connect_cb;
|
||||||
|
|
||||||
#ifdef ENABLE_SECURITY
|
|
||||||
unsigned char m_public_key_ours[crypto_box_PUBLICKEYBYTES];
|
|
||||||
unsigned char m_private_key_ours[crypto_box_SECRETKEYBYTES];
|
|
||||||
unsigned char m_nonce_ours[crypto_box_NONCEBYTES];
|
|
||||||
|
|
||||||
unsigned char m_public_key_theirs[crypto_box_PUBLICKEYBYTES];
|
|
||||||
unsigned char m_nonce_theirs[crypto_box_NONCEBYTES];
|
|
||||||
|
|
||||||
unsigned char m_shared_key[crypto_box_BEFORENMBYTES];
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ EQ::Net::ServertalkLegacyClient::~ServertalkLegacyClient()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void EQ::Net::ServertalkLegacyClient::Send(uint16_t opcode, EQ::Net::Packet &p)
|
void EQ::Net::ServertalkLegacyClient::Send(uint16_t opcode, const EQ::Net::Packet &p)
|
||||||
{
|
{
|
||||||
if (!m_connection)
|
if (!m_connection)
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ namespace EQ
|
|||||||
ServertalkLegacyClient(const std::string &addr, int port, bool ipv6);
|
ServertalkLegacyClient(const std::string &addr, int port, bool ipv6);
|
||||||
~ServertalkLegacyClient();
|
~ServertalkLegacyClient();
|
||||||
|
|
||||||
void Send(uint16_t opcode, EQ::Net::Packet &p);
|
void Send(uint16_t opcode, const EQ::Net::Packet &p);
|
||||||
void SendPacket(ServerPacket *p);
|
void SendPacket(ServerPacket *p);
|
||||||
void OnConnect(std::function<void(ServertalkLegacyClient*)> cb) { m_on_connect_cb = cb; }
|
void OnConnect(std::function<void(ServertalkLegacyClient*)> cb) { m_on_connect_cb = cb; }
|
||||||
void OnMessage(uint16_t opcode, std::function<void(uint16_t, EQ::Net::Packet&)> cb);
|
void OnMessage(uint16_t opcode, std::function<void(uint16_t, EQ::Net::Packet&)> cb);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#include "servertalk_server.h"
|
#include "servertalk_server.h"
|
||||||
|
#include <regex>
|
||||||
|
|
||||||
EQ::Net::ServertalkServer::ServertalkServer()
|
EQ::Net::ServertalkServer::ServertalkServer()
|
||||||
{
|
{
|
||||||
@@ -19,16 +20,26 @@ void EQ::Net::ServertalkServer::Listen(const ServertalkServerOptions& opts)
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void EQ::Net::ServertalkServer::OnConnectionIdentified(const std::string &type, std::function<void(std::shared_ptr<ServertalkServerConnection>)> cb)
|
void EQ::Net::ServertalkServer::OnConnectionIdentified(const std::string &type, IdentityCallback cb)
|
||||||
{
|
{
|
||||||
m_on_ident.insert(std::make_pair(type, cb));
|
m_on_ident.insert(std::make_pair(type, cb));
|
||||||
}
|
}
|
||||||
|
|
||||||
void EQ::Net::ServertalkServer::OnConnectionRemoved(const std::string &type, std::function<void(std::shared_ptr<ServertalkServerConnection>)> cb)
|
void EQ::Net::ServertalkServer::OnConnectionRemoved(const std::string &type, IdentityCallback cb)
|
||||||
{
|
{
|
||||||
m_on_disc.insert(std::make_pair(type, cb));
|
m_on_disc.insert(std::make_pair(type, cb));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EQ::Net::ServertalkServer::OnConnectionIdentified(IdentityCallback cb)
|
||||||
|
{
|
||||||
|
m_on_any_ident = cb;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EQ::Net::ServertalkServer::OnConnectionRemoved(IdentityCallback cb)
|
||||||
|
{
|
||||||
|
m_on_any_disc = cb;
|
||||||
|
}
|
||||||
|
|
||||||
void EQ::Net::ServertalkServer::ConnectionDisconnected(ServertalkServerConnection *conn)
|
void EQ::Net::ServertalkServer::ConnectionDisconnected(ServertalkServerConnection *conn)
|
||||||
{
|
{
|
||||||
if (conn->GetIdentifier().empty()) {
|
if (conn->GetIdentifier().empty()) {
|
||||||
@@ -51,6 +62,11 @@ void EQ::Net::ServertalkServer::ConnectionDisconnected(ServertalkServerConnectio
|
|||||||
if (on_disc != m_on_disc.end()) {
|
if (on_disc != m_on_disc.end()) {
|
||||||
on_disc->second(*iter);
|
on_disc->second(*iter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_on_any_disc) {
|
||||||
|
m_on_any_disc(*iter);
|
||||||
|
}
|
||||||
|
|
||||||
type->second.erase(iter);
|
type->second.erase(iter);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -65,9 +81,16 @@ void EQ::Net::ServertalkServer::ConnectionIdentified(ServertalkServerConnection
|
|||||||
auto iter = m_unident_connections.begin();
|
auto iter = m_unident_connections.begin();
|
||||||
while (iter != m_unident_connections.end()) {
|
while (iter != m_unident_connections.end()) {
|
||||||
if (conn == iter->get()) {
|
if (conn == iter->get()) {
|
||||||
auto on_ident = m_on_ident.find(conn->GetIdentifier());
|
for (auto &ident : m_on_ident) {
|
||||||
if (on_ident != m_on_ident.end()) {
|
std::regex ident_regex(ident.first);
|
||||||
on_ident->second(*iter);
|
|
||||||
|
if (std::regex_match(conn->GetIdentifier(), ident_regex)) {
|
||||||
|
ident.second(*iter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_on_any_ident) {
|
||||||
|
m_on_any_ident(*iter);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_ident_connections.count(conn->GetIdentifier()) > 0) {
|
if (m_ident_connections.count(conn->GetIdentifier()) > 0) {
|
||||||
|
|||||||
@@ -5,10 +5,6 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
#ifdef ENABLE_SECURITY
|
|
||||||
#include <sodium.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace EQ
|
namespace EQ
|
||||||
{
|
{
|
||||||
namespace Net
|
namespace Net
|
||||||
@@ -22,13 +18,8 @@ namespace EQ
|
|||||||
std::string credentials;
|
std::string credentials;
|
||||||
|
|
||||||
ServertalkServerOptions() {
|
ServertalkServerOptions() {
|
||||||
#ifdef ENABLE_SECURITY
|
|
||||||
encrypted = true;
|
|
||||||
allow_downgrade = true;
|
|
||||||
#else
|
|
||||||
encrypted = false;
|
encrypted = false;
|
||||||
allow_downgrade = true;
|
allow_downgrade = true;
|
||||||
#endif
|
|
||||||
ipv6 = false;
|
ipv6 = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -36,12 +27,16 @@ namespace EQ
|
|||||||
class ServertalkServer
|
class ServertalkServer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
typedef std::function<void(std::shared_ptr<ServertalkServerConnection>)> IdentityCallback;
|
||||||
|
|
||||||
ServertalkServer();
|
ServertalkServer();
|
||||||
~ServertalkServer();
|
~ServertalkServer();
|
||||||
|
|
||||||
void Listen(const ServertalkServerOptions& opts);
|
void Listen(const ServertalkServerOptions& opts);
|
||||||
void OnConnectionIdentified(const std::string &type, std::function<void(std::shared_ptr<ServertalkServerConnection>)> cb);
|
void OnConnectionIdentified(const std::string &type, IdentityCallback cb);
|
||||||
void OnConnectionRemoved(const std::string &type, std::function<void(std::shared_ptr<ServertalkServerConnection>)> cb);
|
void OnConnectionRemoved(const std::string &type, IdentityCallback cb);
|
||||||
|
void OnConnectionIdentified(IdentityCallback cb);
|
||||||
|
void OnConnectionRemoved(IdentityCallback cb);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void ConnectionDisconnected(ServertalkServerConnection *conn);
|
void ConnectionDisconnected(ServertalkServerConnection *conn);
|
||||||
@@ -52,8 +47,10 @@ namespace EQ
|
|||||||
std::vector<std::shared_ptr<ServertalkServerConnection>> m_unident_connections;
|
std::vector<std::shared_ptr<ServertalkServerConnection>> m_unident_connections;
|
||||||
std::map<std::string, std::vector<std::shared_ptr<ServertalkServerConnection>>> m_ident_connections;
|
std::map<std::string, std::vector<std::shared_ptr<ServertalkServerConnection>>> m_ident_connections;
|
||||||
|
|
||||||
std::map<std::string, std::function<void(std::shared_ptr<ServertalkServerConnection>)>> m_on_ident;
|
std::map<std::string, IdentityCallback> m_on_ident;
|
||||||
std::map<std::string, std::function<void(std::shared_ptr<ServertalkServerConnection>)>> m_on_disc;
|
std::map<std::string, IdentityCallback> m_on_disc;
|
||||||
|
IdentityCallback m_on_any_ident;
|
||||||
|
IdentityCallback m_on_any_disc;
|
||||||
bool m_encrypted;
|
bool m_encrypted;
|
||||||
bool m_allow_downgrade;
|
bool m_allow_downgrade;
|
||||||
std::string m_credentials;
|
std::string m_credentials;
|
||||||
|
|||||||
@@ -19,33 +19,12 @@ EQ::Net::ServertalkServerConnection::~ServertalkServerConnection()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void EQ::Net::ServertalkServerConnection::Send(uint16_t opcode, EQ::Net::Packet & p)
|
void EQ::Net::ServertalkServerConnection::Send(uint16_t opcode, const EQ::Net::Packet & p)
|
||||||
{
|
{
|
||||||
EQ::Net::DynamicPacket out;
|
EQ::Net::DynamicPacket out;
|
||||||
#ifdef ENABLE_SECURITY
|
|
||||||
if (m_encrypted) {
|
|
||||||
if (p.Length() == 0) {
|
|
||||||
p.PutUInt8(0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
out.PutUInt32(0, p.Length() + crypto_secretbox_MACBYTES);
|
|
||||||
out.PutUInt16(4, opcode);
|
|
||||||
|
|
||||||
std::unique_ptr<unsigned char[]> cipher(new unsigned char[p.Length() + crypto_secretbox_MACBYTES]);
|
|
||||||
crypto_box_easy_afternm(&cipher[0], (unsigned char*)p.Data(), p.Length(), m_nonce_ours, m_shared_key);
|
|
||||||
(*(uint64_t*)&m_nonce_ours[0])++;
|
|
||||||
out.PutData(6, &cipher[0], p.Length() + crypto_secretbox_MACBYTES);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
out.PutUInt32(0, p.Length());
|
out.PutUInt32(0, p.Length());
|
||||||
out.PutUInt16(4, opcode);
|
out.PutUInt16(4, opcode);
|
||||||
out.PutPacket(6, p);
|
out.PutPacket(6, p);
|
||||||
}
|
|
||||||
#else
|
|
||||||
out.PutUInt32(0, p.Length());
|
|
||||||
out.PutUInt16(4, opcode);
|
|
||||||
out.PutPacket(6, p);
|
|
||||||
#endif
|
|
||||||
InternalSend(ServertalkMessage, out);
|
InternalSend(ServertalkMessage, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,29 +134,7 @@ void EQ::Net::ServertalkServerConnection::OnDisconnect(TCPConnection *c)
|
|||||||
void EQ::Net::ServertalkServerConnection::SendHello()
|
void EQ::Net::ServertalkServerConnection::SendHello()
|
||||||
{
|
{
|
||||||
EQ::Net::DynamicPacket hello;
|
EQ::Net::DynamicPacket hello;
|
||||||
|
|
||||||
#ifdef ENABLE_SECURITY
|
|
||||||
memset(m_public_key_ours, 0, crypto_box_PUBLICKEYBYTES);
|
|
||||||
memset(m_public_key_theirs, 0, crypto_box_PUBLICKEYBYTES);
|
|
||||||
memset(m_private_key_ours, 0, crypto_box_SECRETKEYBYTES);
|
|
||||||
memset(m_nonce_ours, 0, crypto_box_NONCEBYTES);
|
|
||||||
memset(m_nonce_theirs, 0, crypto_box_NONCEBYTES);
|
|
||||||
|
|
||||||
if (m_encrypted) {
|
|
||||||
hello.PutInt8(0, 1);
|
|
||||||
|
|
||||||
crypto_box_keypair(m_public_key_ours, m_private_key_ours);
|
|
||||||
randombytes_buf(m_nonce_ours, crypto_box_NONCEBYTES);
|
|
||||||
|
|
||||||
hello.PutData(1, m_public_key_ours, crypto_box_PUBLICKEYBYTES);
|
|
||||||
hello.PutData(1 + crypto_box_PUBLICKEYBYTES, m_nonce_ours, crypto_box_NONCEBYTES);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
hello.PutInt8(0, 0);
|
hello.PutInt8(0, 0);
|
||||||
}
|
|
||||||
#else
|
|
||||||
hello.PutInt8(0, 0);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
InternalSend(ServertalkServerHello, hello);
|
InternalSend(ServertalkServerHello, hello);
|
||||||
}
|
}
|
||||||
@@ -199,51 +156,6 @@ void EQ::Net::ServertalkServerConnection::InternalSend(ServertalkPacketType type
|
|||||||
|
|
||||||
void EQ::Net::ServertalkServerConnection::ProcessHandshake(EQ::Net::Packet &p, bool downgrade_security)
|
void EQ::Net::ServertalkServerConnection::ProcessHandshake(EQ::Net::Packet &p, bool downgrade_security)
|
||||||
{
|
{
|
||||||
#ifdef ENABLE_SECURITY
|
|
||||||
if (downgrade_security && m_allow_downgrade && m_encrypted) {
|
|
||||||
LogF(Logs::General, Logs::TCP_Connection, "Downgraded encrypted connection to plaintext because otherside didn't support encryption {0}:{1}",
|
|
||||||
m_connection->RemoteIP(), m_connection->RemotePort());
|
|
||||||
m_encrypted = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_encrypted) {
|
|
||||||
try {
|
|
||||||
if (p.Length() > (crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES)) {
|
|
||||||
memcpy(m_public_key_theirs, (char*)p.Data(), crypto_box_PUBLICKEYBYTES);
|
|
||||||
memcpy(m_nonce_theirs, (char*)p.Data() + crypto_box_PUBLICKEYBYTES, crypto_box_NONCEBYTES);
|
|
||||||
|
|
||||||
crypto_box_beforenm(m_shared_key, m_public_key_theirs, m_private_key_ours);
|
|
||||||
|
|
||||||
size_t cipher_len = p.Length() - crypto_box_PUBLICKEYBYTES - crypto_box_NONCEBYTES;
|
|
||||||
size_t message_len = cipher_len - crypto_secretbox_MACBYTES;
|
|
||||||
std::unique_ptr<unsigned char[]> decrypted_text(new unsigned char[message_len]);
|
|
||||||
|
|
||||||
if (crypto_box_open_easy_afternm(&decrypted_text[0], (unsigned char*)p.Data() + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES, cipher_len, m_nonce_theirs, m_shared_key))
|
|
||||||
{
|
|
||||||
LogF(Logs::General, Logs::Error, "Error decrypting handshake from client, dropping connection.");
|
|
||||||
m_connection->Disconnect();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_identifier = (const char*)&decrypted_text[0];
|
|
||||||
std::string credentials = (const char*)&decrypted_text[0] + (m_identifier.length() + 1);
|
|
||||||
|
|
||||||
if (!m_parent->CheckCredentials(credentials)) {
|
|
||||||
LogF(Logs::General, Logs::Error, "Got incoming connection with invalid credentials during handshake, dropping connection.");
|
|
||||||
m_connection->Disconnect();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_parent->ConnectionIdentified(this);
|
|
||||||
(*(uint64_t*)&m_nonce_theirs[0])++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (std::exception &ex) {
|
|
||||||
LogF(Logs::General, Logs::Error, "Error parsing handshake from client: {0}", ex.what());
|
|
||||||
m_connection->Disconnect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
try {
|
try {
|
||||||
m_identifier = p.GetCString(0);
|
m_identifier = p.GetCString(0);
|
||||||
auto credentials = p.GetCString(m_identifier.length() + 1);
|
auto credentials = p.GetCString(m_identifier.length() + 1);
|
||||||
@@ -260,25 +172,6 @@ void EQ::Net::ServertalkServerConnection::ProcessHandshake(EQ::Net::Packet &p, b
|
|||||||
LogF(Logs::General, Logs::Error, "Error parsing handshake from client: {0}", ex.what());
|
LogF(Logs::General, Logs::Error, "Error parsing handshake from client: {0}", ex.what());
|
||||||
m_connection->Disconnect();
|
m_connection->Disconnect();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
#else
|
|
||||||
try {
|
|
||||||
m_identifier = p.GetCString(0);
|
|
||||||
auto credentials = p.GetCString(m_identifier.length() + 1);
|
|
||||||
|
|
||||||
if (!m_parent->CheckCredentials(credentials)) {
|
|
||||||
LogF(Logs::General, Logs::Error, "Got incoming connection with invalid credentials during handshake, dropping connection.");
|
|
||||||
m_connection->Disconnect();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_parent->ConnectionIdentified(this);
|
|
||||||
}
|
|
||||||
catch (std::exception &ex) {
|
|
||||||
LogF(Logs::General, Logs::Error, "Error parsing handshake from client: {0}", ex.what());
|
|
||||||
m_connection->Disconnect();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EQ::Net::ServertalkServerConnection::ProcessMessage(EQ::Net::Packet &p)
|
void EQ::Net::ServertalkServerConnection::ProcessMessage(EQ::Net::Packet &p)
|
||||||
@@ -288,32 +181,6 @@ void EQ::Net::ServertalkServerConnection::ProcessMessage(EQ::Net::Packet &p)
|
|||||||
auto opcode = p.GetUInt16(4);
|
auto opcode = p.GetUInt16(4);
|
||||||
if (length > 0) {
|
if (length > 0) {
|
||||||
auto data = p.GetString(6, length);
|
auto data = p.GetString(6, length);
|
||||||
#ifdef ENABLE_SECURITY
|
|
||||||
if (m_encrypted) {
|
|
||||||
size_t message_len = length - crypto_secretbox_MACBYTES;
|
|
||||||
std::unique_ptr<unsigned char[]> decrypted_text(new unsigned char[message_len]);
|
|
||||||
|
|
||||||
if (crypto_box_open_easy_afternm(&decrypted_text[0], (unsigned char*)&data[0], length, m_nonce_theirs, m_shared_key))
|
|
||||||
{
|
|
||||||
LogF(Logs::General, Logs::Error, "Error decrypting message from client");
|
|
||||||
(*(uint64_t*)&m_nonce_theirs[0])++;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
EQ::Net::StaticPacket decrypted_packet(&decrypted_text[0], message_len);
|
|
||||||
|
|
||||||
(*(uint64_t*)&m_nonce_theirs[0])++;
|
|
||||||
|
|
||||||
auto cb = m_message_callbacks.find(opcode);
|
|
||||||
if (cb != m_message_callbacks.end()) {
|
|
||||||
cb->second(opcode, decrypted_packet);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_message_callback) {
|
|
||||||
m_message_callback(opcode, decrypted_packet);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
size_t message_len = length;
|
size_t message_len = length;
|
||||||
EQ::Net::StaticPacket packet(&data[0], message_len);
|
EQ::Net::StaticPacket packet(&data[0], message_len);
|
||||||
|
|
||||||
@@ -326,21 +193,6 @@ void EQ::Net::ServertalkServerConnection::ProcessMessage(EQ::Net::Packet &p)
|
|||||||
m_message_callback(opcode, packet);
|
m_message_callback(opcode, packet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
|
||||||
size_t message_len = length;
|
|
||||||
EQ::Net::StaticPacket packet(&data[0], message_len);
|
|
||||||
|
|
||||||
auto cb = m_message_callbacks.find(opcode);
|
|
||||||
if (cb != m_message_callbacks.end()) {
|
|
||||||
cb->second(opcode, packet);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_message_callback) {
|
|
||||||
m_message_callback(opcode, packet);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (std::exception &ex) {
|
catch (std::exception &ex) {
|
||||||
LogF(Logs::General, Logs::Error, "Error parsing message from client: {0}", ex.what());
|
LogF(Logs::General, Logs::Error, "Error parsing message from client: {0}", ex.what());
|
||||||
|
|||||||
@@ -4,9 +4,6 @@
|
|||||||
#include "servertalk_common.h"
|
#include "servertalk_common.h"
|
||||||
#include "packet.h"
|
#include "packet.h"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#ifdef ENABLE_SECURITY
|
|
||||||
#include <sodium.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace EQ
|
namespace EQ
|
||||||
{
|
{
|
||||||
@@ -19,7 +16,7 @@ namespace EQ
|
|||||||
ServertalkServerConnection(std::shared_ptr<EQ::Net::TCPConnection> c, ServertalkServer *parent, bool encrypted, bool allow_downgrade);
|
ServertalkServerConnection(std::shared_ptr<EQ::Net::TCPConnection> c, ServertalkServer *parent, bool encrypted, bool allow_downgrade);
|
||||||
~ServertalkServerConnection();
|
~ServertalkServerConnection();
|
||||||
|
|
||||||
void Send(uint16_t opcode, EQ::Net::Packet &p);
|
void Send(uint16_t opcode, const EQ::Net::Packet &p);
|
||||||
void SendPacket(ServerPacket *p);
|
void SendPacket(ServerPacket *p);
|
||||||
void OnMessage(uint16_t opcode, std::function<void(uint16_t, EQ::Net::Packet&)> cb);
|
void OnMessage(uint16_t opcode, std::function<void(uint16_t, EQ::Net::Packet&)> cb);
|
||||||
void OnMessage(std::function<void(uint16_t, EQ::Net::Packet&)> cb);
|
void OnMessage(std::function<void(uint16_t, EQ::Net::Packet&)> cb);
|
||||||
@@ -48,16 +45,6 @@ namespace EQ
|
|||||||
|
|
||||||
bool m_encrypted;
|
bool m_encrypted;
|
||||||
bool m_allow_downgrade;
|
bool m_allow_downgrade;
|
||||||
#ifdef ENABLE_SECURITY
|
|
||||||
unsigned char m_public_key_ours[crypto_box_PUBLICKEYBYTES];
|
|
||||||
unsigned char m_private_key_ours[crypto_box_SECRETKEYBYTES];
|
|
||||||
unsigned char m_nonce_ours[crypto_box_NONCEBYTES];
|
|
||||||
|
|
||||||
unsigned char m_public_key_theirs[crypto_box_PUBLICKEYBYTES];
|
|
||||||
unsigned char m_nonce_theirs[crypto_box_NONCEBYTES];
|
|
||||||
|
|
||||||
unsigned char m_shared_key[crypto_box_BEFORENMBYTES];
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
import "google/protobuf/any.proto";
|
||||||
|
|
||||||
|
package EQ.Proto;
|
||||||
|
|
||||||
|
message TaskMessage {
|
||||||
|
int32 message = 1;
|
||||||
|
google.protobuf.Any details = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message ClientTaskStateRequest {
|
||||||
|
int32 client_id = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message ClientTaskStateResponse {
|
||||||
|
int32 client_id = 1;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -187,6 +187,7 @@ public:
|
|||||||
const unsigned char *buffer() const { return m_buffer; }
|
const unsigned char *buffer() const { return m_buffer; }
|
||||||
|
|
||||||
friend class BasePacket;
|
friend class BasePacket;
|
||||||
|
friend class ServerPacket;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void Grow(size_t new_size);
|
void Grow(size_t new_size);
|
||||||
|
|||||||
+233
-197
@@ -1,218 +1,220 @@
|
|||||||
#ifndef EQ_SOPCODES_H
|
#pragma once
|
||||||
#define EQ_SOPCODES_H
|
|
||||||
|
|
||||||
#include "../common/types.h"
|
#include "../common/types.h"
|
||||||
#include "../common/packet_functions.h"
|
#include "../common/packet_functions.h"
|
||||||
#include "../common/eq_packet_structs.h"
|
#include "../common/eq_packet_structs.h"
|
||||||
|
#include "../common/serialize_buffer.h"
|
||||||
#include "../net/packet.h"
|
#include "../net/packet.h"
|
||||||
#include <cereal/cereal.hpp>
|
#include <cereal/cereal.hpp>
|
||||||
#include <cereal/types/string.hpp>
|
#include <cereal/types/string.hpp>
|
||||||
|
|
||||||
#define SERVER_TIMEOUT 45000 // how often keepalive gets sent
|
constexpr auto INTERSERVER_TIMER = 10000;
|
||||||
#define INTERSERVER_TIMER 10000
|
constexpr auto LoginServer_StatusUpdateInterval = 15000;
|
||||||
#define LoginServer_StatusUpdateInterval 15000
|
|
||||||
#define LoginServer_AuthStale 60000
|
|
||||||
#define AUTHCHANGE_TIMEOUT 900 // in seconds
|
|
||||||
|
|
||||||
#define ServerOP_KeepAlive 0x0001 // packet to test if port is still open
|
//Certain ops needed for backwards compat with old LS can't enum without being really annoying.
|
||||||
#define ServerOP_ChannelMessage 0x0002 // broadcast/guildsay
|
constexpr auto ServerOP_UsertoWorldReq = 0xAB00;
|
||||||
#define ServerOP_SetZone 0x0003 // client -> server zoneinfo
|
constexpr auto ServerOP_UsertoWorldResp = 0xAB01;
|
||||||
#define ServerOP_ShutdownAll 0x0004 // exit(0);
|
constexpr auto ServerOP_LSClientAuth = 0x1002;
|
||||||
#define ServerOP_ZoneShutdown 0x0005 // unload all data, goto sleep mode
|
constexpr auto ServerOP_LSFatalError = 0x1003;
|
||||||
#define ServerOP_ZoneBootup 0x0006 // come out of sleep mode and load zone specified
|
constexpr auto ServerOP_SystemwideMessage = 0x1005;
|
||||||
#define ServerOP_ZoneStatus 0x0007 // Shows status of all zones
|
constexpr auto ServerOP_LSRemoteAddr = 0x1009;
|
||||||
#define ServerOP_SetConnectInfo 0x0008 // Tells server address and port #
|
constexpr auto ServerOP_LSAccountUpdate = 0x100A;
|
||||||
#define ServerOP_EmoteMessage 0x0009 // Worldfarts
|
constexpr auto ServerOP_NewLSInfo = 0x1008;
|
||||||
#define ServerOP_ClientList 0x000A // Update worldserver's client list, for #whos
|
constexpr auto ServerOP_LSInfo = 0x1000;
|
||||||
#define ServerOP_Who 0x000B // #who
|
constexpr auto ServerOP_LSStatus = 0x1001;
|
||||||
#define ServerOP_ZonePlayer 0x000C // #zone, or #summon
|
|
||||||
#define ServerOP_KickPlayer 0x000D // #kick
|
|
||||||
|
|
||||||
#define ServerOP_RefreshGuild 0x000E // Notice to all zoneservers to refresh their guild cache for ID# in packet (ServerGuildRefresh_Struct)
|
enum ServerOpcode : int
|
||||||
#define ServerOP_VoiceMacro 0x000F
|
{
|
||||||
//#define ServerOP_GuildInvite 0x0010
|
ServerOP_ChannelMessage,
|
||||||
#define ServerOP_DeleteGuild 0x0011 // ServerGuildID_Struct
|
ServerOP_SetZone,
|
||||||
#define ServerOP_GuildRankUpdate 0x0012
|
ServerOP_ShutdownAll,
|
||||||
#define ServerOP_GuildCharRefresh 0x0013
|
ServerOP_ZoneShutdown,
|
||||||
#define ServerOP_GuildMemberUpdate 0x0014
|
ServerOP_ZoneBootup,
|
||||||
#define ServerOP_RequestOnlineGuildMembers 0x0015
|
ServerOP_ZoneStatus,
|
||||||
#define ServerOP_OnlineGuildMembersResponse 0x0016
|
ServerOP_SetConnectInfo,
|
||||||
#define ServerOP_LFGuildUpdate 0x0017
|
ServerOP_EmoteMessage,
|
||||||
|
ServerOP_ClientList,
|
||||||
|
ServerOP_Who,
|
||||||
|
ServerOP_ZonePlayer,
|
||||||
|
ServerOP_KickPlayer,
|
||||||
|
ServerOP_RefreshGuild,
|
||||||
|
ServerOP_VoiceMacro,
|
||||||
|
//ServerOP_GuildInvite,
|
||||||
|
ServerOP_DeleteGuild,
|
||||||
|
ServerOP_GuildRankUpdate,
|
||||||
|
ServerOP_GuildCharRefresh,
|
||||||
|
ServerOP_GuildMemberUpdate,
|
||||||
|
ServerOP_RequestOnlineGuildMembers,
|
||||||
|
ServerOP_OnlineGuildMembersResponse,
|
||||||
|
ServerOP_LFGuildUpdate,
|
||||||
|
ServerOP_FlagUpdate,
|
||||||
|
ServerOP_GMGoto,
|
||||||
|
ServerOP_MultiLineMsg,
|
||||||
|
ServerOP_Lock,
|
||||||
|
ServerOP_Motd,
|
||||||
|
ServerOP_Uptime,
|
||||||
|
ServerOP_Petition,
|
||||||
|
ServerOP_KillPlayer,
|
||||||
|
ServerOP_UpdateGM,
|
||||||
|
ServerOP_RezzPlayer,
|
||||||
|
ServerOP_ZoneReboot,
|
||||||
|
ServerOP_ZoneToZoneRequest,
|
||||||
|
ServerOP_AcceptWorldEntrance,
|
||||||
|
ServerOP_ZAAuth,
|
||||||
|
ServerOP_ZAAuthFailed,
|
||||||
|
ServerOP_ZoneIncClient,
|
||||||
|
ServerOP_ClientListKA,
|
||||||
|
ServerOP_ChangeWID,
|
||||||
|
ServerOP_IPLookup,
|
||||||
|
ServerOP_LockZone,
|
||||||
|
ServerOP_ItemStatus,
|
||||||
|
ServerOP_OOCMute,
|
||||||
|
ServerOP_Revoke,
|
||||||
|
ServerOP_WebInterfaceCall,
|
||||||
|
ServerOP_GroupIDReq,
|
||||||
|
ServerOP_GroupIDReply,
|
||||||
|
ServerOP_GroupLeave,
|
||||||
|
ServerOP_RezzPlayerAccept,
|
||||||
|
ServerOP_SpawnCondition,
|
||||||
|
ServerOP_SpawnEvent,
|
||||||
|
ServerOP_SetLaunchName,
|
||||||
|
ServerOP_RezzPlayerReject,
|
||||||
|
ServerOP_SpawnPlayerCorpse,
|
||||||
|
ServerOP_Consent,
|
||||||
|
ServerOP_Consent_Response,
|
||||||
|
ServerOP_ForceGroupUpdate,
|
||||||
|
ServerOP_OOZGroupMessage,
|
||||||
|
ServerOP_DisbandGroup,
|
||||||
|
ServerOP_GroupJoin,
|
||||||
|
ServerOP_UpdateSpawn,
|
||||||
|
ServerOP_SpawnStatusChange,
|
||||||
|
ServerOP_ReloadTasks,
|
||||||
|
ServerOP_DepopAllPlayersCorpses,
|
||||||
|
ServerOP_ReloadTitles,
|
||||||
|
ServerOP_QGlobalUpdate,
|
||||||
|
ServerOP_QGlobalDelete,
|
||||||
|
ServerOP_DepopPlayerCorpse,
|
||||||
|
ServerOP_RequestTellQueue,
|
||||||
|
ServerOP_ChangeSharedMem,
|
||||||
|
ServerOP_WebInterfaceEvent,
|
||||||
|
ServerOP_WebInterfaceSubscribe,
|
||||||
|
ServerOP_WebInterfaceUnsubscribe,
|
||||||
|
ServerOP_RaidAdd,
|
||||||
|
ServerOP_RaidRemove,
|
||||||
|
ServerOP_RaidDisband,
|
||||||
|
ServerOP_RaidLockFlag,
|
||||||
|
ServerOP_RaidGroupLeader,
|
||||||
|
ServerOP_RaidLeader,
|
||||||
|
ServerOP_RaidGroupSay,
|
||||||
|
ServerOP_RaidSay,
|
||||||
|
ServerOP_DetailsChange,
|
||||||
|
ServerOP_UpdateGroup,
|
||||||
|
ServerOP_RaidGroupDisband,
|
||||||
|
ServerOP_RaidChangeGroup,
|
||||||
|
ServerOP_RaidGroupAdd,
|
||||||
|
ServerOP_RaidGroupRemove,
|
||||||
|
ServerOP_GroupInvite,
|
||||||
|
ServerOP_GroupFollow,
|
||||||
|
ServerOP_GroupFollowAck,
|
||||||
|
ServerOP_GroupCancelInvite,
|
||||||
|
ServerOP_RaidMOTD,
|
||||||
|
ServerOP_InstanceUpdateTime,
|
||||||
|
ServerOP_AdventureRequest,
|
||||||
|
ServerOP_AdventureRequestAccept,
|
||||||
|
ServerOP_AdventureRequestDeny,
|
||||||
|
ServerOP_AdventureRequestCreate,
|
||||||
|
ServerOP_AdventureData,
|
||||||
|
ServerOP_AdventureDataClear,
|
||||||
|
ServerOP_AdventureCreateDeny,
|
||||||
|
ServerOP_AdventureDataRequest,
|
||||||
|
ServerOP_AdventureClickDoor,
|
||||||
|
ServerOP_AdventureClickDoorReply,
|
||||||
|
ServerOP_AdventureClickDoorError,
|
||||||
|
ServerOP_AdventureLeave,
|
||||||
|
ServerOP_AdventureLeaveReply,
|
||||||
|
ServerOP_AdventureLeaveDeny,
|
||||||
|
ServerOP_AdventureCountUpdate,
|
||||||
|
ServerOP_AdventureZoneData,
|
||||||
|
ServerOP_AdventureAssaCountUpdate,
|
||||||
|
ServerOP_AdventureFinish,
|
||||||
|
ServerOP_AdventureLeaderboard,
|
||||||
|
ServerOP_WhoAll,
|
||||||
|
ServerOP_FriendsWho,
|
||||||
|
ServerOP_LFGMatches,
|
||||||
|
ServerOP_LFPUpdate,
|
||||||
|
ServerOP_LFPMatches,
|
||||||
|
ServerOP_ClientVersionSummary,
|
||||||
|
ServerOP_ListWorlds,
|
||||||
|
ServerOP_PeerConnect,
|
||||||
|
ServerOP_TaskRequest,
|
||||||
|
ServerOP_TaskGrant,
|
||||||
|
ServerOP_TaskReject,
|
||||||
|
ServerOP_TaskAddPlayer,
|
||||||
|
ServerOP_TaskRemovePlayer,
|
||||||
|
ServerOP_TaskZoneCreated,
|
||||||
|
ServerOP_TaskZoneFailed,
|
||||||
|
ServerOP_EncapPacket,
|
||||||
|
ServerOP_WorldListUpdate,
|
||||||
|
ServerOP_WorldListRemove,
|
||||||
|
ServerOP_TriggerWorldListRefresh,
|
||||||
|
ServerOP_WhoAllReply,
|
||||||
|
ServerOP_SetWorldTime,
|
||||||
|
ServerOP_GetWorldTime,
|
||||||
|
ServerOP_SyncWorldTime,
|
||||||
|
ServerOP_RefreshCensorship,
|
||||||
|
ServerOP_LSZoneInfo,
|
||||||
|
ServerOP_LSZoneStart,
|
||||||
|
ServerOP_LSZoneBoot,
|
||||||
|
ServerOP_LSZoneShutdown,
|
||||||
|
ServerOP_LSZoneSleep,
|
||||||
|
ServerOP_LSPlayerLeftWorld,
|
||||||
|
ServerOP_LSPlayerJoinWorld,
|
||||||
|
ServerOP_LSPlayerZoneChange,
|
||||||
|
ServerOP_LauncherConnectInfo,
|
||||||
|
ServerOP_LauncherZoneRequest,
|
||||||
|
ServerOP_LauncherZoneStatus,
|
||||||
|
ServerOP_DoZoneCommand,
|
||||||
|
ServerOP_UCSMessage,
|
||||||
|
ServerOP_UCSMailMessage,
|
||||||
|
ServerOP_ReloadRules,
|
||||||
|
ServerOP_ReloadRulesWorld,
|
||||||
|
ServerOP_CameraShake,
|
||||||
|
ServerOP_QueryServGeneric,
|
||||||
|
ServerOP_CZSignalClient,
|
||||||
|
ServerOP_CZSignalClientByName,
|
||||||
|
ServerOP_CZMessagePlayer,
|
||||||
|
ServerOP_ReloadWorld,
|
||||||
|
ServerOP_ReloadLogs,
|
||||||
|
ServerOP_ReloadPerlExportSettings,
|
||||||
|
ServerOP_CZSetEntityVariableByClientName,
|
||||||
|
ServerOP_UCSServerStatusRequest,
|
||||||
|
ServerOP_UCSServerStatusReply,
|
||||||
|
ServerOP_Speech,
|
||||||
|
ServerOP_QSPlayerLogTrades,
|
||||||
|
ServerOP_QSPlayerLogHandins,
|
||||||
|
ServerOP_QSPlayerLogNPCKills,
|
||||||
|
ServerOP_QSPlayerLogDeletes,
|
||||||
|
ServerOP_QSPlayerLogMoves,
|
||||||
|
ServerOP_QSPlayerLogMerchantTransactions,
|
||||||
|
ServerOP_QSSendQuery,
|
||||||
|
ServerOP_CZSignalNPC,
|
||||||
|
ServerOP_CZSetEntityVariableByNPCTypeID,
|
||||||
|
ServerOP_WWMarquee,
|
||||||
|
ServerOP_QSPlayerDropItem,
|
||||||
|
ServerOP_RouteTo,
|
||||||
|
|
||||||
#define ServerOP_FlagUpdate 0x0018 // GM Flag updated for character, refresh the memory cache
|
/*Tasks*/
|
||||||
#define ServerOP_GMGoto 0x0019
|
ServerOP_GetClientTaskState
|
||||||
#define ServerOP_MultiLineMsg 0x001A
|
};
|
||||||
#define ServerOP_Lock 0x001B // For #lock/#unlock inside server
|
|
||||||
#define ServerOP_Motd 0x001C // For changing MoTD inside server.
|
|
||||||
#define ServerOP_Uptime 0x001D
|
|
||||||
#define ServerOP_Petition 0x001E
|
|
||||||
#define ServerOP_KillPlayer 0x001F
|
|
||||||
#define ServerOP_UpdateGM 0x0020
|
|
||||||
#define ServerOP_RezzPlayer 0x0021
|
|
||||||
#define ServerOP_ZoneReboot 0x0022
|
|
||||||
#define ServerOP_ZoneToZoneRequest 0x0023
|
|
||||||
#define ServerOP_AcceptWorldEntrance 0x0024
|
|
||||||
#define ServerOP_ZAAuth 0x0025
|
|
||||||
#define ServerOP_ZAAuthFailed 0x0026
|
|
||||||
#define ServerOP_ZoneIncClient 0x0027 // Incoming client
|
|
||||||
#define ServerOP_ClientListKA 0x0028
|
|
||||||
#define ServerOP_ChangeWID 0x0029
|
|
||||||
#define ServerOP_IPLookup 0x002A
|
|
||||||
#define ServerOP_LockZone 0x002B
|
|
||||||
#define ServerOP_ItemStatus 0x002C
|
|
||||||
#define ServerOP_OOCMute 0x002D
|
|
||||||
#define ServerOP_Revoke 0x002E
|
|
||||||
#define ServerOP_WebInterfaceCall 0x002F
|
|
||||||
#define ServerOP_GroupIDReq 0x0030
|
|
||||||
#define ServerOP_GroupIDReply 0x0031
|
|
||||||
#define ServerOP_GroupLeave 0x0032 // for disbanding out of zone folks
|
|
||||||
#define ServerOP_RezzPlayerAccept 0x0033
|
|
||||||
#define ServerOP_SpawnCondition 0x0034
|
|
||||||
#define ServerOP_SpawnEvent 0x0035
|
|
||||||
#define ServerOP_SetLaunchName 0x0036
|
|
||||||
#define ServerOP_RezzPlayerReject 0x0037
|
|
||||||
#define ServerOP_SpawnPlayerCorpse 0x0038
|
|
||||||
#define ServerOP_Consent 0x0039
|
|
||||||
#define ServerOP_Consent_Response 0x003a
|
|
||||||
#define ServerOP_ForceGroupUpdate 0x003b
|
|
||||||
#define ServerOP_OOZGroupMessage 0x003c
|
|
||||||
#define ServerOP_DisbandGroup 0x003d //for disbanding a whole group cross zone
|
|
||||||
#define ServerOP_GroupJoin 0x003e //for joining ooz folks
|
|
||||||
#define ServerOP_UpdateSpawn 0x003f
|
|
||||||
#define ServerOP_SpawnStatusChange 0x0040
|
|
||||||
#define ServerOP_ReloadTasks 0x0060
|
|
||||||
#define ServerOP_DepopAllPlayersCorpses 0x0061
|
|
||||||
#define ServerOP_ReloadTitles 0x0062
|
|
||||||
#define ServerOP_QGlobalUpdate 0x0063
|
|
||||||
#define ServerOP_QGlobalDelete 0x0064
|
|
||||||
#define ServerOP_DepopPlayerCorpse 0x0065
|
|
||||||
#define ServerOP_RequestTellQueue 0x0066 // client asks for it's tell queues
|
|
||||||
#define ServerOP_ChangeSharedMem 0x0067
|
|
||||||
#define ServerOP_WebInterfaceEvent 0x0068
|
|
||||||
#define ServerOP_WebInterfaceSubscribe 0x0069
|
|
||||||
#define ServerOP_WebInterfaceUnsubscribe 0x0070
|
|
||||||
|
|
||||||
#define ServerOP_RaidAdd 0x0100 //in use
|
|
||||||
#define ServerOP_RaidRemove 0x0101 //in use
|
|
||||||
#define ServerOP_RaidDisband 0x0102 //in use
|
|
||||||
#define ServerOP_RaidLockFlag 0x0103 //in use
|
|
||||||
#define ServerOP_RaidGroupLeader 0x0104 //in use
|
|
||||||
#define ServerOP_RaidLeader 0x0105 //in use
|
|
||||||
#define ServerOP_RaidGroupSay 0x0106 //in use
|
|
||||||
#define ServerOP_RaidSay 0x0107 //in use
|
|
||||||
#define ServerOP_DetailsChange 0x0108 //in use
|
|
||||||
|
|
||||||
#define ServerOP_UpdateGroup 0x010A //in use
|
|
||||||
#define ServerOP_RaidGroupDisband 0x010B //in use
|
|
||||||
#define ServerOP_RaidChangeGroup 0x010C //in use
|
|
||||||
#define ServerOP_RaidGroupAdd 0x010D
|
|
||||||
#define ServerOP_RaidGroupRemove 0x010E
|
|
||||||
#define ServerOP_GroupInvite 0x010F
|
|
||||||
#define ServerOP_GroupFollow 0x0110
|
|
||||||
#define ServerOP_GroupFollowAck 0x0111
|
|
||||||
#define ServerOP_GroupCancelInvite 0x0112
|
|
||||||
#define ServerOP_RaidMOTD 0x0113
|
|
||||||
|
|
||||||
#define ServerOP_InstanceUpdateTime 0x014F
|
|
||||||
#define ServerOP_AdventureRequest 0x0150
|
|
||||||
#define ServerOP_AdventureRequestAccept 0x0151
|
|
||||||
#define ServerOP_AdventureRequestDeny 0x0152
|
|
||||||
#define ServerOP_AdventureRequestCreate 0x0153
|
|
||||||
#define ServerOP_AdventureData 0x0154
|
|
||||||
#define ServerOP_AdventureDataClear 0x0155
|
|
||||||
#define ServerOP_AdventureCreateDeny 0x0156
|
|
||||||
#define ServerOP_AdventureDataRequest 0x0157
|
|
||||||
#define ServerOP_AdventureClickDoor 0x0158
|
|
||||||
#define ServerOP_AdventureClickDoorReply 0x0159
|
|
||||||
#define ServerOP_AdventureClickDoorError 0x015a
|
|
||||||
#define ServerOP_AdventureLeave 0x015b
|
|
||||||
#define ServerOP_AdventureLeaveReply 0x015c
|
|
||||||
#define ServerOP_AdventureLeaveDeny 0x015d
|
|
||||||
#define ServerOP_AdventureCountUpdate 0x015e
|
|
||||||
#define ServerOP_AdventureZoneData 0x015f
|
|
||||||
#define ServerOP_AdventureAssaCountUpdate 0x0160
|
|
||||||
#define ServerOP_AdventureFinish 0x0161
|
|
||||||
#define ServerOP_AdventureLeaderboard 0x0162
|
|
||||||
|
|
||||||
#define ServerOP_WhoAll 0x0210
|
|
||||||
#define ServerOP_FriendsWho 0x0211
|
|
||||||
#define ServerOP_LFGMatches 0x0212
|
|
||||||
#define ServerOP_LFPUpdate 0x0213
|
|
||||||
#define ServerOP_LFPMatches 0x0214
|
|
||||||
#define ServerOP_ClientVersionSummary 0x0215
|
|
||||||
#define ServerOP_LSInfo 0x1000
|
|
||||||
#define ServerOP_LSStatus 0x1001
|
|
||||||
#define ServerOP_LSClientAuth 0x1002
|
|
||||||
#define ServerOP_LSFatalError 0x1003
|
|
||||||
#define ServerOP_SystemwideMessage 0x1005
|
|
||||||
#define ServerOP_ListWorlds 0x1006
|
|
||||||
#define ServerOP_PeerConnect 0x1007
|
|
||||||
#define ServerOP_NewLSInfo 0x1008
|
|
||||||
#define ServerOP_LSRemoteAddr 0x1009
|
|
||||||
#define ServerOP_LSAccountUpdate 0x100A
|
|
||||||
|
|
||||||
#define ServerOP_EncapPacket 0x2007 // Packet within a packet
|
|
||||||
#define ServerOP_WorldListUpdate 0x2008
|
|
||||||
#define ServerOP_WorldListRemove 0x2009
|
|
||||||
#define ServerOP_TriggerWorldListRefresh 0x200A
|
|
||||||
#define ServerOP_WhoAllReply 0x2010
|
|
||||||
#define ServerOP_SetWorldTime 0x200B
|
|
||||||
#define ServerOP_GetWorldTime 0x200C
|
|
||||||
#define ServerOP_SyncWorldTime 0x200E
|
|
||||||
#define ServerOP_RefreshCensorship 0x200F
|
|
||||||
|
|
||||||
#define ServerOP_LSZoneInfo 0x3001
|
|
||||||
#define ServerOP_LSZoneStart 0x3002
|
|
||||||
#define ServerOP_LSZoneBoot 0x3003
|
|
||||||
#define ServerOP_LSZoneShutdown 0x3004
|
|
||||||
#define ServerOP_LSZoneSleep 0x3005
|
|
||||||
#define ServerOP_LSPlayerLeftWorld 0x3006
|
|
||||||
#define ServerOP_LSPlayerJoinWorld 0x3007
|
|
||||||
#define ServerOP_LSPlayerZoneChange 0x3008
|
|
||||||
|
|
||||||
#define ServerOP_UsertoWorldReq 0xAB00
|
|
||||||
#define ServerOP_UsertoWorldResp 0xAB01
|
|
||||||
|
|
||||||
#define ServerOP_LauncherConnectInfo 0x3000
|
|
||||||
#define ServerOP_LauncherZoneRequest 0x3001
|
|
||||||
#define ServerOP_LauncherZoneStatus 0x3002
|
|
||||||
#define ServerOP_DoZoneCommand 0x3003
|
|
||||||
|
|
||||||
#define ServerOP_UCSMessage 0x4000
|
|
||||||
#define ServerOP_UCSMailMessage 0x4001
|
|
||||||
#define ServerOP_ReloadRules 0x4002
|
|
||||||
#define ServerOP_ReloadRulesWorld 0x4003
|
|
||||||
#define ServerOP_CameraShake 0x4004
|
|
||||||
#define ServerOP_QueryServGeneric 0x4005
|
|
||||||
#define ServerOP_CZSignalClient 0x4006
|
|
||||||
#define ServerOP_CZSignalClientByName 0x4007
|
|
||||||
#define ServerOP_CZMessagePlayer 0x4008
|
|
||||||
#define ServerOP_ReloadWorld 0x4009
|
|
||||||
#define ServerOP_ReloadLogs 0x4010
|
|
||||||
#define ServerOP_ReloadPerlExportSettings 0x4011
|
|
||||||
#define ServerOP_CZSetEntityVariableByClientName 0x4012
|
|
||||||
#define ServerOP_UCSServerStatusRequest 0x4013
|
|
||||||
#define ServerOP_UCSServerStatusReply 0x4014
|
|
||||||
/* Query Server OP Codes */
|
|
||||||
#define ServerOP_QSPlayerLogTrades 0x5010
|
|
||||||
#define ServerOP_QSPlayerLogHandins 0x5011
|
|
||||||
#define ServerOP_QSPlayerLogNPCKills 0x5012
|
|
||||||
#define ServerOP_QSPlayerLogDeletes 0x5013
|
|
||||||
#define ServerOP_QSPlayerLogMoves 0x5014
|
|
||||||
#define ServerOP_QSPlayerLogMerchantTransactions 0x5015
|
|
||||||
#define ServerOP_QSSendQuery 0x5016
|
|
||||||
#define ServerOP_CZSignalNPC 0x5017
|
|
||||||
#define ServerOP_CZSetEntityVariableByNPCTypeID 0x5018
|
|
||||||
#define ServerOP_WWMarquee 0x5019
|
|
||||||
#define ServerOP_QSPlayerDropItem 0x5020
|
|
||||||
|
|
||||||
/* Query Serv Generic Packet Flag/Type Enumeration */
|
/* Query Serv Generic Packet Flag/Type Enumeration */
|
||||||
enum { QSG_LFGuild = 0 };
|
enum { QSG_LFGuild = 0 };
|
||||||
enum { QSG_LFGuild_PlayerMatches = 0, QSG_LFGuild_UpdatePlayerInfo, QSG_LFGuild_RequestPlayerInfo, QSG_LFGuild_UpdateGuildInfo, QSG_LFGuild_GuildMatches,
|
enum { QSG_LFGuild_PlayerMatches = 0, QSG_LFGuild_UpdatePlayerInfo, QSG_LFGuild_RequestPlayerInfo, QSG_LFGuild_UpdateGuildInfo, QSG_LFGuild_GuildMatches,
|
||||||
QSG_LFGuild_RequestGuildInfo };
|
QSG_LFGuild_RequestGuildInfo };
|
||||||
|
|
||||||
#define ServerOP_Speech 0x4513
|
|
||||||
|
|
||||||
/************ PACKET RELATED STRUCT ************/
|
/************ PACKET RELATED STRUCT ************/
|
||||||
class ServerPacket
|
class ServerPacket
|
||||||
{
|
{
|
||||||
@@ -248,6 +250,19 @@ public:
|
|||||||
_rpos = 0;
|
_rpos = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ServerPacket(uint16 in_opcode, SerializeBuffer &buf)
|
||||||
|
{
|
||||||
|
compressed = false;
|
||||||
|
size = buf.m_pos;
|
||||||
|
buf.m_pos = 0;
|
||||||
|
opcode = in_opcode;
|
||||||
|
pBuffer = buf.m_buffer;
|
||||||
|
buf.m_buffer = 0;
|
||||||
|
buf.m_capacity = 0;
|
||||||
|
_wpos = 0;
|
||||||
|
_rpos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
ServerPacket* Copy() {
|
ServerPacket* Copy() {
|
||||||
if (this == 0) {
|
if (this == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
@@ -1314,6 +1329,27 @@ struct UCSServerStatus_Struct {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
#pragma pack()
|
// shared task related communications
|
||||||
|
struct ServerSharedTaskMember_Struct { // used for various things we just need the ID and a name (add, remove, etc)
|
||||||
|
uint32 id;
|
||||||
|
char name[64];
|
||||||
|
};
|
||||||
|
// error constants
|
||||||
|
#define TASKJOINOOZ_CAN 0
|
||||||
|
#define TASKJOINOOZ_NOTASK 1
|
||||||
|
#define TASKJOINOOZ_HAVEONE 2
|
||||||
|
#define TASKJOINOOZ_LEVEL 3
|
||||||
|
#define TASKJOINOOZ_TIMER 4
|
||||||
|
|
||||||
#endif
|
/*
|
||||||
|
* Routing
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct RouteToMessage
|
||||||
|
{
|
||||||
|
char filter[32];
|
||||||
|
char identifier[32];
|
||||||
|
char id[32];
|
||||||
|
};
|
||||||
|
|
||||||
|
#pragma pack()
|
||||||
|
|||||||
@@ -0,0 +1,75 @@
|
|||||||
|
#include "service.h"
|
||||||
|
#include "event/event_loop.h"
|
||||||
|
#include "event/timer.h"
|
||||||
|
#include <thread>
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
struct EQ::Service::Impl
|
||||||
|
{
|
||||||
|
bool running;
|
||||||
|
std::string identifier;
|
||||||
|
size_t heartbeat_duration_ms;
|
||||||
|
size_t sleep_duration_ms;
|
||||||
|
std::unique_ptr<EQ::WorldConnection> world_connection;
|
||||||
|
std::unique_ptr<EQ::Timer> heartbeat_timer;
|
||||||
|
std::chrono::steady_clock::time_point last_time;
|
||||||
|
};
|
||||||
|
|
||||||
|
EQ::Service::Service(const std::string &identifier, size_t heartbeat_duration_ms, size_t sleep_duration_ms)
|
||||||
|
{
|
||||||
|
_impl.reset(new Impl());
|
||||||
|
_impl->running = false;
|
||||||
|
_impl->identifier = identifier;
|
||||||
|
_impl->heartbeat_duration_ms = heartbeat_duration_ms;
|
||||||
|
_impl->sleep_duration_ms = sleep_duration_ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
EQ::Service::~Service()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void EQ::Service::Run()
|
||||||
|
{
|
||||||
|
_impl->running = true;
|
||||||
|
|
||||||
|
OnStart();
|
||||||
|
|
||||||
|
//If start canceled our run then just quit, dont bother initializing everything else
|
||||||
|
if (!_impl->running) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_impl->world_connection.reset(new EQ::WorldConnection(_impl->identifier));
|
||||||
|
_impl->world_connection->SetOnRoutedMessageHandler([this](const std::string& filter, const std::string& identifier, const std::string& id, const EQ::Net::Packet& payload) {
|
||||||
|
OnRoutedMessage(filter, identifier, id, payload);
|
||||||
|
});
|
||||||
|
_impl->last_time = std::chrono::steady_clock::now();
|
||||||
|
|
||||||
|
_impl->heartbeat_timer.reset(new EQ::Timer(_impl->heartbeat_duration_ms, true, [this](EQ::Timer *t) {
|
||||||
|
auto now = std::chrono::steady_clock::now();
|
||||||
|
auto time_since = std::chrono::duration_cast<std::chrono::duration<double>>(now - _impl->last_time);
|
||||||
|
OnHeartbeat(time_since.count());
|
||||||
|
_impl->last_time = now;
|
||||||
|
}));
|
||||||
|
|
||||||
|
auto &loop = EQ::EventLoop::Get();
|
||||||
|
auto sleep_duration = _impl->sleep_duration_ms;
|
||||||
|
while (_impl->running) {
|
||||||
|
loop.Process();
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(sleep_duration));
|
||||||
|
}
|
||||||
|
|
||||||
|
_impl->heartbeat_timer.release();
|
||||||
|
_impl->world_connection.release();
|
||||||
|
|
||||||
|
OnStop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EQ::Service::RouteMessage(const std::string &filter, const std::string &id, const EQ::Net::Packet &p)
|
||||||
|
{
|
||||||
|
_impl->world_connection->RouteMessage(filter, id, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EQ::Service::Stop() {
|
||||||
|
_impl->running = false;
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "world_connection.h"
|
||||||
|
#include "net/packet.h"
|
||||||
|
#include "eqemu_logsys.h"
|
||||||
|
#include "platform.h"
|
||||||
|
#include "crash.h"
|
||||||
|
|
||||||
|
#define EQRegisterService(type) EQEmuLogSys LogSys; \
|
||||||
|
int main(int argc, char **argv) { \
|
||||||
|
LogSys.LoadLogSettingsDefaults(); \
|
||||||
|
set_exception_handler(); \
|
||||||
|
type srv; \
|
||||||
|
srv.Run(); \
|
||||||
|
return 0; \
|
||||||
|
} \
|
||||||
|
|
||||||
|
namespace EQ
|
||||||
|
{
|
||||||
|
class Service
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Service(const std::string &identifier, size_t heartbeat_duration_ms, size_t sleep_duration);
|
||||||
|
virtual ~Service();
|
||||||
|
|
||||||
|
void Run();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void OnStart() = 0;
|
||||||
|
virtual void OnStop() = 0;
|
||||||
|
virtual void OnHeartbeat(double time_since_last) = 0;
|
||||||
|
virtual void OnRoutedMessage(const std::string& filter, const std::string& identifier, const std::string& id, const EQ::Net::Packet& payload) = 0;
|
||||||
|
|
||||||
|
void RouteMessage(const std::string &filter, const std::string &id, const EQ::Net::Packet& p);
|
||||||
|
void Stop();
|
||||||
|
private:
|
||||||
|
struct Impl;
|
||||||
|
std::unique_ptr<Impl> _impl;
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
#include "world_connection.h"
|
||||||
|
#include "eqemu_config.h"
|
||||||
|
#include "string_util.h"
|
||||||
|
|
||||||
|
EQ::WorldConnection::WorldConnection(const std::string &type) {
|
||||||
|
auto config = EQEmuConfig::get();
|
||||||
|
|
||||||
|
m_connection.reset(new EQ::Net::ServertalkClient(config->WorldIP, config->WorldTCPPort, false, type, config->SharedKey));
|
||||||
|
m_connection->OnConnect([this](EQ::Net::ServertalkClient *client) {
|
||||||
|
if (m_on_connected) {
|
||||||
|
m_on_connected();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
m_connection->OnMessage(std::bind(&WorldConnection::_HandleMessage, this, std::placeholders::_1, std::placeholders::_2));
|
||||||
|
m_connection->OnMessage(ServerOP_RouteTo, std::bind(&WorldConnection::_HandleRoutedMessage, this, std::placeholders::_1, std::placeholders::_2));
|
||||||
|
}
|
||||||
|
|
||||||
|
EQ::WorldConnection::~WorldConnection() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void EQ::WorldConnection::SendPacket(ServerPacket* pack) {
|
||||||
|
m_connection->SendPacket(pack);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string EQ::WorldConnection::GetIP() const {
|
||||||
|
return m_connection->Handle()->RemoteIP();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16 EQ::WorldConnection::GetPort() const {
|
||||||
|
return m_connection->Handle()->RemotePort();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EQ::WorldConnection::Connected() const {
|
||||||
|
return m_connection->Connected();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EQ::WorldConnection::RouteMessage(const std::string &filter, const std::string &id, const EQ::Net::Packet& payload)
|
||||||
|
{
|
||||||
|
if (!m_connection->Connected()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto identifier = m_connection->GetIdentifier();
|
||||||
|
|
||||||
|
RouteToMessage msg;
|
||||||
|
strn0cpy(msg.filter, filter.c_str(), 32);
|
||||||
|
strn0cpy(msg.identifier, identifier.c_str(), 32);
|
||||||
|
strn0cpy(msg.id, id.c_str(), 32);
|
||||||
|
|
||||||
|
EQ::Net::DynamicPacket out;
|
||||||
|
out.Reserve(sizeof(RouteToMessage) + payload.Length());
|
||||||
|
out.PutData(0, &msg, sizeof(RouteToMessage));
|
||||||
|
out.PutPacket(sizeof(RouteToMessage), payload);
|
||||||
|
|
||||||
|
m_connection->Send(ServerOP_RouteTo, out);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EQ::WorldConnection::_HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
|
||||||
|
{
|
||||||
|
if (m_on_message) {
|
||||||
|
m_on_message(opcode, p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EQ::WorldConnection::_HandleRoutedMessage(uint16 opcode, const EQ::Net::Packet &p)
|
||||||
|
{
|
||||||
|
if (m_on_routed_message) {
|
||||||
|
auto msg = (RouteToMessage*)p.Data();
|
||||||
|
auto payload = p.GetPacket(sizeof(RouteToMessage), p.Length() - sizeof(RouteToMessage));
|
||||||
|
|
||||||
|
m_on_routed_message(msg->filter, msg->identifier, msg->id, payload);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "eq_packet_structs.h"
|
||||||
|
#include "net/servertalk_client_connection.h"
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
namespace EQ
|
||||||
|
{
|
||||||
|
class WorldConnection
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef std::function<void()> OnConnectedHandler;
|
||||||
|
typedef std::function<void(uint16, const EQ::Net::Packet&)> OnMessageHandler;
|
||||||
|
typedef std::function<void(const std::string&, const std::string&, const std::string&, const EQ::Net::Packet&)> OnRoutedMessageHandler;
|
||||||
|
|
||||||
|
WorldConnection(const std::string &type);
|
||||||
|
virtual ~WorldConnection();
|
||||||
|
|
||||||
|
void SendPacket(ServerPacket* pack);
|
||||||
|
std::string GetIP() const;
|
||||||
|
uint16 GetPort() const;
|
||||||
|
bool Connected() const;
|
||||||
|
|
||||||
|
void SetOnConnectedHandler(OnConnectedHandler handler) {
|
||||||
|
m_on_connected = handler;
|
||||||
|
};
|
||||||
|
|
||||||
|
void SetOnMessageHandler(OnMessageHandler handler) {
|
||||||
|
m_on_message = handler;
|
||||||
|
};
|
||||||
|
|
||||||
|
void SetOnRoutedMessageHandler(OnRoutedMessageHandler handler) {
|
||||||
|
m_on_routed_message = handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RouteMessage(const std::string &filter, const std::string &id, const EQ::Net::Packet& payload);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
OnConnectedHandler m_on_connected;
|
||||||
|
OnMessageHandler m_on_message;
|
||||||
|
OnRoutedMessageHandler m_on_routed_message;
|
||||||
|
std::unique_ptr<EQ::Net::ServertalkClient> m_connection;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void _HandleMessage(uint16 opcode, const EQ::Net::Packet& p);
|
||||||
|
void _HandleRoutedMessage(uint16 opcode, const EQ::Net::Packet& p);
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -25,16 +25,14 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
#include "zone_launch.h"
|
#include "zone_launch.h"
|
||||||
|
|
||||||
WorldServer::WorldServer(std::map<std::string, ZoneLaunch *> &zones, const char *name, const EQEmuConfig *config)
|
WorldServer::WorldServer(std::map<std::string, ZoneLaunch *> &zones, const char *name, const EQEmuConfig *config)
|
||||||
: m_name(name),
|
:
|
||||||
|
WorldConnection::WorldConnection("Launcher"),
|
||||||
|
m_name(name),
|
||||||
m_config(config),
|
m_config(config),
|
||||||
m_zones(zones)
|
m_zones(zones)
|
||||||
{
|
{
|
||||||
m_connection.reset(new EQ::Net::ServertalkClient(config->WorldIP, config->WorldTCPPort, false, "Launcher", config->SharedKey));
|
SetOnConnectedHandler(std::bind(&WorldServer::OnConnected, this));
|
||||||
m_connection->OnConnect([this](EQ::Net::ServertalkClient *client) {
|
SetOnMessageHandler(std::bind(&WorldServer::HandleMessage, this, std::placeholders::_1, std::placeholders::_2));
|
||||||
OnConnected();
|
|
||||||
});
|
|
||||||
|
|
||||||
m_connection->OnMessage(std::bind(&WorldServer::HandleMessage, this, std::placeholders::_1, std::placeholders::_2));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
WorldServer::~WorldServer() {
|
WorldServer::~WorldServer() {
|
||||||
@@ -57,19 +55,11 @@ void WorldServer::OnConnected() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldServer::HandleMessage(uint16 opcode, EQ::Net::Packet &p) {
|
void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
|
||||||
ServerPacket tpack(opcode, p);
|
ServerPacket tpack(opcode, p);
|
||||||
ServerPacket *pack = &tpack;
|
ServerPacket *pack = &tpack;
|
||||||
|
|
||||||
switch (opcode) {
|
switch (opcode) {
|
||||||
case 0: {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ServerOP_EmoteMessage:
|
|
||||||
case ServerOP_KeepAlive: {
|
|
||||||
// ignore this
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ServerOP_LauncherZoneRequest: {
|
case ServerOP_LauncherZoneRequest: {
|
||||||
if (pack->size != sizeof(LauncherZoneRequest)) {
|
if (pack->size != sizeof(LauncherZoneRequest)) {
|
||||||
Log(Logs::Detail, Logs::Launcher, "Invalid size of LauncherZoneRequest: %d", pack->size);
|
Log(Logs::Detail, Logs::Launcher, "Invalid size of LauncherZoneRequest: %d", pack->size);
|
||||||
@@ -126,8 +116,6 @@ void WorldServer::HandleMessage(uint16 opcode, EQ::Net::Packet &p) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void WorldServer::SendStatus(const char *short_name, uint32 start_count, bool running) {
|
void WorldServer::SendStatus(const char *short_name, uint32 start_count, bool running) {
|
||||||
auto pack = new ServerPacket(ServerOP_LauncherZoneStatus, sizeof(LauncherZoneStatus));
|
auto pack = new ServerPacket(ServerOP_LauncherZoneStatus, sizeof(LauncherZoneStatus));
|
||||||
LauncherZoneStatus* it = (LauncherZoneStatus*)pack->pBuffer;
|
LauncherZoneStatus* it = (LauncherZoneStatus*)pack->pBuffer;
|
||||||
|
|||||||
@@ -18,28 +18,23 @@
|
|||||||
#ifndef WORLDSERVER_H
|
#ifndef WORLDSERVER_H
|
||||||
#define WORLDSERVER_H
|
#define WORLDSERVER_H
|
||||||
|
|
||||||
#include "../common/net/servertalk_client_connection.h"
|
#include "../common/world_connection.h"
|
||||||
#include <memory>
|
|
||||||
#include <string>
|
|
||||||
#include <queue>
|
#include <queue>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
class ZoneLaunch;
|
class ZoneLaunch;
|
||||||
class EQEmuConfig;
|
class EQEmuConfig;
|
||||||
|
|
||||||
class WorldServer {
|
class WorldServer : public EQ::WorldConnection {
|
||||||
public:
|
public:
|
||||||
WorldServer(std::map<std::string, ZoneLaunch *> &zones, const char *name, const EQEmuConfig *config);
|
WorldServer(std::map<std::string, ZoneLaunch *> &zones, const char *name, const EQEmuConfig *config);
|
||||||
~WorldServer();
|
~WorldServer();
|
||||||
|
|
||||||
void HandleMessage(uint16 opcode, EQ::Net::Packet &p);
|
|
||||||
|
|
||||||
void SendStatus(const char *short_name, uint32 start_count, bool running);
|
void SendStatus(const char *short_name, uint32 start_count, bool running);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual void OnConnected();
|
void HandleMessage(uint16 opcode, const EQ::Net::Packet &p);
|
||||||
|
void OnConnected();
|
||||||
|
|
||||||
std::unique_ptr<EQ::Net::ServertalkClient> m_connection;
|
|
||||||
const char *const m_name;
|
const char *const m_name;
|
||||||
const EQEmuConfig *const m_config;
|
const EQEmuConfig *const m_config;
|
||||||
std::map<std::string, ZoneLaunch *> &m_zones;
|
std::map<std::string, ZoneLaunch *> &m_zones;
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
#include "../common/packet_dump.h"
|
#include "../common/packet_dump.h"
|
||||||
#include "../common/rulesys.h"
|
#include "../common/rulesys.h"
|
||||||
|
|
||||||
extern WorldServer *worldserver;
|
extern std::unique_ptr<WorldServer> worldserver;
|
||||||
extern Database database;
|
extern Database database;
|
||||||
|
|
||||||
PlayerLookingForGuild::PlayerLookingForGuild(char *Name, char *Comments, uint32 Level, uint32 Class, uint32 AACount, uint32 Timezone, uint32 TimePosted)
|
PlayerLookingForGuild::PlayerLookingForGuild(char *Name, char *Comments, uint32 Level, uint32 Class, uint32 AACount, uint32 Timezone, uint32 TimePosted)
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ Database database;
|
|||||||
LFGuildManager lfguildmanager;
|
LFGuildManager lfguildmanager;
|
||||||
std::string WorldShortName;
|
std::string WorldShortName;
|
||||||
const queryservconfig *Config;
|
const queryservconfig *Config;
|
||||||
WorldServer *worldserver = 0;
|
std::unique_ptr<WorldServer> worldserver;
|
||||||
EQEmuLogSys LogSys;
|
EQEmuLogSys LogSys;
|
||||||
|
|
||||||
void CatchSignal(int sig_num) {
|
void CatchSignal(int sig_num) {
|
||||||
@@ -88,8 +88,7 @@ int main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Initial Connection to Worldserver */
|
/* Initial Connection to Worldserver */
|
||||||
worldserver = new WorldServer;
|
worldserver.reset(new WorldServer());
|
||||||
worldserver->Connect();
|
|
||||||
|
|
||||||
/* Load Looking For Guild Manager */
|
/* Load Looking For Guild Manager */
|
||||||
lfguildmanager.LoadDatabase();
|
lfguildmanager.LoadDatabase();
|
||||||
|
|||||||
@@ -43,49 +43,18 @@ extern Database database;
|
|||||||
extern LFGuildManager lfguildmanager;
|
extern LFGuildManager lfguildmanager;
|
||||||
|
|
||||||
WorldServer::WorldServer()
|
WorldServer::WorldServer()
|
||||||
|
: WorldConnection::WorldConnection("QueryServ")
|
||||||
{
|
{
|
||||||
|
SetOnMessageHandler(std::bind(&WorldServer::HandleMessage, this, std::placeholders::_1, std::placeholders::_2));
|
||||||
}
|
}
|
||||||
|
|
||||||
WorldServer::~WorldServer()
|
WorldServer::~WorldServer()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldServer::Connect()
|
|
||||||
{
|
|
||||||
m_connection.reset(new EQ::Net::ServertalkClient(Config->WorldIP, Config->WorldTCPPort, false, "QueryServ", Config->SharedKey));
|
|
||||||
m_connection->OnMessage(std::bind(&WorldServer::HandleMessage, this, std::placeholders::_1, std::placeholders::_2));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool WorldServer::SendPacket(ServerPacket *pack)
|
|
||||||
{
|
|
||||||
m_connection->SendPacket(pack);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string WorldServer::GetIP() const
|
|
||||||
{
|
|
||||||
return m_connection->Handle()->RemoteIP();
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16 WorldServer::GetPort() const
|
|
||||||
{
|
|
||||||
return m_connection->Handle()->RemotePort();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool WorldServer::Connected() const
|
|
||||||
{
|
|
||||||
return m_connection->Connected();
|
|
||||||
}
|
|
||||||
|
|
||||||
void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
|
void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
|
||||||
{
|
{
|
||||||
switch (opcode) {
|
switch (opcode) {
|
||||||
case 0: {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ServerOP_KeepAlive: {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ServerOP_Speech: {
|
case ServerOP_Speech: {
|
||||||
Server_Speech_Struct *SSS = (Server_Speech_Struct*)p.Data();
|
Server_Speech_Struct *SSS = (Server_Speech_Struct*)p.Data();
|
||||||
std::string tmp1 = SSS->from;
|
std::string tmp1 = SSS->from;
|
||||||
|
|||||||
+3
-10
@@ -18,20 +18,13 @@
|
|||||||
#ifndef WORLDSERVER_H
|
#ifndef WORLDSERVER_H
|
||||||
#define WORLDSERVER_H
|
#define WORLDSERVER_H
|
||||||
|
|
||||||
#include "../common/eq_packet_structs.h"
|
#include "../common/world_connection.h"
|
||||||
#include "../common/net/servertalk_client_connection.h"
|
|
||||||
|
|
||||||
class WorldServer
|
class WorldServer : public EQ::WorldConnection
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
WorldServer();
|
WorldServer();
|
||||||
~WorldServer();
|
virtual ~WorldServer();
|
||||||
|
|
||||||
void Connect();
|
|
||||||
bool SendPacket(ServerPacket* pack);
|
|
||||||
std::string GetIP() const;
|
|
||||||
uint16 GetPort() const;
|
|
||||||
bool Connected() const;
|
|
||||||
|
|
||||||
void HandleMessage(uint16 opcode, const EQ::Net::Packet &p);
|
void HandleMessage(uint16 opcode, const EQ::Net::Packet &p);
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
|
||||||
|
|
||||||
|
SET(service_sources
|
||||||
|
tasks_database.cpp
|
||||||
|
tasks_service.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
SET(service_headers
|
||||||
|
tasks_database.h
|
||||||
|
tasks_service.h
|
||||||
|
)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(tasks_service ${service_sources} ${service_headers})
|
||||||
|
|
||||||
|
INSTALL(TARGETS tasks_service RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
|
||||||
|
|
||||||
|
TARGET_LINK_LIBRARIES(tasks_service ${SERVER_LIBS})
|
||||||
|
|
||||||
|
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
#include "tasks_database.h"
|
||||||
|
|
||||||
|
TasksDatabase::TasksDatabase()
|
||||||
|
: Database()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
TasksDatabase::TasksDatabase(const char* host, const char* user, const char* passwd, const char* database, uint32 port)
|
||||||
|
: Database(host, user, passwd, database, port)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
TasksDatabase::~TasksDatabase() {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../../common/global_define.h"
|
||||||
|
#include "../../common/types.h"
|
||||||
|
#include "../../common/database.h"
|
||||||
|
|
||||||
|
class TasksDatabase : public Database {
|
||||||
|
public:
|
||||||
|
TasksDatabase();
|
||||||
|
TasksDatabase(const char* host, const char* user, const char* passwd, const char* database, uint32 port);
|
||||||
|
~TasksDatabase();
|
||||||
|
};
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
#include "tasks_service.h"
|
||||||
|
#include "../../common/eqemu_logsys.h"
|
||||||
|
#include "../../common/eqemu_config.h"
|
||||||
|
|
||||||
|
EQ::TasksService::TasksService()
|
||||||
|
: EQ::Service("Tasks", 100, 1)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
EQ::TasksService::~TasksService() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void EQ::TasksService::OnStart() {
|
||||||
|
Log(Logs::General, Logs::Status, "Connecting to database...");
|
||||||
|
|
||||||
|
auto config = EQEmuConfig::get();
|
||||||
|
|
||||||
|
m_db.reset(new TasksDatabase());
|
||||||
|
|
||||||
|
auto r = m_db->Connect(
|
||||||
|
config->DatabaseHost.c_str(),
|
||||||
|
config->DatabaseUsername.c_str(),
|
||||||
|
config->DatabasePassword.c_str(),
|
||||||
|
config->DatabaseDB.c_str(),
|
||||||
|
config->DatabasePort);
|
||||||
|
|
||||||
|
if (false == r) {
|
||||||
|
Log(Logs::General, Logs::Status, "Unable to connect to database.");
|
||||||
|
Stop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log(Logs::General, Logs::Status, "Connected to database.");
|
||||||
|
|
||||||
|
m_db->LoadLogSettings(LogSys.log_settings);
|
||||||
|
LogSys.StartFileLogs();
|
||||||
|
|
||||||
|
//Load task info here
|
||||||
|
}
|
||||||
|
|
||||||
|
void EQ::TasksService::OnStop() {
|
||||||
|
m_db.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EQ::TasksService::OnHeartbeat(double time_since_last) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void EQ::TasksService::OnRoutedMessage(const std::string& filter, const std::string& identifier, const std::string& id, const EQ::Net::Packet& payload)
|
||||||
|
{
|
||||||
|
LogF(Logs::General, Logs::Status, "On routed message with payload size {0}", payload.Length());
|
||||||
|
|
||||||
|
//auto msg_type = payload.GetInt32(0);
|
||||||
|
//
|
||||||
|
//switch (msg_type) {
|
||||||
|
//case TaskGetClientTaskState:
|
||||||
|
//{
|
||||||
|
// Log(Logs::General, Logs::Status, "Task state request");
|
||||||
|
// auto req = payload.GetSerialize<GetClientTaskStateRequest>(4);
|
||||||
|
// //Get the task state request
|
||||||
|
// break;
|
||||||
|
//}
|
||||||
|
//default:
|
||||||
|
// break;
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
|
EQRegisterService(EQ::TasksService);
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../../common/service.h"
|
||||||
|
#include "tasks_database.h"
|
||||||
|
|
||||||
|
namespace EQ
|
||||||
|
{
|
||||||
|
class TasksService : public EQ::Service
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TasksService();
|
||||||
|
virtual ~TasksService();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void OnStart();
|
||||||
|
virtual void OnStop();
|
||||||
|
virtual void OnHeartbeat(double time_since_last);
|
||||||
|
virtual void OnRoutedMessage(const std::string& filter, const std::string& identifier, const std::string& id, const EQ::Net::Packet& payload);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unique_ptr<TasksDatabase> m_db;
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
|
||||||
|
|
||||||
|
SET(service_sources
|
||||||
|
test1_service.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
SET(service_headers
|
||||||
|
test1_service.h
|
||||||
|
)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(test1_service ${service_sources} ${service_headers})
|
||||||
|
|
||||||
|
INSTALL(TARGETS test1_service RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
|
||||||
|
|
||||||
|
TARGET_LINK_LIBRARIES(test1_service ${SERVER_LIBS})
|
||||||
|
|
||||||
|
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
#include "test1_service.h"
|
||||||
|
#include "../../common/eqemu_logsys.h"
|
||||||
|
#include "../../common/eqemu_config.h"
|
||||||
|
|
||||||
|
EQ::Test1Service::Test1Service()
|
||||||
|
: EQ::Service("Test1", 1, 1)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
struct TestPacket
|
||||||
|
{
|
||||||
|
int64_t f1;
|
||||||
|
int64_t f2;
|
||||||
|
int64_t f3;
|
||||||
|
int64_t f4;
|
||||||
|
int64_t f5;
|
||||||
|
int64_t f6;
|
||||||
|
int64_t f7;
|
||||||
|
char f8[4092];
|
||||||
|
|
||||||
|
template <class Archive>
|
||||||
|
void serialize(Archive &ar)
|
||||||
|
{
|
||||||
|
ar(f1, f2, f3, f4, f5, f6, f7, f8);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
EQ::Test1Service::~Test1Service() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void EQ::Test1Service::OnStart() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void EQ::Test1Service::OnStop() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void EQ::Test1Service::OnHeartbeat(double time_since_last) {
|
||||||
|
TestPacket p;
|
||||||
|
p.f1 = 33;
|
||||||
|
p.f2 = 43;
|
||||||
|
p.f3 = 56;
|
||||||
|
p.f4 = 90;
|
||||||
|
|
||||||
|
EQ::Net::DynamicPacket out;
|
||||||
|
out.PutInt32(0, 1234);
|
||||||
|
out.PutSerialize(4, p);
|
||||||
|
|
||||||
|
for (int i = 0; i < 250; ++i) {
|
||||||
|
RouteMessage("Test2", "", out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EQ::Test1Service::OnRoutedMessage(const std::string& filter, const std::string& identifier, const std::string& id, const EQ::Net::Packet& payload)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
EQRegisterService(EQ::Test1Service);
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../../common/service.h"
|
||||||
|
|
||||||
|
namespace EQ
|
||||||
|
{
|
||||||
|
class Test1Service : public EQ::Service
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Test1Service();
|
||||||
|
virtual ~Test1Service();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void OnStart();
|
||||||
|
virtual void OnStop();
|
||||||
|
virtual void OnHeartbeat(double time_since_last);
|
||||||
|
virtual void OnRoutedMessage(const std::string& filter, const std::string& identifier, const std::string& id, const EQ::Net::Packet& payload);
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
|
||||||
|
|
||||||
|
SET(service_sources
|
||||||
|
test2_service.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
SET(service_headers
|
||||||
|
test2_service.h
|
||||||
|
)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(test2_service ${service_sources} ${service_headers})
|
||||||
|
|
||||||
|
INSTALL(TARGETS test2_service RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
|
||||||
|
|
||||||
|
TARGET_LINK_LIBRARIES(test2_service ${SERVER_LIBS})
|
||||||
|
|
||||||
|
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
#include "test2_service.h"
|
||||||
|
#include "../../common/eqemu_logsys.h"
|
||||||
|
#include "../../common/eqemu_config.h"
|
||||||
|
|
||||||
|
EQ::Test2Service::Test2Service()
|
||||||
|
: EQ::Service("Test2", 3000, 1)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
EQ::Test2Service::~Test2Service() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void EQ::Test2Service::OnStart() {
|
||||||
|
bytes = 0;
|
||||||
|
packets = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EQ::Test2Service::OnStop() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void EQ::Test2Service::OnHeartbeat(double time_since_last) {
|
||||||
|
|
||||||
|
auto bytes_per_sec = bytes / time_since_last;
|
||||||
|
auto packets_per_sec = packets / time_since_last;
|
||||||
|
printf("Transfer rate %.2f KB/sec %.2f Packets/sec\n", bytes_per_sec / 1000.0, packets_per_sec);
|
||||||
|
|
||||||
|
bytes = 0;
|
||||||
|
packets = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EQ::Test2Service::OnRoutedMessage(const std::string& filter, const std::string& identifier, const std::string& id, const EQ::Net::Packet& payload)
|
||||||
|
{
|
||||||
|
bytes += sizeof(RouteToMessage);
|
||||||
|
bytes += payload.Length();
|
||||||
|
packets++;
|
||||||
|
}
|
||||||
|
|
||||||
|
EQRegisterService(EQ::Test2Service);
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../../common/service.h"
|
||||||
|
|
||||||
|
namespace EQ
|
||||||
|
{
|
||||||
|
class Test2Service : public EQ::Service
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Test2Service();
|
||||||
|
virtual ~Test2Service();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void OnStart();
|
||||||
|
virtual void OnStop();
|
||||||
|
virtual void OnHeartbeat(double time_since_last);
|
||||||
|
virtual void OnRoutedMessage(const std::string& filter, const std::string& identifier, const std::string& id, const EQ::Net::Packet& payload);
|
||||||
|
|
||||||
|
private:
|
||||||
|
size_t bytes;
|
||||||
|
size_t packets;
|
||||||
|
};
|
||||||
|
}
|
||||||
+2
-2
@@ -40,7 +40,7 @@ ChatChannelList *ChannelList;
|
|||||||
Clientlist *g_Clientlist;
|
Clientlist *g_Clientlist;
|
||||||
EQEmuLogSys LogSys;
|
EQEmuLogSys LogSys;
|
||||||
Database database;
|
Database database;
|
||||||
WorldServer *worldserver = nullptr;
|
std::unique_ptr<WorldServer> worldserver;
|
||||||
|
|
||||||
const ucsconfig *Config;
|
const ucsconfig *Config;
|
||||||
|
|
||||||
@@ -142,7 +142,7 @@ int main() {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
worldserver = new WorldServer;
|
worldserver.reset(new WorldServer());
|
||||||
|
|
||||||
while(RunLoops) {
|
while(RunLoops) {
|
||||||
|
|
||||||
|
|||||||
+3
-10
@@ -47,16 +47,16 @@ void Client50ToServerSayLink(std::string& serverSayLink, const std::string& clie
|
|||||||
void Client55ToServerSayLink(std::string& serverSayLink, const std::string& clientSayLink);
|
void Client55ToServerSayLink(std::string& serverSayLink, const std::string& clientSayLink);
|
||||||
|
|
||||||
WorldServer::WorldServer()
|
WorldServer::WorldServer()
|
||||||
|
: WorldConnection::WorldConnection("UCS")
|
||||||
{
|
{
|
||||||
m_connection.reset(new EQ::Net::ServertalkClient(Config->WorldIP, Config->WorldTCPPort, false, "UCS", Config->SharedKey));
|
SetOnMessageHandler(std::bind(&WorldServer::ProcessMessage, this, std::placeholders::_1, std::placeholders::_2));
|
||||||
m_connection->OnMessage(std::bind(&WorldServer::ProcessMessage, this, std::placeholders::_1, std::placeholders::_2));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
WorldServer::~WorldServer()
|
WorldServer::~WorldServer()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldServer::ProcessMessage(uint16 opcode, EQ::Net::Packet &p)
|
void WorldServer::ProcessMessage(uint16 opcode, const EQ::Net::Packet &p)
|
||||||
{
|
{
|
||||||
ServerPacket tpack(opcode, p);
|
ServerPacket tpack(opcode, p);
|
||||||
ServerPacket *pack = &tpack;
|
ServerPacket *pack = &tpack;
|
||||||
@@ -65,13 +65,6 @@ void WorldServer::ProcessMessage(uint16 opcode, EQ::Net::Packet &p)
|
|||||||
|
|
||||||
switch (opcode)
|
switch (opcode)
|
||||||
{
|
{
|
||||||
case 0: {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ServerOP_KeepAlive:
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ServerOP_UCSMessage:
|
case ServerOP_UCSMessage:
|
||||||
{
|
{
|
||||||
char *Buffer = (char *)pack->pBuffer;
|
char *Buffer = (char *)pack->pBuffer;
|
||||||
|
|||||||
+3
-9
@@ -18,20 +18,14 @@
|
|||||||
#ifndef WORLDSERVER_H
|
#ifndef WORLDSERVER_H
|
||||||
#define WORLDSERVER_H
|
#define WORLDSERVER_H
|
||||||
|
|
||||||
#include "../net/servertalk_client_connection.h"
|
#include "../world_connection.h"
|
||||||
#include "../common/eq_packet_structs.h"
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
class WorldServer
|
class WorldServer : public EQ::WorldConnection
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
WorldServer();
|
WorldServer();
|
||||||
~WorldServer();
|
~WorldServer();
|
||||||
void ProcessMessage(uint16 opcode, EQ::Net::Packet &);
|
void ProcessMessage(uint16 opcode, const EQ::Net::Packet &p);
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
std::unique_ptr<EQ::Net::ServertalkClient> m_connection;
|
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -563,6 +563,8 @@ OP_TaskHistoryRequest=0x6cf6
|
|||||||
OP_TaskHistoryReply=0x25eb
|
OP_TaskHistoryReply=0x25eb
|
||||||
OP_DeclineAllTasks=0x0000
|
OP_DeclineAllTasks=0x0000
|
||||||
OP_TaskRequestTimer=0x4b76
|
OP_TaskRequestTimer=0x4b76
|
||||||
|
OP_AcceptNewSharedTask=0x3e5e
|
||||||
|
OP_SharedTaskMemberList=0x4ddb
|
||||||
|
|
||||||
# Title opcodes
|
# Title opcodes
|
||||||
OP_NewTitlesAvailable=0x45d1
|
OP_NewTitlesAvailable=0x45d1
|
||||||
|
|||||||
@@ -568,6 +568,8 @@ OP_TaskHistoryRequest=0x5f1c
|
|||||||
OP_TaskHistoryReply=0x3d05
|
OP_TaskHistoryReply=0x3d05
|
||||||
OP_DeclineAllTasks=0x0000
|
OP_DeclineAllTasks=0x0000
|
||||||
OP_TaskRequestTimer=0x7a48
|
OP_TaskRequestTimer=0x7a48
|
||||||
|
OP_AcceptNewSharedTask=0x6646
|
||||||
|
OP_SharedTaskMemberList=0x1e7d
|
||||||
|
|
||||||
# Title opcodes
|
# Title opcodes
|
||||||
OP_NewTitlesAvailable=0x0d32
|
OP_NewTitlesAvailable=0x0d32
|
||||||
|
|||||||
@@ -534,6 +534,8 @@ OP_TaskHistoryReply=0x3d2a # C
|
|||||||
OP_CancelTask=0x726b # C
|
OP_CancelTask=0x726b # C
|
||||||
OP_DeclineAllTasks=0x0000 #
|
OP_DeclineAllTasks=0x0000 #
|
||||||
OP_TaskRequestTimer=0x2e70
|
OP_TaskRequestTimer=0x2e70
|
||||||
|
OP_AcceptNewSharedTask=0x4751
|
||||||
|
OP_SharedTaskMemberList=0x55f4
|
||||||
|
|
||||||
|
|
||||||
OP_Shroud=0x6d1f
|
OP_Shroud=0x6d1f
|
||||||
|
|||||||
@@ -500,7 +500,7 @@ OP_TaskHistoryRequest=0x3035 #
|
|||||||
OP_TaskHistoryReply=0x3A60 #
|
OP_TaskHistoryReply=0x3A60 #
|
||||||
OP_CancelTask=0x4db6 #Xinu or 0x2c8c or 0x4db6
|
OP_CancelTask=0x4db6 #Xinu or 0x2c8c or 0x4db6
|
||||||
OP_DeclineAllTasks=0x0000 #not sure, 12 bytes
|
OP_DeclineAllTasks=0x0000 #not sure, 12 bytes
|
||||||
OP_TaskMemberList=0x3713
|
#OP_TaskMemberList=0x3713
|
||||||
OP_TaskMemberInvite=0x3cde
|
OP_TaskMemberInvite=0x3cde
|
||||||
OP_TaskMemberInviteResponse=0x6cab
|
OP_TaskMemberInviteResponse=0x6cab
|
||||||
OP_TaskMemberChange=0x354a
|
OP_TaskMemberChange=0x354a
|
||||||
@@ -510,6 +510,8 @@ OP_TaskRemovePlayer=0x516f
|
|||||||
OP_TaskPlayerList=0x0ad6
|
OP_TaskPlayerList=0x0ad6
|
||||||
OP_TaskQuit=0x2c8c
|
OP_TaskQuit=0x2c8c
|
||||||
OP_TaskRequestTimer=0x0b08
|
OP_TaskRequestTimer=0x0b08
|
||||||
|
OP_AcceptNewSharedTask=0x5bed
|
||||||
|
OP_SharedTaskMemberList=0x3713
|
||||||
|
|
||||||
#Title opcodes
|
#Title opcodes
|
||||||
OP_NewTitlesAvailable=0x179c #
|
OP_NewTitlesAvailable=0x179c #
|
||||||
|
|||||||
@@ -458,7 +458,7 @@ OP_TaskActivityComplete=0x54eb
|
|||||||
OP_CompletedTasks=0x76a2 # ShowEQ 10/27/05
|
OP_CompletedTasks=0x76a2 # ShowEQ 10/27/05
|
||||||
OP_TaskDescription=0x5ef7 # ShowEQ 10/27/05
|
OP_TaskDescription=0x5ef7 # ShowEQ 10/27/05
|
||||||
OP_TaskActivity=0x682d # ShowEQ 10/27/05
|
OP_TaskActivity=0x682d # ShowEQ 10/27/05
|
||||||
OP_TaskMemberList=0x722f #not sure
|
#OP_TaskMemberList=0x722f #not sure
|
||||||
OP_OpenNewTasksWindow=0x5e7c #combined with OP_AvaliableTask I think
|
OP_OpenNewTasksWindow=0x5e7c #combined with OP_AvaliableTask I think
|
||||||
OP_AvaliableTask=0x0000
|
OP_AvaliableTask=0x0000
|
||||||
OP_AcceptNewTask=0x207f
|
OP_AcceptNewTask=0x207f
|
||||||
@@ -475,6 +475,8 @@ OP_TaskRemovePlayer=0x37b9
|
|||||||
OP_TaskPlayerList=0x3961
|
OP_TaskPlayerList=0x3961
|
||||||
OP_TaskQuit=0x35dd
|
OP_TaskQuit=0x35dd
|
||||||
OP_TaskRequestTimer=0x6a1d
|
OP_TaskRequestTimer=0x6a1d
|
||||||
|
OP_AcceptNewSharedTask=0x194d
|
||||||
|
OP_SharedTaskMemberList=0x722f
|
||||||
#task complete related: 0x0000 (24 bytes), 0x0000 (8 bytes), 0x0000 (4 bytes)
|
#task complete related: 0x0000 (24 bytes), 0x0000 (8 bytes), 0x0000 (4 bytes)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -557,6 +557,8 @@ OP_TaskHistoryReply=0x4524 # C
|
|||||||
OP_CancelTask=0x3bf5 # C
|
OP_CancelTask=0x3bf5 # C
|
||||||
OP_DeclineAllTasks=0x0000 #
|
OP_DeclineAllTasks=0x0000 #
|
||||||
OP_TaskRequestTimer=0x719e
|
OP_TaskRequestTimer=0x719e
|
||||||
|
OP_AcceptNewSharedTask=0x6ded
|
||||||
|
OP_SharedTaskMemberList=0x584e
|
||||||
|
|
||||||
# Title opcodes
|
# Title opcodes
|
||||||
OP_NewTitlesAvailable=0x4b49 # C
|
OP_NewTitlesAvailable=0x4b49 # C
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
ALTER TABLE `tasks` ADD `reward_points` INT NOT NULL DEFAULT '0' AFTER `rewardmethod`;
|
||||||
|
ALTER TABLE `tasks` ADD `reward_type` INT NOT NULL DEFAULT '0' AFTER `reward_points`;
|
||||||
|
ALTER TABLE `tasks` ADD `replay_group` INT NOT NULL DEFAULT '0';
|
||||||
|
ALTER TABLE `tasks` ADD `min_players` INT NOT NULL DEFAULT '0';
|
||||||
|
ALTER TABLE `tasks` ADD `max_players` INT NOT NULL DEFAULT '0';
|
||||||
|
ALTER TABLE `tasks` ADD `task_lock_step` INT NOT NULL DEFAULT '0';
|
||||||
|
ALTER TABLE `tasks` ADD `instance_zone_id` INT NOT NULL DEFAULT '0';
|
||||||
|
ALTER TABLE `tasks` ADD `zone_version` INT NOT NULL DEFAULT '0';
|
||||||
|
ALTER TABLE `tasks` ADD `zone_in_zone_id` INT NOT NULL DEFAULT '0';
|
||||||
|
ALTER TABLE `tasks` ADD `zone_in_x` FLOAT NOT NULL DEFAULT '0';
|
||||||
|
ALTER TABLE `tasks` ADD `zone_in_y` FLOAT NOT NULL DEFAULT '0';
|
||||||
|
ALTER TABLE `tasks` ADD `zone_in_object_id` TINYINT NOT NULL DEFAULT '0';
|
||||||
|
ALTER TABLE `tasks` ADD `dest_x` FLOAT NOT NULL DEFAULT '0';
|
||||||
|
ALTER TABLE `tasks` ADD `dest_y` FLOAT NOT NULL DEFAULT '0';
|
||||||
|
ALTER TABLE `tasks` ADD `dest_z` FLOAT NOT NULL DEFAULT '0';
|
||||||
|
ALTER TABLE `tasks` ADD `dest_h` FLOAT NOT NULL DEFAULT '0';
|
||||||
|
CREATE TABLE `task_replay_groups` (
|
||||||
|
`id` INT NOT NULL,
|
||||||
|
`duration` INT NOT NULL,
|
||||||
|
`name` VARCHAR(128) NOT NULL DEFAULT '',
|
||||||
|
PRIMARY KEY(`id`)
|
||||||
|
);
|
||||||
|
CREATE TABLE `character_task_lockouts` (
|
||||||
|
`character_id` INT NOT NULL,
|
||||||
|
`replay_group` INT NOT NULL,
|
||||||
|
`original_id` INT NOT NULL,
|
||||||
|
`timestamp` INT NOT NULL,
|
||||||
|
PRIMARY KEY(`character_id`, `replay_group`)
|
||||||
|
);
|
||||||
|
CREATE TABLE `shared_task_state` (
|
||||||
|
`id` INT NOT NULL,
|
||||||
|
`task_id` INT NOT NULL,
|
||||||
|
`accepted_time` INT NOT NULL,
|
||||||
|
`is_locked` TINYINT NOT NULL DEFAULT '0',
|
||||||
|
PRIMARY KEY(`id`)
|
||||||
|
);
|
||||||
|
CREATE TABLE `shared_task_activities` (
|
||||||
|
`shared_task_id` INT NOT NULL,
|
||||||
|
`activity_id` INT NOT NULL,
|
||||||
|
`done_count` INT NOT NULL,
|
||||||
|
`completed` TINYINT,
|
||||||
|
PRIMARY KEY(`shared_task_id`, `activity_id`)
|
||||||
|
);
|
||||||
|
CREATE TABLE `shared_task_members` (
|
||||||
|
`shared_task_id` INT NOT NULL,
|
||||||
|
`character_id` INT NOT NULL,
|
||||||
|
`character_name` VARCHAR(64) NOT NULL,
|
||||||
|
`is_leader` TINYINT DEFAULT 0,
|
||||||
|
PRIMARY KEY(shared_task_id, character_id)
|
||||||
|
);
|
||||||
@@ -15,6 +15,8 @@ SET(world_sources
|
|||||||
login_server_list.cpp
|
login_server_list.cpp
|
||||||
net.cpp
|
net.cpp
|
||||||
queryserv.cpp
|
queryserv.cpp
|
||||||
|
router.cpp
|
||||||
|
shared_tasks.cpp
|
||||||
ucs.cpp
|
ucs.cpp
|
||||||
web_interface.cpp
|
web_interface.cpp
|
||||||
web_interface_eqw.cpp
|
web_interface_eqw.cpp
|
||||||
@@ -42,6 +44,8 @@ SET(world_headers
|
|||||||
login_server_list.h
|
login_server_list.h
|
||||||
net.h
|
net.h
|
||||||
queryserv.h
|
queryserv.h
|
||||||
|
router.h
|
||||||
|
shared_tasks.h
|
||||||
sof_char_create_data.h
|
sof_char_create_data.h
|
||||||
ucs.h
|
ucs.h
|
||||||
web_interface.h
|
web_interface.h
|
||||||
|
|||||||
@@ -1221,6 +1221,7 @@ void Client::EnterWorld(bool TryBootup) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cle->SetChar(charid, char_name);
|
cle->SetChar(charid, char_name);
|
||||||
|
cle->LoadTaskLockouts();
|
||||||
database.UpdateLiveChar(char_name, GetAccountID());
|
database.UpdateLiveChar(char_name, GetAccountID());
|
||||||
|
|
||||||
Log(Logs::General, Logs::World_Server,
|
Log(Logs::General, Logs::World_Server,
|
||||||
|
|||||||
@@ -25,6 +25,9 @@
|
|||||||
#include "world_config.h"
|
#include "world_config.h"
|
||||||
#include "../common/guilds.h"
|
#include "../common/guilds.h"
|
||||||
#include "../common/string_util.h"
|
#include "../common/string_util.h"
|
||||||
|
#include "shared_tasks.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
extern uint32 numplayers;
|
extern uint32 numplayers;
|
||||||
extern LoginServerList loginserverlist;
|
extern LoginServerList loginserverlist;
|
||||||
@@ -50,6 +53,8 @@ ClientListEntry::ClientListEntry(uint32 in_id, uint32 iLSID, const char* iLoginN
|
|||||||
pLFGToLevel = 0;
|
pLFGToLevel = 0;
|
||||||
pLFGMatchFilter = false;
|
pLFGMatchFilter = false;
|
||||||
memset(pLFGComments, 0, 64);
|
memset(pLFGComments, 0, 64);
|
||||||
|
shared_task_id = 0;
|
||||||
|
m_shared_task = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
ClientListEntry::ClientListEntry(uint32 in_id, uint32 iAccID, const char* iAccName, MD5& iMD5Pass, int16 iAdmin)
|
ClientListEntry::ClientListEntry(uint32 in_id, uint32 iAccID, const char* iAccName, MD5& iMD5Pass, int16 iAdmin)
|
||||||
@@ -71,6 +76,8 @@ ClientListEntry::ClientListEntry(uint32 in_id, uint32 iAccID, const char* iAccNa
|
|||||||
pLFGToLevel = 0;
|
pLFGToLevel = 0;
|
||||||
pLFGMatchFilter = false;
|
pLFGMatchFilter = false;
|
||||||
memset(pLFGComments, 0, 64);
|
memset(pLFGComments, 0, 64);
|
||||||
|
shared_task_id = 0;
|
||||||
|
m_shared_task = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
ClientListEntry::ClientListEntry(uint32 in_id, ZoneServer* iZS, ServerClientList_Struct* scl, int8 iOnline)
|
ClientListEntry::ClientListEntry(uint32 in_id, ZoneServer* iZS, ServerClientList_Struct* scl, int8 iOnline)
|
||||||
@@ -93,6 +100,8 @@ ClientListEntry::ClientListEntry(uint32 in_id, ZoneServer* iZS, ServerClientList
|
|||||||
pLFGToLevel = 0;
|
pLFGToLevel = 0;
|
||||||
pLFGMatchFilter = false;
|
pLFGMatchFilter = false;
|
||||||
memset(pLFGComments, 0, 64);
|
memset(pLFGComments, 0, 64);
|
||||||
|
shared_task_id = 0;
|
||||||
|
m_shared_task = nullptr;
|
||||||
|
|
||||||
if (iOnline >= CLE_Status_Zoning)
|
if (iOnline >= CLE_Status_Zoning)
|
||||||
Update(iZS, scl, iOnline);
|
Update(iZS, scl, iOnline);
|
||||||
@@ -105,6 +114,8 @@ ClientListEntry::~ClientListEntry() {
|
|||||||
Camp(); // updates zoneserver's numplayers
|
Camp(); // updates zoneserver's numplayers
|
||||||
client_list.RemoveCLEReferances(this);
|
client_list.RemoveCLEReferances(this);
|
||||||
}
|
}
|
||||||
|
if (m_shared_task != nullptr)
|
||||||
|
m_shared_task->MemberLeftGame(this);
|
||||||
for (auto &elem : tell_queue)
|
for (auto &elem : tell_queue)
|
||||||
safe_delete_array(elem);
|
safe_delete_array(elem);
|
||||||
tell_queue.clear();
|
tell_queue.clear();
|
||||||
@@ -248,6 +259,8 @@ void ClientListEntry::ClearVars(bool iAll) {
|
|||||||
pLFG = 0;
|
pLFG = 0;
|
||||||
gm = 0;
|
gm = 0;
|
||||||
pClientVersion = 0;
|
pClientVersion = 0;
|
||||||
|
shared_task_id = 0;
|
||||||
|
m_shared_task = nullptr;
|
||||||
for (auto &elem : tell_queue)
|
for (auto &elem : tell_queue)
|
||||||
safe_delete_array(elem);
|
safe_delete_array(elem);
|
||||||
tell_queue.clear();
|
tell_queue.clear();
|
||||||
@@ -261,6 +274,9 @@ void ClientListEntry::Camp(ZoneServer* iZS) {
|
|||||||
LSUpdate(pzoneserver);
|
LSUpdate(pzoneserver);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_shared_task != nullptr)
|
||||||
|
m_shared_task->MemberLeftGame(this);
|
||||||
|
|
||||||
ClearVars();
|
ClearVars();
|
||||||
|
|
||||||
stale = 0;
|
stale = 0;
|
||||||
@@ -331,3 +347,72 @@ void ClientListEntry::ProcessTellQueue()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* returns expire timestamp
|
||||||
|
*/
|
||||||
|
|
||||||
|
int ClientListEntry::GetTaskLockoutExpire(int id) const
|
||||||
|
{
|
||||||
|
auto it = std::find_if(m_task_replay_timers.begin(), m_task_replay_timers.end(),
|
||||||
|
[id](const TaskTimer &a) { return a.ID == id; });
|
||||||
|
|
||||||
|
if (it != m_task_replay_timers.end())
|
||||||
|
return it->expires;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* returns seconds until expires
|
||||||
|
* returns <= 0 if expired
|
||||||
|
*/
|
||||||
|
|
||||||
|
int ClientListEntry::GetTaskLockoutTimeLeft(int id) const
|
||||||
|
{
|
||||||
|
auto it = std::find_if(m_task_replay_timers.begin(), m_task_replay_timers.end(),
|
||||||
|
[id](const TaskTimer &a) { return a.ID == id; });
|
||||||
|
|
||||||
|
if (it != m_task_replay_timers.end())
|
||||||
|
return it->expires - time(nullptr);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Cleans up expired lockouts from the DB
|
||||||
|
*/
|
||||||
|
bool ClientListEntry::CleanExpiredTaskLockouts() const
|
||||||
|
{
|
||||||
|
std::string query =
|
||||||
|
StringFormat("DELETE FROM `character_task_lockouts` WHERE `character_id` = %i AND `timestamp` > %i", pcharid,
|
||||||
|
Timer::GetCurrentTime());
|
||||||
|
auto results = database.QueryDatabase(query);
|
||||||
|
return results.Success();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Loads task lockouts
|
||||||
|
*/
|
||||||
|
bool ClientListEntry::LoadTaskLockouts()
|
||||||
|
{
|
||||||
|
CleanExpiredTaskLockouts();
|
||||||
|
std::string query = StringFormat(
|
||||||
|
"SELECT `replay_group`, `original_id`, `timestamp` FROM `character_task_lockouts` WHERE `character_id` = %i",
|
||||||
|
pcharid);
|
||||||
|
auto results = database.QueryDatabase(query);
|
||||||
|
if (!results.Success())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (results.RowCount() > 0) {
|
||||||
|
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||||
|
TaskTimer t;
|
||||||
|
t.ID = atoi(row[0]);
|
||||||
|
t.original_id = atoi(row[1]);
|
||||||
|
t.expires = atoi(row[2]);
|
||||||
|
m_task_replay_timers.push_back(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
//#include "../common/eq_packet_structs.h"
|
//#include "../common/eq_packet_structs.h"
|
||||||
#include "../common/servertalk.h"
|
#include "../common/servertalk.h"
|
||||||
#include "../common/rulesys.h"
|
#include "../common/rulesys.h"
|
||||||
|
#include "../common/global_tasks.h"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
|
||||||
@@ -18,6 +19,7 @@
|
|||||||
|
|
||||||
class ZoneServer;
|
class ZoneServer;
|
||||||
struct ServerClientList_Struct;
|
struct ServerClientList_Struct;
|
||||||
|
class SharedTask;
|
||||||
|
|
||||||
class ClientListEntry {
|
class ClientListEntry {
|
||||||
public:
|
public:
|
||||||
@@ -88,6 +90,17 @@ public:
|
|||||||
inline void PushToTellQueue(ServerChannelMessage_Struct *scm) { tell_queue.push_back(scm); }
|
inline void PushToTellQueue(ServerChannelMessage_Struct *scm) { tell_queue.push_back(scm); }
|
||||||
void ProcessTellQueue();
|
void ProcessTellQueue();
|
||||||
|
|
||||||
|
// shared task stuff
|
||||||
|
bool CleanExpiredTaskLockouts() const;
|
||||||
|
bool LoadTaskLockouts();
|
||||||
|
int GetTaskLockoutExpire(int id) const;
|
||||||
|
int GetTaskLockoutTimeLeft(int id) const;
|
||||||
|
inline int GetCurrentSharedTaskID() const { return shared_task_id; }
|
||||||
|
inline void SetCurrentSharedTaskID(int in) { shared_task_id = in; }
|
||||||
|
inline bool HasFreeSharedTaskSlot() const { return shared_task_id == 0; }
|
||||||
|
inline void SetSharedTask(SharedTask *in) { m_shared_task = in; }
|
||||||
|
inline SharedTask *GetSharedTask() const { return m_shared_task; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void ClearVars(bool iAll = false);
|
void ClearVars(bool iAll = false);
|
||||||
|
|
||||||
@@ -129,6 +142,13 @@ private:
|
|||||||
bool pLFGMatchFilter;
|
bool pLFGMatchFilter;
|
||||||
char pLFGComments[64];
|
char pLFGComments[64];
|
||||||
|
|
||||||
|
// shared task stuff
|
||||||
|
// stub for now
|
||||||
|
int shared_task_id; // ID in the TaskManager
|
||||||
|
SharedTask *m_shared_task; // just for quick reference so we can tell it to clean up our pointer
|
||||||
|
|
||||||
|
std::vector<TaskTimer> m_task_replay_timers;
|
||||||
|
|
||||||
// Tell Queue -- really a vector :D
|
// Tell Queue -- really a vector :D
|
||||||
std::vector<ServerChannelMessage_Struct *> tell_queue;
|
std::vector<ServerChannelMessage_Struct *> tell_queue;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -72,12 +72,6 @@ void LauncherLink::ProcessMessage(uint16 opcode, EQ::Net::Packet &p)
|
|||||||
ServerPacket *pack = &tpack;
|
ServerPacket *pack = &tpack;
|
||||||
|
|
||||||
switch (opcode) {
|
switch (opcode) {
|
||||||
case 0:
|
|
||||||
break;
|
|
||||||
case ServerOP_KeepAlive: {
|
|
||||||
// ignore this
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ServerOP_ZAAuth: {
|
case ServerOP_ZAAuth: {
|
||||||
Log(Logs::Detail, Logs::World_Server, "Got authentication from %s when they are already authenticated.", m_name.c_str());
|
Log(Logs::Detail, Logs::World_Server, "Got authentication from %s when they are already authenticated.", m_name.c_str());
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -83,6 +83,8 @@ union semun {
|
|||||||
#include "queryserv.h"
|
#include "queryserv.h"
|
||||||
#include "web_interface.h"
|
#include "web_interface.h"
|
||||||
#include "console.h"
|
#include "console.h"
|
||||||
|
#include "shared_tasks.h"
|
||||||
|
#include "router.h"
|
||||||
|
|
||||||
#include "../common/net/servertalk_server.h"
|
#include "../common/net/servertalk_server.h"
|
||||||
#include "../zone/data_bucket.h"
|
#include "../zone/data_bucket.h"
|
||||||
@@ -103,6 +105,7 @@ bool holdzones = false;
|
|||||||
const WorldConfig *Config;
|
const WorldConfig *Config;
|
||||||
EQEmuLogSys LogSys;
|
EQEmuLogSys LogSys;
|
||||||
WebInterfaceList web_interface;
|
WebInterfaceList web_interface;
|
||||||
|
SharedTaskManager shared_tasks;
|
||||||
|
|
||||||
void CatchSignal(int sig_num);
|
void CatchSignal(int sig_num);
|
||||||
void CheckForServerScript(bool force_download = false);
|
void CheckForServerScript(bool force_download = false);
|
||||||
@@ -394,6 +397,9 @@ int main(int argc, char** argv) {
|
|||||||
adventure_manager.Load();
|
adventure_manager.Load();
|
||||||
adventure_manager.LoadLeaderboardInfo();
|
adventure_manager.LoadLeaderboardInfo();
|
||||||
|
|
||||||
|
shared_tasks.LoadSharedTasks();
|
||||||
|
shared_tasks.LoadSharedTaskState();
|
||||||
|
|
||||||
Log(Logs::General, Logs::World_Server, "Purging expired instances");
|
Log(Logs::General, Logs::World_Server, "Purging expired instances");
|
||||||
database.PurgeExpiredInstances();
|
database.PurgeExpiredInstances();
|
||||||
|
|
||||||
@@ -414,6 +420,7 @@ int main(int argc, char** argv) {
|
|||||||
std::unique_ptr<EQ::Net::ServertalkServer> server_connection;
|
std::unique_ptr<EQ::Net::ServertalkServer> server_connection;
|
||||||
server_connection.reset(new EQ::Net::ServertalkServer());
|
server_connection.reset(new EQ::Net::ServertalkServer());
|
||||||
|
|
||||||
|
Router router;
|
||||||
EQ::Net::ServertalkServerOptions server_opts;
|
EQ::Net::ServertalkServerOptions server_opts;
|
||||||
server_opts.port = Config->WorldTCPPort;
|
server_opts.port = Config->WorldTCPPort;
|
||||||
server_opts.ipv6 = false;
|
server_opts.ipv6 = false;
|
||||||
@@ -497,6 +504,20 @@ int main(int argc, char** argv) {
|
|||||||
web_interface.RemoveConnection(connection);
|
web_interface.RemoveConnection(connection);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
server_connection->OnConnectionIdentified([&router](std::shared_ptr<EQ::Net::ServertalkServerConnection> connection) {
|
||||||
|
LogF(Logs::General, Logs::World_Server, "New connection from {0} with identifier {1}",
|
||||||
|
connection->GetUUID(), connection->GetIdentifier());
|
||||||
|
|
||||||
|
router.AddConnection(connection);
|
||||||
|
});
|
||||||
|
|
||||||
|
server_connection->OnConnectionRemoved([&router](std::shared_ptr<EQ::Net::ServertalkServerConnection> connection) {
|
||||||
|
LogF(Logs::General, Logs::World_Server, "Removed connection from {0} with identifier {1}",
|
||||||
|
connection->GetUUID(), connection->GetIdentifier());
|
||||||
|
|
||||||
|
router.RemoveConnection(connection);
|
||||||
|
});
|
||||||
|
|
||||||
EQ::Net::EQStreamManagerOptions opts(9000, false, false);
|
EQ::Net::EQStreamManagerOptions opts(9000, false, false);
|
||||||
opts.daybreak_options.resend_delay_ms = RuleI(Network, ResendDelayBaseMS);
|
opts.daybreak_options.resend_delay_ms = RuleI(Network, ResendDelayBaseMS);
|
||||||
opts.daybreak_options.resend_delay_factor = RuleR(Network, ResendDelayFactor);
|
opts.daybreak_options.resend_delay_factor = RuleR(Network, ResendDelayFactor);
|
||||||
|
|||||||
@@ -0,0 +1,73 @@
|
|||||||
|
#include "router.h"
|
||||||
|
#include "../common/string_util.h"
|
||||||
|
|
||||||
|
Router::Router()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Router::~Router()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Router::AddConnection(std::shared_ptr<EQ::Net::ServertalkServerConnection> connection)
|
||||||
|
{
|
||||||
|
m_connections.push_back(connection);
|
||||||
|
connection->OnMessage(ServerOP_RouteTo, std::bind(&Router::OnRouterMessage, this, connection, std::placeholders::_1, std::placeholders::_2));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Router::RemoveConnection(std::shared_ptr<EQ::Net::ServertalkServerConnection> connection)
|
||||||
|
{
|
||||||
|
auto iter = m_connections.begin();
|
||||||
|
while (iter != m_connections.end()) {
|
||||||
|
if ((*iter) == connection) {
|
||||||
|
m_connections.erase(iter);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
iter++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Router::OnRouterMessage(std::shared_ptr<EQ::Net::ServertalkServerConnection> connection, uint16 opcode, const EQ::Net::Packet &p)
|
||||||
|
{
|
||||||
|
auto msg = (RouteToMessage*)p.Data();
|
||||||
|
char to_id[32];
|
||||||
|
strn0cpy(to_id, msg->id, 32);
|
||||||
|
|
||||||
|
strn0cpy(msg->id, connection->GetUUID().c_str(), 32);
|
||||||
|
|
||||||
|
|
||||||
|
if (to_id[0] != '\0' && msg->filter[0] != '\0') {
|
||||||
|
for (auto &connection : m_connections) {
|
||||||
|
auto id = connection->GetUUID();
|
||||||
|
auto identifier = connection->GetIdentifier();
|
||||||
|
if (strcmp(to_id, id.c_str()) == 0) {
|
||||||
|
connection->Send(ServerOP_RouteTo, p);
|
||||||
|
}
|
||||||
|
else if (strcmp(msg->filter, identifier.c_str()) == 0) {
|
||||||
|
connection->Send(ServerOP_RouteTo, p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (msg->filter[0] != '\0') {
|
||||||
|
for (auto &connection : m_connections) {
|
||||||
|
auto identifier = connection->GetIdentifier();
|
||||||
|
if (strcmp(msg->filter, identifier.c_str()) == 0) {
|
||||||
|
connection->Send(ServerOP_RouteTo, p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (to_id[0] != '\0') {
|
||||||
|
for (auto &connection : m_connections) {
|
||||||
|
auto id = connection->GetUUID();
|
||||||
|
if (strcmp(to_id, id.c_str()) == 0) {
|
||||||
|
connection->Send(ServerOP_RouteTo, p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (auto &connection : m_connections) {
|
||||||
|
connection->Send(ServerOP_RouteTo, p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../common/net/servertalk_server_connection.h"
|
||||||
|
#include <memory>
|
||||||
|
#include <list>
|
||||||
|
|
||||||
|
class Router
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Router();
|
||||||
|
~Router();
|
||||||
|
|
||||||
|
void AddConnection(std::shared_ptr<EQ::Net::ServertalkServerConnection> connection);
|
||||||
|
void RemoveConnection(std::shared_ptr<EQ::Net::ServertalkServerConnection> connection);
|
||||||
|
private:
|
||||||
|
std::list<std::shared_ptr<EQ::Net::ServertalkServerConnection>> m_connections;
|
||||||
|
|
||||||
|
void OnRouterMessage(std::shared_ptr<EQ::Net::ServertalkServerConnection> connection, uint16 opcode, const EQ::Net::Packet &p);
|
||||||
|
};
|
||||||
@@ -0,0 +1,535 @@
|
|||||||
|
#include "../common/string_util.h"
|
||||||
|
#include "cliententry.h"
|
||||||
|
#include "clientlist.h"
|
||||||
|
#include "shared_tasks.h"
|
||||||
|
#include "worlddb.h"
|
||||||
|
#include "zonelist.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
extern ClientList client_list;
|
||||||
|
extern ZSList zoneserver_list;
|
||||||
|
extern SharedTaskManager shared_tasks;
|
||||||
|
|
||||||
|
void SharedTaskManager::HandleTaskRequest(ServerPacket *pack)
|
||||||
|
{
|
||||||
|
if (!pack)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Things done in zone:
|
||||||
|
* Verified we were requesting a shared task
|
||||||
|
* Verified leader has a slot available (guess we should double check this one)
|
||||||
|
* Verified leader met level reqs
|
||||||
|
* Verified repeatable or not completed (not doing that here?)
|
||||||
|
* Verified leader doesn't have a lock out
|
||||||
|
* Verified the group/raid met min/max player counts
|
||||||
|
*/
|
||||||
|
|
||||||
|
char tmp_str[64] = { 0 };
|
||||||
|
int task_id = pack->ReadUInt32();
|
||||||
|
int npc_id = pack->ReadUInt32();
|
||||||
|
pack->ReadString(tmp_str);
|
||||||
|
std::string leader_name = tmp_str;
|
||||||
|
int player_count = pack->ReadUInt32();
|
||||||
|
std::vector<std::string> players;
|
||||||
|
for (int i = 0; i < player_count; ++i) {
|
||||||
|
pack->ReadString(tmp_str);
|
||||||
|
players.push_back(tmp_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if the task exist, we only load shared tasks in world, so we know the type is correct if found
|
||||||
|
auto it = task_information.find(task_id);
|
||||||
|
if (it == task_information.end()) { // not loaded! bad id or not shared task
|
||||||
|
auto pc = client_list.FindCharacter(leader_name.c_str());
|
||||||
|
if (pc) {
|
||||||
|
// failure TODO: appropriate message
|
||||||
|
auto pack = new ServerPacket(ServerOP_TaskReject, leader_name.size() + 1 + 8);
|
||||||
|
pack->WriteUInt32(0); // string ID or just generic fail message
|
||||||
|
pack->WriteUInt32(npc_id);
|
||||||
|
pack->WriteString(leader_name.c_str());
|
||||||
|
zoneserver_list.SendPacket(pc->zone(), pc->instance(), pack);
|
||||||
|
safe_delete(pack);
|
||||||
|
} // oh well
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int id = GetNextID();
|
||||||
|
auto ret = tasks.insert({id, {id, task_id}});
|
||||||
|
if (!ret.second) {
|
||||||
|
auto pc = client_list.FindCharacter(leader_name.c_str());
|
||||||
|
if (pc) {
|
||||||
|
// failure TODO: appropriate message
|
||||||
|
auto pack = new ServerPacket(ServerOP_TaskReject, leader_name.size() + 1 + 8);
|
||||||
|
pack->WriteUInt32(0); // string ID or just generic fail message
|
||||||
|
pack->WriteUInt32(npc_id);
|
||||||
|
pack->WriteString(leader_name.c_str());
|
||||||
|
zoneserver_list.SendPacket(pc->zone(), pc->instance(), pack);
|
||||||
|
safe_delete(pack);
|
||||||
|
} // oh well
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto cle_leader = client_list.FindCharacter(leader_name.c_str());
|
||||||
|
if (cle_leader == nullptr) {// something went wrong
|
||||||
|
tasks.erase(ret.first);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cle_leader->HasFreeSharedTaskSlot()) { // they have a task already ...
|
||||||
|
tasks.erase(ret.first);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto &task = ret.first->second;
|
||||||
|
task.AddMember(leader_name, cle_leader, cle_leader->CharID(), true);
|
||||||
|
|
||||||
|
if (players.empty()) {
|
||||||
|
// send instant success to leader
|
||||||
|
SerializeBuffer buf(10);
|
||||||
|
buf.WriteInt32(id); // shared task's ID
|
||||||
|
buf.WriteInt32(task_id); // ID of the task's data
|
||||||
|
buf.WriteInt32(npc_id); // NPC we're requesting from
|
||||||
|
buf.WriteString(leader_name); // leader's name
|
||||||
|
buf.WriteInt32(0); // member list minus leader
|
||||||
|
|
||||||
|
auto pack = new ServerPacket(ServerOP_TaskGrant, buf);
|
||||||
|
zoneserver_list.SendPacket(cle_leader->zone(), cle_leader->instance(), pack);
|
||||||
|
safe_delete(pack);
|
||||||
|
|
||||||
|
task.SetCLESharedTasks();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &&name : players) {
|
||||||
|
// look up CLEs by name, tell them we need to know if they can be added
|
||||||
|
auto cle = client_list.FindCharacter(name.c_str());
|
||||||
|
if (cle) {
|
||||||
|
// make sure we don't have a shared task already
|
||||||
|
if (!cle->HasFreeSharedTaskSlot()) {
|
||||||
|
// failure TODO: appropriate message
|
||||||
|
auto pack = new ServerPacket(ServerOP_TaskReject, leader_name.size() + 1 + 8);
|
||||||
|
pack->WriteUInt32(0); // string ID or just generic fail message
|
||||||
|
pack->WriteUInt32(npc_id);
|
||||||
|
pack->WriteString(leader_name.c_str());
|
||||||
|
zoneserver_list.SendPacket(cle_leader->zone(), cle_leader->instance(), pack);
|
||||||
|
safe_delete(pack);
|
||||||
|
tasks.erase(ret.first);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure our level is right
|
||||||
|
if (!AppropriateLevel(task_id, cle->level())) {
|
||||||
|
// failure TODO: appropriate message
|
||||||
|
auto pack = new ServerPacket(ServerOP_TaskReject, leader_name.size() + 1 + 8);
|
||||||
|
pack->WriteUInt32(0); // string ID or just generic fail message
|
||||||
|
pack->WriteUInt32(npc_id);
|
||||||
|
pack->WriteString(leader_name.c_str());
|
||||||
|
zoneserver_list.SendPacket(cle_leader->zone(), cle_leader->instance(), pack);
|
||||||
|
safe_delete(pack);
|
||||||
|
tasks.erase(ret.first);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check our lock out timer
|
||||||
|
int expires = cle->GetTaskLockoutExpire(task_id);
|
||||||
|
if ((expires - time(nullptr)) >= 0) {
|
||||||
|
// failure TODO: appropriate message, we need to send the timestamp here
|
||||||
|
auto pack = new ServerPacket(ServerOP_TaskReject, leader_name.size() + 1 + 8);
|
||||||
|
pack->WriteUInt32(0); // string ID or just generic fail message
|
||||||
|
pack->WriteUInt32(npc_id);
|
||||||
|
pack->WriteString(leader_name.c_str());
|
||||||
|
zoneserver_list.SendPacket(cle_leader->zone(), cle_leader->instance(), pack);
|
||||||
|
safe_delete(pack);
|
||||||
|
tasks.erase(ret.first);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we're good, add to task
|
||||||
|
task.AddMember(name, cle, cle->CharID());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// this will also prevent any of these clients from requesting or being added to another, lets do it now before we tell zone
|
||||||
|
task.SetCLESharedTasks();
|
||||||
|
task.InitActivities();
|
||||||
|
// fire off to zone we're done!
|
||||||
|
SerializeBuffer buf(10 + 10 * players.size());
|
||||||
|
buf.WriteInt32(id); // shared task's ID
|
||||||
|
buf.WriteInt32(task_id); // ID of the task's data
|
||||||
|
buf.WriteInt32(npc_id); // NPC we're requesting from
|
||||||
|
buf.WriteInt32(task.GetAcceptedTime()); // time we accepted it
|
||||||
|
buf.WriteString(leader_name); // leader's name
|
||||||
|
task.SerializeMembers(buf, false); // everyone but leader
|
||||||
|
|
||||||
|
auto reply = new ServerPacket(ServerOP_TaskGrant, buf);
|
||||||
|
zoneserver_list.SendPacket(cle_leader->zone(), cle_leader->instance(), reply);
|
||||||
|
safe_delete(reply);
|
||||||
|
|
||||||
|
task.Save();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Just sends the ID of the task that was successfully created zone side
|
||||||
|
* We now need to tell all the other clients to join the task
|
||||||
|
* We could probably try to find all the clients already in the zone and not
|
||||||
|
* worry about them here, but it's simpler this way
|
||||||
|
*/
|
||||||
|
void SharedTaskManager::HandleTaskZoneCreated(ServerPacket *pack)
|
||||||
|
{
|
||||||
|
if (!pack)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int id = pack->ReadUInt32();
|
||||||
|
|
||||||
|
auto task = GetSharedTask(id);
|
||||||
|
|
||||||
|
if (!task) // hmm guess we should tell zone something is broken TODO
|
||||||
|
return;
|
||||||
|
|
||||||
|
// we reuse this, easier this way
|
||||||
|
auto outpack = new ServerPacket(ServerOP_TaskZoneCreated, sizeof(ServerSharedTaskMember_Struct));
|
||||||
|
auto stm = (ServerSharedTaskMember_Struct *)outpack->pBuffer;
|
||||||
|
stm->id = id;
|
||||||
|
|
||||||
|
for (auto &&m : task->members) {
|
||||||
|
if (m.leader) // leader done!
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!m.cle) // hmmm
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!m.cle->Server()) // hmm
|
||||||
|
continue;
|
||||||
|
|
||||||
|
strn0cpy(stm->name, m.name.c_str(), 64);
|
||||||
|
zoneserver_list.SendPacket(m.cle->zone(), m.cle->instance(), outpack);
|
||||||
|
}
|
||||||
|
|
||||||
|
safe_delete(outpack);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Loads in the tasks and task_activity tables
|
||||||
|
* We limit to shared to save some memory
|
||||||
|
* This can be called while reloading tasks (because deving etc)
|
||||||
|
* This data is loaded into the task_information map
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool SharedTaskManager::LoadSharedTasks(int single_task)
|
||||||
|
{
|
||||||
|
std::string query;
|
||||||
|
|
||||||
|
if (single_task == 0) {
|
||||||
|
query =
|
||||||
|
StringFormat("SELECT `id`, `type`, `duration`, `duration_code`, `title`, `description`, `reward`, "
|
||||||
|
"`rewardid`, `cashreward`, `xpreward`, `rewardmethod`, `faction_reward`, `minlevel`, "
|
||||||
|
"`maxlevel`, `repeatable`, `completion_emote`, `reward_points`, `reward_type`, "
|
||||||
|
"`replay_group`, `min_players`, `max_players`, `task_lock_step`, `instance_zone_id`, "
|
||||||
|
"`zone_version`, `zone_in_zone_id`, `zone_in_x`, `zone_in_y`, `zone_in_object_id`, "
|
||||||
|
"`dest_x`, `dest_y`, `dest_z`, `dest_h` FROM `tasks` WHERE `type` = %i",
|
||||||
|
static_cast<int>(TaskType::Shared));
|
||||||
|
} else {
|
||||||
|
query =
|
||||||
|
StringFormat("SELECT `id`, `type`, `duration`, `duration_code`, `title`, `description`, `reward`, "
|
||||||
|
"`rewardid`, `cashreward`, `xpreward`, `rewardmethod`, `faction_reward`, `minlevel`, "
|
||||||
|
"`maxlevel`, `repeatable`, `completion_emote`, `reward_points`, `reward_type`, "
|
||||||
|
"`replay_group`, `min_players`, `max_players`, `task_lock_step`, `instance_zone_id`, "
|
||||||
|
"`zone_version`, `zone_in_zone_id`, `zone_in_x`, `zone_in_y`, `zone_in_object_id`, "
|
||||||
|
"`dest_x`, `dest_y`, `dest_z`, `dest_h` FROM `tasks` WHERE `id` = %i AND `type` = %i",
|
||||||
|
single_task, static_cast<int>(TaskType::Shared));
|
||||||
|
}
|
||||||
|
auto results = database.QueryDatabase(query);
|
||||||
|
if (!results.Success()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||||
|
int task_id = atoi(row[0]);
|
||||||
|
|
||||||
|
auto &task = task_information[task_id];
|
||||||
|
task.type = static_cast<TaskType>(atoi(row[1]));
|
||||||
|
task.Duration = atoi(row[2]);
|
||||||
|
task.dur_code = static_cast<DurationCode>(atoi(row[3]));
|
||||||
|
task.Title = row[4];
|
||||||
|
task.Description = row[5];
|
||||||
|
task.Reward = row[6];
|
||||||
|
task.RewardID = atoi(row[7]);
|
||||||
|
task.CashReward = atoi(row[8]);
|
||||||
|
task.XPReward = atoi(row[9]);
|
||||||
|
task.RewardMethod = (TaskMethodType)atoi(row[10]);
|
||||||
|
task.faction_reward = atoi(row[11]);
|
||||||
|
task.MinLevel = atoi(row[12]);
|
||||||
|
task.MaxLevel = atoi(row[13]);
|
||||||
|
task.Repeatable = atoi(row[14]);
|
||||||
|
task.completion_emote = row[15];
|
||||||
|
task.reward_points = atoi(row[16]);
|
||||||
|
task.reward_type = static_cast<PointType>(atoi(row[17]));
|
||||||
|
task.replay_group = atoi(row[18]);
|
||||||
|
task.min_players = atoi(row[19]);
|
||||||
|
task.max_players = atoi(row[20]);
|
||||||
|
task.task_lock_step = atoi(row[21]);
|
||||||
|
task.instance_zone_id = atoi(row[22]);
|
||||||
|
task.zone_version = atoi(row[23]);
|
||||||
|
task.zone_in_zone_id = atoi(row[24]);
|
||||||
|
task.zone_in_x = atof(row[25]);
|
||||||
|
task.zone_in_y = atof(row[26]);
|
||||||
|
task.zone_in_object_id = atoi(row[27]);
|
||||||
|
task.dest_x = atof(row[28]);
|
||||||
|
task.dest_y = atof(row[29]);
|
||||||
|
task.dest_z = atof(row[30]);
|
||||||
|
task.dest_h = atof(row[31]);
|
||||||
|
task.ActivityCount = 0;
|
||||||
|
task.SequenceMode = ActivitiesSequential;
|
||||||
|
task.LastStep = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// hmm need to limit to shared tasks only ...
|
||||||
|
if (single_task == 0)
|
||||||
|
query = StringFormat(
|
||||||
|
"SELECT `taskid`, `step`, `activityid`, `activitytype`, `target_name`, `item_list`, `skill_list`, "
|
||||||
|
"`spell_list`, `description_override`, `goalid`, `goalmethod`, `goalcount`, `delivertonpc`, "
|
||||||
|
"`zones`, `optional` FROM `task_activities` WHERE `activityid` < %i AND `taskid` IN (SELECT `id` "
|
||||||
|
"FROM `tasks` WHERE `type` = %i) ORDER BY taskid, activityid ASC",
|
||||||
|
MAXACTIVITIESPERTASK, static_cast<int>(TaskType::Shared));
|
||||||
|
else
|
||||||
|
query = StringFormat(
|
||||||
|
"SELECT `taskid`, `step`, `activityid`, `activitytype`, `target_name`, `item_list`, `skill_list`, "
|
||||||
|
"`spell_list`, `description_override`, `goalid`, `goalmethod`, `goalcount`, `delivertonpc`, "
|
||||||
|
"`zones`, `optional` FROM `task_activities` WHERE `taskid` = %i AND `activityid` < %i AND `taskid` "
|
||||||
|
"IN (SELECT `id` FROM `tasks` WHERE `type` = %i) ORDER BY taskid, activityid ASC",
|
||||||
|
single_task, MAXACTIVITIESPERTASK, static_cast<int>(TaskType::Shared));
|
||||||
|
results = database.QueryDatabase(query);
|
||||||
|
if (!results.Success()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||||
|
int task_id = atoi(row[0]);
|
||||||
|
int step = atoi(row[1]);
|
||||||
|
|
||||||
|
int activity_id = atoi(row[2]);
|
||||||
|
|
||||||
|
if (activity_id < 0 || activity_id >= MAXACTIVITIESPERTASK) {
|
||||||
|
// This shouldn't happen, as the SELECT is bounded by MAXTASKS
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (task_information.count(task_id) == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto &task = task_information[task_id];
|
||||||
|
|
||||||
|
task.Activity[task.ActivityCount].StepNumber = step;
|
||||||
|
|
||||||
|
if (step != 0)
|
||||||
|
task.SequenceMode = ActivitiesStepped;
|
||||||
|
|
||||||
|
if (step > task.LastStep)
|
||||||
|
task.LastStep = step;
|
||||||
|
|
||||||
|
// Task Activities MUST be numbered sequentially from 0. If not, log an error
|
||||||
|
// and set the task to nullptr. Subsequent activities for this task will raise
|
||||||
|
// ERR_NOTASK errors.
|
||||||
|
// Change to (activityID != (task.ActivityCount + 1)) to index from 1
|
||||||
|
if (activity_id != task.ActivityCount) {
|
||||||
|
task_information.erase(task_id);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
task.Activity[task.ActivityCount].Type = atoi(row[3]);
|
||||||
|
|
||||||
|
task.Activity[task.ActivityCount].target_name = row[4];
|
||||||
|
task.Activity[task.ActivityCount].item_list = row[5];
|
||||||
|
task.Activity[task.ActivityCount].skill_list = row[6];
|
||||||
|
task.Activity[task.ActivityCount].skill_id = atoi(row[6]); // for older clients
|
||||||
|
task.Activity[task.ActivityCount].spell_list = row[7];
|
||||||
|
task.Activity[task.ActivityCount].spell_id = atoi(row[7]); // for older clients
|
||||||
|
task.Activity[task.ActivityCount].desc_override = row[8];
|
||||||
|
|
||||||
|
task.Activity[task.ActivityCount].GoalID = atoi(row[9]);
|
||||||
|
task.Activity[task.ActivityCount].GoalMethod = (TaskMethodType)atoi(row[10]);
|
||||||
|
task.Activity[task.ActivityCount].GoalCount = atoi(row[11]);
|
||||||
|
task.Activity[task.ActivityCount].DeliverToNPC = atoi(row[12]);
|
||||||
|
task.Activity[task.ActivityCount].zones = row[13];
|
||||||
|
auto zones = SplitString(task.Activity[task.ActivityCount].zones, ';');
|
||||||
|
for (auto && e : zones)
|
||||||
|
task.Activity[task.ActivityCount].ZoneIDs.push_back(std::stoi(e));
|
||||||
|
task.Activity[task.ActivityCount].Optional = atoi(row[14]);
|
||||||
|
|
||||||
|
task.ActivityCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is called once during boot of world
|
||||||
|
* We need to load next_id, clean up expired tasks (?), and populate the map
|
||||||
|
*/
|
||||||
|
bool SharedTaskManager::LoadSharedTaskState()
|
||||||
|
{
|
||||||
|
// one may think we should clean up expired tasks, but we don't just in case world is booting back up after a crash
|
||||||
|
// we will clean them up in the normal process loop so zones get told to clean up
|
||||||
|
std::string query = "SELECT `id`, `task_id`, `accepted_time`, `is_locked` FROM `shared_task_state`";
|
||||||
|
auto results = database.QueryDatabase(query);
|
||||||
|
|
||||||
|
if (results.Success() && results.RowCount() > 0) {
|
||||||
|
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||||
|
int id = atoi(row[0]);
|
||||||
|
|
||||||
|
auto &task = tasks[id];
|
||||||
|
task.SetID(id);
|
||||||
|
task.SetTaskID(atoi(row[1]));
|
||||||
|
task.SetAcceptedTime(atoi(row[2]));
|
||||||
|
task.SetLocked(atoi(row[3]) != 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
query = "SELECT `shared_task_id`, `character_id`, `character_name`, `is_leader` FROM `shared_task_members` ORDER BY shared_task_id ASC";
|
||||||
|
results = database.QueryDatabase(query);
|
||||||
|
if (results.Success() && results.RowCount() > 0) {
|
||||||
|
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||||
|
int task_id = atoi(row[0]);
|
||||||
|
// hmm not sure best way to do this, fine for now
|
||||||
|
if (tasks.count(task_id) == 1)
|
||||||
|
tasks[task_id].AddMember(row[2], nullptr, atoi(row[1]), atoi(row[3]) != 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load existing tasks. We may not want to actually do this here and wait for a client to log in
|
||||||
|
// But the crash case may actually dictate we should :P
|
||||||
|
|
||||||
|
// set next_id to highest used ID
|
||||||
|
query = "SELECT IFNULL(MAX(id), 0) FROM shared_task_state";
|
||||||
|
results = database.QueryDatabase(query);
|
||||||
|
if (results.Success() && results.RowCount() == 1) {
|
||||||
|
auto row = results.begin();
|
||||||
|
next_id = atoi(row[0]);
|
||||||
|
} else {
|
||||||
|
next_id = 0; // oh well
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return the next unused ID
|
||||||
|
* Hopefully this does not grow too large.
|
||||||
|
*/
|
||||||
|
int SharedTaskManager::GetNextID()
|
||||||
|
{
|
||||||
|
next_id++;
|
||||||
|
// let's not be extra clever here ...
|
||||||
|
while (tasks.count(next_id) != 0)
|
||||||
|
next_id++;
|
||||||
|
|
||||||
|
return next_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* returns true if the level fits in the task's defined range
|
||||||
|
*/
|
||||||
|
bool SharedTaskManager::AppropriateLevel(int id, int level) const
|
||||||
|
{
|
||||||
|
auto it = task_information.find(id);
|
||||||
|
// doesn't exist
|
||||||
|
if (it == task_information.end())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto &task = it->second;
|
||||||
|
|
||||||
|
if (task.MinLevel && level < task.MinLevel)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (task.MaxLevel && level > task.MaxLevel)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This will check if any tasks have expired
|
||||||
|
*/
|
||||||
|
void SharedTaskManager::Process()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When a player leaves world they will tell us to clean up their pointer
|
||||||
|
* This is NOT leaving the shared task, just crashed or something
|
||||||
|
*/
|
||||||
|
|
||||||
|
void SharedTask::MemberLeftGame(ClientListEntry *cle)
|
||||||
|
{
|
||||||
|
auto it = std::find_if(members.begin(), members.end(), [cle](SharedTaskMember &m) { return m.cle == cle; });
|
||||||
|
|
||||||
|
// ahh okay ...
|
||||||
|
if (it == members.end())
|
||||||
|
return;
|
||||||
|
|
||||||
|
it->cle = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Serializes Members into the SerializeBuffer
|
||||||
|
* Starts with count then followed by names null-termed
|
||||||
|
* In the future this will include monster mission shit
|
||||||
|
* This should probably send the SharedMember struct or something more like it, fine for now
|
||||||
|
*/
|
||||||
|
void SharedTask::SerializeMembers(SerializeBuffer &buf, bool include_leader) const
|
||||||
|
{
|
||||||
|
buf.WriteInt32(include_leader ? members.size() : members.size() - 1);
|
||||||
|
|
||||||
|
for (auto && m : members) {
|
||||||
|
if (!include_leader && m.leader)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
buf.WriteString(m.name);
|
||||||
|
// TODO: live also has monster mission class choice in here
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This sets the CLE's quick look up shared task stuff
|
||||||
|
*/
|
||||||
|
void SharedTask::SetCLESharedTasks()
|
||||||
|
{
|
||||||
|
for (auto &&m : members) {
|
||||||
|
if (m.cle == nullptr) // shouldn't happen ....
|
||||||
|
continue;
|
||||||
|
|
||||||
|
m.cle->SetSharedTask(this);
|
||||||
|
m.cle->SetCurrentSharedTaskID(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SharedTask::Save() const
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* sets up activity stuff
|
||||||
|
*/
|
||||||
|
void SharedTask::InitActivities()
|
||||||
|
{
|
||||||
|
task_state.TaskID = task_id;
|
||||||
|
task_state.AcceptedTime = time(nullptr);
|
||||||
|
task_state.Updated = true;
|
||||||
|
task_state.CurrentStep = -1;
|
||||||
|
|
||||||
|
for (int i = 0; i < shared_tasks.GetTaskActivityCount(task_id); i++) {
|
||||||
|
task_state.Activity[i].ActivityID = i;
|
||||||
|
task_state.Activity[i].DoneCount = 0;
|
||||||
|
task_state.Activity[i].State = ActivityHidden;
|
||||||
|
task_state.Activity[i].Updated = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SharedTask::UnlockActivities()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
#ifndef SHARED_TASKS_H
|
||||||
|
#define SHARED_TASKS_H
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "../common/servertalk.h"
|
||||||
|
#include "../common/global_tasks.h"
|
||||||
|
#include "cliententry.h"
|
||||||
|
|
||||||
|
class ClientListEntry;
|
||||||
|
|
||||||
|
struct SharedTaskMember {
|
||||||
|
std::string name;
|
||||||
|
ClientListEntry *cle;
|
||||||
|
int char_id;
|
||||||
|
bool leader;
|
||||||
|
// TODO: monster mission stuff
|
||||||
|
SharedTaskMember() : cle(nullptr), char_id(0), leader(false) {}
|
||||||
|
SharedTaskMember(std::string name, ClientListEntry *cle, int char_id, bool leader)
|
||||||
|
: name(name), cle(cle), char_id(char_id), leader(leader)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class SharedTask {
|
||||||
|
public:
|
||||||
|
SharedTask() : id(0), task_id(0), locked(false) {}
|
||||||
|
SharedTask(int id, int task_id) : id(id), task_id(task_id), locked(false) {}
|
||||||
|
~SharedTask() {}
|
||||||
|
|
||||||
|
void AddMember(std::string name, ClientListEntry *cle = nullptr, int char_id = 0, bool leader = false)
|
||||||
|
{
|
||||||
|
members.push_back({name, cle, char_id, leader});
|
||||||
|
if (leader)
|
||||||
|
leader_name = name;
|
||||||
|
if (char_id == 0)
|
||||||
|
return;
|
||||||
|
auto it = std::find(char_ids.begin(), char_ids.end(), char_id);
|
||||||
|
if (it == char_ids.end())
|
||||||
|
char_ids.push_back(char_id);
|
||||||
|
}
|
||||||
|
void MemberLeftGame(ClientListEntry *cle);
|
||||||
|
inline const std::string &GetLeaderName() const { return leader_name; }
|
||||||
|
inline SharedTaskMember *GetLeader() {
|
||||||
|
auto it = std::find_if(members.begin(), members.end(), [](const SharedTaskMember &m) { return m.leader; });
|
||||||
|
if (it != members.end())
|
||||||
|
return &(*it);
|
||||||
|
else
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SerializeMembers(SerializeBuffer &buf, bool include_leader = true) const;
|
||||||
|
void SetCLESharedTasks();
|
||||||
|
void InitActivities();
|
||||||
|
bool UnlockActivities();
|
||||||
|
|
||||||
|
void Save() const; // save to database
|
||||||
|
|
||||||
|
private:
|
||||||
|
inline void SetID(int in) { id = in; }
|
||||||
|
inline void SetTaskID(int in) { task_id = in; }
|
||||||
|
inline void SetAcceptedTime(int in) { task_state.AcceptedTime = in; }
|
||||||
|
inline void SetLocked(bool in) { locked = in; }
|
||||||
|
|
||||||
|
inline int GetAcceptedTime() const { return task_state.AcceptedTime; }
|
||||||
|
int id; // id we have in our map
|
||||||
|
int task_id; // ID of the task we're on
|
||||||
|
bool locked;
|
||||||
|
std::string leader_name;
|
||||||
|
std::vector<SharedTaskMember> members;
|
||||||
|
std::vector<int> char_ids; // every char id of someone to be locked out, different in case they leave/removed
|
||||||
|
ClientTaskInformation task_state; // book keeping
|
||||||
|
|
||||||
|
friend class SharedTaskManager;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SharedTaskManager {
|
||||||
|
public:
|
||||||
|
SharedTaskManager() : next_id(0) {}
|
||||||
|
~SharedTaskManager() {}
|
||||||
|
|
||||||
|
bool LoadSharedTaskState();
|
||||||
|
bool LoadSharedTasks(int single_task = 0);
|
||||||
|
|
||||||
|
bool AppropriateLevel(int id, int level) const;
|
||||||
|
|
||||||
|
inline SharedTask *GetSharedTask(int id) {
|
||||||
|
auto it = tasks.find(id);
|
||||||
|
if (it != tasks.end())
|
||||||
|
return &it->second;
|
||||||
|
else
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int GetTaskActivityCount(int task_id) const {
|
||||||
|
auto it = task_information.find(task_id);
|
||||||
|
if (it != task_information.end())
|
||||||
|
return it->second.ActivityCount;
|
||||||
|
else
|
||||||
|
return 0; // hmm
|
||||||
|
}
|
||||||
|
|
||||||
|
// IPC packet processing
|
||||||
|
void HandleTaskRequest(ServerPacket *pack);
|
||||||
|
void HandleTaskZoneCreated(ServerPacket *pack);
|
||||||
|
|
||||||
|
void Process();
|
||||||
|
|
||||||
|
private:
|
||||||
|
int GetNextID();
|
||||||
|
int next_id;
|
||||||
|
std::unordered_map<int, SharedTask> tasks; // current active shared task states
|
||||||
|
std::unordered_map<int, TaskInformation> task_information; // task info shit
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* !SHARED_TASKS_H */
|
||||||
@@ -36,14 +36,6 @@ void UCSConnection::ProcessPacket(uint16 opcode, EQ::Net::Packet &p)
|
|||||||
|
|
||||||
switch (opcode)
|
switch (opcode)
|
||||||
{
|
{
|
||||||
case 0:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ServerOP_KeepAlive:
|
|
||||||
{
|
|
||||||
// ignore this
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ServerOP_ZAAuth:
|
case ServerOP_ZAAuth:
|
||||||
{
|
{
|
||||||
Log(Logs::Detail, Logs::UCS_Server, "Got authentication from UCS when they are already authenticated.");
|
Log(Logs::Detail, Logs::UCS_Server, "Got authentication from UCS when they are already authenticated.");
|
||||||
|
|||||||
@@ -43,7 +43,6 @@ ZSList::ZSList()
|
|||||||
memset(pLockedZones, 0, sizeof(pLockedZones));
|
memset(pLockedZones, 0, sizeof(pLockedZones));
|
||||||
|
|
||||||
m_tick.reset(new EQ::Timer(5000, true, std::bind(&ZSList::OnTick, this, std::placeholders::_1)));
|
m_tick.reset(new EQ::Timer(5000, true, std::bind(&ZSList::OnTick, this, std::placeholders::_1)));
|
||||||
m_keepalive.reset(new EQ::Timer(2500, true, std::bind(&ZSList::OnKeepAlive, this, std::placeholders::_1)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ZSList::~ZSList() {
|
ZSList::~ZSList() {
|
||||||
@@ -748,9 +747,3 @@ void ZSList::OnTick(EQ::Timer *t)
|
|||||||
web_interface.SendEvent(out);
|
web_interface.SendEvent(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ZSList::OnKeepAlive(EQ::Timer *t)
|
|
||||||
{
|
|
||||||
for (auto &zone : list) {
|
|
||||||
zone->SendKeepAlive();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -63,7 +63,6 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void OnTick(EQ::Timer *t);
|
void OnTick(EQ::Timer *t);
|
||||||
void OnKeepAlive(EQ::Timer *t);
|
|
||||||
uint32 NextID;
|
uint32 NextID;
|
||||||
std::list<std::unique_ptr<ZoneServer>> list;
|
std::list<std::unique_ptr<ZoneServer>> list;
|
||||||
uint16 pLockedZones[MaxLockedZones];
|
uint16 pLockedZones[MaxLockedZones];
|
||||||
|
|||||||
+12
-13
@@ -35,6 +35,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
#include "adventure_manager.h"
|
#include "adventure_manager.h"
|
||||||
#include "ucs.h"
|
#include "ucs.h"
|
||||||
#include "queryserv.h"
|
#include "queryserv.h"
|
||||||
|
#include "shared_tasks.h"
|
||||||
|
|
||||||
extern ClientList client_list;
|
extern ClientList client_list;
|
||||||
extern GroupLFPList LFPGroupList;
|
extern GroupLFPList LFPGroupList;
|
||||||
@@ -45,6 +46,7 @@ extern volatile bool UCSServerAvailable_;
|
|||||||
extern AdventureManager adventure_manager;
|
extern AdventureManager adventure_manager;
|
||||||
extern UCSConnection UCSLink;
|
extern UCSConnection UCSLink;
|
||||||
extern QueryServConnection QSLink;
|
extern QueryServConnection QSLink;
|
||||||
|
extern SharedTaskManager shared_tasks;
|
||||||
void CatchSignal(int sig_num);
|
void CatchSignal(int sig_num);
|
||||||
|
|
||||||
ZoneServer::ZoneServer(std::shared_ptr<EQ::Net::ServertalkServerConnection> connection, EQ::Net::ConsoleServer *console)
|
ZoneServer::ZoneServer(std::shared_ptr<EQ::Net::ServertalkServerConnection> connection, EQ::Net::ConsoleServer *console)
|
||||||
@@ -186,12 +188,6 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
|
|||||||
ServerPacket *pack = &tpack;
|
ServerPacket *pack = &tpack;
|
||||||
|
|
||||||
switch (opcode) {
|
switch (opcode) {
|
||||||
case 0:
|
|
||||||
break;
|
|
||||||
case ServerOP_KeepAlive: {
|
|
||||||
// ignore this
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ServerOP_ZAAuth: {
|
case ServerOP_ZAAuth: {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1349,6 +1345,16 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
|
|||||||
cle->ProcessTellQueue();
|
cle->ProcessTellQueue();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case ServerOP_TaskRequest:
|
||||||
|
{
|
||||||
|
shared_tasks.HandleTaskRequest(pack);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ServerOP_TaskZoneCreated:
|
||||||
|
{
|
||||||
|
shared_tasks.HandleTaskZoneCreated(pack);
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
Log(Logs::Detail, Logs::World_Server, "Unknown ServerOPcode from zone 0x%04x, size %d", pack->opcode, pack->size);
|
Log(Logs::Detail, Logs::World_Server, "Unknown ServerOPcode from zone 0x%04x, size %d", pack->opcode, pack->size);
|
||||||
@@ -1405,13 +1411,6 @@ void ZoneServer::SendGroupIDs() {
|
|||||||
delete pack;
|
delete pack;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ZoneServer::SendKeepAlive()
|
|
||||||
{
|
|
||||||
ServerPacket pack(ServerOP_KeepAlive, 0);
|
|
||||||
SendPacket(&pack);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ZoneServer::ChangeWID(uint32 iCharID, uint32 iWID) {
|
void ZoneServer::ChangeWID(uint32 iCharID, uint32 iWID) {
|
||||||
auto pack = new ServerPacket(ServerOP_ChangeWID, sizeof(ServerChangeWID_Struct));
|
auto pack = new ServerPacket(ServerOP_ChangeWID, sizeof(ServerChangeWID_Struct));
|
||||||
ServerChangeWID_Struct* scw = (ServerChangeWID_Struct*)pack->pBuffer;
|
ServerChangeWID_Struct* scw = (ServerChangeWID_Struct*)pack->pBuffer;
|
||||||
|
|||||||
@@ -39,7 +39,6 @@ public:
|
|||||||
void SendPacket(ServerPacket* pack) { tcpc->SendPacket(pack); }
|
void SendPacket(ServerPacket* pack) { tcpc->SendPacket(pack); }
|
||||||
void SendEmoteMessage(const char* to, uint32 to_guilddbid, int16 to_minstatus, uint32 type, const char* message, ...);
|
void SendEmoteMessage(const char* to, uint32 to_guilddbid, int16 to_minstatus, uint32 type, const char* message, ...);
|
||||||
void SendEmoteMessageRaw(const char* to, uint32 to_guilddbid, int16 to_minstatus, uint32 type, const char* message);
|
void SendEmoteMessageRaw(const char* to, uint32 to_guilddbid, int16 to_minstatus, uint32 type, const char* message);
|
||||||
void SendKeepAlive();
|
|
||||||
bool SetZone(uint32 iZoneID, uint32 iInstanceID = 0, bool iStaticZone = false);
|
bool SetZone(uint32 iZoneID, uint32 iInstanceID = 0, bool iStaticZone = false);
|
||||||
void TriggerBootup(uint32 iZoneID = 0, uint32 iInstanceID = 0, const char* iAdminName = 0, bool iMakeStatic = false);
|
void TriggerBootup(uint32 iZoneID = 0, uint32 iInstanceID = 0, const char* iAdminName = 0, bool iMakeStatic = false);
|
||||||
void Disconnect() { auto handle = tcpc->Handle(); if (handle) { handle->Disconnect(); } }
|
void Disconnect() { auto handle = tcpc->Handle(); if (handle) { handle->Disconnect(); } }
|
||||||
|
|||||||
@@ -1877,6 +1877,10 @@ bool Client::Death(Mob* killerMob, int32 damage, uint16 spell, EQEmu::skills::Sk
|
|||||||
if (r)
|
if (r)
|
||||||
r->MemberZoned(this);
|
r->MemberZoned(this);
|
||||||
|
|
||||||
|
auto shared_task = GetSharedTask();
|
||||||
|
if (shared_task)
|
||||||
|
shared_task->MemberZoned(this);
|
||||||
|
|
||||||
dead_timer.Start(5000, true);
|
dead_timer.Start(5000, true);
|
||||||
m_pp.zone_id = m_pp.binds[0].zoneId;
|
m_pp.zone_id = m_pp.binds[0].zoneId;
|
||||||
m_pp.zoneInstance = m_pp.binds[0].instance_id;
|
m_pp.zoneInstance = m_pp.binds[0].instance_id;
|
||||||
|
|||||||
@@ -3396,6 +3396,11 @@ void Client::LinkDead()
|
|||||||
if(raid){
|
if(raid){
|
||||||
raid->MemberZoned(this);
|
raid->MemberZoned(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto shared_task = GetSharedTask();
|
||||||
|
if (shared_task)
|
||||||
|
shared_task->MemberZoned(this);
|
||||||
|
|
||||||
// save_timer.Start(2500);
|
// save_timer.Start(2500);
|
||||||
linkdead_timer.Start(RuleI(Zone,ClientLinkdeadMS));
|
linkdead_timer.Start(RuleI(Zone,ClientLinkdeadMS));
|
||||||
SendAppearancePacket(AT_Linkdead, 1);
|
SendAppearancePacket(AT_Linkdead, 1);
|
||||||
|
|||||||
+7
-2
@@ -1021,13 +1021,15 @@ public:
|
|||||||
inline void UpdateTasksOnExplore(int ExploreID) { if(taskstate) taskstate->UpdateTasksOnExplore(this, ExploreID); }
|
inline void UpdateTasksOnExplore(int ExploreID) { if(taskstate) taskstate->UpdateTasksOnExplore(this, ExploreID); }
|
||||||
inline bool UpdateTasksOnSpeakWith(int NPCTypeID) { if(taskstate) return taskstate->UpdateTasksOnSpeakWith(this, NPCTypeID); else return false; }
|
inline bool UpdateTasksOnSpeakWith(int NPCTypeID) { if(taskstate) return taskstate->UpdateTasksOnSpeakWith(this, NPCTypeID); else return false; }
|
||||||
inline bool UpdateTasksOnDeliver(std::list<EQEmu::ItemInstance*>& Items, int Cash, int NPCTypeID) { if (taskstate) return taskstate->UpdateTasksOnDeliver(this, Items, Cash, NPCTypeID); else return false; }
|
inline bool UpdateTasksOnDeliver(std::list<EQEmu::ItemInstance*>& Items, int Cash, int NPCTypeID) { if (taskstate) return taskstate->UpdateTasksOnDeliver(this, Items, Cash, NPCTypeID); else return false; }
|
||||||
inline void TaskSetSelector(Mob *mob, int TaskSetID) { if(taskmanager) taskmanager->TaskSetSelector(this, taskstate, mob, TaskSetID); }
|
inline void TaskSetSelector(Mob *mob, int TaskSetID, bool shared = false) { if(taskmanager) taskmanager->TaskSetSelector(this, taskstate, mob, TaskSetID, shared); }
|
||||||
inline void TaskQuestSetSelector(Mob *mob, int count, int *tasks) { if(taskmanager) taskmanager->TaskQuestSetSelector(this, taskstate, mob, count, tasks); }
|
inline void TaskQuestSetSelector(Mob *mob, int count, int *tasks, bool shared = false) { if(taskmanager) taskmanager->TaskQuestSetSelector(this, taskstate, mob, count, tasks, shared); }
|
||||||
inline void EnableTask(int TaskCount, int *TaskList) { if(taskstate) taskstate->EnableTask(CharacterID(), TaskCount, TaskList); }
|
inline void EnableTask(int TaskCount, int *TaskList) { if(taskstate) taskstate->EnableTask(CharacterID(), TaskCount, TaskList); }
|
||||||
inline void DisableTask(int TaskCount, int *TaskList) { if(taskstate) taskstate->DisableTask(CharacterID(), TaskCount, TaskList); }
|
inline void DisableTask(int TaskCount, int *TaskList) { if(taskstate) taskstate->DisableTask(CharacterID(), TaskCount, TaskList); }
|
||||||
inline bool IsTaskEnabled(int TaskID) { return (taskstate ? taskstate->IsTaskEnabled(TaskID) : false); }
|
inline bool IsTaskEnabled(int TaskID) { return (taskstate ? taskstate->IsTaskEnabled(TaskID) : false); }
|
||||||
inline void ProcessTaskProximities(float X, float Y, float Z) { if(taskstate) taskstate->ProcessTaskProximities(this, X, Y, Z); }
|
inline void ProcessTaskProximities(float X, float Y, float Z) { if(taskstate) taskstate->ProcessTaskProximities(this, X, Y, Z); }
|
||||||
inline void AssignTask(int TaskID, int NPCID, bool enforce_level_requirement = false) { if (taskstate) taskstate->AcceptNewTask(this, TaskID, NPCID, enforce_level_requirement); }
|
inline void AssignTask(int TaskID, int NPCID, bool enforce_level_requirement = false) { if (taskstate) taskstate->AcceptNewTask(this, TaskID, NPCID, enforce_level_requirement); }
|
||||||
|
inline void AssignSharedTask(int TaskID, int NPCID, int id, int accepted_time, std::vector<std::string> &members) { if (taskstate) taskstate->AcceptNewSharedTask(this, TaskID, NPCID, id, accepted_time, members); }
|
||||||
|
inline void AddToSharedTask(int TaskID) { if (taskstate) taskstate->AddToSharedTask(this, TaskID); }
|
||||||
inline int ActiveSpeakTask(int NPCID) { if(taskstate) return taskstate->ActiveSpeakTask(NPCID); else return 0; }
|
inline int ActiveSpeakTask(int NPCID) { if(taskstate) return taskstate->ActiveSpeakTask(NPCID); else return 0; }
|
||||||
inline int ActiveSpeakActivity(int NPCID, int TaskID) { if(taskstate) return taskstate->ActiveSpeakActivity(NPCID, TaskID); else return 0; }
|
inline int ActiveSpeakActivity(int NPCID, int TaskID) { if(taskstate) return taskstate->ActiveSpeakActivity(NPCID, TaskID); else return 0; }
|
||||||
inline void FailTask(int TaskID) { if(taskstate) taskstate->FailTask(this, TaskID); }
|
inline void FailTask(int TaskID) { if(taskstate) taskstate->FailTask(this, TaskID); }
|
||||||
@@ -1044,6 +1046,9 @@ public:
|
|||||||
inline int GetTaskActivityDoneCountFromTaskID(int TaskID, int ActivityID) { return (taskstate ? taskstate->GetTaskActivityDoneCountFromTaskID(TaskID, ActivityID) :0); }
|
inline int GetTaskActivityDoneCountFromTaskID(int TaskID, int ActivityID) { return (taskstate ? taskstate->GetTaskActivityDoneCountFromTaskID(TaskID, ActivityID) :0); }
|
||||||
inline int ActiveTasksInSet(int TaskSet) { return (taskstate ? taskstate->ActiveTasksInSet(TaskSet) :0); }
|
inline int ActiveTasksInSet(int TaskSet) { return (taskstate ? taskstate->ActiveTasksInSet(TaskSet) :0); }
|
||||||
inline int CompletedTasksInSet(int TaskSet) { return (taskstate ? taskstate->CompletedTasksInSet(TaskSet) :0); }
|
inline int CompletedTasksInSet(int TaskSet) { return (taskstate ? taskstate->CompletedTasksInSet(TaskSet) :0); }
|
||||||
|
inline int GetTaskLockoutExpire(int id) { return 0; } // stub
|
||||||
|
inline int GetTaskLockoutTimeLeft(int id) { return 0; } // stub
|
||||||
|
inline SharedTaskState *GetSharedTask() { return taskstate ? taskstate->GetSharedTask() : nullptr; }
|
||||||
|
|
||||||
inline const EQEmu::versions::ClientVersion ClientVersion() const { return m_ClientVersion; }
|
inline const EQEmu::versions::ClientVersion ClientVersion() const { return m_ClientVersion; }
|
||||||
inline const uint32 ClientVersionBit() const { return m_ClientVersionBit; }
|
inline const uint32 ClientVersionBit() const { return m_ClientVersionBit; }
|
||||||
|
|||||||
@@ -115,6 +115,7 @@ void MapOpcodes()
|
|||||||
ConnectedOpcodes[OP_0x0193] = &Client::Handle_0x0193;
|
ConnectedOpcodes[OP_0x0193] = &Client::Handle_0x0193;
|
||||||
ConnectedOpcodes[OP_AAAction] = &Client::Handle_OP_AAAction;
|
ConnectedOpcodes[OP_AAAction] = &Client::Handle_OP_AAAction;
|
||||||
ConnectedOpcodes[OP_AcceptNewTask] = &Client::Handle_OP_AcceptNewTask;
|
ConnectedOpcodes[OP_AcceptNewTask] = &Client::Handle_OP_AcceptNewTask;
|
||||||
|
ConnectedOpcodes[OP_AcceptNewSharedTask] = &Client::Handle_OP_AcceptNewSharedTask;
|
||||||
ConnectedOpcodes[OP_AdventureInfoRequest] = &Client::Handle_OP_AdventureInfoRequest;
|
ConnectedOpcodes[OP_AdventureInfoRequest] = &Client::Handle_OP_AdventureInfoRequest;
|
||||||
ConnectedOpcodes[OP_AdventureLeaderboardRequest] = &Client::Handle_OP_AdventureLeaderboardRequest;
|
ConnectedOpcodes[OP_AdventureLeaderboardRequest] = &Client::Handle_OP_AdventureLeaderboardRequest;
|
||||||
ConnectedOpcodes[OP_AdventureMerchantPurchase] = &Client::Handle_OP_AdventureMerchantPurchase;
|
ConnectedOpcodes[OP_AdventureMerchantPurchase] = &Client::Handle_OP_AdventureMerchantPurchase;
|
||||||
@@ -1787,6 +1788,20 @@ void Client::Handle_OP_AcceptNewTask(const EQApplicationPacket *app)
|
|||||||
taskstate->AcceptNewTask(this, ant->task_id, ant->task_master_id);
|
taskstate->AcceptNewTask(this, ant->task_id, ant->task_master_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Client::Handle_OP_AcceptNewSharedTask(const EQApplicationPacket *app)
|
||||||
|
{
|
||||||
|
if (app->size != sizeof(AcceptNewSharedTask_Struct)) {
|
||||||
|
Log(Logs::General, Logs::None, "Size mismatch in OP_AcceptNewSharedTask expected %i got %i",
|
||||||
|
sizeof(AcceptNewSharedTask_Struct), app->size);
|
||||||
|
DumpPacket(app);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto *ant = (AcceptNewSharedTask_Struct*)app->pBuffer;
|
||||||
|
|
||||||
|
if (ant->task_id > 0 && RuleB(TaskSystem, EnableTaskSystem) && taskstate)
|
||||||
|
taskstate->RequestSharedTask(this, ant->task_id, ant->task_master_id);
|
||||||
|
}
|
||||||
|
|
||||||
void Client::Handle_OP_AdventureInfoRequest(const EQApplicationPacket *app)
|
void Client::Handle_OP_AdventureInfoRequest(const EQApplicationPacket *app)
|
||||||
{
|
{
|
||||||
if (app->size < sizeof(EntityId_Struct))
|
if (app->size < sizeof(EntityId_Struct))
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
void Handle_0x01e7(const EQApplicationPacket *app);
|
void Handle_0x01e7(const EQApplicationPacket *app);
|
||||||
void Handle_OP_AAAction(const EQApplicationPacket *app);
|
void Handle_OP_AAAction(const EQApplicationPacket *app);
|
||||||
void Handle_OP_AcceptNewTask(const EQApplicationPacket *app);
|
void Handle_OP_AcceptNewTask(const EQApplicationPacket *app);
|
||||||
|
void Handle_OP_AcceptNewSharedTask(const EQApplicationPacket *app);
|
||||||
void Handle_OP_AdventureInfoRequest(const EQApplicationPacket *app);
|
void Handle_OP_AdventureInfoRequest(const EQApplicationPacket *app);
|
||||||
void Handle_OP_AdventureLeaderboardRequest(const EQApplicationPacket *app);
|
void Handle_OP_AdventureLeaderboardRequest(const EQApplicationPacket *app);
|
||||||
void Handle_OP_AdventureMerchantPurchase(const EQApplicationPacket *app);
|
void Handle_OP_AdventureMerchantPurchase(const EQApplicationPacket *app);
|
||||||
|
|||||||
@@ -149,6 +149,9 @@ bool Client::Process() {
|
|||||||
{
|
{
|
||||||
myraid->MemberZoned(this);
|
myraid->MemberZoned(this);
|
||||||
}
|
}
|
||||||
|
auto shared_task = GetSharedTask();
|
||||||
|
if (shared_task)
|
||||||
|
shared_task->MemberZoned(this);
|
||||||
return(false);
|
return(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,6 +174,9 @@ bool Client::Process() {
|
|||||||
if (myraid) {
|
if (myraid) {
|
||||||
myraid->MemberZoned(this);
|
myraid->MemberZoned(this);
|
||||||
}
|
}
|
||||||
|
auto shared_task = GetSharedTask();
|
||||||
|
if (shared_task)
|
||||||
|
shared_task->MemberZoned(this);
|
||||||
return false; //delete client
|
return false; //delete client
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -653,6 +659,9 @@ bool Client::Process() {
|
|||||||
myraid->MemberZoned(this);
|
myraid->MemberZoned(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
auto shared_task = GetSharedTask();
|
||||||
|
if (shared_task)
|
||||||
|
shared_task->MemberZoned(this);
|
||||||
OnDisconnect(false);
|
OnDisconnect(false);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -694,6 +703,10 @@ void Client::OnDisconnect(bool hard_disconnect) {
|
|||||||
if (MyRaid)
|
if (MyRaid)
|
||||||
MyRaid->MemberZoned(this);
|
MyRaid->MemberZoned(this);
|
||||||
|
|
||||||
|
auto shared_task = GetSharedTask();
|
||||||
|
if (shared_task)
|
||||||
|
shared_task->MemberZoned(this);
|
||||||
|
|
||||||
parse->EventPlayer(EVENT_DISCONNECT, this, "", 0);
|
parse->EventPlayer(EVENT_DISCONNECT, this, "", 0);
|
||||||
|
|
||||||
/* QS: PlayerLogConnectDisconnect */
|
/* QS: PlayerLogConnectDisconnect */
|
||||||
@@ -2101,6 +2114,10 @@ void Client::HandleRespawnFromHover(uint32 Option)
|
|||||||
if(r)
|
if(r)
|
||||||
r->MemberZoned(this);
|
r->MemberZoned(this);
|
||||||
|
|
||||||
|
auto shared_task = GetSharedTask();
|
||||||
|
if (shared_task)
|
||||||
|
shared_task->MemberZoned(this);
|
||||||
|
|
||||||
m_pp.zone_id = chosen->zone_id;
|
m_pp.zone_id = chosen->zone_id;
|
||||||
m_pp.zoneInstance = chosen->instance_id;
|
m_pp.zoneInstance = chosen->instance_id;
|
||||||
database.MoveCharacterToZone(CharacterID(), database.GetZoneName(chosen->zone_id));
|
database.MoveCharacterToZone(CharacterID(), database.GetZoneName(chosen->zone_id));
|
||||||
|
|||||||
+17
-7
@@ -39,6 +39,8 @@
|
|||||||
#include <ctime>
|
#include <ctime>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
|
#include <task.pb.h>
|
||||||
|
|
||||||
#ifdef _WINDOWS
|
#ifdef _WINDOWS
|
||||||
#define strcasecmp _stricmp
|
#define strcasecmp _stricmp
|
||||||
#endif
|
#endif
|
||||||
@@ -2831,14 +2833,22 @@ void command_spawn(Client *c, const Seperator *sep)
|
|||||||
|
|
||||||
void command_test(Client *c, const Seperator *sep)
|
void command_test(Client *c, const Seperator *sep)
|
||||||
{
|
{
|
||||||
c->Message(15, "Triggering test command");
|
EQ::Proto::ClientTaskStateRequest req;
|
||||||
|
req.set_client_id(123);
|
||||||
|
|
||||||
if (sep->arg[1]) {
|
EQ::Net::DynamicPacket p;
|
||||||
c->SetPrimaryWeaponOrnamentation(atoi(sep->arg[1]));
|
p.PutProtobuf(0, &req);
|
||||||
}
|
|
||||||
if (sep->arg[2]) {
|
worldserver.RouteMessage("Tasks", "", p);
|
||||||
c->SetSecondaryWeaponOrnamentation(atoi(sep->arg[2]));
|
|
||||||
}
|
//c->Message(15, "Triggering test command");
|
||||||
|
//
|
||||||
|
//if (sep->arg[1]) {
|
||||||
|
// c->SetPrimaryWeaponOrnamentation(atoi(sep->arg[1]));
|
||||||
|
//}
|
||||||
|
//if (sep->arg[2]) {
|
||||||
|
// c->SetSecondaryWeaponOrnamentation(atoi(sep->arg[2]));
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
void command_texture(Client *c, const Seperator *sep)
|
void command_texture(Client *c, const Seperator *sep)
|
||||||
|
|||||||
@@ -2127,6 +2127,23 @@ XS(XS__taskselector) {
|
|||||||
|
|
||||||
XSRETURN_EMPTY;
|
XSRETURN_EMPTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
XS(XS__sharedtaskselector);
|
||||||
|
XS(XS__sharedtaskselector) {
|
||||||
|
dXSARGS;
|
||||||
|
if ((items >= 1) && (items <= MAXCHOOSERENTRIES)) {
|
||||||
|
int tasks[MAXCHOOSERENTRIES];
|
||||||
|
for (int i = 0; i < items; i++) {
|
||||||
|
tasks[i] = (int) SvIV(ST(i));
|
||||||
|
}
|
||||||
|
quest_manager.taskselector(items, tasks, true);
|
||||||
|
} else {
|
||||||
|
Perl_croak(aTHX_ "Usage: quest::sharedtaskselector(int task_id, 2, 3, 4, 5 [up to 40])");
|
||||||
|
}
|
||||||
|
|
||||||
|
XSRETURN_EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
XS(XS__task_setselector);
|
XS(XS__task_setselector);
|
||||||
XS(XS__task_setselector) {
|
XS(XS__task_setselector) {
|
||||||
dXSARGS;
|
dXSARGS;
|
||||||
@@ -3942,6 +3959,7 @@ EXTERN_C XS(boot_quest) {
|
|||||||
newXS(strcpy(buf, "targlobal"), XS__targlobal, file);
|
newXS(strcpy(buf, "targlobal"), XS__targlobal, file);
|
||||||
newXS(strcpy(buf, "taskexploredarea"), XS__taskexploredarea, file);
|
newXS(strcpy(buf, "taskexploredarea"), XS__taskexploredarea, file);
|
||||||
newXS(strcpy(buf, "taskselector"), XS__taskselector, file);
|
newXS(strcpy(buf, "taskselector"), XS__taskselector, file);
|
||||||
|
newXS(strcpy(buf, "sharedtaskselector"), XS__sharedtaskselector, file);
|
||||||
newXS(strcpy(buf, "task_setselector"), XS__task_setselector, file);
|
newXS(strcpy(buf, "task_setselector"), XS__task_setselector, file);
|
||||||
newXS(strcpy(buf, "tasktimeleft"), XS__tasktimeleft, file);
|
newXS(strcpy(buf, "tasktimeleft"), XS__tasktimeleft, file);
|
||||||
newXS(strcpy(buf, "toggle_spawn_event"), XS__toggle_spawn_event, file);
|
newXS(strcpy(buf, "toggle_spawn_event"), XS__toggle_spawn_event, file);
|
||||||
|
|||||||
@@ -537,6 +537,9 @@ void EntityList::MobProcess()
|
|||||||
Log(Logs::General, Logs::Error, "About to delete a client still in a raid.");
|
Log(Logs::General, Logs::Error, "About to delete a client still in a raid.");
|
||||||
r->MemberZoned(mob->CastToClient());
|
r->MemberZoned(mob->CastToClient());
|
||||||
}
|
}
|
||||||
|
auto shared_task = mob->CastToClient()->GetSharedTask();
|
||||||
|
if (shared_task)
|
||||||
|
shared_task->MemberZoned(mob);
|
||||||
entity_list.RemoveClient(id);
|
entity_list.RemoveClient(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+28
-1
@@ -581,6 +581,32 @@ void lua_task_selector(luabind::adl::object table) {
|
|||||||
quest_manager.taskselector(count, tasks);
|
quest_manager.taskselector(count, tasks);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void lua_task_selector(luabind::adl::object table, bool shared) {
|
||||||
|
if(luabind::type(table) != LUA_TTABLE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int tasks[MAXCHOOSERENTRIES] = { 0 };
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
for(int i = 1; i <= MAXCHOOSERENTRIES; ++i) {
|
||||||
|
auto cur = table[i];
|
||||||
|
int cur_value = 0;
|
||||||
|
if(luabind::type(cur) != LUA_TNIL) {
|
||||||
|
try {
|
||||||
|
cur_value = luabind::object_cast<int>(cur);
|
||||||
|
} catch(luabind::cast_failed) {
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
count = i - 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks[i - 1] = cur_value;
|
||||||
|
}
|
||||||
|
quest_manager.taskselector(count, tasks, shared);
|
||||||
|
}
|
||||||
|
|
||||||
void lua_task_set_selector(int task_set) {
|
void lua_task_set_selector(int task_set) {
|
||||||
quest_manager.tasksetselector(task_set);
|
quest_manager.tasksetselector(task_set);
|
||||||
}
|
}
|
||||||
@@ -1652,7 +1678,8 @@ luabind::scope lua_register_general() {
|
|||||||
luabind::def("summon_all_player_corpses", &lua_summon_all_player_corpses),
|
luabind::def("summon_all_player_corpses", &lua_summon_all_player_corpses),
|
||||||
luabind::def("get_player_buried_corpse_count", &lua_get_player_buried_corpse_count),
|
luabind::def("get_player_buried_corpse_count", &lua_get_player_buried_corpse_count),
|
||||||
luabind::def("bury_player_corpse", &lua_bury_player_corpse),
|
luabind::def("bury_player_corpse", &lua_bury_player_corpse),
|
||||||
luabind::def("task_selector", &lua_task_selector),
|
luabind::def("task_selector", (void(*)(luabind::adl::object))&lua_task_selector),
|
||||||
|
luabind::def("task_selector", (void(*)(luabind::adl::object,bool))&lua_task_selector),
|
||||||
luabind::def("task_set_selector", &lua_task_set_selector),
|
luabind::def("task_set_selector", &lua_task_set_selector),
|
||||||
luabind::def("enable_task", &lua_enable_task),
|
luabind::def("enable_task", &lua_enable_task),
|
||||||
luabind::def("disable_task", &lua_disable_task),
|
luabind::def("disable_task", &lua_disable_task),
|
||||||
|
|||||||
+4
-4
@@ -2221,10 +2221,10 @@ bool QuestManager::createBot(const char *name, const char *lastname, uint8 level
|
|||||||
|
|
||||||
#endif //BOTS
|
#endif //BOTS
|
||||||
|
|
||||||
void QuestManager::taskselector(int taskcount, int *tasks) {
|
void QuestManager::taskselector(int taskcount, int *tasks, bool shared) {
|
||||||
QuestManagerCurrentQuestVars();
|
QuestManagerCurrentQuestVars();
|
||||||
if(RuleB(TaskSystem, EnableTaskSystem) && initiator && owner && taskmanager)
|
if(RuleB(TaskSystem, EnableTaskSystem) && initiator && owner && taskmanager)
|
||||||
initiator->TaskQuestSetSelector(owner, taskcount, tasks);
|
initiator->TaskQuestSetSelector(owner, taskcount, tasks, shared);
|
||||||
}
|
}
|
||||||
void QuestManager::enabletask(int taskcount, int *tasks) {
|
void QuestManager::enabletask(int taskcount, int *tasks) {
|
||||||
QuestManagerCurrentQuestVars();
|
QuestManagerCurrentQuestVars();
|
||||||
@@ -2249,11 +2249,11 @@ bool QuestManager::istaskenabled(int taskid) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QuestManager::tasksetselector(int tasksetid) {
|
void QuestManager::tasksetselector(int tasksetid, bool shared) {
|
||||||
QuestManagerCurrentQuestVars();
|
QuestManagerCurrentQuestVars();
|
||||||
Log(Logs::General, Logs::Tasks, "[UPDATE] TaskSetSelector called for task set %i", tasksetid);
|
Log(Logs::General, Logs::Tasks, "[UPDATE] TaskSetSelector called for task set %i", tasksetid);
|
||||||
if(RuleB(TaskSystem, EnableTaskSystem) && initiator && owner && taskmanager)
|
if(RuleB(TaskSystem, EnableTaskSystem) && initiator && owner && taskmanager)
|
||||||
initiator->TaskSetSelector(owner, tasksetid);
|
initiator->TaskSetSelector(owner, tasksetid, shared);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QuestManager::istaskactive(int task) {
|
bool QuestManager::istaskactive(int task) {
|
||||||
|
|||||||
+2
-2
@@ -188,8 +188,8 @@ public:
|
|||||||
void playerfeature(char *feature, int setting);
|
void playerfeature(char *feature, int setting);
|
||||||
void npcfeature(char *feature, int setting);
|
void npcfeature(char *feature, int setting);
|
||||||
void popup(const char *title, const char *text, uint32 popupid, uint32 buttons, uint32 Duration);
|
void popup(const char *title, const char *text, uint32 popupid, uint32 buttons, uint32 Duration);
|
||||||
void taskselector(int taskcount, int *tasks);
|
void taskselector(int taskcount, int *tasks, bool shared = false);
|
||||||
void tasksetselector(int tasksettid);
|
void tasksetselector(int tasksettid, bool shared = false);
|
||||||
void enabletask(int taskcount, int *tasks);
|
void enabletask(int taskcount, int *tasks);
|
||||||
void disabletask(int taskcount, int *tasks);
|
void disabletask(int taskcount, int *tasks);
|
||||||
bool istaskenabled(int taskid);
|
bool istaskenabled(int taskid);
|
||||||
|
|||||||
@@ -359,6 +359,7 @@
|
|||||||
#define LDON_NO_LOCKPICK 7564 //You must have a lock pick in your inventory to do this.
|
#define LDON_NO_LOCKPICK 7564 //You must have a lock pick in your inventory to do this.
|
||||||
#define LDON_WAS_NOT_LOCKED 7565 //%1 was not locked.
|
#define LDON_WAS_NOT_LOCKED 7565 //%1 was not locked.
|
||||||
#define LDON_WAS_NOT_TRAPPED 7566 //%1 was not trapped
|
#define LDON_WAS_NOT_TRAPPED 7566 //%1 was not trapped
|
||||||
|
#define TASK_REJECT_LOCKEDOUT_ME 8017 //This task can not be assigned to you because you must wait %1d:%2h:%3m before you can do another task of this type.
|
||||||
#define GAIN_GROUP_LEADERSHIP_POINT 8585 //
|
#define GAIN_GROUP_LEADERSHIP_POINT 8585 //
|
||||||
#define GAIN_RAID_LEADERSHIP_POINT 8589 //
|
#define GAIN_RAID_LEADERSHIP_POINT 8589 //
|
||||||
#define MAX_GROUP_LEADERSHIP_POINTS 8584 //
|
#define MAX_GROUP_LEADERSHIP_POINTS 8584 //
|
||||||
@@ -369,6 +370,15 @@
|
|||||||
#define GAIN_GROUP_LEADERSHIP_EXP 8788 //
|
#define GAIN_GROUP_LEADERSHIP_EXP 8788 //
|
||||||
#define GAIN_RAID_LEADERSHIP_EXP 8789 //
|
#define GAIN_RAID_LEADERSHIP_EXP 8789 //
|
||||||
#define BUFF_MINUTES_REMAINING 8799 //%1 (%2 minutes remaining)
|
#define BUFF_MINUTES_REMAINING 8799 //%1 (%2 minutes remaining)
|
||||||
|
#define TASK_REJECT_MAX_COUNT 8891 //You can not be assigned this shared task because your party exceeds the maximum allowed number of players.
|
||||||
|
#define TASK_REJECT_LEADER_REQ 8892 //You can not be assigned this shared task because the leader does not meet the shared task requirements.
|
||||||
|
#define TASK_REJECT_MIN_COUNT 8895 //You can not be assigned this shared task because your party does not contain the minimum required number of players.
|
||||||
|
#define TASK_REJECT_HAVE_ONE 8935 //You may not request a shared task because you already have one.
|
||||||
|
#define TASK_REJECT_RAID_HAVE_ONE 8936 //You may not request a shared task because someone in your raid, %1, already has one.
|
||||||
|
#define TASK_REJECT_GROUP_HAVE_ONE 8937 //You may not request a shared task because someone in your group, %1, already has one.
|
||||||
|
#define TASK_REJECT_LOCKEDOUT 8946 //You may not request this shared task because you must wait %1d:%2h:%3m before you can do another task of this type.
|
||||||
|
#define TASK_REJECT_LOCKEDOUT_OTHER 8947 //You may not request this shared task because %1 must wait %2d:%3h:%4m before they can do another task of this type.
|
||||||
|
#define SHARED_TASK_LOCK 8961 //Your shared task is now locked. You may no longer add or remove players.
|
||||||
#define NO_MORE_TRAPS 9002 //You have already placed your maximum number of traps.
|
#define NO_MORE_TRAPS 9002 //You have already placed your maximum number of traps.
|
||||||
#define FEAR_TOO_HIGH 9035 //Your target is too high of a level for your fear spell.
|
#define FEAR_TOO_HIGH 9035 //Your target is too high of a level for your fear spell.
|
||||||
#define SLOW_MOSTLY_SUCCESSFUL 9029 //Your spell was mostly successful.
|
#define SLOW_MOSTLY_SUCCESSFUL 9029 //Your spell was mostly successful.
|
||||||
|
|||||||
+389
-49
@@ -30,16 +30,19 @@ Copyright (C) 2001-2008 EQEMu Development Team (http://eqemulator.net)
|
|||||||
#include "../common/rulesys.h"
|
#include "../common/rulesys.h"
|
||||||
#include "../common/string_util.h"
|
#include "../common/string_util.h"
|
||||||
#include "../common/say_link.h"
|
#include "../common/say_link.h"
|
||||||
|
#include "../common/data_verification.h"
|
||||||
|
|
||||||
#include "client.h"
|
#include "client.h"
|
||||||
#include "entity.h"
|
#include "entity.h"
|
||||||
#include "mob.h"
|
#include "mob.h"
|
||||||
#include "string_ids.h"
|
#include "string_ids.h"
|
||||||
|
#include "worldserver.h"
|
||||||
|
|
||||||
#include "queryserv.h"
|
#include "queryserv.h"
|
||||||
#include "quest_parser_collection.h"
|
#include "quest_parser_collection.h"
|
||||||
|
|
||||||
extern QueryServ* QServ;
|
extern QueryServ* QServ;
|
||||||
|
extern WorldServer worldserver;
|
||||||
|
|
||||||
TaskManager::TaskManager() {
|
TaskManager::TaskManager() {
|
||||||
for(int i=0; i<MAXTASKS; i++)
|
for(int i=0; i<MAXTASKS; i++)
|
||||||
@@ -116,14 +119,25 @@ bool TaskManager::LoadTasks(int singleTask)
|
|||||||
if (!LoadTaskSets())
|
if (!LoadTaskSets())
|
||||||
Log(Logs::Detail, Logs::Tasks, "TaskManager::LoadTasks LoadTaskSets failed");
|
Log(Logs::Detail, Logs::Tasks, "TaskManager::LoadTasks LoadTaskSets failed");
|
||||||
|
|
||||||
query = StringFormat("SELECT `id`, `type`, `duration`, `duration_code`, `title`, `description`, "
|
if (!LoadReplayGroups())
|
||||||
"`reward`, `rewardid`, `cashreward`, `xpreward`, `rewardmethod`, `faction_reward`,"
|
Log(Logs::Detail, Logs::Tasks, "TaskManager::LoadTasks LoadReplayGroups failed");
|
||||||
"`minlevel`, `maxlevel`, `repeatable`, `completion_emote` FROM `tasks` WHERE `id` < %i",
|
|
||||||
|
query =
|
||||||
|
StringFormat("SELECT `id`, `type`, `duration`, `duration_code`, `title`, `description`, `reward`, "
|
||||||
|
"`rewardid`, `cashreward`, `xpreward`, `rewardmethod`, `faction_reward`, `minlevel`, "
|
||||||
|
"`maxlevel`, `repeatable`, `completion_emote`, `reward_points`, `reward_type`, "
|
||||||
|
"`replay_group`, `min_players`, `max_players`, `task_lock_step`, `instance_zone_id`, "
|
||||||
|
"`zone_version`, `zone_in_zone_id`, `zone_in_x`, `zone_in_y`, `zone_in_object_id`, "
|
||||||
|
"`dest_x`, `dest_y`, `dest_z`, `dest_h` FROM `tasks` WHERE `id` < %i",
|
||||||
MAXTASKS);
|
MAXTASKS);
|
||||||
} else
|
} else
|
||||||
query = StringFormat("SELECT `id`, `type`, `duration`, `duration_code`, `title`, `description`, "
|
query =
|
||||||
"`reward`, `rewardid`, `cashreward`, `xpreward`, `rewardmethod`, `faction_reward`,"
|
StringFormat("SELECT `id`, `type`, `duration`, `duration_code`, `title`, `description`, `reward`, "
|
||||||
"`minlevel`, `maxlevel`, `repeatable`, `completion_emote` FROM `tasks` WHERE `id` = %i",
|
"`rewardid`, `cashreward`, `xpreward`, `rewardmethod`, `faction_reward`, `minlevel`, "
|
||||||
|
"`maxlevel`, `repeatable`, `completion_emote`, `reward_points`, `reward_type`, "
|
||||||
|
"`replay_group`, `min_players`, `max_players`, `task_lock_step`, `instance_zone_id`, "
|
||||||
|
"`zone_version`, `zone_in_zone_id`, `zone_in_x`, `zone_in_y`, `zone_in_object_id`, "
|
||||||
|
"`dest_x`, `dest_y`, `dest_z`, `dest_h` FROM `tasks` WHERE `id` = %i",
|
||||||
singleTask);
|
singleTask);
|
||||||
|
|
||||||
const char *ERR_MYSQLERROR = "[TASKS]Error in TaskManager::LoadTasks: %s";
|
const char *ERR_MYSQLERROR = "[TASKS]Error in TaskManager::LoadTasks: %s";
|
||||||
@@ -160,6 +174,22 @@ bool TaskManager::LoadTasks(int singleTask)
|
|||||||
Tasks[taskID]->MaxLevel = atoi(row[13]);
|
Tasks[taskID]->MaxLevel = atoi(row[13]);
|
||||||
Tasks[taskID]->Repeatable = atoi(row[14]);
|
Tasks[taskID]->Repeatable = atoi(row[14]);
|
||||||
Tasks[taskID]->completion_emote = row[15];
|
Tasks[taskID]->completion_emote = row[15];
|
||||||
|
Tasks[taskID]->reward_points = atoi(row[16]);
|
||||||
|
Tasks[taskID]->reward_type = static_cast<PointType>(atoi(row[17]));
|
||||||
|
Tasks[taskID]->replay_group = atoi(row[18]);
|
||||||
|
Tasks[taskID]->min_players = atoi(row[19]);
|
||||||
|
Tasks[taskID]->max_players = atoi(row[20]);
|
||||||
|
Tasks[taskID]->task_lock_step = atoi(row[21]);
|
||||||
|
Tasks[taskID]->instance_zone_id = atoi(row[22]);
|
||||||
|
Tasks[taskID]->zone_version = atoi(row[23]);
|
||||||
|
Tasks[taskID]->zone_in_zone_id = atoi(row[24]);
|
||||||
|
Tasks[taskID]->zone_in_x = atof(row[25]);
|
||||||
|
Tasks[taskID]->zone_in_y = atof(row[26]);
|
||||||
|
Tasks[taskID]->zone_in_object_id = atoi(row[27]);
|
||||||
|
Tasks[taskID]->dest_x = atof(row[28]);
|
||||||
|
Tasks[taskID]->dest_y = atof(row[29]);
|
||||||
|
Tasks[taskID]->dest_z = atof(row[30]);
|
||||||
|
Tasks[taskID]->dest_h = atof(row[31]);
|
||||||
Tasks[taskID]->ActivityCount = 0;
|
Tasks[taskID]->ActivityCount = 0;
|
||||||
Tasks[taskID]->SequenceMode = ActivitiesSequential;
|
Tasks[taskID]->SequenceMode = ActivitiesSequential;
|
||||||
Tasks[taskID]->LastStep = 0;
|
Tasks[taskID]->LastStep = 0;
|
||||||
@@ -281,6 +311,22 @@ bool TaskManager::LoadTasks(int singleTask)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool TaskManager::LoadReplayGroups()
|
||||||
|
{
|
||||||
|
replay_groups.clear();
|
||||||
|
std::string query = "SELECT `id`, `name`, `duration` FROM `task_replay_groups` WHERE `id` > 0 ORDER BY `id` ASC";
|
||||||
|
|
||||||
|
auto results = database.QueryDatabase(query);
|
||||||
|
|
||||||
|
if (!results.Success())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (auto row = results.begin(); row != results.end(); ++row)
|
||||||
|
replay_groups[atoi(row[0])] = {row[1], atoi(row[2])};
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool TaskManager::SaveClientState(Client *c, ClientTaskState *state)
|
bool TaskManager::SaveClientState(Client *c, ClientTaskState *state)
|
||||||
{
|
{
|
||||||
// I am saving the slot in the ActiveTasks table, because unless a Task is cancelled/completed, the client
|
// I am saving the slot in the ActiveTasks table, because unless a Task is cancelled/completed, the client
|
||||||
@@ -425,29 +471,22 @@ bool TaskManager::SaveClientState(Client *c, ClientTaskState *state)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Client::LoadClientTaskState() {
|
void Client::LoadClientTaskState() {
|
||||||
|
//GetClientTaskStateRequest req;
|
||||||
if(RuleB(TaskSystem, EnableTaskSystem) && taskmanager) {
|
//req.client_id = CharacterID();
|
||||||
if(taskstate)
|
//
|
||||||
safe_delete(taskstate);
|
//EQ::Net::DynamicPacket p;
|
||||||
|
//p.PutInt32(0, TaskGetClientTaskState);
|
||||||
taskstate = new ClientTaskState;
|
//p.PutSerialize(4, req);
|
||||||
if(!taskmanager->LoadClientState(this, taskstate)) {
|
//
|
||||||
safe_delete(taskstate);
|
//worldserver.RouteMessage("Tasks", "", p);
|
||||||
}
|
|
||||||
else {
|
|
||||||
taskmanager->SendActiveTasksToClient(this);
|
|
||||||
taskmanager->SendCompletedTasksToClient(this, taskstate);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::RemoveClientTaskState() {
|
void Client::RemoveClientTaskState() {
|
||||||
|
|
||||||
if(taskstate) {
|
//if(taskstate) {
|
||||||
taskstate->CancelAllTasks(this);
|
// taskstate->CancelAllTasks(this);
|
||||||
safe_delete(taskstate);
|
// safe_delete(taskstate);
|
||||||
}
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TaskManager::LoadClientState(Client *c, ClientTaskState *state)
|
bool TaskManager::LoadClientState(Client *c, ClientTaskState *state)
|
||||||
@@ -905,7 +944,7 @@ bool ClientTaskState::HasSlotForTask(TaskInformation *task)
|
|||||||
case TaskType::Task:
|
case TaskType::Task:
|
||||||
return ActiveTask.TaskID == TASKSLOTEMPTY;
|
return ActiveTask.TaskID == TASKSLOTEMPTY;
|
||||||
case TaskType::Shared:
|
case TaskType::Shared:
|
||||||
return false; // todo
|
return ActiveSharedTask == nullptr; // todo
|
||||||
case TaskType::Quest:
|
case TaskType::Quest:
|
||||||
for (int i = 0; i < MAXACTIVEQUESTS; ++i)
|
for (int i = 0; i < MAXACTIVEQUESTS; ++i)
|
||||||
if (ActiveQuests[i].TaskID == TASKSLOTEMPTY)
|
if (ActiveQuests[i].TaskID == TASKSLOTEMPTY)
|
||||||
@@ -988,7 +1027,7 @@ int TaskManager::GetTaskMaxLevel(int TaskID)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TaskManager::TaskSetSelector(Client *c, ClientTaskState *state, Mob *mob, int TaskSetID)
|
void TaskManager::TaskSetSelector(Client *c, ClientTaskState *state, Mob *mob, int TaskSetID, bool shared)
|
||||||
{
|
{
|
||||||
int TaskList[MAXCHOOSERENTRIES];
|
int TaskList[MAXCHOOSERENTRIES];
|
||||||
int TaskListIndex = 0;
|
int TaskListIndex = 0;
|
||||||
@@ -1024,14 +1063,14 @@ void TaskManager::TaskSetSelector(Client *c, ClientTaskState *state, Mob *mob, i
|
|||||||
// we aren't currently on another, and if it's enabled if not all_enabled
|
// we aren't currently on another, and if it's enabled if not all_enabled
|
||||||
if ((all_enabled || state->IsTaskEnabled(task)) && AppropriateLevel(task, PlayerLevel) &&
|
if ((all_enabled || state->IsTaskEnabled(task)) && AppropriateLevel(task, PlayerLevel) &&
|
||||||
!state->IsTaskActive(task) && state->HasSlotForTask(Tasks[task]) && // this slot checking is a bit silly, but we allow mixing of task types ...
|
!state->IsTaskActive(task) && state->HasSlotForTask(Tasks[task]) && // this slot checking is a bit silly, but we allow mixing of task types ...
|
||||||
(IsTaskRepeatable(task) || !state->IsTaskCompleted(task)))
|
(IsTaskRepeatable(task) || !state->IsTaskCompleted(task)) && (shared == (Tasks[task]->type == TaskType::Shared)))
|
||||||
TaskList[TaskListIndex++] = task;
|
TaskList[TaskListIndex++] = task;
|
||||||
|
|
||||||
++Iterator;
|
++Iterator;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TaskListIndex > 0) {
|
if (TaskListIndex > 0) {
|
||||||
SendTaskSelector(c, mob, TaskListIndex, TaskList);
|
SendTaskSelector(c, mob, TaskListIndex, TaskList, shared);
|
||||||
} else {
|
} else {
|
||||||
mob->SayTo_StringID(c, CC_Yellow, MAX_ACTIVE_TASKS, c->GetName()); // check color, I think this might be only for (Shared) Tasks, w/e -- think should be yellow
|
mob->SayTo_StringID(c, CC_Yellow, MAX_ACTIVE_TASKS, c->GetName()); // check color, I think this might be only for (Shared) Tasks, w/e -- think should be yellow
|
||||||
}
|
}
|
||||||
@@ -1041,7 +1080,7 @@ void TaskManager::TaskSetSelector(Client *c, ClientTaskState *state, Mob *mob, i
|
|||||||
|
|
||||||
// unlike the non-Quest version of this function, it does not check enabled, that is assumed the responsibility of the quest to handle
|
// unlike the non-Quest version of this function, it does not check enabled, that is assumed the responsibility of the quest to handle
|
||||||
// we do however still want it to check the other stuff like level, active, room, etc
|
// we do however still want it to check the other stuff like level, active, room, etc
|
||||||
void TaskManager::TaskQuestSetSelector(Client *c, ClientTaskState *state, Mob *mob, int count, int *tasks)
|
void TaskManager::TaskQuestSetSelector(Client *c, ClientTaskState *state, Mob *mob, int count, int *tasks, bool shared)
|
||||||
{
|
{
|
||||||
int TaskList[MAXCHOOSERENTRIES];
|
int TaskList[MAXCHOOSERENTRIES];
|
||||||
int TaskListIndex = 0;
|
int TaskListIndex = 0;
|
||||||
@@ -1058,12 +1097,12 @@ void TaskManager::TaskQuestSetSelector(Client *c, ClientTaskState *state, Mob *m
|
|||||||
// we aren't currently on another, and if it's enabled if not all_enabled
|
// we aren't currently on another, and if it's enabled if not all_enabled
|
||||||
if (AppropriateLevel(task, PlayerLevel) &&
|
if (AppropriateLevel(task, PlayerLevel) &&
|
||||||
!state->IsTaskActive(task) && state->HasSlotForTask(Tasks[task]) && // this slot checking is a bit silly, but we allow mixing of task types ...
|
!state->IsTaskActive(task) && state->HasSlotForTask(Tasks[task]) && // this slot checking is a bit silly, but we allow mixing of task types ...
|
||||||
(IsTaskRepeatable(task) || !state->IsTaskCompleted(task)))
|
(IsTaskRepeatable(task) || !state->IsTaskCompleted(task)) && (shared == (Tasks[task]->type == TaskType::Shared)))
|
||||||
TaskList[TaskListIndex++] = task;
|
TaskList[TaskListIndex++] = task;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TaskListIndex > 0) {
|
if (TaskListIndex > 0) {
|
||||||
SendTaskSelector(c, mob, TaskListIndex, TaskList);
|
SendTaskSelector(c, mob, TaskListIndex, TaskList, shared);
|
||||||
} else {
|
} else {
|
||||||
mob->SayTo_StringID(c, CC_Yellow, MAX_ACTIVE_TASKS, c->GetName()); // check color, I think this might be only for (Shared) Tasks, w/e -- think should be yellow
|
mob->SayTo_StringID(c, CC_Yellow, MAX_ACTIVE_TASKS, c->GetName()); // check color, I think this might be only for (Shared) Tasks, w/e -- think should be yellow
|
||||||
}
|
}
|
||||||
@@ -1071,11 +1110,11 @@ void TaskManager::TaskQuestSetSelector(Client *c, ClientTaskState *state, Mob *m
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TaskManager::SendTaskSelector(Client *c, Mob *mob, int TaskCount, int *TaskList) {
|
void TaskManager::SendTaskSelector(Client *c, Mob *mob, int TaskCount, int *TaskList, bool shared) {
|
||||||
|
|
||||||
if (c->ClientVersion() >= EQEmu::versions::ClientVersion::RoF)
|
if (c->ClientVersion() >= EQEmu::versions::ClientVersion::RoF)
|
||||||
{
|
{
|
||||||
SendTaskSelectorNew(c, mob, TaskCount, TaskList);
|
SendTaskSelectorNew(c, mob, TaskCount, TaskList, shared);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Titanium OpCode: 0x5e7c
|
// Titanium OpCode: 0x5e7c
|
||||||
@@ -1108,7 +1147,7 @@ void TaskManager::SendTaskSelector(Client *c, Mob *mob, int TaskCount, int *Task
|
|||||||
|
|
||||||
|
|
||||||
buf.WriteUInt32(ValidTasks);
|
buf.WriteUInt32(ValidTasks);
|
||||||
buf.WriteUInt32(2); // task type, live doesn't let you send more than one type, but we do?
|
buf.WriteUInt32(shared ? static_cast<uint32>(TaskType::Shared) : static_cast<uint32>(TaskType::Quest)); // hack, we need to send only shared tasks when doing shared tasks since they use different reply ops
|
||||||
buf.WriteUInt32(mob->GetID());
|
buf.WriteUInt32(mob->GetID());
|
||||||
|
|
||||||
for (int i = 0; i < TaskCount; i++) {
|
for (int i = 0; i < TaskCount; i++) {
|
||||||
@@ -1153,12 +1192,14 @@ void TaskManager::SendTaskSelector(Client *c, Mob *mob, int TaskCount, int *Task
|
|||||||
|
|
||||||
auto outapp = new EQApplicationPacket(OP_OpenNewTasksWindow, buf);
|
auto outapp = new EQApplicationPacket(OP_OpenNewTasksWindow, buf);
|
||||||
|
|
||||||
|
DumpPacket(outapp, true);
|
||||||
|
|
||||||
c->QueuePacket(outapp);
|
c->QueuePacket(outapp);
|
||||||
safe_delete(outapp);
|
safe_delete(outapp);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TaskManager::SendTaskSelectorNew(Client *c, Mob *mob, int TaskCount, int *TaskList)
|
void TaskManager::SendTaskSelectorNew(Client *c, Mob *mob, int TaskCount, int *TaskList, bool shared)
|
||||||
{
|
{
|
||||||
Log(Logs::General, Logs::Tasks, "[UPDATE] TaskSelector for %i Tasks", TaskCount);
|
Log(Logs::General, Logs::Tasks, "[UPDATE] TaskSelector for %i Tasks", TaskCount);
|
||||||
|
|
||||||
@@ -1188,9 +1229,7 @@ void TaskManager::SendTaskSelectorNew(Client *c, Mob *mob, int TaskCount, int *T
|
|||||||
SerializeBuffer buf(50 * ValidTasks);
|
SerializeBuffer buf(50 * ValidTasks);
|
||||||
|
|
||||||
buf.WriteUInt32(ValidTasks); // TaskCount
|
buf.WriteUInt32(ValidTasks); // TaskCount
|
||||||
buf.WriteUInt32(2); // Type, valid values: 0-3. 0 = Task, 1 = Shared Task, 2 = Quest, 3 = ??? -- should fix maybe some day, but we let more than 1 type through :P
|
buf.WriteUInt32(shared ? static_cast<uint32>(TaskType::Shared) : static_cast<uint32>(TaskType::Quest)); // hack, we need to send only shared tasks when doing shared tasks since they use different reply ops
|
||||||
// so I guess an NPC can only offer one type of quests or we can only open a selection with one type :P (so quest call can tell us I guess)
|
|
||||||
// this is also sent in OP_TaskDescription
|
|
||||||
buf.WriteUInt32(mob->GetID()); // TaskGiver
|
buf.WriteUInt32(mob->GetID()); // TaskGiver
|
||||||
|
|
||||||
for (int i = 0; i < TaskCount; i++) { // max 40
|
for (int i = 0; i < TaskCount; i++) { // max 40
|
||||||
@@ -1240,6 +1279,8 @@ void TaskManager::SendTaskSelectorNew(Client *c, Mob *mob, int TaskCount, int *T
|
|||||||
|
|
||||||
auto outapp = new EQApplicationPacket(OP_OpenNewTasksWindow, buf);
|
auto outapp = new EQApplicationPacket(OP_OpenNewTasksWindow, buf);
|
||||||
|
|
||||||
|
DumpPacket(outapp, true);
|
||||||
|
|
||||||
c->QueuePacket(outapp);
|
c->QueuePacket(outapp);
|
||||||
safe_delete(outapp);
|
safe_delete(outapp);
|
||||||
|
|
||||||
@@ -1304,7 +1345,8 @@ ClientTaskState::ClientTaskState() {
|
|||||||
|
|
||||||
ActiveTask.slot = 0;
|
ActiveTask.slot = 0;
|
||||||
ActiveTask.TaskID = TASKSLOTEMPTY;
|
ActiveTask.TaskID = TASKSLOTEMPTY;
|
||||||
// TODO: shared task
|
|
||||||
|
ActiveSharedTask = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
ClientTaskState::~ClientTaskState() {
|
ClientTaskState::~ClientTaskState() {
|
||||||
@@ -2406,6 +2448,15 @@ bool TaskManager::IsTaskRepeatable(int TaskID) {
|
|||||||
return Task->Repeatable;
|
return Task->Repeatable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SharedTaskState *TaskManager::CreateSharedTask(int id, int task_id)
|
||||||
|
{
|
||||||
|
auto ret = SharedTasks.insert({id, {id, task_id}});
|
||||||
|
if (!ret.second) // hmm was already created
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
return &(ret.first->second);
|
||||||
|
}
|
||||||
|
|
||||||
bool ClientTaskState::TaskOutOfTime(TaskType type, int Index)
|
bool ClientTaskState::TaskOutOfTime(TaskType type, int Index)
|
||||||
{
|
{
|
||||||
// Returns true if the Task in the specified slot has a time limit that has been exceeded.
|
// Returns true if the Task in the specified slot has a time limit that has been exceeded.
|
||||||
@@ -2496,7 +2547,7 @@ void Client::SendTaskComplete(int TaskIndex) {
|
|||||||
tcs->unknown04 = 0x00000002;
|
tcs->unknown04 = 0x00000002;
|
||||||
|
|
||||||
Log.LogDebugType(Logs::Detail, Logs::Tasks, "SendTasksComplete");
|
Log.LogDebugType(Logs::Detail, Logs::Tasks, "SendTasksComplete");
|
||||||
DumpPacket(outapp); fflush(stdout);
|
DumpPacket(outapp, true); fflush(stdout);
|
||||||
|
|
||||||
QueuePacket(outapp);
|
QueuePacket(outapp);
|
||||||
safe_delete(outapp);
|
safe_delete(outapp);
|
||||||
@@ -2577,6 +2628,7 @@ void ClientTaskState::SendTaskHistory(Client *c, int TaskIndex) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DumpPacket(outapp, true);
|
||||||
|
|
||||||
c->QueuePacket(outapp);
|
c->QueuePacket(outapp);
|
||||||
safe_delete(outapp);
|
safe_delete(outapp);
|
||||||
@@ -2602,6 +2654,7 @@ void Client::SendTaskActivityComplete(int TaskID, int ActivityID, int TaskIndex,
|
|||||||
tac->task_completed = 0x00000001;
|
tac->task_completed = 0x00000001;
|
||||||
tac->stage_complete = TaskIncomplete;
|
tac->stage_complete = TaskIncomplete;
|
||||||
|
|
||||||
|
DumpPacket(outapp, true);
|
||||||
|
|
||||||
QueuePacket(outapp);
|
QueuePacket(outapp);
|
||||||
safe_delete(outapp);
|
safe_delete(outapp);
|
||||||
@@ -2631,6 +2684,8 @@ void Client::SendTaskFailed(int TaskID, int TaskIndex, TaskType type)
|
|||||||
|
|
||||||
Log(Logs::General, Logs::Tasks, "[UPDATE] TaskFailed");
|
Log(Logs::General, Logs::Tasks, "[UPDATE] TaskFailed");
|
||||||
|
|
||||||
|
DumpPacket(outapp, true);
|
||||||
|
|
||||||
QueuePacket(outapp);
|
QueuePacket(outapp);
|
||||||
safe_delete(outapp);
|
safe_delete(outapp);
|
||||||
}
|
}
|
||||||
@@ -2686,6 +2741,7 @@ void TaskManager::SendCompletedTasksToClient(Client *c, ClientTaskState *State)
|
|||||||
buf = buf + 4;
|
buf = buf + 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DumpPacket(outapp, true);
|
||||||
|
|
||||||
c->QueuePacket(outapp);
|
c->QueuePacket(outapp);
|
||||||
safe_delete(outapp);
|
safe_delete(outapp);
|
||||||
@@ -2710,6 +2766,8 @@ void TaskManager::SendTaskActivityShort(Client *c, int TaskID, int ActivityID, i
|
|||||||
outapp->WriteUInt32(0);
|
outapp->WriteUInt32(0);
|
||||||
outapp->WriteUInt32(0xffffffff);
|
outapp->WriteUInt32(0xffffffff);
|
||||||
outapp->WriteUInt8(0);
|
outapp->WriteUInt8(0);
|
||||||
|
|
||||||
|
DumpPacket(outapp, true);
|
||||||
c->FastQueuePacket(&outapp);
|
c->FastQueuePacket(&outapp);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@@ -2727,7 +2785,7 @@ void TaskManager::SendTaskActivityShort(Client *c, int TaskID, int ActivityID, i
|
|||||||
tass->ActivityType = 0xffffffff;
|
tass->ActivityType = 0xffffffff;
|
||||||
tass->unknown4 = 0x00000000;
|
tass->unknown4 = 0x00000000;
|
||||||
|
|
||||||
|
DumpPacket(outapp, true);
|
||||||
c->QueuePacket(outapp);
|
c->QueuePacket(outapp);
|
||||||
safe_delete(outapp);
|
safe_delete(outapp);
|
||||||
}
|
}
|
||||||
@@ -2789,6 +2847,8 @@ void TaskManager::SendTaskActivityLong(Client *c, int TaskID, int ActivityID, in
|
|||||||
|
|
||||||
auto outapp = new EQApplicationPacket(OP_TaskActivity, buf);
|
auto outapp = new EQApplicationPacket(OP_TaskActivity, buf);
|
||||||
|
|
||||||
|
DumpPacket(outapp, true);
|
||||||
|
|
||||||
c->QueuePacket(outapp);
|
c->QueuePacket(outapp);
|
||||||
safe_delete(outapp);
|
safe_delete(outapp);
|
||||||
|
|
||||||
@@ -2849,6 +2909,8 @@ void TaskManager::SendTaskActivityNew(Client *c, int TaskID, int ActivityID, int
|
|||||||
|
|
||||||
auto outapp = new EQApplicationPacket(OP_TaskActivity, buf);
|
auto outapp = new EQApplicationPacket(OP_TaskActivity, buf);
|
||||||
|
|
||||||
|
DumpPacket(outapp, true);
|
||||||
|
|
||||||
c->QueuePacket(outapp);
|
c->QueuePacket(outapp);
|
||||||
safe_delete(outapp);
|
safe_delete(outapp);
|
||||||
|
|
||||||
@@ -3016,10 +3078,27 @@ void TaskManager::SendActiveTaskDescription(Client *c, int TaskID, ClientTaskInf
|
|||||||
tdt->Points = 0x00000000; // Points Count TODO: this does have a visible affect on the client ...
|
tdt->Points = 0x00000000; // Points Count TODO: this does have a visible affect on the client ...
|
||||||
tdt->has_reward_selection = 0; // TODO: new rewards window
|
tdt->has_reward_selection = 0; // TODO: new rewards window
|
||||||
|
|
||||||
|
DumpPacket(outapp, true);
|
||||||
|
|
||||||
c->QueuePacket(outapp);
|
c->QueuePacket(outapp);
|
||||||
safe_delete(outapp);
|
safe_delete(outapp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: stub
|
||||||
|
SharedTaskState *TaskManager::LoadSharedTask(int id)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
SharedTaskState *TaskManager::GetSharedTask(int id)
|
||||||
|
{
|
||||||
|
auto it = SharedTasks.find(id);
|
||||||
|
if (it == SharedTasks.end())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
return &(it->second);
|
||||||
|
}
|
||||||
|
|
||||||
bool ClientTaskState::IsTaskActivityCompleted(TaskType type, int index, int ActivityID)
|
bool ClientTaskState::IsTaskActivityCompleted(TaskType type, int index, int ActivityID)
|
||||||
{
|
{
|
||||||
switch (type) {
|
switch (type) {
|
||||||
@@ -3140,6 +3219,8 @@ void ClientTaskState::CancelTask(Client *c, int SequenceNumber, TaskType type, b
|
|||||||
|
|
||||||
Log(Logs::General, Logs::Tasks, "[UPDATE] CancelTask");
|
Log(Logs::General, Logs::Tasks, "[UPDATE] CancelTask");
|
||||||
|
|
||||||
|
DumpPacket(outapp, true);
|
||||||
|
|
||||||
c->QueuePacket(outapp);
|
c->QueuePacket(outapp);
|
||||||
safe_delete(outapp);
|
safe_delete(outapp);
|
||||||
|
|
||||||
@@ -3222,10 +3303,8 @@ void ClientTaskState::AcceptNewTask(Client *c, int TaskID, int NPCID, bool enfor
|
|||||||
if (ActiveTask.TaskID != TASKSLOTEMPTY)
|
if (ActiveTask.TaskID != TASKSLOTEMPTY)
|
||||||
max_tasks = true;
|
max_tasks = true;
|
||||||
break;
|
break;
|
||||||
case TaskType::Shared: // TODO: shared tasks
|
case TaskType::Shared: // shared tasks shouldn't call this function. should we log?
|
||||||
// if (something)
|
return;
|
||||||
max_tasks = true;
|
|
||||||
break;
|
|
||||||
case TaskType::Quest:
|
case TaskType::Quest:
|
||||||
if (ActiveTaskCount == MAXACTIVEQUESTS)
|
if (ActiveTaskCount == MAXACTIVEQUESTS)
|
||||||
max_tasks = true;
|
max_tasks = true;
|
||||||
@@ -3267,9 +3346,8 @@ void ClientTaskState::AcceptNewTask(Client *c, int TaskID, int NPCID, bool enfor
|
|||||||
case TaskType::Task:
|
case TaskType::Task:
|
||||||
active_slot = &ActiveTask;
|
active_slot = &ActiveTask;
|
||||||
break;
|
break;
|
||||||
case TaskType::Shared: // TODO: shared
|
case TaskType::Shared: // shared aren't done here, should have returned already :P
|
||||||
active_slot = nullptr;
|
return;
|
||||||
break;
|
|
||||||
case TaskType::Quest:
|
case TaskType::Quest:
|
||||||
for (int i = 0; i < MAXACTIVEQUESTS; i++) {
|
for (int i = 0; i < MAXACTIVEQUESTS; i++) {
|
||||||
Log(Logs::General, Logs::Tasks,
|
Log(Logs::General, Logs::Tasks,
|
||||||
@@ -3324,6 +3402,213 @@ void ClientTaskState::AcceptNewTask(Client *c, int TaskID, int NPCID, bool enfor
|
|||||||
parse->EventNPC(EVENT_TASK_ACCEPTED, npc, c, buf.c_str(), 0);
|
parse->EventNPC(EVENT_TASK_ACCEPTED, npc, c, buf.c_str(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function is a proxy for OP_AccetNewSharedTask since it has to fire to
|
||||||
|
* world. We do a handful of checks on the leader, then build a packet with a
|
||||||
|
* list of all the members in our group/raid if applicable. The verification for
|
||||||
|
* the other members is done in world.
|
||||||
|
*/
|
||||||
|
void ClientTaskState::RequestSharedTask(Client *c, int TaskID, int NPCID, bool enforce_level_requirement)
|
||||||
|
{
|
||||||
|
if (!taskmanager || TaskID < 0 || TaskID >= MAXTASKS) {
|
||||||
|
c->Message(13, "Task system not functioning, or TaskID %i out of range.", TaskID);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto task = taskmanager->Tasks[TaskID];
|
||||||
|
|
||||||
|
if (task == nullptr) {
|
||||||
|
c->Message(13, "Invalid TaskID %i", TaskID);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (task->type != TaskType::Shared) {
|
||||||
|
c->Message(13, "Trying to shared task a non shared task %i", TaskID);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ActiveSharedTask != nullptr) {
|
||||||
|
c->Message_StringID(13, TASK_REJECT_HAVE_ONE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enforce_level_requirement && !taskmanager->AppropriateLevel(TaskID, c->GetLevel())) {
|
||||||
|
c->Message(13, "You are outside the level range of this task.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!taskmanager->IsTaskRepeatable(TaskID) && IsTaskCompleted(TaskID))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (task->replay_group) {
|
||||||
|
auto expires = c->GetTaskLockoutTimeLeft(task->replay_group);
|
||||||
|
if (expires > 0) {
|
||||||
|
std::string days = std::to_string(expires / 86400);
|
||||||
|
expires = expires % 86400;
|
||||||
|
std::string hours = std::to_string(expires / 3600);
|
||||||
|
expires = expires % 3600;
|
||||||
|
std::string minutes = std::to_string(expires / 60);
|
||||||
|
c->Message_StringID(13, TASK_REJECT_LOCKEDOUT, days.c_str(), hours.c_str(), minutes.c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now we need to verify we meet min_player and max_players for raid/group
|
||||||
|
Group *group = nullptr;
|
||||||
|
Raid *raid = nullptr;
|
||||||
|
int player_count = 1; // 1 is just us!
|
||||||
|
if (c->IsGrouped()) {
|
||||||
|
group = c->GetGroup();
|
||||||
|
player_count = group->GroupCount();
|
||||||
|
} else if (c->IsRaidGrouped()) {
|
||||||
|
raid = c->GetRaid();
|
||||||
|
player_count = raid->RaidCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!EQEmu::ValueWithin(player_count, task->min_players, task->max_players)) {
|
||||||
|
if (player_count < task->min_players)
|
||||||
|
c->Message_StringID(13, TASK_REJECT_MIN_COUNT);
|
||||||
|
else
|
||||||
|
c->Message_StringID(13, TASK_REJECT_MAX_COUNT);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// okay, we verified a few things on the requestor, now we need to fire off to world to do the rest
|
||||||
|
SerializeBuffer buf(25 + 10 * player_count);
|
||||||
|
buf.WriteInt32(TaskID); // Task ID
|
||||||
|
buf.WriteInt32(NPCID); // NPC we're requesting from
|
||||||
|
buf.WriteString(c->GetName()); // leader name
|
||||||
|
buf.WriteInt32(player_count - 1); // count, not leader
|
||||||
|
if (group) {
|
||||||
|
for (int i = 0; i < MAX_GROUP_MEMBERS; ++i) {
|
||||||
|
if (group->members[i] == c) // skipping requestor
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// TODO: mercs/bots
|
||||||
|
if (group->members[i] != nullptr && group->members[i]->IsClient())
|
||||||
|
buf.WriteString(group->membername[i]);
|
||||||
|
}
|
||||||
|
} else if (raid) {
|
||||||
|
for (int i = 0; i < MAX_RAID_MEMBERS; ++i) {
|
||||||
|
if (raid->members[i].member == c) // skipping requestor
|
||||||
|
continue;
|
||||||
|
// TODO: bots if they ever can live in a raid
|
||||||
|
if (raid->members[i].membername[0] != '\0')
|
||||||
|
buf.WriteString(raid->members[i].membername);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto pack = new ServerPacket(ServerOP_TaskRequest, buf);
|
||||||
|
worldserver.SendPacket(pack);
|
||||||
|
delete pack;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientTaskState::AcceptNewSharedTask(Client *c, int TaskID, int NPCID, int id, int accepted_time,
|
||||||
|
std::vector<std::string> &members)
|
||||||
|
{
|
||||||
|
// all of this data should have been verified already
|
||||||
|
// first we need to create the new SharedTaskState
|
||||||
|
auto task_state = taskmanager->CreateSharedTask(id, TaskID);
|
||||||
|
if (!task_state) {
|
||||||
|
// TODO: something failed, tell world
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we need to init the activity now
|
||||||
|
auto task_activity = task_state->GetActivity();
|
||||||
|
|
||||||
|
task_activity->TaskID = TaskID;
|
||||||
|
task_activity->AcceptedTime = accepted_time;
|
||||||
|
task_activity->Updated = true;
|
||||||
|
task_activity->CurrentStep = -1;
|
||||||
|
|
||||||
|
for (int i = 0; i < taskmanager->Tasks[TaskID]->ActivityCount; i++) {
|
||||||
|
task_activity->Activity[i].ActivityID = i;
|
||||||
|
task_activity->Activity[i].DoneCount = 0;
|
||||||
|
task_activity->Activity[i].State = ActivityHidden;
|
||||||
|
task_activity->Activity[i].Updated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: figure out packet order
|
||||||
|
// unsure if we unlock now packet wise, just copying normal tasks for now
|
||||||
|
UnlockActivities(c->CharacterID(), *task_activity);
|
||||||
|
|
||||||
|
taskmanager->SendSingleActiveTaskToClient(c, *task_activity, false, true);
|
||||||
|
c->Message(0, "You have been assigned the task '%s'.", taskmanager->Tasks[TaskID]->Title.c_str());
|
||||||
|
|
||||||
|
// send member list of just leader
|
||||||
|
task_state->AddMember(c->GetName(), c, true);
|
||||||
|
task_state->SendMembersList(c);
|
||||||
|
|
||||||
|
// send compass shit
|
||||||
|
|
||||||
|
// add everyone else and send that
|
||||||
|
// we could try to find these members so they could know about it ... but ahh not sure :P
|
||||||
|
for (auto &m : members)
|
||||||
|
task_state->AddMember(m);
|
||||||
|
|
||||||
|
task_state->SendMembersList(c);
|
||||||
|
|
||||||
|
std::string buf = std::to_string(TaskID);
|
||||||
|
NPC *npc = entity_list.GetID(NPCID)->CastToNPC();
|
||||||
|
if(!npc) {
|
||||||
|
c->Message(clientMessageYellow, "Task Giver ID is %i", NPCID);
|
||||||
|
c->Message(clientMessageError, "Unable to find NPC to send EVENT_TASKACCEPTED to. Report this bug.");
|
||||||
|
// TODO: ahh do we wanna do this? clean up world at least
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: save state -- for the client
|
||||||
|
parse->EventNPC(EVENT_TASK_ACCEPTED, npc, c, buf.c_str(), 0);
|
||||||
|
|
||||||
|
auto pack = new ServerPacket(ServerOP_TaskZoneCreated, sizeof(uint32)); // just the ID saying to continue
|
||||||
|
pack->WriteUInt32(id);
|
||||||
|
worldserver.SendPacket(pack);
|
||||||
|
delete pack;
|
||||||
|
|
||||||
|
ActiveSharedTask = task_state;
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
// there are a few issues we need to solve with this
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function is called when world sends ServerOP_TaskZoneCreated to trigger
|
||||||
|
* members to join. If the task doesn't already exist, we need to load it from
|
||||||
|
* the DB.
|
||||||
|
*
|
||||||
|
* This is also called in LoadClientTaskState() when they notice they have a
|
||||||
|
* shared task they need to join. (Called from first OP_ZoneEntry)
|
||||||
|
*/
|
||||||
|
void ClientTaskState::AddToSharedTask(Client *c, int TaskID)
|
||||||
|
{
|
||||||
|
auto task = taskmanager->GetSharedTask(TaskID);
|
||||||
|
if (!task)
|
||||||
|
task = taskmanager->LoadSharedTask(TaskID);
|
||||||
|
|
||||||
|
if (!task) {// FUCK
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
task->MemberEnterZone(c);
|
||||||
|
|
||||||
|
// send packets
|
||||||
|
auto task_activity = task->GetActivity();
|
||||||
|
taskmanager->SendSingleActiveTaskToClient(c, *task_activity, false, true);
|
||||||
|
task->SendMembersList(c);
|
||||||
|
|
||||||
|
// So normally getting a task we would send EVENT_TASK_ACCEPTED here, but
|
||||||
|
// this isn't an accept step. I guess we should add another event in case
|
||||||
|
// they need the same thing TODO
|
||||||
|
|
||||||
|
ActiveSharedTask = task;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
void ClientTaskState::ProcessTaskProximities(Client *c, float X, float Y, float Z) {
|
void ClientTaskState::ProcessTaskProximities(Client *c, float X, float Y, float Z) {
|
||||||
|
|
||||||
float LastX = c->ProximityX();
|
float LastX = c->ProximityX();
|
||||||
@@ -3537,3 +3822,58 @@ int TaskProximityManager::CheckProximities(float X, float Y, float Z) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SharedTaskState::LockTask()
|
||||||
|
{
|
||||||
|
SetLocked(true);
|
||||||
|
|
||||||
|
for (auto & m : members)
|
||||||
|
if (m.entity != nullptr)
|
||||||
|
m.entity->Message_StringID(CC_Yellow, SHARED_TASK_LOCK);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SharedTaskState::MemberZoned(Mob *player)
|
||||||
|
{
|
||||||
|
auto it = std::find_if(members.begin(), members.end(),
|
||||||
|
[&player](const SharedTaskMember &a) { return a.entity == player; });
|
||||||
|
|
||||||
|
if (it == members.end()) // guess they weren't in this group, w/e
|
||||||
|
return;
|
||||||
|
|
||||||
|
it->entity = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SharedTaskState::MemberEnterZone(Mob *player)
|
||||||
|
{
|
||||||
|
auto it = std::find_if(members.begin(), members.end(),
|
||||||
|
[&player](const SharedTaskMember &a) { return a.name == player->GetName(); });
|
||||||
|
|
||||||
|
if (it == members.end()) // guess they weren't in this group, w/e
|
||||||
|
return;
|
||||||
|
|
||||||
|
it->entity = player;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SharedTaskState::SendMembersList(Client *to) const
|
||||||
|
{
|
||||||
|
if (!to)
|
||||||
|
return;
|
||||||
|
|
||||||
|
SerializeBuffer buf(sizeof(TaskMemberList_Struct) + 15 * members.size());
|
||||||
|
buf.WriteInt32(0); // unknown ids
|
||||||
|
buf.WriteInt32(0);
|
||||||
|
buf.WriteInt32(members.size());
|
||||||
|
|
||||||
|
for (auto &&m : members) {
|
||||||
|
buf.WriteString(m.name);
|
||||||
|
buf.WriteInt32(0); // monster mission shit
|
||||||
|
buf.WriteInt8(m.leader);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto outapp = new EQApplicationPacket(OP_SharedTaskMemberList, buf);
|
||||||
|
|
||||||
|
DumpPacket(outapp, true);
|
||||||
|
|
||||||
|
to->QueuePacket(outapp);
|
||||||
|
safe_delete(outapp);
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
+69
-110
@@ -21,29 +21,14 @@ Copyright (C) 2001-2004 EQEMu Development Team (http://eqemulator.net)
|
|||||||
#define TASKS_H
|
#define TASKS_H
|
||||||
|
|
||||||
#include "../common/types.h"
|
#include "../common/types.h"
|
||||||
|
#include "../common/global_tasks.h"
|
||||||
|
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <unordered_map>
|
||||||
#define MAXTASKS 10000
|
#include <map>
|
||||||
#define MAXTASKSETS 1000
|
|
||||||
// The Client has a hard cap of 19 active quests, 29 in SoD+
|
|
||||||
#define MAXACTIVEQUESTS 19
|
|
||||||
// The Max Chooser (Task Selector entries) is capped at 40 in the Titanium Client.
|
|
||||||
#define MAXCHOOSERENTRIES 40
|
|
||||||
// The Client has a hard cap of 20 activities per task.
|
|
||||||
#define MAXACTIVITIESPERTASK 20
|
|
||||||
// This is used to determine if a client's active task slot is empty.
|
|
||||||
#define TASKSLOTEMPTY 0
|
|
||||||
|
|
||||||
// Command Codes for worldserver ServerOP_ReloadTasks
|
|
||||||
//
|
|
||||||
#define RELOADTASKS 0
|
|
||||||
#define RELOADTASKGOALLISTS 1
|
|
||||||
#define RELOADTASKPROXIMITIES 2
|
|
||||||
#define RELOADTASKSETS 3
|
|
||||||
|
|
||||||
class Client;
|
class Client;
|
||||||
class Mob;
|
class Mob;
|
||||||
@@ -98,94 +83,6 @@ private:
|
|||||||
std::vector<TaskProximity> TaskProximities;
|
std::vector<TaskProximity> TaskProximities;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef enum { METHODSINGLEID = 0, METHODLIST = 1, METHODQUEST = 2 } TaskMethodType;
|
|
||||||
|
|
||||||
struct ActivityInformation {
|
|
||||||
int StepNumber;
|
|
||||||
int Type;
|
|
||||||
std::string target_name; // name mob, location -- default empty
|
|
||||||
std::string item_list; // likely defaults to empty
|
|
||||||
std::string skill_list; // IDs ; separated -- default -1
|
|
||||||
std::string spell_list; // IDs ; separated -- default 0
|
|
||||||
std::string desc_override; // overrides auto generated description -- default empty
|
|
||||||
int skill_id; // older clients, first id from above
|
|
||||||
int spell_id; // older clients, first id from above
|
|
||||||
int GoalID;
|
|
||||||
TaskMethodType GoalMethod;
|
|
||||||
int GoalCount;
|
|
||||||
int DeliverToNPC;
|
|
||||||
std::vector<int> ZoneIDs;
|
|
||||||
std::string zones; // IDs ; searated, ZoneID is the first in this list for older clients -- default empty string
|
|
||||||
bool Optional;
|
|
||||||
|
|
||||||
inline bool CheckZone(int zone_id) {
|
|
||||||
if (ZoneIDs.empty())
|
|
||||||
return true;
|
|
||||||
return std::find(ZoneIDs.begin(), ZoneIDs.end(), zone_id) != ZoneIDs.end();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef enum { ActivitiesSequential = 0, ActivitiesStepped = 1 } SequenceType;
|
|
||||||
|
|
||||||
enum class TaskType {
|
|
||||||
Task = 0, // can have at max 1
|
|
||||||
Shared = 1, // can have at max 1
|
|
||||||
Quest = 2, // can have at max 19 or 29 depending on client
|
|
||||||
E = 3 // can have at max 19 or 29 depending on client, not present in live anymore
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class DurationCode {
|
|
||||||
None = 0,
|
|
||||||
Short = 1,
|
|
||||||
Medium = 2,
|
|
||||||
Long = 3
|
|
||||||
};
|
|
||||||
|
|
||||||
struct TaskInformation {
|
|
||||||
TaskType type;
|
|
||||||
int Duration;
|
|
||||||
DurationCode dur_code; // description for time investment for when Duration == 0
|
|
||||||
std::string Title; // max length 64
|
|
||||||
std::string Description; // max length 4000, 2048 on Tit
|
|
||||||
std::string Reward;
|
|
||||||
std::string item_link; // max length 128 older clients, item link gets own string
|
|
||||||
std::string completion_emote; // emote after completing task, yellow. Maybe should make more generic ... but yellow for now!
|
|
||||||
int RewardID;
|
|
||||||
int CashReward; // Expressed in copper
|
|
||||||
int XPReward;
|
|
||||||
int faction_reward; // just a npc_faction_id
|
|
||||||
TaskMethodType RewardMethod;
|
|
||||||
int ActivityCount;
|
|
||||||
SequenceType SequenceMode;
|
|
||||||
int LastStep;
|
|
||||||
short MinLevel;
|
|
||||||
short MaxLevel;
|
|
||||||
bool Repeatable;
|
|
||||||
ActivityInformation Activity[MAXACTIVITIESPERTASK];
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef enum { ActivityHidden = 0, ActivityActive = 1, ActivityCompleted = 2 } ActivityState;
|
|
||||||
|
|
||||||
typedef enum { ActivityDeliver = 1, ActivityKill = 2, ActivityLoot = 3, ActivitySpeakWith = 4, ActivityExplore = 5,
|
|
||||||
ActivityTradeSkill = 6, ActivityFish = 7, ActivityForage = 8, ActivityCastOn = 9, ActivitySkillOn = 10,
|
|
||||||
ActivityTouch = 11, ActivityCollect = 13, ActivityGiveCash = 100 } ActivityType;
|
|
||||||
|
|
||||||
|
|
||||||
struct ClientActivityInformation {
|
|
||||||
int ActivityID;
|
|
||||||
int DoneCount;
|
|
||||||
ActivityState State;
|
|
||||||
bool Updated; // Flag so we know if we need to update the database
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ClientTaskInformation {
|
|
||||||
int slot; // intrusive, but makes things easier :P
|
|
||||||
int TaskID;
|
|
||||||
int CurrentStep;
|
|
||||||
int AcceptedTime;
|
|
||||||
bool Updated;
|
|
||||||
ClientActivityInformation Activity[MAXACTIVITIESPERTASK];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct CompletedTaskInformation {
|
struct CompletedTaskInformation {
|
||||||
int TaskID;
|
int TaskID;
|
||||||
@@ -193,6 +90,49 @@ struct CompletedTaskInformation {
|
|||||||
bool ActivityDone[MAXACTIVITIESPERTASK];
|
bool ActivityDone[MAXACTIVITIESPERTASK];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct SharedTaskMember {
|
||||||
|
std::string name;
|
||||||
|
Mob *entity; // needs to be managed
|
||||||
|
bool leader;
|
||||||
|
SharedTaskMember() : entity(nullptr), leader(false) {}
|
||||||
|
SharedTaskMember(std::string name, Mob *entity, bool leader) : name(name), entity(entity), leader(leader) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
class SharedTaskState {
|
||||||
|
public:
|
||||||
|
SharedTaskState() : locked(false) {}
|
||||||
|
SharedTaskState(int id, int task_id) : id(id), task_id(task_id), locked(false) { }
|
||||||
|
// ~SharedTaskState();
|
||||||
|
|
||||||
|
inline const bool IsLocked() const { return locked; }
|
||||||
|
inline void SetLocked(bool v) { locked = v; }
|
||||||
|
void LockTask(); // notified clients (if they are etc)
|
||||||
|
|
||||||
|
void MemberZoned(Mob *player); // player left zone, update their pointer
|
||||||
|
void MemberEnterZone(Mob *player); // player entered zone, update their pointer
|
||||||
|
|
||||||
|
void AddMember(std::string name, Mob *entity = nullptr, bool leader = false)
|
||||||
|
{
|
||||||
|
members.push_back({name, entity, leader});
|
||||||
|
if (leader)
|
||||||
|
leader_name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SendMembersList(Client *to) const;
|
||||||
|
|
||||||
|
ClientTaskInformation *GetActivity() { return &activity; }
|
||||||
|
|
||||||
|
friend class TaskManager;
|
||||||
|
|
||||||
|
private:
|
||||||
|
int id;
|
||||||
|
int task_id;
|
||||||
|
std::vector<SharedTaskMember> members;
|
||||||
|
std::string leader_name;
|
||||||
|
ClientTaskInformation activity;
|
||||||
|
bool locked;
|
||||||
|
};
|
||||||
|
|
||||||
class ClientTaskState {
|
class ClientTaskState {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -238,9 +178,15 @@ public:
|
|||||||
int ActiveTasksInSet(int TaskSetID);
|
int ActiveTasksInSet(int TaskSetID);
|
||||||
int CompletedTasksInSet(int TaskSetID);
|
int CompletedTasksInSet(int TaskSetID);
|
||||||
bool HasSlotForTask(TaskInformation *task);
|
bool HasSlotForTask(TaskInformation *task);
|
||||||
|
// shared task related functions
|
||||||
|
void AcceptNewSharedTask(Client *c, int TaskID, int NPCID, int id, int accepted_time, std::vector<std::string> &members);
|
||||||
|
void AddToSharedTask(Client *c, int TaskID);
|
||||||
|
void RequestSharedTask(Client *c, int TaskID, int NPCID, bool enforce_level_requirement = false);
|
||||||
|
|
||||||
inline bool HasFreeTaskSlot() { return ActiveTask.TaskID == TASKSLOTEMPTY; }
|
inline bool HasFreeTaskSlot() { return ActiveTask.TaskID == TASKSLOTEMPTY; }
|
||||||
|
|
||||||
|
inline SharedTaskState *GetSharedTask() { return ActiveSharedTask ; }
|
||||||
|
|
||||||
friend class TaskManager;
|
friend class TaskManager;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -255,6 +201,8 @@ private:
|
|||||||
info = &ActiveTask;
|
info = &ActiveTask;
|
||||||
break;
|
break;
|
||||||
case TaskType::Shared:
|
case TaskType::Shared:
|
||||||
|
if (index == 0 && ActiveSharedTask)
|
||||||
|
info = ActiveSharedTask->GetActivity();
|
||||||
break;
|
break;
|
||||||
case TaskType::Quest:
|
case TaskType::Quest:
|
||||||
if (index < MAXACTIVEQUESTS)
|
if (index < MAXACTIVEQUESTS)
|
||||||
@@ -273,6 +221,7 @@ private:
|
|||||||
};
|
};
|
||||||
ClientTaskInformation ActiveTasks[MAXACTIVEQUESTS + 1];
|
ClientTaskInformation ActiveTasks[MAXACTIVEQUESTS + 1];
|
||||||
};
|
};
|
||||||
|
SharedTaskState *ActiveSharedTask; // pointer to our shared task managed by TaskManager
|
||||||
// Shared tasks should be limited to 1 as well
|
// Shared tasks should be limited to 1 as well
|
||||||
std::vector<int> EnabledTasks;
|
std::vector<int> EnabledTasks;
|
||||||
std::vector<CompletedTaskInformation> CompletedTasks;
|
std::vector<CompletedTaskInformation> CompletedTasks;
|
||||||
@@ -280,6 +229,10 @@ private:
|
|||||||
bool CheckedTouchActivities;
|
bool CheckedTouchActivities;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct TaskReplayGroups {
|
||||||
|
std::string name;
|
||||||
|
int duration;
|
||||||
|
};
|
||||||
|
|
||||||
class TaskManager {
|
class TaskManager {
|
||||||
|
|
||||||
@@ -289,18 +242,19 @@ public:
|
|||||||
int GetActivityCount(int TaskID);
|
int GetActivityCount(int TaskID);
|
||||||
bool LoadSingleTask(int TaskID);
|
bool LoadSingleTask(int TaskID);
|
||||||
bool LoadTasks(int SingleTask=0);
|
bool LoadTasks(int SingleTask=0);
|
||||||
|
bool LoadReplayGroups();
|
||||||
void ReloadGoalLists();
|
void ReloadGoalLists();
|
||||||
inline void LoadProximities(int ZoneID) { ProximityManager.LoadProximities(ZoneID); }
|
inline void LoadProximities(int ZoneID) { ProximityManager.LoadProximities(ZoneID); }
|
||||||
bool LoadTaskSets();
|
bool LoadTaskSets();
|
||||||
bool LoadClientState(Client *c, ClientTaskState *state);
|
bool LoadClientState(Client *c, ClientTaskState *state);
|
||||||
bool SaveClientState(Client *c, ClientTaskState *state);
|
bool SaveClientState(Client *c, ClientTaskState *state);
|
||||||
void SendTaskSelector(Client *c, Mob *mob, int TaskCount, int *TaskList);
|
void SendTaskSelector(Client *c, Mob *mob, int TaskCount, int *TaskList, bool shared = false); // dumb hack cuz we do dumb things
|
||||||
void SendTaskSelectorNew(Client *c, Mob *mob, int TaskCount, int *TaskList);
|
void SendTaskSelectorNew(Client *c, Mob *mob, int TaskCount, int *TaskList, bool shared = false);
|
||||||
bool AppropriateLevel(int TaskID, int PlayerLevel);
|
bool AppropriateLevel(int TaskID, int PlayerLevel);
|
||||||
int GetTaskMinLevel(int TaskID);
|
int GetTaskMinLevel(int TaskID);
|
||||||
int GetTaskMaxLevel(int TaskID);
|
int GetTaskMaxLevel(int TaskID);
|
||||||
void TaskSetSelector(Client *c, ClientTaskState *state, Mob *mob, int TaskSetID);
|
void TaskSetSelector(Client *c, ClientTaskState *state, Mob *mob, int TaskSetID, bool shared = false);
|
||||||
void TaskQuestSetSelector(Client *c, ClientTaskState *state, Mob *mob, int count, int *tasks); // task list provided by QuestManager (perl/lua)
|
void TaskQuestSetSelector(Client *c, ClientTaskState *state, Mob *mob, int count, int *tasks, bool shared = false); // task list provided by QuestManager (perl/lua)
|
||||||
void SendActiveTasksToClient(Client *c, bool TaskComplete=false);
|
void SendActiveTasksToClient(Client *c, bool TaskComplete=false);
|
||||||
void SendSingleActiveTaskToClient(Client *c, ClientTaskInformation &task_info, bool TaskComplete, bool BringUpTaskJournal = false);
|
void SendSingleActiveTaskToClient(Client *c, ClientTaskInformation &task_info, bool TaskComplete, bool BringUpTaskJournal = false);
|
||||||
void SendTaskActivityShort(Client *c, int TaskID, int ActivityID, int ClientTaskIndex);
|
void SendTaskActivityShort(Client *c, int TaskID, int ActivityID, int ClientTaskIndex);
|
||||||
@@ -316,6 +270,9 @@ public:
|
|||||||
bool IsTaskRepeatable(int TaskID);
|
bool IsTaskRepeatable(int TaskID);
|
||||||
friend class ClientTaskState;
|
friend class ClientTaskState;
|
||||||
|
|
||||||
|
SharedTaskState *LoadSharedTask(int id); // loads the shared task state
|
||||||
|
SharedTaskState *CreateSharedTask(int id, int task_id);
|
||||||
|
SharedTaskState *GetSharedTask(int id);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TaskGoalListManager GoalListManager;
|
TaskGoalListManager GoalListManager;
|
||||||
@@ -323,6 +280,8 @@ private:
|
|||||||
TaskInformation* Tasks[MAXTASKS];
|
TaskInformation* Tasks[MAXTASKS];
|
||||||
std::vector<int> TaskSets[MAXTASKSETS];
|
std::vector<int> TaskSets[MAXTASKSETS];
|
||||||
void SendActiveTaskDescription(Client *c, int TaskID, ClientTaskInformation &task_info, int StartTime, int Duration, bool BringUpTaskJournal=false);
|
void SendActiveTaskDescription(Client *c, int TaskID, ClientTaskInformation &task_info, int StartTime, int Duration, bool BringUpTaskJournal=false);
|
||||||
|
std::unordered_map<int, SharedTaskState> SharedTasks;
|
||||||
|
std::map<int, TaskReplayGroups> replay_groups;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+101
-42
@@ -79,33 +79,50 @@ WorldServer::~WorldServer() {
|
|||||||
|
|
||||||
void WorldServer::Connect()
|
void WorldServer::Connect()
|
||||||
{
|
{
|
||||||
m_connection.reset(new EQ::Net::ServertalkClient(Config->WorldIP, Config->WorldTCPPort, false, "Zone", Config->SharedKey));
|
m_connection.reset(new EQ::WorldConnection("Zone"));
|
||||||
m_connection->OnConnect([this](EQ::Net::ServertalkClient *client) {
|
m_connection->SetOnConnectedHandler(std::bind(&WorldServer::OnConnected, this));
|
||||||
OnConnected();
|
m_connection->SetOnMessageHandler(std::bind(&WorldServer::HandleMessage, this, std::placeholders::_1, std::placeholders::_2));
|
||||||
});
|
|
||||||
|
|
||||||
m_connection->OnMessage(std::bind(&WorldServer::HandleMessage, this, std::placeholders::_1, std::placeholders::_2));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool WorldServer::SendPacket(ServerPacket *pack)
|
|
||||||
{
|
|
||||||
m_connection->SendPacket(pack);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string WorldServer::GetIP() const
|
|
||||||
{
|
|
||||||
return m_connection->Handle()->RemoteIP();
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16 WorldServer::GetPort() const
|
|
||||||
{
|
|
||||||
return m_connection->Handle()->RemotePort();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WorldServer::Connected() const
|
bool WorldServer::Connected() const
|
||||||
{
|
{
|
||||||
|
if (m_connection) {
|
||||||
return m_connection->Connected();
|
return m_connection->Connected();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WorldServer::SendPacket(ServerPacket *pack)
|
||||||
|
{
|
||||||
|
if (m_connection) {
|
||||||
|
m_connection->SendPacket(pack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string WorldServer::GetIP() const
|
||||||
|
{
|
||||||
|
if (m_connection) {
|
||||||
|
return m_connection->GetIP();
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16 WorldServer::GetPort() const
|
||||||
|
{
|
||||||
|
if (m_connection) {
|
||||||
|
return m_connection->GetPort();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WorldServer::RouteMessage(const std::string &filter, const std::string &id, const EQ::Net::Packet &p)
|
||||||
|
{
|
||||||
|
if (m_connection) {
|
||||||
|
m_connection->RouteMessage(filter, id, p);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldServer::SetZoneData(uint32 iZoneID, uint32 iInstanceID) {
|
void WorldServer::SetZoneData(uint32 iZoneID, uint32 iInstanceID) {
|
||||||
@@ -179,13 +196,6 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
|
|||||||
ServerPacket *pack = &tpack;
|
ServerPacket *pack = &tpack;
|
||||||
|
|
||||||
switch (opcode) {
|
switch (opcode) {
|
||||||
case 0: {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ServerOP_KeepAlive: {
|
|
||||||
// ignore this
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// World is tellins us what port to use.
|
// World is tellins us what port to use.
|
||||||
case ServerOP_SetConnectInfo: {
|
case ServerOP_SetConnectInfo: {
|
||||||
if (pack->size != sizeof(ServerConnectInfo))
|
if (pack->size != sizeof(ServerConnectInfo))
|
||||||
@@ -1942,6 +1952,56 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case ServerOP_TaskGrant:
|
||||||
|
{
|
||||||
|
int id = pack->ReadUInt32();
|
||||||
|
int task_id = pack->ReadUInt32();
|
||||||
|
int taskmaster_id = pack->ReadUInt32();
|
||||||
|
int accepted_time = pack->ReadUInt32();
|
||||||
|
char name[64] = { 0 };
|
||||||
|
pack->ReadString(name);
|
||||||
|
auto client = entity_list.GetClientByName(name);
|
||||||
|
if (client) { // guess we just do nothing if they're not here
|
||||||
|
std::vector<std::string> members;
|
||||||
|
int count = pack->ReadUInt32();
|
||||||
|
for (int i = 0; i < count; ++i) {
|
||||||
|
pack->ReadString(name);
|
||||||
|
members.push_back(name);
|
||||||
|
}
|
||||||
|
client->AssignSharedTask(task_id, taskmaster_id, id, accepted_time, members);
|
||||||
|
} else {
|
||||||
|
// TODO: something failed, tell world to clean up
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ServerOP_TaskReject:
|
||||||
|
{
|
||||||
|
// this will be reworked to not use the pend shit, we will depend on hoping successive requests just get thrown out
|
||||||
|
int message = pack->ReadUInt32();
|
||||||
|
int taskmaster_id = pack->ReadUInt32();
|
||||||
|
char name[64] = { 0 };
|
||||||
|
pack->ReadString(name);
|
||||||
|
auto client = entity_list.GetClientByName(name);
|
||||||
|
if (client) {
|
||||||
|
if (message == 0)
|
||||||
|
client->Message(13, "Shared task assignment has failed.");
|
||||||
|
else if (message > 0)
|
||||||
|
client->Message_StringID(13, message);
|
||||||
|
// negative nothing I guess
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ServerOP_TaskZoneCreated:
|
||||||
|
{
|
||||||
|
int task_id = pack->ReadUInt32();
|
||||||
|
char name[64] = { 0 };
|
||||||
|
pack->ReadString(name);
|
||||||
|
|
||||||
|
auto client = entity_list.GetClientByName(name);
|
||||||
|
if (client)
|
||||||
|
client->AddToSharedTask(task_id);
|
||||||
|
break;
|
||||||
|
}
|
||||||
default: {
|
default: {
|
||||||
std::cout << " Unknown ZSopcode:" << (int)pack->opcode;
|
std::cout << " Unknown ZSopcode:" << (int)pack->opcode;
|
||||||
std::cout << " size:" << pack->size << std::endl;
|
std::cout << " size:" << pack->size << std::endl;
|
||||||
@@ -1987,9 +2047,9 @@ bool WorldServer::SendChannelMessage(Client* from, const char* to, uint8 chan_nu
|
|||||||
scm->queued = 0;
|
scm->queued = 0;
|
||||||
strcpy(scm->message, buffer);
|
strcpy(scm->message, buffer);
|
||||||
|
|
||||||
bool ret = SendPacket(pack);
|
SendPacket(pack);
|
||||||
safe_delete(pack);
|
safe_delete(pack);
|
||||||
return ret;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WorldServer::SendEmoteMessage(const char* to, uint32 to_guilddbid, uint32 type, const char* message, ...) {
|
bool WorldServer::SendEmoteMessage(const char* to, uint32 to_guilddbid, uint32 type, const char* message, ...) {
|
||||||
@@ -2025,9 +2085,9 @@ bool WorldServer::SendEmoteMessage(const char* to, uint32 to_guilddbid, int16 to
|
|||||||
sem->minstatus = to_minstatus;
|
sem->minstatus = to_minstatus;
|
||||||
strcpy(sem->message, buffer);
|
strcpy(sem->message, buffer);
|
||||||
|
|
||||||
bool ret = SendPacket(pack);
|
SendPacket(pack);
|
||||||
safe_delete(pack);
|
safe_delete(pack);
|
||||||
return ret;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WorldServer::SendVoiceMacro(Client* From, uint32 Type, char* Target, uint32 MacroNumber, uint32 GroupOrRaidID) {
|
bool WorldServer::SendVoiceMacro(Client* From, uint32 Type, char* Target, uint32 MacroNumber, uint32 GroupOrRaidID) {
|
||||||
@@ -2062,15 +2122,19 @@ bool WorldServer::SendVoiceMacro(Client* From, uint32 Type, char* Target, uint32
|
|||||||
|
|
||||||
svm->MacroNumber = MacroNumber;
|
svm->MacroNumber = MacroNumber;
|
||||||
|
|
||||||
bool Ret = SendPacket(pack);
|
SendPacket(pack);
|
||||||
|
|
||||||
safe_delete(pack);
|
safe_delete(pack);
|
||||||
|
|
||||||
return Ret;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WorldServer::RezzPlayer(EQApplicationPacket* rpack, uint32 rezzexp, uint32 dbid, uint16 opcode)
|
bool WorldServer::RezzPlayer(EQApplicationPacket* rpack, uint32 rezzexp, uint32 dbid, uint16 opcode)
|
||||||
{
|
{
|
||||||
|
if (!Connected()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Log(Logs::Detail, Logs::Spells, "WorldServer::RezzPlayer rezzexp is %i (0 is normal for RezzComplete", rezzexp);
|
Log(Logs::Detail, Logs::Spells, "WorldServer::RezzPlayer rezzexp is %i (0 is normal for RezzComplete", rezzexp);
|
||||||
auto pack = new ServerPacket(ServerOP_RezzPlayer, sizeof(RezzPlayer_Struct));
|
auto pack = new ServerPacket(ServerOP_RezzPlayer, sizeof(RezzPlayer_Struct));
|
||||||
RezzPlayer_Struct* sem = (RezzPlayer_Struct*)pack->pBuffer;
|
RezzPlayer_Struct* sem = (RezzPlayer_Struct*)pack->pBuffer;
|
||||||
@@ -2078,14 +2142,9 @@ bool WorldServer::RezzPlayer(EQApplicationPacket* rpack, uint32 rezzexp, uint32
|
|||||||
sem->rez = *(Resurrect_Struct*)rpack->pBuffer;
|
sem->rez = *(Resurrect_Struct*)rpack->pBuffer;
|
||||||
sem->exp = rezzexp;
|
sem->exp = rezzexp;
|
||||||
sem->dbid = dbid;
|
sem->dbid = dbid;
|
||||||
bool ret = SendPacket(pack);
|
SendPacket(pack);
|
||||||
if (ret)
|
|
||||||
Log(Logs::Detail, Logs::Spells, "Sending player rezz packet to world spellid:%i", sem->rez.spellid);
|
|
||||||
else
|
|
||||||
Log(Logs::Detail, Logs::Spells, "NOT Sending player rezz packet to world");
|
|
||||||
|
|
||||||
safe_delete(pack);
|
safe_delete(pack);
|
||||||
return ret;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldServer::SendReloadTasks(int Command, int TaskID) {
|
void WorldServer::SendReloadTasks(int Command, int TaskID) {
|
||||||
|
|||||||
+6
-5
@@ -18,8 +18,8 @@
|
|||||||
#ifndef WORLDSERVER_H
|
#ifndef WORLDSERVER_H
|
||||||
#define WORLDSERVER_H
|
#define WORLDSERVER_H
|
||||||
|
|
||||||
#include "../common/eq_packet_structs.h"
|
#include "../common/world_connection.h"
|
||||||
#include "../common/net/servertalk_client_connection.h"
|
#include <memory>
|
||||||
|
|
||||||
class ServerPacket;
|
class ServerPacket;
|
||||||
class EQApplicationPacket;
|
class EQApplicationPacket;
|
||||||
@@ -31,10 +31,11 @@ public:
|
|||||||
~WorldServer();
|
~WorldServer();
|
||||||
|
|
||||||
void Connect();
|
void Connect();
|
||||||
bool SendPacket(ServerPacket* pack);
|
bool Connected() const;
|
||||||
|
void SendPacket(ServerPacket* pack);
|
||||||
std::string GetIP() const;
|
std::string GetIP() const;
|
||||||
uint16 GetPort() const;
|
uint16 GetPort() const;
|
||||||
bool Connected() const;
|
void RouteMessage(const std::string &filter, const std::string &id, const EQ::Net::Packet& p);
|
||||||
|
|
||||||
void HandleMessage(uint16 opcode, const EQ::Net::Packet &p);
|
void HandleMessage(uint16 opcode, const EQ::Net::Packet &p);
|
||||||
|
|
||||||
@@ -72,7 +73,7 @@ private:
|
|||||||
uint32 cur_groupid;
|
uint32 cur_groupid;
|
||||||
uint32 last_groupid;
|
uint32 last_groupid;
|
||||||
|
|
||||||
std::unique_ptr<EQ::Net::ServertalkClient> m_connection;
|
std::unique_ptr<EQ::WorldConnection> m_connection;
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user