mirror of
https://github.com/EQEmu/Server.git
synced 2026-05-25 19:22:27 +00:00
Compare commits
164 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b9b2bf0477 | |||
| 0b26c80d8f | |||
| 8497042eef | |||
| 1304b9c80f | |||
| 65c9c86556 | |||
| ece9251bd6 | |||
| 290133803e | |||
| 4627bfe271 | |||
| 3cbd0fe0f6 | |||
| 8141f831b1 | |||
| b3a3d9bec5 | |||
| c3e10a7409 | |||
| 65e429a596 | |||
| fa2b5166fb | |||
| 8dc25c838b | |||
| 229de34afc | |||
| 70bdd35b69 | |||
| e99354223d | |||
| 8a8e922f46 | |||
| c1484a698c | |||
| bd96d676be | |||
| 2a637a031b | |||
| f7c7f5646e | |||
| 577e67f4ee | |||
| 1084b71d8d | |||
| 63933f53c8 | |||
| d23a6e646e | |||
| c2ab2a232b | |||
| c5f739cbda | |||
| 385732f403 | |||
| b972ec581f | |||
| 32e04cd264 | |||
| b0dff0c006 | |||
| c093b3e2ab | |||
| 2690e4de4d | |||
| 1122d29e19 | |||
| c5bf71f221 | |||
| 977c3ca3dc | |||
| 408ce4650f | |||
| bc0f705227 | |||
| 5c1ab3b24c | |||
| 85a858fcd6 | |||
| 6ab2e46f42 | |||
| 96acb1e638 | |||
| eb98eef1b9 | |||
| e1bb3301a5 | |||
| 358ce2ca94 | |||
| ad790ac8ef | |||
| d7abf3f26c | |||
| 6739eea78b | |||
| 6856d1540b | |||
| cd1306d52c | |||
| 20aa1cbe77 | |||
| cd3125ced0 | |||
| dfd9a3c714 | |||
| 72e0320509 | |||
| 15ff0bf5c3 | |||
| a402f01514 | |||
| dfe4bb5b78 | |||
| c24bfaf35f | |||
| 7dc1e10956 | |||
| 54da27424f | |||
| 6e1f317c60 | |||
| 3e8ef681a3 | |||
| e009e064f3 | |||
| 9654beda9f | |||
| 3105577c1b | |||
| c06774ca61 | |||
| e1e3d99a79 | |||
| 8942c0ea24 | |||
| 1603ea097f | |||
| 0426a15fec | |||
| 5b374927f2 | |||
| d59170f84f | |||
| 8aaf39d2d9 | |||
| 2bb305305a | |||
| e8127f4b8a | |||
| 762de03be7 | |||
| f18b9c99b5 | |||
| 8f9a859c56 | |||
| 5e008a5a97 | |||
| fa2052236c | |||
| c04bf79b0f | |||
| f75c5b6fc8 | |||
| 63045fadd9 | |||
| 850b32f2ca | |||
| 60d5c11c43 | |||
| 03458b88a4 | |||
| 0852468b88 | |||
| 3d1dda888d | |||
| a4c171cb1d | |||
| 20de6acfea | |||
| 9c42f28b0d | |||
| 75d3329d37 | |||
| 26a95998da | |||
| 6715977a1f | |||
| fd990136f7 | |||
| 3db3e53f11 | |||
| ca4e23695d | |||
| 293a18301d | |||
| 3eb80e3111 | |||
| 4a0126eec3 | |||
| 98e6fcf21c | |||
| ce2e74c9a6 | |||
| 2eb884e9b0 | |||
| 84f288d572 | |||
| 88b3d11167 | |||
| 96089e1718 | |||
| f89a0297b4 | |||
| 6dbd579f4f | |||
| aa9611d494 | |||
| 380e5d5084 | |||
| 726a996a25 | |||
| cb9f0fbe31 | |||
| b156b078ed | |||
| 37915f5b7e | |||
| 3a8f206841 | |||
| 2af4d3d67d | |||
| 43a488d5b5 | |||
| 0b4dcb4271 | |||
| abf39c4ff7 | |||
| 3bdd6c20a5 | |||
| bef849b5c1 | |||
| 146e28f708 | |||
| f84fed7335 | |||
| 3cffe5f7ef | |||
| ad97968d5e | |||
| c8b7b3e74f | |||
| 1d0b00caf7 | |||
| 93394e0edc | |||
| 230d6ae964 | |||
| 46ead8e29e | |||
| e3d5200310 | |||
| 5474661e11 | |||
| d7e98bba17 | |||
| ca6bcdb1f9 | |||
| bd47e2121f | |||
| 90b46c7bda | |||
| 4b21f901b9 | |||
| 6c1e3ae3d6 | |||
| 3cb548f72e | |||
| 37ed923302 | |||
| d20ea3852c | |||
| f3608edd62 | |||
| b5cc006e46 | |||
| e71eefab50 | |||
| 469224cfe7 | |||
| 3b21d2eb26 | |||
| 3487086d46 | |||
| 50997ad0ec | |||
| 688e37f108 | |||
| 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_PACKAGE(ZLIB REQUIRED)
|
||||
FIND_PACKAGE(MySQL REQUIRED)
|
||||
FIND_PACKAGE(Protobuf REQUIRED)
|
||||
IF(EQEMU_BUILD_PERL)
|
||||
FIND_PACKAGE(PerlLibs REQUIRED)
|
||||
INCLUDE_DIRECTORIES(SYSTEM "${PERL_INCLUDE_PATH}")
|
||||
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)
|
||||
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)
|
||||
INCLUDE_DIRECTORIES(SYSTEM "${SODIUM_INCLUDE_DIRS}")
|
||||
ADD_DEFINITIONS(-DENABLE_SECURITY)
|
||||
@@ -340,6 +341,7 @@ ENDIF(EQEMU_BUILD_LUA)
|
||||
|
||||
INCLUDE_DIRECTORIES(SYSTEM "${ZLIB_INCLUDE_DIRS}")
|
||||
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}/libs/cereal")
|
||||
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/recast/detour/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)
|
||||
ADD_SUBDIRECTORY(common)
|
||||
@@ -359,6 +368,7 @@ IF(EQEMU_BUILD_SERVER)
|
||||
ADD_SUBDIRECTORY(ucs)
|
||||
ADD_SUBDIRECTORY(queryserv)
|
||||
ADD_SUBDIRECTORY(eqlaunch)
|
||||
ADD_SUBDIRECTORY(services/tasks)
|
||||
ENDIF(EQEMU_BUILD_SERVER)
|
||||
IF(EQEMU_BUILD_LOGIN)
|
||||
ADD_SUBDIRECTORY(loginserver)
|
||||
|
||||
+94
-2
@@ -1,8 +1,100 @@
|
||||
EQEMu Changelog (Started on Sept 24, 2003 15:50)
|
||||
-------------------------------------------------------
|
||||
|
||||
== 2/5/2019 ==
|
||||
Uleat: Updated profanity manager to only redact in 'public' channels
|
||||
== 3/1/2019 ==
|
||||
Noudess: Major faction conversion to use client data.
|
||||
|
||||
Pull request #802 New min/max personal faction per faction. Use of actual
|
||||
client mods for race/class/deity.
|
||||
|
||||
This PR involves major changes to your database and your quests.
|
||||
|
||||
The clients recently exposed raw data included
|
||||
|
||||
- the min/max personal faction for each faction
|
||||
- the actual faction id the client uses for each faction
|
||||
- the actual mods that come into play when a PC cons an opponent that
|
||||
determine your overall con to that faction.
|
||||
|
||||
|
||||
The approach I took resulted in minimal change to the code base. I did
|
||||
alter the code to enforce the new validated min/max from the client. This
|
||||
min/max applies to personally earned faction. So if a faction has a min
|
||||
of 0 and a max of 2000, that means your personally earned value can never
|
||||
go below 0 or over 2000. The actual con, will, however often do so because
|
||||
of class/race/deity modifications. I also changed the con ranges, per
|
||||
Mackal's data that was proven to be accurate:
|
||||
|
||||
Ally = 1100+
|
||||
Warmly = 750 to 1099
|
||||
Kindly = 500 to 749
|
||||
Amiable = 100 to 499
|
||||
Indifferent = 0 to 99
|
||||
Apprehensive = -1 to -100
|
||||
Dubious = -101 to -500
|
||||
Threateningly = -501 to -750
|
||||
Ready to Attack = -751
|
||||
|
||||
The above means that dubious is a much smaller range now. For that reason
|
||||
the scripts modify any custom faction base values to put them in the same
|
||||
range, hopefully as the creators of the custom factions intended.
|
||||
|
||||
Also to be noted as characters that have a faction between -501 and -700
|
||||
wont be dubious anymore, they will be threateningly. This is expected with
|
||||
the new ranges, but might take players by suprise as the old ranges we used
|
||||
were more liberal but were incorrect.
|
||||
|
||||
The database is changed extensively, but really only content. We're
|
||||
translating faction_list to use the clients ids. As such every place a
|
||||
faction_is is used, namely (see below) are being converted.
|
||||
|
||||
- faction_list
|
||||
- faction_list_mod
|
||||
- npc_faction (primary_faction field only)
|
||||
- npc_faction_entries (faction_id field only)
|
||||
- faction_values
|
||||
|
||||
Quests will also automatically be adjusted. This MUST be done after the
|
||||
PR sql and before starting the server. This is automated by
|
||||
eqemu_server.pl (or starting world)
|
||||
|
||||
Be assured, custom factions that you may have created, or obsolete or
|
||||
duplicate factions in our original faction_list, that you may have used,
|
||||
will be preserved. Anything that does not map directly is being moved to
|
||||
the 5000 range in faction_list and any references are corrected to point
|
||||
there.
|
||||
|
||||
A great example of this is Ebon Mask and Hall of the Ebon Mask. Many peqdb
|
||||
style servers have both of these. Some have used one, some the other. We
|
||||
map Ebon Mask to the clients Ebon mask and the Hall of the Ebon Mask gets
|
||||
moved to the 5000 range, and all its references are preserved. However,
|
||||
if you would like to make proper use of client mobs to Ebon mask, or other
|
||||
factions that have duplicitous entries, I recommend you manually move to
|
||||
using the correct one. In that way all of the new raw data mapped in from
|
||||
the client into faction_list_mod will get used instead of what your db had
|
||||
before these values were known.
|
||||
|
||||
In my experience converting 4 different server's data, there are only
|
||||
about 20 factions moved into the 5000 range.
|
||||
|
||||
This PR has only 1 new, permanent table faction_base_data, which is taken
|
||||
right from the client. The base field is left in case you want to mod your
|
||||
server, but we are very sure that the client doesn't use a base. It uses
|
||||
global mods to race or class for this as you'll see in the
|
||||
new faction_list_mod.
|
||||
|
||||
The PR makes many backup tables, and two mapping tables that are used during
|
||||
the conversion process to fix quests. This table was hand created by
|
||||
analysis. This table serves no purpose after conversion except an audit
|
||||
trail if we see any issues.
|
||||
|
||||
I will release a new PR that will clean up all these backups and temporary
|
||||
tables in about a month.
|
||||
|
||||
== 2/7/2019 ==
|
||||
Uleat: Put merc and bot classes on the same stance standard (mercs)
|
||||
- Both classes will now use the same stance standard
|
||||
- Pushed stance types up to EQEmu::constants
|
||||
|
||||
== 2/4/2019 ==
|
||||
Uleat: Added command 'profanity' (aliased 'prof')
|
||||
|
||||
@@ -60,6 +60,29 @@ int main(int argc, char **argv) {
|
||||
database.LoadLogSettings(LogSys.log_settings);
|
||||
LogSys.StartFileLogs();
|
||||
|
||||
std::string arg_1;
|
||||
|
||||
if (argv[1]) {
|
||||
arg_1 = argv[1];
|
||||
}
|
||||
|
||||
if (arg_1 == "spells") {
|
||||
ExportSpells(&database);
|
||||
return 0;
|
||||
}
|
||||
if (arg_1 == "skills") {
|
||||
ExportSkillCaps(&database);
|
||||
return 0;
|
||||
}
|
||||
if (arg_1 == "basedata") {
|
||||
ExportBaseData(&database);
|
||||
return 0;
|
||||
}
|
||||
if (arg_1 == "dbstring") {
|
||||
ExportDBStrings(&database);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ExportSpells(&database);
|
||||
ExportSkillCaps(&database);
|
||||
ExportBaseData(&database);
|
||||
|
||||
+14
-6
@@ -54,6 +54,7 @@ SET(common_sources
|
||||
packet_functions.cpp
|
||||
perl_eqdb.cpp
|
||||
perl_eqdb_res.cpp
|
||||
platform.cpp
|
||||
proc_launcher.cpp
|
||||
profanity_manager.cpp
|
||||
ptimer.cpp
|
||||
@@ -63,6 +64,7 @@ SET(common_sources
|
||||
say_link.cpp
|
||||
serialize_buffer.cpp
|
||||
serverinfo.cpp
|
||||
service.cpp
|
||||
shareddb.cpp
|
||||
skills.cpp
|
||||
spdat.cpp
|
||||
@@ -71,9 +73,8 @@ SET(common_sources
|
||||
textures.cpp
|
||||
timer.cpp
|
||||
unix.cpp
|
||||
world_connection.cpp
|
||||
xml_parser.cpp
|
||||
platform.cpp
|
||||
event/event_loop.cpp
|
||||
json/jsoncpp.cpp
|
||||
net/console_server.cpp
|
||||
net/console_server_connection.cpp
|
||||
@@ -152,6 +153,7 @@ SET(common_headers
|
||||
fixed_memory_hash_set.h
|
||||
fixed_memory_variable_hash_set.h
|
||||
global_define.h
|
||||
global_tasks.h
|
||||
guild_base.h
|
||||
guilds.h
|
||||
inventory_profile.h
|
||||
@@ -196,6 +198,7 @@ SET(common_headers
|
||||
serialize_buffer.h
|
||||
serverinfo.h
|
||||
servertalk.h
|
||||
service.h
|
||||
shareddb.h
|
||||
skills.h
|
||||
spdat.h
|
||||
@@ -207,10 +210,11 @@ SET(common_headers
|
||||
unix.h
|
||||
useperl.h
|
||||
version.h
|
||||
world_connection.h
|
||||
xml_parser.h
|
||||
zone_numbers.h
|
||||
event/background_task.h
|
||||
event/event_loop.h
|
||||
event/task.h
|
||||
event/timer.h
|
||||
json/json.h
|
||||
json/json-forwards.h
|
||||
@@ -267,10 +271,9 @@ SET(common_headers
|
||||
)
|
||||
|
||||
SOURCE_GROUP(Event FILES
|
||||
event/background_task.h
|
||||
event/event_loop.cpp
|
||||
event/event_loop.h
|
||||
event/timer.h
|
||||
event/task.h
|
||||
)
|
||||
|
||||
SOURCE_GROUP(Json FILES
|
||||
@@ -380,7 +383,12 @@ SOURCE_GROUP(Util FILES
|
||||
|
||||
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)
|
||||
SET_SOURCE_FILES_PROPERTIES("SocketLib/Mime.cpp" PROPERTY COMPILE_FLAGS -Wno-unused-result)
|
||||
|
||||
+13
-16
@@ -171,30 +171,27 @@ void Database::LoginIP(uint32 AccountID, const char* LoginIP) {
|
||||
QueryDatabase(query);
|
||||
}
|
||||
|
||||
int16 Database::CheckStatus(uint32 account_id) {
|
||||
std::string query = StringFormat("SELECT `status`, UNIX_TIMESTAMP(`suspendeduntil`) as `suspendeduntil`, UNIX_TIMESTAMP() as `current`"
|
||||
" FROM `account` WHERE `id` = %i", account_id);
|
||||
int16 Database::CheckStatus(uint32 account_id)
|
||||
{
|
||||
std::string query = StringFormat(
|
||||
"SELECT `status`, TIMESTAMPDIFF(SECOND, NOW(), `suspendeduntil`) FROM `account` WHERE `id` = %i",
|
||||
account_id);
|
||||
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (results.RowCount() != 1)
|
||||
return 0;
|
||||
|
||||
auto row = results.begin();
|
||||
int16 status = atoi(row[0]);
|
||||
int32 suspendeduntil = 0;
|
||||
|
||||
// MariaDB initalizes with NULL if unix_timestamp() is out of range
|
||||
if (row[1] != nullptr) {
|
||||
suspendeduntil = atoi(row[1]);
|
||||
}
|
||||
auto row = results.begin();
|
||||
int16 status = atoi(row[0]);
|
||||
int32 date_diff = 0;
|
||||
|
||||
int32 current = atoi(row[2]);
|
||||
if (row[1] != nullptr)
|
||||
date_diff = atoi(row[1]);
|
||||
|
||||
if(suspendeduntil > current)
|
||||
if (date_diff > 0)
|
||||
return -1;
|
||||
|
||||
return status;
|
||||
|
||||
@@ -118,3 +118,37 @@ EQEmu::bug::CategoryID EQEmu::bug::CategoryNameToCategoryID(const char* category
|
||||
|
||||
return catOther;
|
||||
}
|
||||
|
||||
const char *EQEmu::constants::GetStanceName(StanceType stance_type) {
|
||||
switch (stance_type) {
|
||||
case stanceUnknown:
|
||||
return "Unknown";
|
||||
case stancePassive:
|
||||
return "Passive";
|
||||
case stanceBalanced:
|
||||
return "Balanced";
|
||||
case stanceEfficient:
|
||||
return "Efficient";
|
||||
case stanceReactive:
|
||||
return "Reactive";
|
||||
case stanceAggressive:
|
||||
return "Aggressive";
|
||||
case stanceAssist:
|
||||
return "Assist";
|
||||
case stanceBurn:
|
||||
return "Burn";
|
||||
case stanceEfficient2:
|
||||
return "Efficient2";
|
||||
case stanceBurnAE:
|
||||
return "BurnAE";
|
||||
default:
|
||||
return "Invalid";
|
||||
}
|
||||
}
|
||||
|
||||
int EQEmu::constants::ConvertStanceTypeToIndex(StanceType stance_type) {
|
||||
if (stance_type >= EQEmu::constants::stancePassive && stance_type <= EQEmu::constants::stanceBurnAE)
|
||||
return (stance_type - EQEmu::constants::stancePassive);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -203,6 +203,26 @@ namespace EQEmu
|
||||
const size_t SAY_LINK_CLOSER_SIZE = 1;
|
||||
const size_t SAY_LINK_MAXIMUM_SIZE = (SAY_LINK_OPENER_SIZE + SAY_LINK_BODY_SIZE + SAY_LINK_TEXT_SIZE + SAY_LINK_CLOSER_SIZE);
|
||||
|
||||
enum StanceType : int {
|
||||
stanceUnknown = 0,
|
||||
stancePassive,
|
||||
stanceBalanced,
|
||||
stanceEfficient,
|
||||
stanceReactive,
|
||||
stanceAggressive,
|
||||
stanceAssist,
|
||||
stanceBurn,
|
||||
stanceEfficient2,
|
||||
stanceBurnAE
|
||||
};
|
||||
|
||||
const char *GetStanceName(StanceType stance_type);
|
||||
int ConvertStanceTypeToIndex(StanceType stance_type);
|
||||
|
||||
const int STANCE_TYPE_FIRST = stancePassive;
|
||||
const int STANCE_TYPE_LAST = stanceBurnAE;
|
||||
const int STANCE_TYPE_COUNT = stanceBurnAE;
|
||||
|
||||
} /*constants*/
|
||||
|
||||
namespace profile {
|
||||
@@ -287,6 +307,12 @@ namespace EQEmu
|
||||
|
||||
} // namespace bug
|
||||
|
||||
enum WaypointStatus : int {
|
||||
RoamBoxPauseInProgress = -3,
|
||||
QuestControlNoGrid = -2,
|
||||
QuestControlGrid = -1
|
||||
};
|
||||
|
||||
} /*EQEmu*/
|
||||
|
||||
#endif /*COMMON_EMU_CONSTANTS_H*/
|
||||
|
||||
@@ -6,6 +6,7 @@ N(OP_0x0347),
|
||||
N(OP_AAAction),
|
||||
N(OP_AAExpUpdate),
|
||||
N(OP_AcceptNewTask),
|
||||
N(OP_AcceptNewSharedTask),
|
||||
N(OP_AckPacket),
|
||||
N(OP_Action),
|
||||
N(OP_Action2),
|
||||
@@ -461,6 +462,7 @@ N(OP_SetServerFilter),
|
||||
N(OP_SetStartCity),
|
||||
N(OP_SetTitle),
|
||||
N(OP_SetTitleReply),
|
||||
N(OP_SharedTaskMemberList),
|
||||
N(OP_Shielding),
|
||||
N(OP_ShopDelItem),
|
||||
N(OP_ShopEnd),
|
||||
|
||||
@@ -3698,6 +3698,7 @@ struct TaskMemberList_Struct {
|
||||
/*12*/ char list_pointer[0];
|
||||
/* list is of the form:
|
||||
char member_name[1] //null terminated string
|
||||
uint32 monster_mission; // class chosen
|
||||
uint8 task_leader //boolean flag
|
||||
*/
|
||||
};
|
||||
@@ -3799,6 +3800,14 @@ struct AcceptNewTask_Struct {
|
||||
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
|
||||
struct CancelTask_Struct {
|
||||
uint32 SequenceNumber;
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <string>
|
||||
#include "emu_versions.h"
|
||||
#include "eq_packet.h"
|
||||
#include "net/daybreak_connection.h"
|
||||
|
||||
typedef enum {
|
||||
ESTABLISHED,
|
||||
@@ -56,6 +57,8 @@ public:
|
||||
virtual const uint32 GetBytesSentPerSecond() const { return 0; }
|
||||
virtual const uint32 GetBytesRecvPerSecond() const { return 0; }
|
||||
virtual const EQEmu::versions::ClientVersion ClientVersion() const { return EQEmu::versions::ClientVersion::Unknown; }
|
||||
|
||||
virtual std::shared_ptr<EQ::Net::DaybreakConnection> GetRawConnection() = 0;
|
||||
};
|
||||
|
||||
#endif /*EQSTREAMINTF_H_*/
|
||||
|
||||
@@ -110,6 +110,10 @@ void EQStreamProxy::RemoveData() {
|
||||
m_stream->RemoveData();
|
||||
}
|
||||
|
||||
std::shared_ptr<EQ::Net::DaybreakConnection> EQStreamProxy::GetRawConnection() {
|
||||
return m_stream->GetRawConnection();
|
||||
}
|
||||
|
||||
bool EQStreamProxy::CheckState(EQStreamState state) {
|
||||
if(m_stream)
|
||||
return(m_stream->CheckState(state));
|
||||
|
||||
@@ -37,6 +37,8 @@ public:
|
||||
virtual const uint32 GetBytesSentPerSecond() const;
|
||||
virtual const uint32 GetBytesRecvPerSecond() const;
|
||||
|
||||
virtual std::shared_ptr<EQ::Net::DaybreakConnection> GetRawConnection();
|
||||
|
||||
protected:
|
||||
std::shared_ptr<EQStreamInterface> const m_stream; //we own this stream object.
|
||||
const StructStrategy *const m_structs; //we do not own this object.
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
#pragma once
|
||||
#include <functional>
|
||||
#include "../any.h"
|
||||
#include "event_loop.h"
|
||||
|
||||
namespace EQ {
|
||||
class BackgroundTask
|
||||
{
|
||||
public:
|
||||
typedef std::function<void(EQEmu::Any&)> BackgroundTaskFunction;
|
||||
struct BackgroundTaskBaton
|
||||
{
|
||||
BackgroundTaskFunction fn;
|
||||
BackgroundTaskFunction on_finish;
|
||||
EQEmu::Any data;
|
||||
};
|
||||
|
||||
BackgroundTask(BackgroundTaskFunction fn, BackgroundTaskFunction on_finish, EQEmu::Any data) {
|
||||
uv_work_t *m_work = new uv_work_t;
|
||||
memset(m_work, 0, sizeof(uv_work_t));
|
||||
BackgroundTaskBaton *baton = new BackgroundTaskBaton();
|
||||
baton->fn = fn;
|
||||
baton->on_finish = on_finish;
|
||||
baton->data = data;
|
||||
|
||||
m_work->data = baton;
|
||||
uv_queue_work(EventLoop::Get().Handle(), m_work, [](uv_work_t* req) {
|
||||
BackgroundTaskBaton *baton = (BackgroundTaskBaton*)req->data;
|
||||
baton->fn(baton->data);
|
||||
}, [](uv_work_t* req, int status) {
|
||||
BackgroundTaskBaton *baton = (BackgroundTaskBaton*)req->data;
|
||||
baton->on_finish(baton->data);
|
||||
delete baton;
|
||||
delete req;
|
||||
});
|
||||
}
|
||||
|
||||
~BackgroundTask() {
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
#pragma once
|
||||
#include <functional>
|
||||
#include <exception>
|
||||
#include "event_loop.h"
|
||||
#include "../any.h"
|
||||
|
||||
namespace EQ {
|
||||
class Task
|
||||
{
|
||||
public:
|
||||
typedef std::function<void(const EQEmu::Any&)> ResolveFn;
|
||||
typedef std::function<void(const std::exception&)> RejectFn;
|
||||
typedef std::function<void()> FinallyFn;
|
||||
typedef std::function<void(ResolveFn, RejectFn)> TaskFn;
|
||||
struct TaskBaton
|
||||
{
|
||||
TaskFn fn;
|
||||
ResolveFn on_then;
|
||||
RejectFn on_catch;
|
||||
FinallyFn on_finally;
|
||||
bool has_result;
|
||||
EQEmu::Any result;
|
||||
bool has_error;
|
||||
std::exception error;
|
||||
};
|
||||
|
||||
Task(TaskFn fn) {
|
||||
m_fn = fn;
|
||||
}
|
||||
|
||||
~Task() {
|
||||
|
||||
}
|
||||
|
||||
Task& Then(ResolveFn fn) {
|
||||
m_then = fn;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Task& Catch(RejectFn fn) {
|
||||
m_catch = fn;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Task& Finally(FinallyFn fn) {
|
||||
m_finally = fn;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Run() {
|
||||
uv_work_t *m_work = new uv_work_t;
|
||||
memset(m_work, 0, sizeof(uv_work_t));
|
||||
TaskBaton *baton = new TaskBaton();
|
||||
baton->fn = m_fn;
|
||||
baton->on_then = m_then;
|
||||
baton->on_catch = m_catch;
|
||||
baton->on_finally = m_finally;
|
||||
baton->has_result = false;
|
||||
baton->has_error = false;
|
||||
|
||||
m_work->data = baton;
|
||||
|
||||
uv_queue_work(EventLoop::Get().Handle(), m_work, [](uv_work_t* req) {
|
||||
TaskBaton *baton = (TaskBaton*)req->data;
|
||||
|
||||
baton->fn([baton](const EQEmu::Any& result) {
|
||||
baton->has_error = false;
|
||||
baton->has_result = true;
|
||||
baton->result = result;
|
||||
}, [baton](const std::exception &err) {
|
||||
baton->has_error = true;
|
||||
baton->has_result = false;
|
||||
baton->error = err;
|
||||
});
|
||||
}, [](uv_work_t* req, int status) {
|
||||
TaskBaton *baton = (TaskBaton*)req->data;
|
||||
|
||||
if (baton->has_error && baton->on_catch) {
|
||||
baton->on_catch(baton->error);
|
||||
}
|
||||
else if (baton->has_result && baton->on_then) {
|
||||
baton->on_then(baton->result);
|
||||
}
|
||||
|
||||
if (baton->on_finally) {
|
||||
baton->on_finally();
|
||||
}
|
||||
|
||||
delete baton;
|
||||
delete req;
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
TaskFn m_fn;
|
||||
ResolveFn m_then;
|
||||
RejectFn m_catch;
|
||||
FinallyFn m_finally;
|
||||
};
|
||||
}
|
||||
+10
-12
@@ -18,6 +18,7 @@
|
||||
|
||||
#include "faction.h"
|
||||
#include "races.h"
|
||||
#include "rulesys.h"
|
||||
|
||||
const char *FactionValueToString(FACTION_VALUE fv)
|
||||
{
|
||||
@@ -59,34 +60,31 @@ FACTION_VALUE CalculateFaction(FactionMods* fm, int32 tmpCharacter_value)
|
||||
if (fm) {
|
||||
character_value += fm->base + fm->class_mod + fm->race_mod + fm->deity_mod;
|
||||
}
|
||||
if (character_value >= 1101) {
|
||||
if (character_value >= RuleI(Faction, AllyFactionMinimum)) {
|
||||
return FACTION_ALLY;
|
||||
}
|
||||
if (character_value >= 701 && character_value <= 1100) {
|
||||
if (character_value >= RuleI(Faction, WarmlyFactionMinimum)) {
|
||||
return FACTION_WARMLY;
|
||||
}
|
||||
if (character_value >= 401 && character_value <= 700) {
|
||||
if (character_value >= RuleI(Faction, KindlyFactionMinimum)) {
|
||||
return FACTION_KINDLY;
|
||||
}
|
||||
if (character_value >= 101 && character_value <= 400) {
|
||||
if (character_value >= RuleI(Faction, AmiablyFactionMinimum)) {
|
||||
return FACTION_AMIABLE;
|
||||
}
|
||||
if (character_value >= 0 && character_value <= 100) {
|
||||
if (character_value >= RuleI(Faction, IndifferentlyFactionMinimum)) {
|
||||
return FACTION_INDIFFERENT;
|
||||
}
|
||||
if (character_value >= -100 && character_value <= -1) {
|
||||
if (character_value >= RuleI(Faction, ApprehensivelyFactionMinimum)) {
|
||||
return FACTION_APPREHENSIVE;
|
||||
}
|
||||
if (character_value >= -700 && character_value <= -101) {
|
||||
if (character_value >= RuleI(Faction, DubiouslyFactionMinimum)) {
|
||||
return FACTION_DUBIOUS;
|
||||
}
|
||||
if (character_value >= -999 && character_value <= -701) {
|
||||
if (character_value >= RuleI(Faction, ThreateninglyFactionMinimum)) {
|
||||
return FACTION_THREATENLY;
|
||||
}
|
||||
if (character_value <= -1000) {
|
||||
return FACTION_SCOWLS;
|
||||
}
|
||||
return FACTION_INDIFFERENT;
|
||||
return FACTION_SCOWLS;
|
||||
}
|
||||
|
||||
// this function should check if some races have more than one race define
|
||||
|
||||
Regular → Executable
+4
@@ -50,6 +50,8 @@ struct NPCFactionList {
|
||||
struct FactionMods
|
||||
{
|
||||
int32 base;
|
||||
int16 min; // The lowest your personal earned faction can go - before race/class/diety adjustments.
|
||||
int16 max; // The highest your personal earned faction can go - before race/class/diety adjustments.
|
||||
int32 class_mod;
|
||||
int32 race_mod;
|
||||
int32 deity_mod;
|
||||
@@ -59,6 +61,8 @@ struct Faction {
|
||||
int32 id;
|
||||
std::map<std::string, int16> mods;
|
||||
int16 base;
|
||||
int16 min; // The lowest your personal earned faction can go - before race/class/diety adjustments.
|
||||
int16 max; // The highest your personal earned faction can go - before race/class/diety adjustments.
|
||||
char name[50];
|
||||
};
|
||||
|
||||
|
||||
@@ -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 */
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "daybreak_connection.h"
|
||||
#include "../event/event_loop.h"
|
||||
#include "../event/task.h"
|
||||
#include "../eqemu_logsys.h"
|
||||
#include "../data_verification.h"
|
||||
#include "crc32.h"
|
||||
@@ -278,7 +279,6 @@ EQ::Net::DaybreakConnection::DaybreakConnection(DaybreakConnectionManager *owner
|
||||
m_hold_time = Clock::now();
|
||||
m_buffered_packets_length = 0;
|
||||
m_rolling_ping = 500;
|
||||
m_resend_delay = (m_rolling_ping * m_owner->m_options.resend_delay_factor) + m_owner->m_options.resend_delay_ms;
|
||||
m_combined.reset(new char[512]);
|
||||
m_combined[0] = 0;
|
||||
m_combined[1] = OP_Combined;
|
||||
@@ -301,7 +301,6 @@ EQ::Net::DaybreakConnection::DaybreakConnection(DaybreakConnectionManager *owner
|
||||
m_hold_time = Clock::now();
|
||||
m_buffered_packets_length = 0;
|
||||
m_rolling_ping = 500;
|
||||
m_resend_delay = (m_rolling_ping * m_owner->m_options.resend_delay_factor) + m_owner->m_options.resend_delay_ms;
|
||||
m_combined.reset(new char[512]);
|
||||
m_combined[0] = 0;
|
||||
m_combined[1] = OP_Combined;
|
||||
@@ -356,9 +355,6 @@ void EQ::Net::DaybreakConnection::ResetStats()
|
||||
void EQ::Net::DaybreakConnection::Process()
|
||||
{
|
||||
try {
|
||||
m_resend_delay = (size_t)(m_rolling_ping * m_owner->m_options.resend_delay_factor) + m_owner->m_options.resend_delay_ms;
|
||||
m_resend_delay = EQEmu::Clamp(m_resend_delay, m_owner->m_options.resend_delay_min, m_owner->m_options.resend_delay_max);
|
||||
|
||||
auto now = Clock::now();
|
||||
auto time_since_hold = (size_t)std::chrono::duration_cast<std::chrono::milliseconds>(now - m_hold_time).count();
|
||||
if (time_since_hold >= m_owner->m_options.hold_length_ms) {
|
||||
@@ -946,7 +942,7 @@ uint32_t Deflate(const uint8_t* in, uint32_t in_len, uint8_t* out, uint32_t out_
|
||||
zstream.avail_in = in_len;
|
||||
zstream.opaque = Z_NULL;
|
||||
|
||||
deflateInit(&zstream, Z_FINISH);
|
||||
deflateInit(&zstream, Z_BEST_SPEED);
|
||||
zstream.next_out = out;
|
||||
zstream.avail_out = out_len;
|
||||
|
||||
@@ -1020,17 +1016,19 @@ void EQ::Net::DaybreakConnection::ProcessResend(int stream)
|
||||
if (m_status == DbProtocolStatus::StatusDisconnected) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
auto resends = 0;
|
||||
auto now = Clock::now();
|
||||
auto s = &m_streams[stream];
|
||||
for (auto &entry : s->sent_packets) {
|
||||
auto time_since_last_send = std::chrono::duration_cast<std::chrono::milliseconds>(now - entry.second.last_sent);
|
||||
if (entry.second.times_resent == 0) {
|
||||
if ((size_t)time_since_last_send.count() > m_resend_delay) {
|
||||
if ((size_t)time_since_last_send.count() > entry.second.resend_delay) {
|
||||
InternalBufferedSend(entry.second.packet);
|
||||
entry.second.last_sent = now;
|
||||
entry.second.times_resent++;
|
||||
m_rolling_ping += 100;
|
||||
entry.second.resend_delay = EQEmu::Clamp(entry.second.resend_delay * 2, m_owner->m_options.resend_delay_min, m_owner->m_options.resend_delay_max);
|
||||
resends++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -1039,12 +1037,13 @@ void EQ::Net::DaybreakConnection::ProcessResend(int stream)
|
||||
Close();
|
||||
return;
|
||||
}
|
||||
|
||||
if ((size_t)time_since_last_send.count() > m_resend_delay) {
|
||||
|
||||
if ((size_t)time_since_last_send.count() > entry.second.resend_delay) {
|
||||
InternalBufferedSend(entry.second.packet);
|
||||
entry.second.last_sent = now;
|
||||
entry.second.times_resent++;
|
||||
m_rolling_ping += 100;
|
||||
entry.second.resend_delay = EQEmu::Clamp(entry.second.resend_delay * 2, m_owner->m_options.resend_delay_min, m_owner->m_options.resend_delay_max);
|
||||
resends++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1195,20 +1194,20 @@ void EQ::Net::DaybreakConnection::InternalSend(Packet &p)
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
switch (m_encode_passes[i]) {
|
||||
case EncodeCompression:
|
||||
if(out.GetInt8(0) == 0)
|
||||
Compress(out, DaybreakHeader::size(), out.Length() - DaybreakHeader::size());
|
||||
else
|
||||
Compress(out, 1, out.Length() - 1);
|
||||
break;
|
||||
case EncodeXOR:
|
||||
if (out.GetInt8(0) == 0)
|
||||
Encode(out, DaybreakHeader::size(), out.Length() - DaybreakHeader::size());
|
||||
else
|
||||
Encode(out, 1, out.Length() - 1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
case EncodeCompression:
|
||||
if (out.GetInt8(0) == 0)
|
||||
Compress(out, DaybreakHeader::size(), out.Length() - DaybreakHeader::size());
|
||||
else
|
||||
Compress(out, 1, out.Length() - 1);
|
||||
break;
|
||||
case EncodeXOR:
|
||||
if (out.GetInt8(0) == 0)
|
||||
Encode(out, DaybreakHeader::size(), out.Length() - DaybreakHeader::size());
|
||||
else
|
||||
Encode(out, 1, out.Length() - 1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1294,6 +1293,10 @@ void EQ::Net::DaybreakConnection::InternalQueuePacket(Packet &p, int stream_id,
|
||||
sent.last_sent = Clock::now();
|
||||
sent.first_sent = Clock::now();
|
||||
sent.times_resent = 0;
|
||||
sent.resend_delay = EQEmu::Clamp(
|
||||
static_cast<size_t>((m_rolling_ping * m_owner->m_options.resend_delay_factor) + m_owner->m_options.resend_delay_ms),
|
||||
m_owner->m_options.resend_delay_min,
|
||||
m_owner->m_options.resend_delay_max);
|
||||
stream->sent_packets.insert(std::make_pair(stream->sequence_out, sent));
|
||||
stream->sequence_out++;
|
||||
|
||||
@@ -1322,6 +1325,10 @@ void EQ::Net::DaybreakConnection::InternalQueuePacket(Packet &p, int stream_id,
|
||||
sent.last_sent = Clock::now();
|
||||
sent.first_sent = Clock::now();
|
||||
sent.times_resent = 0;
|
||||
sent.resend_delay = EQEmu::Clamp(
|
||||
static_cast<size_t>((m_rolling_ping * m_owner->m_options.resend_delay_factor) + m_owner->m_options.resend_delay_ms),
|
||||
m_owner->m_options.resend_delay_min,
|
||||
m_owner->m_options.resend_delay_max);
|
||||
stream->sent_packets.insert(std::make_pair(stream->sequence_out, sent));
|
||||
stream->sequence_out++;
|
||||
|
||||
@@ -1342,6 +1349,10 @@ void EQ::Net::DaybreakConnection::InternalQueuePacket(Packet &p, int stream_id,
|
||||
sent.last_sent = Clock::now();
|
||||
sent.first_sent = Clock::now();
|
||||
sent.times_resent = 0;
|
||||
sent.resend_delay = EQEmu::Clamp(
|
||||
static_cast<size_t>((m_rolling_ping * m_owner->m_options.resend_delay_factor) + m_owner->m_options.resend_delay_ms),
|
||||
m_owner->m_options.resend_delay_min,
|
||||
m_owner->m_options.resend_delay_max);
|
||||
stream->sent_packets.insert(std::make_pair(stream->sequence_out, sent));
|
||||
stream->sequence_out++;
|
||||
|
||||
|
||||
@@ -109,10 +109,16 @@ namespace EQ
|
||||
void QueuePacket(Packet &p);
|
||||
void QueuePacket(Packet &p, int stream);
|
||||
void QueuePacket(Packet &p, int stream, bool reliable);
|
||||
|
||||
const DaybreakConnectionStats& GetStats() const { return m_stats; }
|
||||
DaybreakConnectionStats &GetStats() { return m_stats; }
|
||||
void ResetStats();
|
||||
size_t GetRollingPing() const { return m_rolling_ping; }
|
||||
DbProtocolStatus GetStatus() { return m_status; }
|
||||
DbProtocolStatus GetStatus() const { return m_status; }
|
||||
|
||||
const DaybreakEncodeType* GetEncodePasses() const { return m_encode_passes; }
|
||||
const DaybreakConnectionManager* GetManager() const { return m_owner; }
|
||||
DaybreakConnectionManager* GetManager() { return m_owner; }
|
||||
private:
|
||||
DaybreakConnectionManager *m_owner;
|
||||
std::string m_endpoint;
|
||||
@@ -132,7 +138,6 @@ namespace EQ
|
||||
std::unique_ptr<char[]> m_combined;
|
||||
DaybreakConnectionStats m_stats;
|
||||
Timestamp m_last_session_stats;
|
||||
size_t m_resend_delay;
|
||||
size_t m_rolling_ping;
|
||||
Timestamp m_close_time;
|
||||
|
||||
@@ -142,6 +147,7 @@ namespace EQ
|
||||
Timestamp last_sent;
|
||||
Timestamp first_sent;
|
||||
size_t times_resent;
|
||||
size_t resend_delay;
|
||||
};
|
||||
|
||||
struct DaybreakStream
|
||||
@@ -205,10 +211,10 @@ namespace EQ
|
||||
DaybreakConnectionManagerOptions() {
|
||||
max_connection_count = 0;
|
||||
keepalive_delay_ms = 9000;
|
||||
resend_delay_ms = 150;
|
||||
resend_delay_factor = 1.5;
|
||||
resend_delay_ms = 30;
|
||||
resend_delay_factor = 1.25;
|
||||
resend_delay_min = 150;
|
||||
resend_delay_max = 1000;
|
||||
resend_delay_max = 5000;
|
||||
connect_delay_ms = 500;
|
||||
stale_connection_ms = 90000;
|
||||
connect_stale_ms = 5000;
|
||||
@@ -261,6 +267,8 @@ namespace EQ
|
||||
void OnNewConnection(std::function<void(std::shared_ptr<DaybreakConnection>)> func) { m_on_new_connection = func; }
|
||||
void OnConnectionStateChange(std::function<void(std::shared_ptr<DaybreakConnection>, DbProtocolStatus, DbProtocolStatus)> func) { m_on_connection_state_change = func; }
|
||||
void OnPacketRecv(std::function<void(std::shared_ptr<DaybreakConnection>, const Packet &)> func) { m_on_packet_recv = func; }
|
||||
|
||||
DaybreakConnectionManagerOptions& GetOptions() { return m_options; }
|
||||
private:
|
||||
void Attach(uv_loop_t *loop);
|
||||
void Detach();
|
||||
|
||||
@@ -84,6 +84,10 @@ namespace EQ
|
||||
m_opcode_manager = opm;
|
||||
}
|
||||
|
||||
virtual std::shared_ptr<EQ::Net::DaybreakConnection> GetRawConnection() {
|
||||
return m_connection;
|
||||
}
|
||||
|
||||
const std::string& RemoteEndpoint() const { return m_connection->RemoteEndpoint(); }
|
||||
const DaybreakConnectionStats& GetStats() const { return m_connection->GetStats(); }
|
||||
void ResetStats() { m_connection->ResetStats(); }
|
||||
@@ -96,4 +100,4 @@ namespace EQ
|
||||
friend class EQStreamManager;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "endian.h"
|
||||
#include <fmt/format.h>
|
||||
#include <cctype>
|
||||
#include <google/protobuf/message.h>
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
if (Length() < offset + 1) {
|
||||
@@ -276,6 +294,11 @@ std::string EQ::Net::Packet::GetCString(size_t offset) const
|
||||
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) {
|
||||
if (std::isprint(in)) {
|
||||
return in;
|
||||
|
||||
+13
-1
@@ -8,8 +8,17 @@
|
||||
#include <cereal/cereal.hpp>
|
||||
#include <cereal/archives/binary.hpp>
|
||||
|
||||
namespace google
|
||||
{
|
||||
namespace protobuf
|
||||
{
|
||||
class Message;
|
||||
}
|
||||
}
|
||||
|
||||
namespace EQ {
|
||||
namespace Net {
|
||||
class StaticPacket;
|
||||
class Packet
|
||||
{
|
||||
public:
|
||||
@@ -64,6 +73,7 @@ namespace EQ {
|
||||
void PutCString(size_t offset, const char *str);
|
||||
void PutPacket(size_t offset, const Packet &p);
|
||||
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;
|
||||
int16_t GetInt16(size_t offset) const;
|
||||
@@ -77,6 +87,8 @@ namespace EQ {
|
||||
double GetDouble(size_t offset) const;
|
||||
std::string GetString(size_t offset, size_t length) 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(size_t line_length) const;
|
||||
@@ -127,4 +139,4 @@ namespace EQ {
|
||||
std::vector<char> m_data;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
#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.PutUInt16(4, opcode);
|
||||
out.PutPacket(6, p);
|
||||
}
|
||||
#else
|
||||
out.PutUInt32(0, p.Length());
|
||||
out.PutUInt16(4, opcode);
|
||||
out.PutPacket(6, p);
|
||||
#endif
|
||||
InternalSend(ServertalkMessage, out);
|
||||
}
|
||||
|
||||
@@ -188,51 +166,6 @@ void EQ::Net::ServertalkClient::ProcessReadBuffer()
|
||||
|
||||
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 {
|
||||
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);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void EQ::Net::ServertalkClient::ProcessMessage(EQ::Net::Packet &p)
|
||||
@@ -269,45 +201,6 @@ void EQ::Net::ServertalkClient::ProcessMessage(EQ::Net::Packet &p)
|
||||
auto opcode = p.GetUInt16(4);
|
||||
if (length > 0) {
|
||||
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;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
size_t message_len = length;
|
||||
EQ::Net::StaticPacket packet(&data[0], message_len);
|
||||
|
||||
@@ -319,7 +212,6 @@ void EQ::Net::ServertalkClient::ProcessMessage(EQ::Net::Packet &p)
|
||||
if (m_message_callback) {
|
||||
m_message_callback(opcode, packet);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
catch (std::exception &ex) {
|
||||
@@ -330,46 +222,9 @@ void EQ::Net::ServertalkClient::ProcessMessage(EQ::Net::Packet &p)
|
||||
void EQ::Net::ServertalkClient::SendHandshake(bool downgrade)
|
||||
{
|
||||
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(m_identifier.length() + 1, m_credentials);
|
||||
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) {
|
||||
InternalSend(ServertalkClientDowngradeSecurityHandshake, handshake);
|
||||
|
||||
@@ -4,9 +4,6 @@
|
||||
#include "../event/timer.h"
|
||||
#include "servertalk_common.h"
|
||||
#include "packet.h"
|
||||
#ifdef ENABLE_SECURITY
|
||||
#include <sodium.h>
|
||||
#endif
|
||||
|
||||
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();
|
||||
|
||||
void Send(uint16_t opcode, EQ::Net::Packet &p);
|
||||
void Send(uint16_t opcode, const EQ::Net::Packet &p);
|
||||
void SendPacket(ServerPacket *p);
|
||||
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);
|
||||
@@ -26,6 +23,8 @@ namespace EQ
|
||||
bool Connected() const { return m_connecting != true; }
|
||||
|
||||
std::shared_ptr<EQ::Net::TCPConnection> Handle() { return m_connection; }
|
||||
|
||||
std::string GetIdentifier() const { return m_identifier; }
|
||||
private:
|
||||
void Connect();
|
||||
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::function<void(uint16_t, EQ::Net::Packet&)> m_message_callback;
|
||||
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)
|
||||
return;
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace EQ
|
||||
ServertalkLegacyClient(const std::string &addr, int port, bool ipv6);
|
||||
~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 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);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "servertalk_server.h"
|
||||
#include <regex>
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if (conn->GetIdentifier().empty()) {
|
||||
@@ -51,6 +62,11 @@ void EQ::Net::ServertalkServer::ConnectionDisconnected(ServertalkServerConnectio
|
||||
if (on_disc != m_on_disc.end()) {
|
||||
on_disc->second(*iter);
|
||||
}
|
||||
|
||||
if (m_on_any_disc) {
|
||||
m_on_any_disc(*iter);
|
||||
}
|
||||
|
||||
type->second.erase(iter);
|
||||
return;
|
||||
}
|
||||
@@ -65,9 +81,16 @@ void EQ::Net::ServertalkServer::ConnectionIdentified(ServertalkServerConnection
|
||||
auto iter = m_unident_connections.begin();
|
||||
while (iter != m_unident_connections.end()) {
|
||||
if (conn == iter->get()) {
|
||||
auto on_ident = m_on_ident.find(conn->GetIdentifier());
|
||||
if (on_ident != m_on_ident.end()) {
|
||||
on_ident->second(*iter);
|
||||
for (auto &ident : m_on_ident) {
|
||||
std::regex ident_regex(ident.first);
|
||||
|
||||
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) {
|
||||
|
||||
@@ -5,10 +5,6 @@
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#ifdef ENABLE_SECURITY
|
||||
#include <sodium.h>
|
||||
#endif
|
||||
|
||||
namespace EQ
|
||||
{
|
||||
namespace Net
|
||||
@@ -22,13 +18,8 @@ namespace EQ
|
||||
std::string credentials;
|
||||
|
||||
ServertalkServerOptions() {
|
||||
#ifdef ENABLE_SECURITY
|
||||
encrypted = true;
|
||||
allow_downgrade = true;
|
||||
#else
|
||||
encrypted = false;
|
||||
allow_downgrade = true;
|
||||
#endif
|
||||
ipv6 = false;
|
||||
}
|
||||
};
|
||||
@@ -36,12 +27,16 @@ namespace EQ
|
||||
class ServertalkServer
|
||||
{
|
||||
public:
|
||||
typedef std::function<void(std::shared_ptr<ServertalkServerConnection>)> IdentityCallback;
|
||||
|
||||
ServertalkServer();
|
||||
~ServertalkServer();
|
||||
|
||||
void Listen(const ServertalkServerOptions& opts);
|
||||
void OnConnectionIdentified(const std::string &type, std::function<void(std::shared_ptr<ServertalkServerConnection>)> cb);
|
||||
void OnConnectionRemoved(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, IdentityCallback cb);
|
||||
void OnConnectionIdentified(IdentityCallback cb);
|
||||
void OnConnectionRemoved(IdentityCallback cb);
|
||||
|
||||
private:
|
||||
void ConnectionDisconnected(ServertalkServerConnection *conn);
|
||||
@@ -52,8 +47,10 @@ namespace EQ
|
||||
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::function<void(std::shared_ptr<ServertalkServerConnection>)>> m_on_ident;
|
||||
std::map<std::string, std::function<void(std::shared_ptr<ServertalkServerConnection>)>> m_on_disc;
|
||||
std::map<std::string, IdentityCallback> m_on_ident;
|
||||
std::map<std::string, IdentityCallback> m_on_disc;
|
||||
IdentityCallback m_on_any_ident;
|
||||
IdentityCallback m_on_any_disc;
|
||||
bool m_encrypted;
|
||||
bool m_allow_downgrade;
|
||||
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;
|
||||
#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.PutUInt16(4, opcode);
|
||||
out.PutPacket(6, p);
|
||||
}
|
||||
#else
|
||||
out.PutUInt32(0, p.Length());
|
||||
out.PutUInt16(4, opcode);
|
||||
out.PutPacket(6, p);
|
||||
#endif
|
||||
InternalSend(ServertalkMessage, out);
|
||||
}
|
||||
|
||||
@@ -155,29 +134,7 @@ void EQ::Net::ServertalkServerConnection::OnDisconnect(TCPConnection *c)
|
||||
void EQ::Net::ServertalkServerConnection::SendHello()
|
||||
{
|
||||
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);
|
||||
}
|
||||
#else
|
||||
hello.PutInt8(0, 0);
|
||||
#endif
|
||||
|
||||
InternalSend(ServertalkServerHello, hello);
|
||||
}
|
||||
@@ -199,69 +156,6 @@ void EQ::Net::ServertalkServerConnection::InternalSend(ServertalkPacketType type
|
||||
|
||||
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 {
|
||||
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();
|
||||
}
|
||||
}
|
||||
#else
|
||||
try {
|
||||
m_identifier = p.GetCString(0);
|
||||
auto credentials = p.GetCString(m_identifier.length() + 1);
|
||||
@@ -278,7 +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());
|
||||
m_connection->Disconnect();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void EQ::Net::ServertalkServerConnection::ProcessMessage(EQ::Net::Packet &p)
|
||||
@@ -288,46 +181,6 @@ void EQ::Net::ServertalkServerConnection::ProcessMessage(EQ::Net::Packet &p)
|
||||
auto opcode = p.GetUInt16(4);
|
||||
if (length > 0) {
|
||||
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;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
size_t message_len = length;
|
||||
EQ::Net::StaticPacket packet(&data[0], message_len);
|
||||
|
||||
@@ -339,7 +192,6 @@ void EQ::Net::ServertalkServerConnection::ProcessMessage(EQ::Net::Packet &p)
|
||||
if (m_message_callback) {
|
||||
m_message_callback(opcode, packet);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
catch (std::exception &ex) {
|
||||
|
||||
@@ -4,9 +4,6 @@
|
||||
#include "servertalk_common.h"
|
||||
#include "packet.h"
|
||||
#include <vector>
|
||||
#ifdef ENABLE_SECURITY
|
||||
#include <sodium.h>
|
||||
#endif
|
||||
|
||||
namespace EQ
|
||||
{
|
||||
@@ -19,7 +16,7 @@ namespace EQ
|
||||
ServertalkServerConnection(std::shared_ptr<EQ::Net::TCPConnection> c, ServertalkServer *parent, bool encrypted, bool allow_downgrade);
|
||||
~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 OnMessage(uint16_t opcode, 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_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;
|
||||
}
|
||||
|
||||
@@ -704,6 +704,14 @@ RULE_CATEGORY(Console)
|
||||
RULE_INT(Console, SessionTimeOut, 600000) // Amount of time in ms for the console session to time out
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(Network)
|
||||
RULE_INT(Network, ResendDelayBaseMS, 100)
|
||||
RULE_REAL(Network, ResendDelayFactor, 1.5)
|
||||
RULE_INT(Network, ResendDelayMinMS, 100)
|
||||
RULE_INT(Network, ResendDelayMaxMS, 5000)
|
||||
RULE_INT(Network, ResendsPerCycle, 1000)
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(QueryServ)
|
||||
RULE_BOOL(QueryServ, PlayerLogChat, false) // Logs Player Chat
|
||||
RULE_BOOL(QueryServ, PlayerLogTrades, false) // Logs Player Trades
|
||||
@@ -750,6 +758,17 @@ RULE_BOOL(Bugs, UseOldReportingMethod, true) // Forces the use of the old bug re
|
||||
RULE_BOOL(Bugs, DumpTargetEntity, false) // Dumps the target entity, if one is provided
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(Faction)
|
||||
RULE_INT(Faction, AllyFactionMinimum, 1100)
|
||||
RULE_INT(Faction, WarmlyFactionMinimum, 750)
|
||||
RULE_INT(Faction, KindlyFactionMinimum, 500)
|
||||
RULE_INT(Faction, AmiablyFactionMinimum, 100)
|
||||
RULE_INT(Faction, IndifferentlyFactionMinimum, 0)
|
||||
RULE_INT(Faction, ApprehensivelyFactionMinimum, -100)
|
||||
RULE_INT(Faction, DubiouslyFactionMinimum, -500)
|
||||
RULE_INT(Faction, ThreateninglyFactionMinimum, -750)
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
#undef RULE_CATEGORY
|
||||
#undef RULE_INT
|
||||
#undef RULE_REAL
|
||||
|
||||
@@ -187,6 +187,7 @@ public:
|
||||
const unsigned char *buffer() const { return m_buffer; }
|
||||
|
||||
friend class BasePacket;
|
||||
friend class ServerPacket;
|
||||
|
||||
private:
|
||||
void Grow(size_t new_size);
|
||||
|
||||
+233
-197
@@ -1,218 +1,220 @@
|
||||
#ifndef EQ_SOPCODES_H
|
||||
#define EQ_SOPCODES_H
|
||||
#pragma once
|
||||
|
||||
#include "../common/types.h"
|
||||
#include "../common/packet_functions.h"
|
||||
#include "../common/eq_packet_structs.h"
|
||||
#include "../common/serialize_buffer.h"
|
||||
#include "../net/packet.h"
|
||||
#include <cereal/cereal.hpp>
|
||||
#include <cereal/types/string.hpp>
|
||||
|
||||
#define SERVER_TIMEOUT 45000 // how often keepalive gets sent
|
||||
#define INTERSERVER_TIMER 10000
|
||||
#define LoginServer_StatusUpdateInterval 15000
|
||||
#define LoginServer_AuthStale 60000
|
||||
#define AUTHCHANGE_TIMEOUT 900 // in seconds
|
||||
constexpr auto INTERSERVER_TIMER = 10000;
|
||||
constexpr auto LoginServer_StatusUpdateInterval = 15000;
|
||||
|
||||
#define ServerOP_KeepAlive 0x0001 // packet to test if port is still open
|
||||
#define ServerOP_ChannelMessage 0x0002 // broadcast/guildsay
|
||||
#define ServerOP_SetZone 0x0003 // client -> server zoneinfo
|
||||
#define ServerOP_ShutdownAll 0x0004 // exit(0);
|
||||
#define ServerOP_ZoneShutdown 0x0005 // unload all data, goto sleep mode
|
||||
#define ServerOP_ZoneBootup 0x0006 // come out of sleep mode and load zone specified
|
||||
#define ServerOP_ZoneStatus 0x0007 // Shows status of all zones
|
||||
#define ServerOP_SetConnectInfo 0x0008 // Tells server address and port #
|
||||
#define ServerOP_EmoteMessage 0x0009 // Worldfarts
|
||||
#define ServerOP_ClientList 0x000A // Update worldserver's client list, for #whos
|
||||
#define ServerOP_Who 0x000B // #who
|
||||
#define ServerOP_ZonePlayer 0x000C // #zone, or #summon
|
||||
#define ServerOP_KickPlayer 0x000D // #kick
|
||||
//Certain ops needed for backwards compat with old LS can't enum without being really annoying.
|
||||
constexpr auto ServerOP_UsertoWorldReq = 0xAB00;
|
||||
constexpr auto ServerOP_UsertoWorldResp = 0xAB01;
|
||||
constexpr auto ServerOP_LSClientAuth = 0x1002;
|
||||
constexpr auto ServerOP_LSFatalError = 0x1003;
|
||||
constexpr auto ServerOP_SystemwideMessage = 0x1005;
|
||||
constexpr auto ServerOP_LSRemoteAddr = 0x1009;
|
||||
constexpr auto ServerOP_LSAccountUpdate = 0x100A;
|
||||
constexpr auto ServerOP_NewLSInfo = 0x1008;
|
||||
constexpr auto ServerOP_LSInfo = 0x1000;
|
||||
constexpr auto ServerOP_LSStatus = 0x1001;
|
||||
|
||||
#define ServerOP_RefreshGuild 0x000E // Notice to all zoneservers to refresh their guild cache for ID# in packet (ServerGuildRefresh_Struct)
|
||||
#define ServerOP_VoiceMacro 0x000F
|
||||
//#define ServerOP_GuildInvite 0x0010
|
||||
#define ServerOP_DeleteGuild 0x0011 // ServerGuildID_Struct
|
||||
#define ServerOP_GuildRankUpdate 0x0012
|
||||
#define ServerOP_GuildCharRefresh 0x0013
|
||||
#define ServerOP_GuildMemberUpdate 0x0014
|
||||
#define ServerOP_RequestOnlineGuildMembers 0x0015
|
||||
#define ServerOP_OnlineGuildMembersResponse 0x0016
|
||||
#define ServerOP_LFGuildUpdate 0x0017
|
||||
enum ServerOpcode : int
|
||||
{
|
||||
ServerOP_ChannelMessage,
|
||||
ServerOP_SetZone,
|
||||
ServerOP_ShutdownAll,
|
||||
ServerOP_ZoneShutdown,
|
||||
ServerOP_ZoneBootup,
|
||||
ServerOP_ZoneStatus,
|
||||
ServerOP_SetConnectInfo,
|
||||
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
|
||||
#define ServerOP_GMGoto 0x0019
|
||||
#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
|
||||
/*Tasks*/
|
||||
ServerOP_GetClientTaskState
|
||||
};
|
||||
|
||||
#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 */
|
||||
enum { QSG_LFGuild = 0 };
|
||||
enum { QSG_LFGuild_PlayerMatches = 0, QSG_LFGuild_UpdatePlayerInfo, QSG_LFGuild_RequestPlayerInfo, QSG_LFGuild_UpdateGuildInfo, QSG_LFGuild_GuildMatches,
|
||||
QSG_LFGuild_RequestGuildInfo };
|
||||
|
||||
#define ServerOP_Speech 0x4513
|
||||
|
||||
/************ PACKET RELATED STRUCT ************/
|
||||
class ServerPacket
|
||||
{
|
||||
@@ -248,6 +250,19 @@ public:
|
||||
_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() {
|
||||
if (this == 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;
|
||||
};
|
||||
}
|
||||
+9
-9
@@ -68,16 +68,16 @@ enum SpellTypes : uint32
|
||||
SpellType_InCombatBuffSong = (1 << 18), // bard in-combat group/ae buffs
|
||||
SpellType_OutOfCombatBuffSong = (1 << 19), // bard out-of-combat group/ae buffs
|
||||
SpellType_PreCombatBuff = (1 << 20),
|
||||
SpellType_PreCombatBuffSong = (1 << 21),
|
||||
|
||||
SpellTypes_Detrimental = (SpellType_Nuke | SpellType_Root | SpellType_Lifetap | SpellType_Snare | SpellType_DOT | SpellType_Dispel | SpellType_Mez | SpellType_Charm | SpellType_Debuff | SpellType_Slow),
|
||||
SpellTypes_Beneficial = (SpellType_Heal | SpellType_Buff | SpellType_Escape | SpellType_Pet | SpellType_InCombatBuff | SpellType_Cure | SpellType_HateRedux | SpellType_InCombatBuffSong | SpellType_OutOfCombatBuffSong | SpellType_PreCombatBuff | SpellType_PreCombatBuffSong),
|
||||
|
||||
SpellTypes_Innate = (SpellType_Nuke | SpellType_Lifetap | SpellType_DOT | SpellType_Dispel | SpellType_Mez | SpellType_Slow | SpellType_Debuff | SpellType_Charm | SpellType_Root),
|
||||
|
||||
SpellType_Any = 0xFFFFFFFF
|
||||
SpellType_PreCombatBuffSong = (1 << 21)
|
||||
};
|
||||
|
||||
const uint32 SPELL_TYPE_MIN = (SpellType_Nuke << 1) - 1;
|
||||
const uint32 SPELL_TYPE_MAX = (SpellType_PreCombatBuffSong << 1) - 1;
|
||||
const uint32 SPELL_TYPE_ANY = 0xFFFFFFFF;
|
||||
|
||||
const uint32 SPELL_TYPES_DETRIMENTAL = (SpellType_Nuke | SpellType_Root | SpellType_Lifetap | SpellType_Snare | SpellType_DOT | SpellType_Dispel | SpellType_Mez | SpellType_Charm | SpellType_Debuff | SpellType_Slow);
|
||||
const uint32 SPELL_TYPES_BENEFICIAL = (SpellType_Heal | SpellType_Buff | SpellType_Escape | SpellType_Pet | SpellType_InCombatBuff | SpellType_Cure | SpellType_HateRedux | SpellType_InCombatBuffSong | SpellType_OutOfCombatBuffSong | SpellType_PreCombatBuff | SpellType_PreCombatBuffSong);
|
||||
const uint32 SPELL_TYPES_INNATE = (SpellType_Nuke | SpellType_Lifetap | SpellType_DOT | SpellType_Dispel | SpellType_Mez | SpellType_Slow | SpellType_Debuff | SpellType_Charm | SpellType_Root);
|
||||
|
||||
// These should not be used to determine spell category..
|
||||
// They are a graphical affects (effects?) index only
|
||||
@@ -590,7 +590,7 @@ typedef enum {
|
||||
#define SE_CorruptionCounter 369 // implemented
|
||||
#define SE_ResistCorruption 370 // implemented
|
||||
#define SE_AttackSpeed4 371 // implemented - stackable slow effect 'Inhibit Melee'
|
||||
#define SE_ForageSkill 372 // *not implemented[AA] Will increase the skill cap for those that have the Forage skill and grant the skill and raise the cap to those that do not.
|
||||
#define SE_ForageSkill 372 // implemented[AA] Will increase the skill cap for those that have the Forage skill and grant the skill and raise the cap to those that do not.
|
||||
#define SE_CastOnFadeEffectAlways 373 // implemented - Triggers if fades after natural duration OR from rune/numhits fades.
|
||||
#define SE_ApplyEffect 374 // implemented
|
||||
#define SE_DotCritDmgIncrease 375 // implemented - Increase damage of DoT critical amount
|
||||
|
||||
+4
-2
@@ -30,9 +30,11 @@
|
||||
Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
|
||||
*/
|
||||
|
||||
#define CURRENT_BINARY_DATABASE_VERSION 9136
|
||||
|
||||
#define CURRENT_BINARY_DATABASE_VERSION 9139
|
||||
|
||||
#ifdef BOTS
|
||||
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9021
|
||||
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9022
|
||||
#else
|
||||
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 0 // must be 0
|
||||
#endif
|
||||
|
||||
@@ -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"
|
||||
|
||||
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_zones(zones)
|
||||
{
|
||||
m_connection.reset(new EQ::Net::ServertalkClient(config->WorldIP, config->WorldTCPPort, false, "Launcher", config->SharedKey));
|
||||
m_connection->OnConnect([this](EQ::Net::ServertalkClient *client) {
|
||||
OnConnected();
|
||||
});
|
||||
|
||||
m_connection->OnMessage(std::bind(&WorldServer::HandleMessage, this, std::placeholders::_1, std::placeholders::_2));
|
||||
SetOnConnectedHandler(std::bind(&WorldServer::OnConnected, this));
|
||||
SetOnMessageHandler(std::bind(&WorldServer::HandleMessage, this, std::placeholders::_1, std::placeholders::_2));
|
||||
}
|
||||
|
||||
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 *pack = &tpack;
|
||||
|
||||
switch (opcode) {
|
||||
case 0: {
|
||||
break;
|
||||
}
|
||||
case ServerOP_EmoteMessage:
|
||||
case ServerOP_KeepAlive: {
|
||||
// ignore this
|
||||
break;
|
||||
}
|
||||
case ServerOP_LauncherZoneRequest: {
|
||||
if (pack->size != sizeof(LauncherZoneRequest)) {
|
||||
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) {
|
||||
auto pack = new ServerPacket(ServerOP_LauncherZoneStatus, sizeof(LauncherZoneStatus));
|
||||
LauncherZoneStatus* it = (LauncherZoneStatus*)pack->pBuffer;
|
||||
@@ -138,4 +126,4 @@ void WorldServer::SendStatus(const char *short_name, uint32 start_count, bool ru
|
||||
|
||||
m_connection->SendPacket(pack);
|
||||
safe_delete(pack);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,28 +18,23 @@
|
||||
#ifndef WORLDSERVER_H
|
||||
#define WORLDSERVER_H
|
||||
|
||||
#include "../common/net/servertalk_client_connection.h"
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include "../common/world_connection.h"
|
||||
#include <queue>
|
||||
#include <map>
|
||||
|
||||
class ZoneLaunch;
|
||||
class EQEmuConfig;
|
||||
|
||||
class WorldServer {
|
||||
class WorldServer : public EQ::WorldConnection {
|
||||
public:
|
||||
WorldServer(std::map<std::string, ZoneLaunch *> &zones, const char *name, const EQEmuConfig *config);
|
||||
~WorldServer();
|
||||
|
||||
void HandleMessage(uint16 opcode, EQ::Net::Packet &p);
|
||||
|
||||
void SendStatus(const char *short_name, uint32 start_count, bool running);
|
||||
|
||||
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 EQEmuConfig *const m_config;
|
||||
std::map<std::string, ZoneLaunch *> &m_zones;
|
||||
|
||||
@@ -256,13 +256,15 @@ void ServerManager::DestroyServerByName(std::string l_name, std::string s_name,
|
||||
while (iter != world_servers.end()) {
|
||||
if ((*iter).get() == ignore) {
|
||||
++iter;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((*iter)->GetLongName().compare(l_name) == 0 && (*iter)->GetShortName().compare(s_name) == 0) {
|
||||
(*iter)->GetConnection()->Handle()->Disconnect();
|
||||
iter = world_servers.erase(iter);
|
||||
continue;
|
||||
}
|
||||
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include "../common/packet_dump.h"
|
||||
#include "../common/rulesys.h"
|
||||
|
||||
extern WorldServer *worldserver;
|
||||
extern std::unique_ptr<WorldServer> worldserver;
|
||||
extern Database database;
|
||||
|
||||
PlayerLookingForGuild::PlayerLookingForGuild(char *Name, char *Comments, uint32 Level, uint32 Class, uint32 AACount, uint32 Timezone, uint32 TimePosted)
|
||||
|
||||
@@ -39,7 +39,7 @@ Database database;
|
||||
LFGuildManager lfguildmanager;
|
||||
std::string WorldShortName;
|
||||
const queryservconfig *Config;
|
||||
WorldServer *worldserver = 0;
|
||||
std::unique_ptr<WorldServer> worldserver;
|
||||
EQEmuLogSys LogSys;
|
||||
|
||||
void CatchSignal(int sig_num) {
|
||||
@@ -88,8 +88,7 @@ int main() {
|
||||
}
|
||||
|
||||
/* Initial Connection to Worldserver */
|
||||
worldserver = new WorldServer;
|
||||
worldserver->Connect();
|
||||
worldserver.reset(new WorldServer());
|
||||
|
||||
/* Load Looking For Guild Manager */
|
||||
lfguildmanager.LoadDatabase();
|
||||
|
||||
@@ -43,49 +43,18 @@ extern Database database;
|
||||
extern LFGuildManager lfguildmanager;
|
||||
|
||||
WorldServer::WorldServer()
|
||||
: WorldConnection::WorldConnection("QueryServ")
|
||||
{
|
||||
SetOnMessageHandler(std::bind(&WorldServer::HandleMessage, this, std::placeholders::_1, std::placeholders::_2));
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
switch (opcode) {
|
||||
case 0: {
|
||||
break;
|
||||
}
|
||||
case ServerOP_KeepAlive: {
|
||||
break;
|
||||
}
|
||||
case ServerOP_Speech: {
|
||||
Server_Speech_Struct *SSS = (Server_Speech_Struct*)p.Data();
|
||||
std::string tmp1 = SSS->from;
|
||||
@@ -185,4 +154,4 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-10
@@ -18,20 +18,13 @@
|
||||
#ifndef WORLDSERVER_H
|
||||
#define WORLDSERVER_H
|
||||
|
||||
#include "../common/eq_packet_structs.h"
|
||||
#include "../common/net/servertalk_client_connection.h"
|
||||
#include "../common/world_connection.h"
|
||||
|
||||
class WorldServer
|
||||
class WorldServer : public EQ::WorldConnection
|
||||
{
|
||||
public:
|
||||
WorldServer();
|
||||
~WorldServer();
|
||||
|
||||
void Connect();
|
||||
bool SendPacket(ServerPacket* pack);
|
||||
std::string GetIP() const;
|
||||
uint16 GetPort() const;
|
||||
bool Connected() const;
|
||||
virtual ~WorldServer();
|
||||
|
||||
void HandleMessage(uint16 opcode, const EQ::Net::Packet &p);
|
||||
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;
|
||||
};
|
||||
}
|
||||
@@ -469,6 +469,11 @@ Clientlist::Clientlist(int ChatPort) {
|
||||
EQ::Net::EQStreamManagerOptions chat_opts(ChatPort, false, false);
|
||||
chat_opts.opcode_size = 1;
|
||||
chat_opts.daybreak_options.stale_connection_ms = 300000;
|
||||
chat_opts.daybreak_options.resend_delay_ms = RuleI(Network, ResendDelayBaseMS);
|
||||
chat_opts.daybreak_options.resend_delay_factor = RuleR(Network, ResendDelayFactor);
|
||||
chat_opts.daybreak_options.resend_delay_min = RuleI(Network, ResendDelayMinMS);
|
||||
chat_opts.daybreak_options.resend_delay_max = RuleI(Network, ResendDelayMaxMS);
|
||||
|
||||
chatsf = new EQ::Net::EQStreamManager(chat_opts);
|
||||
|
||||
ChatOpMgr = new RegularOpcodeManager;
|
||||
|
||||
+2
-2
@@ -40,7 +40,7 @@ ChatChannelList *ChannelList;
|
||||
Clientlist *g_Clientlist;
|
||||
EQEmuLogSys LogSys;
|
||||
Database database;
|
||||
WorldServer *worldserver = nullptr;
|
||||
std::unique_ptr<WorldServer> worldserver;
|
||||
|
||||
const ucsconfig *Config;
|
||||
|
||||
@@ -142,7 +142,7 @@ int main() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
worldserver = new WorldServer;
|
||||
worldserver.reset(new WorldServer());
|
||||
|
||||
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);
|
||||
|
||||
WorldServer::WorldServer()
|
||||
: WorldConnection::WorldConnection("UCS")
|
||||
{
|
||||
m_connection.reset(new EQ::Net::ServertalkClient(Config->WorldIP, Config->WorldTCPPort, false, "UCS", Config->SharedKey));
|
||||
m_connection->OnMessage(std::bind(&WorldServer::ProcessMessage, this, std::placeholders::_1, std::placeholders::_2));
|
||||
SetOnMessageHandler(std::bind(&WorldServer::ProcessMessage, this, std::placeholders::_1, std::placeholders::_2));
|
||||
}
|
||||
|
||||
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 *pack = &tpack;
|
||||
@@ -65,13 +65,6 @@ void WorldServer::ProcessMessage(uint16 opcode, EQ::Net::Packet &p)
|
||||
|
||||
switch (opcode)
|
||||
{
|
||||
case 0: {
|
||||
break;
|
||||
}
|
||||
case ServerOP_KeepAlive:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case ServerOP_UCSMessage:
|
||||
{
|
||||
char *Buffer = (char *)pack->pBuffer;
|
||||
|
||||
+3
-9
@@ -18,20 +18,14 @@
|
||||
#ifndef WORLDSERVER_H
|
||||
#define WORLDSERVER_H
|
||||
|
||||
#include "../net/servertalk_client_connection.h"
|
||||
#include "../common/eq_packet_structs.h"
|
||||
#include <memory>
|
||||
#include "../world_connection.h"
|
||||
|
||||
class WorldServer
|
||||
class WorldServer : public EQ::WorldConnection
|
||||
{
|
||||
public:
|
||||
WorldServer();
|
||||
~WorldServer();
|
||||
void ProcessMessage(uint16 opcode, EQ::Net::Packet &);
|
||||
|
||||
private:
|
||||
|
||||
std::unique_ptr<EQ::Net::ServertalkClient> m_connection;
|
||||
void ProcessMessage(uint16 opcode, const EQ::Net::Packet &p);
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
@@ -563,6 +563,8 @@ OP_TaskHistoryRequest=0x6cf6
|
||||
OP_TaskHistoryReply=0x25eb
|
||||
OP_DeclineAllTasks=0x0000
|
||||
OP_TaskRequestTimer=0x4b76
|
||||
OP_AcceptNewSharedTask=0x3e5e
|
||||
OP_SharedTaskMemberList=0x4ddb
|
||||
|
||||
# Title opcodes
|
||||
OP_NewTitlesAvailable=0x45d1
|
||||
|
||||
@@ -568,6 +568,8 @@ OP_TaskHistoryRequest=0x5f1c
|
||||
OP_TaskHistoryReply=0x3d05
|
||||
OP_DeclineAllTasks=0x0000
|
||||
OP_TaskRequestTimer=0x7a48
|
||||
OP_AcceptNewSharedTask=0x6646
|
||||
OP_SharedTaskMemberList=0x1e7d
|
||||
|
||||
# Title opcodes
|
||||
OP_NewTitlesAvailable=0x0d32
|
||||
|
||||
@@ -534,6 +534,8 @@ OP_TaskHistoryReply=0x3d2a # C
|
||||
OP_CancelTask=0x726b # C
|
||||
OP_DeclineAllTasks=0x0000 #
|
||||
OP_TaskRequestTimer=0x2e70
|
||||
OP_AcceptNewSharedTask=0x4751
|
||||
OP_SharedTaskMemberList=0x55f4
|
||||
|
||||
|
||||
OP_Shroud=0x6d1f
|
||||
|
||||
@@ -500,7 +500,7 @@ OP_TaskHistoryRequest=0x3035 #
|
||||
OP_TaskHistoryReply=0x3A60 #
|
||||
OP_CancelTask=0x4db6 #Xinu or 0x2c8c or 0x4db6
|
||||
OP_DeclineAllTasks=0x0000 #not sure, 12 bytes
|
||||
OP_TaskMemberList=0x3713
|
||||
#OP_TaskMemberList=0x3713
|
||||
OP_TaskMemberInvite=0x3cde
|
||||
OP_TaskMemberInviteResponse=0x6cab
|
||||
OP_TaskMemberChange=0x354a
|
||||
@@ -510,6 +510,8 @@ OP_TaskRemovePlayer=0x516f
|
||||
OP_TaskPlayerList=0x0ad6
|
||||
OP_TaskQuit=0x2c8c
|
||||
OP_TaskRequestTimer=0x0b08
|
||||
OP_AcceptNewSharedTask=0x5bed
|
||||
OP_SharedTaskMemberList=0x3713
|
||||
|
||||
#Title opcodes
|
||||
OP_NewTitlesAvailable=0x179c #
|
||||
|
||||
@@ -458,7 +458,7 @@ OP_TaskActivityComplete=0x54eb
|
||||
OP_CompletedTasks=0x76a2 # ShowEQ 10/27/05
|
||||
OP_TaskDescription=0x5ef7 # 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_AvaliableTask=0x0000
|
||||
OP_AcceptNewTask=0x207f
|
||||
@@ -475,6 +475,8 @@ OP_TaskRemovePlayer=0x37b9
|
||||
OP_TaskPlayerList=0x3961
|
||||
OP_TaskQuit=0x35dd
|
||||
OP_TaskRequestTimer=0x6a1d
|
||||
OP_AcceptNewSharedTask=0x194d
|
||||
OP_SharedTaskMemberList=0x722f
|
||||
#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_DeclineAllTasks=0x0000 #
|
||||
OP_TaskRequestTimer=0x719e
|
||||
OP_AcceptNewSharedTask=0x6ded
|
||||
OP_SharedTaskMemberList=0x584e
|
||||
|
||||
# Title opcodes
|
||||
OP_NewTitlesAvailable=0x4b49 # C
|
||||
|
||||
@@ -637,7 +637,7 @@ sub do_self_update_check_routine {
|
||||
if ($OS eq "Linux") {
|
||||
system("chmod 755 eqemu_server.pl");
|
||||
}
|
||||
system("perl eqemu_server.pl start_from_world");
|
||||
exec("perl eqemu_server.pl ran_from_world");
|
||||
}
|
||||
}
|
||||
print "[Install] Done\n";
|
||||
@@ -787,6 +787,7 @@ sub show_menu_prompt {
|
||||
elsif ($input eq "conversions") {
|
||||
print "\n>>> Conversions Menu\n\n";
|
||||
print " [quest_heading_convert] Converts old heading format in quest scripts to new (live format)\n";
|
||||
print " [quest_faction_convert] Converts to new faction values imported from client\n";
|
||||
print " \n> main - go back to main menu\n";
|
||||
print "Enter a command #> ";
|
||||
$last_menu = trim($input);
|
||||
@@ -905,6 +906,10 @@ sub show_menu_prompt {
|
||||
quest_heading_convert();
|
||||
$dc = 1;
|
||||
}
|
||||
elsif ($input eq "quest_faction_convert") {
|
||||
quest_faction_convert();
|
||||
$dc = 1;
|
||||
}
|
||||
elsif ($input eq "source_peq_db") {
|
||||
fetch_peq_db_full();
|
||||
$dc = 1;
|
||||
@@ -1388,11 +1393,13 @@ sub fetch_latest_windows_binaries {
|
||||
}
|
||||
|
||||
sub fetch_latest_windows_binaries_bots {
|
||||
print "[Update] Fetching Latest Windows Binaries with Bots...\n";
|
||||
get_remote_file($install_repository_request_url . "master_windows_build_bots.zip", "updates_staged/master_windows_build_bots.zip", 1);
|
||||
print "[Update] Fetching Latest Windows Binaries (unstable) with Bots...\n";
|
||||
get_remote_file("https://ci.appveyor.com/api/projects/KimLS/server/artifacts/eqemu-x86-bots.zip", "updates_staged/eqemu-x86-bots.zip", 1);
|
||||
#::: old repository kept for reference until no issues reported
|
||||
#::: get_remote_file($install_repository_request_url . "master_windows_build_bots.zip", "updates_staged/master_windows_build_bots.zip", 1);
|
||||
print "[Update] Fetched Latest Windows Binaries with Bots...\n";
|
||||
print "[Update] Extracting...\n";
|
||||
unzip('updates_staged/master_windows_build_bots.zip', 'updates_staged/binaries/');
|
||||
unzip('updates_staged/eqemu-x86-bots.zip', 'updates_staged/binaries/');
|
||||
my @files;
|
||||
my $start_dir = "updates_staged/binaries";
|
||||
find(
|
||||
@@ -2209,6 +2216,10 @@ sub run_database_check {
|
||||
if ($bots_db_management == 1 && $val == 9000) {
|
||||
modify_db_for_bots();
|
||||
}
|
||||
|
||||
if ($val == 9138) {
|
||||
fix_quest_factions();
|
||||
}
|
||||
}
|
||||
$db_run_stage = 2;
|
||||
}
|
||||
@@ -2493,3 +2504,127 @@ sub quest_heading_convert {
|
||||
|
||||
print "Total matches: " . $total_matches . "\n";
|
||||
}
|
||||
|
||||
|
||||
sub quest_faction_convert {
|
||||
|
||||
if(trim(get_mysql_result("SELECT value FROM variables WHERE varname = 'new_faction_conversion'")) eq "true") {
|
||||
print "Conversion script has already ran... doing this again would skew proper faction values in function calls...\n";
|
||||
exit;
|
||||
}
|
||||
|
||||
%matches = (
|
||||
0 => [ "GetCharacterFactionLevel", 0],
|
||||
1 => [ "GetModCharacterFactionLevel", 0],
|
||||
2 => [ "SetFactionLevel2", 1],
|
||||
3 => [ "GetFactionLevel", 5 ],
|
||||
4 => [ "CheckNPCFactionAlly", 0 ],
|
||||
5 => [ ":Faction", 0 ],
|
||||
);
|
||||
|
||||
$total_matches = 0;
|
||||
|
||||
use Scalar::Util qw(looks_like_number);
|
||||
|
||||
my @files;
|
||||
my $start_dir = "quests/.";
|
||||
find(
|
||||
sub {push @files, $File::Find::name unless -d;},
|
||||
$start_dir
|
||||
);
|
||||
for my $file (@files) {
|
||||
|
||||
#::: Skip non script files
|
||||
if ($file !~ /lua|pl/i) {
|
||||
next;
|
||||
}
|
||||
|
||||
if ($file =~ /lua|pl/i) {
|
||||
$print_buffer = "";
|
||||
$changes_made = 0;
|
||||
|
||||
#::: Open and read line by line
|
||||
open(FILE, $file);
|
||||
while (<FILE>) {
|
||||
chomp;
|
||||
$line = $_;
|
||||
|
||||
#::: Loop through matches
|
||||
foreach my $key (sort (keys %matches)) {
|
||||
$argument_position = $matches{$key}[1];
|
||||
$match = $matches{$key}[0];
|
||||
|
||||
if ($line =~ /$match\(/i || $line =~ /$match \(/i) {
|
||||
$line_temp = $line;
|
||||
$line_temp =~ s/^.*$match\(//gi;
|
||||
$line_temp =~ s/^.*$match \(//gi;
|
||||
$line_temp =~ s/"//g;
|
||||
$line_temp =~ s/\);.*//;
|
||||
|
||||
@line_data = split(",", $line_temp);
|
||||
|
||||
$faction_value = $line_data[$argument_position];
|
||||
$faction_value_clean = trim($faction_value);
|
||||
|
||||
if (looks_like_number($faction_value_clean)) {
|
||||
$new_faction = get_mysql_result("select clientid from client_server_faction_map where serverid = $faction_value_clean");
|
||||
chomp $new_faction;
|
||||
if ($new_faction == 0) {
|
||||
$new_faction = get_mysql_result("select new_faction from custom_faction_mappings where old_faction = $faction_value_clean");
|
||||
chomp $new_faction;
|
||||
}
|
||||
if ($new_faction > 0) {
|
||||
print "BEFORE: " . $line . "\n";
|
||||
$line =~ s/$faction_value_clean/$new_faction/g;
|
||||
print "AFTER: " . $line . "\n";
|
||||
$changes_made = 1;
|
||||
}
|
||||
else {
|
||||
print "Unknown Faction: '$match' FACTION VALUE: '" . $faction_value_clean . "'\n";
|
||||
}
|
||||
}
|
||||
|
||||
$total_matches++;
|
||||
}
|
||||
}
|
||||
|
||||
$print_buffer .= $line . "\n";
|
||||
}
|
||||
close(FILE);
|
||||
|
||||
#::: Write changes
|
||||
if ($changes_made == 1) {
|
||||
open(NEW_FILE, '>', $file);
|
||||
print NEW_FILE $print_buffer;
|
||||
close NEW_FILE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#::: Mark conversion as ran
|
||||
print get_mysql_result("INSERT INTO `variables` (varname, value, information, ts) VALUES ('new_faction_conversion', 'true', 'Script ran against quests folder to convert new faction values', NOW())");
|
||||
|
||||
print "Total matches: " . $total_matches . "\n";
|
||||
}
|
||||
|
||||
sub fix_quest_factions {
|
||||
# Backup the quests
|
||||
mkdir('backups');
|
||||
my @files;
|
||||
my $start_dir = "quests/";
|
||||
find(
|
||||
sub { push @files, $File::Find::name unless -d; },
|
||||
$start_dir
|
||||
);
|
||||
for my $file (@files) {
|
||||
$destination_file = $file;
|
||||
my $date = strftime "%m-%d-%Y", localtime;
|
||||
$destination_file =~ s/quests/quests-$date/;
|
||||
print "Backing up :: " . $destination_file . "\n";
|
||||
# unlink($destination_file);
|
||||
copy_file($file, 'backups/' . $destination_file);
|
||||
}
|
||||
|
||||
# Fix the factions
|
||||
quest_faction_convert();
|
||||
}
|
||||
|
||||
@@ -390,6 +390,9 @@
|
||||
9134|2019_01_04_update_global_base_scaling.sql|SELECT * FROM db_version WHERE version >= 9134|empty|
|
||||
9135|2019_01_10_multi_version_spawns.sql|SHOW COLUMNS FROM `spawn2` LIKE 'version'|contains|unsigned|
|
||||
9136|2019_02_04_profanity_command.sql|SHOW TABLES LIKE 'profanity_list'|empty|
|
||||
9137|2018_12_12_client_faction_tables.sql|SHOW TABLES LIKE 'faction_base_data'|empty|
|
||||
9138|2018_12_12_convert_to_client_functions.sql|SELECT `id` FROM `faction_list` WHERE `id` > 4999|empty|
|
||||
9139|2019_03_25_optional_npc_model.sql|SHOW COLUMNS FROM `npc_types` LIKE 'model'|empty|
|
||||
|
||||
# Upgrade conditions:
|
||||
# This won't be needed after this system is implemented, but it is used database that are not
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
9019|2018_04_12_bots_stop_melee_level.sql|SHOW COLUMNS FROM `bot_data` LIKE 'stop_melee_level'|empty|
|
||||
9020|2018_08_13_bots_inventory_update.sql|SELECT * FROM `inventory_versions` WHERE `version` = 2 and `bot_step` = 0|not_empty|
|
||||
9021|2018_10_09_bots_owner_options.sql|SHOW TABLES LIKE 'bot_owner_options'|empty|
|
||||
9022|2019_02_07_bots_stance_type_update.sql|SELECT * FROM `bot_spell_casting_chances` WHERE `spell_type_index` = '255' AND `class_id` = '255' AND `stance_index` = '0'|not_empty|
|
||||
|
||||
# Upgrade conditions:
|
||||
# This won't be needed after this system is implemented, but it is used database that are not
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
-- Update `bot_stances`.`stance_id` to new values
|
||||
UPDATE `bot_stances` SET `stance_id` = '9' WHERE `stance_id` = '6';
|
||||
UPDATE `bot_stances` SET `stance_id` = '7' WHERE `stance_id` = '5';
|
||||
UPDATE `bot_stances` SET `stance_id` = (`stance_id` + 1) WHERE `stance_id` in (0,1,2,3,4);
|
||||
|
||||
-- Update `bot_spell_casting_chances`.`stance_index` to new values
|
||||
UPDATE `bot_spell_casting_chances` SET `stance_index` = '8' WHERE `stance_index` = '6';
|
||||
UPDATE `bot_spell_casting_chances` SET `stance_index` = '6' WHERE `stance_index` = '5';
|
||||
|
||||
-- Update `bot_spell_casting_chances` implicit versioning
|
||||
UPDATE `bot_spell_casting_chances` SET `stance_index` = '1' WHERE `spell_type_index` = '255' AND `class_id` = '255';
|
||||
@@ -0,0 +1,53 @@
|
||||
/* Fix any items with faction adjustments */
|
||||
|
||||
SET SQL_MODE='ALLOW_INVALID_DATES'; /* Some dbs have bad dates which prevents the index creation */
|
||||
|
||||
CREATE INDEX itemfac1 ON items (factionmod1);
|
||||
CREATE INDEX itemfac2 ON items (factionmod2);
|
||||
CREATE INDEX itemfac3 ON items (factionmod3);
|
||||
CREATE INDEX itemfac4 ON items (factionmod4);
|
||||
|
||||
UPDATE items i
|
||||
INNER JOIN custom_faction_mappings m ON i.factionmod1 = m.old_faction
|
||||
SET i.factionmod1 = m.new_faction
|
||||
WHERE i.factionmod1 > 0;
|
||||
|
||||
UPDATE items i
|
||||
INNER JOIN custom_faction_mappings m ON i.factionmod2 = m.old_faction
|
||||
SET i.factionmod2 = m.new_faction
|
||||
WHERE i.factionmod2 > 0;
|
||||
|
||||
UPDATE items i
|
||||
INNER JOIN custom_faction_mappings m ON i.factionmod3 = m.old_faction
|
||||
SET i.factionmod3 = m.new_faction
|
||||
WHERE i.factionmod3 > 0;
|
||||
|
||||
UPDATE items i
|
||||
INNER JOIN custom_faction_mappings m ON i.factionmod4 = m.old_faction
|
||||
SET i.factionmod4 = m.new_faction
|
||||
WHERE i.factionmod4 > 0;
|
||||
|
||||
UPDATE items i
|
||||
INNER JOIN client_server_faction_map m ON i.factionmod1 = m.serverid
|
||||
SET i.factionmod1 = m.clientid
|
||||
WHERE i.factionmod1 > 0;
|
||||
|
||||
UPDATE items i
|
||||
INNER JOIN client_server_faction_map m ON i.factionmod2 = m.serverid
|
||||
SET i.factionmod2 = m.clientid
|
||||
WHERE i.factionmod2 > 0;
|
||||
|
||||
UPDATE items i
|
||||
INNER JOIN client_server_faction_map m ON i.factionmod3 = m.serverid
|
||||
SET i.factionmod3 = m.clientid
|
||||
WHERE i.factionmod3 > 0;
|
||||
|
||||
UPDATE items i
|
||||
INNER JOIN client_server_faction_map m ON i.factionmod4 = m.serverid
|
||||
SET i.factionmod4 = m.clientid
|
||||
WHERE i.factionmod4 > 0;
|
||||
|
||||
DROP INDEX itemfac1 ON items;
|
||||
DROP INDEX itemfac2 ON items;
|
||||
DROP INDEX itemfac3 ON items;
|
||||
DROP INDEX itemfac4 ON items;
|
||||
@@ -0,0 +1,11 @@
|
||||
-- Supplied for convenient configuration of faction thresholds to the values that were in place prior to 2019-03-01 update
|
||||
INSERT INTO rule_values VALUES
|
||||
(0, "Faction:AllyFactionMinimum", 1101),
|
||||
(0, "Faction:WarmlyFactionMinimum", 701),
|
||||
(0, "Faction:KindlyFactionMinimu", 401),
|
||||
(0, "Faction:AmiablyFactionMinimum", 101),
|
||||
(0, "Faction:IndifferentlyFactionMinimum", 0)
|
||||
(0, "Faction:ApprehensivelyFactionMinimum", -100)
|
||||
(0, "Faction:DubiouslyFactionMinimum", -700)
|
||||
(0, "Faction:ThreateninglyFactionMinimum", -999)
|
||||
;
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
This SQL update utilizes the new raw faction data from the client
|
||||
|
||||
First we create a temporary table - which we will use to map any
|
||||
custom factions in the eqemu db, that are either:
|
||||
- eqemu utility factions
|
||||
- obsoleted factions with no new mapping to the client
|
||||
|
||||
This is done so that we can keep these factions while server owners either
|
||||
stay with them, or migrate. They are moved to the 5000+ range, to not conflict
|
||||
with client faction_ids.
|
||||
*/
|
||||
|
||||
/* Create the temp table and start mappings at 5000 */
|
||||
CREATE TABLE custom_faction_mappings (old_faction int, new_faction int, primary key (old_faction)) engine=INNODB;
|
||||
|
||||
select "Moving custom factions to safe range, well above known client values" ``;
|
||||
select @startcustom:=5000;
|
||||
|
||||
/* Insert the custom/obsolete factions into the temp mapping table */
|
||||
insert into custom_faction_mappings (select id, @startcustom := @startcustom +1 from faction_list where id not in (select serverid from client_server_faction_map) and id < 5000);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS faction_list_mod_prefix AS SELECT * from faction_list_mod;
|
||||
|
||||
/* Now we update all the tables for these custom factions */
|
||||
|
||||
update faction_list_mod set faction_id = (select new_faction from custom_faction_mappings where old_faction = faction_id) where faction_id < 5000 and faction_id in (select old_faction from custom_faction_mappings);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS faction_list_prefix AS SELECT * from faction_list;
|
||||
|
||||
DROP TABLE faction_list;
|
||||
|
||||
CREATE TABLE `faction_list` (
|
||||
`id` int(11) NOT NULL,
|
||||
`name` varchar(50) NOT NULL DEFAULT '',
|
||||
`base` smallint(6) NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `id` (`id`)
|
||||
) ENGINE=MyISAM AUTO_INCREMENT=486 DEFAULT CHARSET=utf8 as select id, name, base from faction_list_prefix;
|
||||
|
||||
update faction_list set id =
|
||||
(select new_faction from custom_faction_mappings where old_faction = id) where id < 5000 and id in (select old_faction from custom_faction_mappings);
|
||||
|
||||
/* At this point all faction_mods for unmapped factions will be ids 5000+ */
|
||||
/* So we can delete all the old ones still under 5000 - making room for the */
|
||||
/* new faction ids */
|
||||
|
||||
delete from faction_list_mod where faction_id < 5000;
|
||||
|
||||
delete from faction_list where id < 5000;
|
||||
|
||||
/* Make an entry for each faction */
|
||||
/* No base on client factions */
|
||||
|
||||
insert into faction_list (id, name, base) (select id, name, 0 from client_faction_names);
|
||||
|
||||
/* Now restore any base for factions for which the client has no mods (social factions) */
|
||||
|
||||
DROP TABLE IF EXISTS oldbases;
|
||||
|
||||
CREATE TABLE `oldbases` (
|
||||
`id` int(11) DEFAULT 0,
|
||||
`name` varchar(50) NOT NULL DEFAULT '',
|
||||
`base` smallint(6) NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8 as
|
||||
(select m.clientid as id, p.name, p.base from faction_list_prefix p
|
||||
join client_server_faction_map m on m.serverid = p.id where p.base <> 0
|
||||
&& m.clientid in (select id from faction_list where id not in (SELECT faction_id from client_faction_associations group by faction_id)));
|
||||
|
||||
update faction_list f
|
||||
INNER JOIN oldbases o on o.id = f.id
|
||||
set f.base = o.base;
|
||||
|
||||
/* Adjust for the big change in the dubious range */
|
||||
update faction_list set base = base + 200 where base between -900 and -501;
|
||||
|
||||
DROP TABLE IF EXISTS oldbases;
|
||||
|
||||
/* Create mods based on the client_faction_associations */
|
||||
/* No code changes required */
|
||||
|
||||
insert into faction_list_mod
|
||||
(select null, faction_id, `mod`, concat("r", other_faction_id-50)
|
||||
from client_faction_associations a
|
||||
join client_faction_names n on n.id = a.other_faction_id
|
||||
where other_faction_id between 51 and 180);
|
||||
|
||||
insert into faction_list_mod
|
||||
(select null, faction_id, `mod`, concat("c", other_faction_id)
|
||||
from client_faction_associations a
|
||||
join client_faction_names n on n.id = a.other_faction_id
|
||||
where other_faction_id between 1 and 50);
|
||||
|
||||
insert into faction_list_mod
|
||||
(select null, faction_id, `mod`, concat("d", other_faction_id)
|
||||
from client_faction_associations a
|
||||
join client_faction_names n on n.id = a.other_faction_id
|
||||
where other_faction_id between 201 and 216);
|
||||
|
||||
/* And now we need to fix all the other faction tables to point to the new factions. */
|
||||
|
||||
CREATE TABLE IF NOT EXISTS npc_faction_prefix AS SELECT * from npc_faction;
|
||||
|
||||
update npc_faction set primaryfaction = (select new_faction from custom_faction_mappings where old_faction = primaryfaction)
|
||||
where primaryfaction in (select old_faction from custom_faction_mappings);
|
||||
|
||||
update npc_faction set primaryfaction = (select clientid from client_server_faction_map where serverid = primaryfaction)
|
||||
where primaryfaction in (select serverid from client_server_faction_map);
|
||||
|
||||
update npc_faction_entries set faction_id = (select new_faction from custom_faction_mappings where old_faction = faction_id)
|
||||
where faction_id in (select old_faction from custom_faction_mappings);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS npc_faction_entries_prefix AS SELECT * from npc_faction_entries;
|
||||
|
||||
/* Move existing factions out of wat - the following replace would create key */
|
||||
/* duplicates along the way, but none when complete. */
|
||||
|
||||
update npc_faction_entries set faction_id = faction_id + 20000
|
||||
where faction_id in (select serverid from client_server_faction_map);
|
||||
|
||||
update npc_faction_entries set faction_id = (select clientid from client_server_faction_map where faction_id > 20000 && serverid = (faction_id-20000))
|
||||
where faction_id > 20000 && (faction_id-20000) in (select serverid from client_server_faction_map);
|
||||
|
||||
/* Removes any duplicates from the use of factions that are obsoleted */
|
||||
/* These are entries that have no new mapping whatsoever */
|
||||
delete from npc_faction_entries where faction_id > 20000;
|
||||
|
||||
|
||||
/*
|
||||
Update the faction_values now.
|
||||
*/
|
||||
|
||||
CREATE TABLE IF NOT EXISTS faction_values_prefix AS SELECT * from faction_values;
|
||||
|
||||
delete from faction_values
|
||||
where faction_id not in (select old_faction from custom_faction_mappings) and faction_id not in (select serverid from client_server_faction_map);
|
||||
|
||||
/* Custom faction mappings dont have to worry about range collision */
|
||||
|
||||
select "Updating faction_values for custom factions" ``;
|
||||
|
||||
update faction_values set faction_id = (select new_faction from custom_faction_mappings where old_faction = faction_id)
|
||||
where faction_id in (select old_faction from custom_faction_mappings);
|
||||
|
||||
/*
|
||||
There are so many of these, Im going to update in place to save time.
|
||||
To do this we must remove the unique keys, as these will be violated until
|
||||
the update is complete
|
||||
*/
|
||||
|
||||
select "Updating core faction_values to use new faction ids...." ``;
|
||||
|
||||
alter table faction_values drop primary key;
|
||||
|
||||
update faction_values v
|
||||
join client_server_faction_map m on v.faction_id = m.serverid
|
||||
set faction_id = m.clientid;
|
||||
|
||||
ALTER TABLE `faction_values` ADD PRIMARY KEY `lookup` (`char_id`,`faction_id`);
|
||||
|
||||
/*
|
||||
* The following to be deleted in a future update, once everyone is
|
||||
* happy with the conversion
|
||||
|
||||
DROP TABLE IF EXISTS custom_faction_mappings;
|
||||
DROP TABLE IF EXISTS faction_list_mod_prefix;
|
||||
DROP TABLE IF EXISTS faction_list_prefix;
|
||||
DROP TABLE IF EXISTS npc_faction_prefix;
|
||||
DROP TABLE IF EXISTS npc_faction_entries_prefix;
|
||||
DROP TABLE IF EXISTS faction_values_prefix;
|
||||
|
||||
*/
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE `npc_types` ADD COLUMN `model` SMALLINT(5) NOT NULL DEFAULT '0' AFTER `stuck_behavior`;
|
||||
@@ -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)
|
||||
);
|
||||
@@ -23,6 +23,7 @@ data_buckets
|
||||
db_str
|
||||
doors
|
||||
eqtime
|
||||
faction_base_data
|
||||
faction_list
|
||||
faction_list_mod
|
||||
fear_hints
|
||||
|
||||
@@ -15,6 +15,8 @@ SET(world_sources
|
||||
login_server_list.cpp
|
||||
net.cpp
|
||||
queryserv.cpp
|
||||
router.cpp
|
||||
shared_tasks.cpp
|
||||
ucs.cpp
|
||||
web_interface.cpp
|
||||
web_interface_eqw.cpp
|
||||
@@ -42,6 +44,8 @@ SET(world_headers
|
||||
login_server_list.h
|
||||
net.h
|
||||
queryserv.h
|
||||
router.h
|
||||
shared_tasks.h
|
||||
sof_char_create_data.h
|
||||
ucs.h
|
||||
web_interface.h
|
||||
|
||||
@@ -1221,6 +1221,7 @@ void Client::EnterWorld(bool TryBootup) {
|
||||
}
|
||||
|
||||
cle->SetChar(charid, char_name);
|
||||
cle->LoadTaskLockouts();
|
||||
database.UpdateLiveChar(char_name, GetAccountID());
|
||||
|
||||
Log(Logs::General, Logs::World_Server,
|
||||
|
||||
@@ -25,6 +25,9 @@
|
||||
#include "world_config.h"
|
||||
#include "../common/guilds.h"
|
||||
#include "../common/string_util.h"
|
||||
#include "shared_tasks.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
extern uint32 numplayers;
|
||||
extern LoginServerList loginserverlist;
|
||||
@@ -50,6 +53,8 @@ ClientListEntry::ClientListEntry(uint32 in_id, uint32 iLSID, const char* iLoginN
|
||||
pLFGToLevel = 0;
|
||||
pLFGMatchFilter = false;
|
||||
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)
|
||||
@@ -71,6 +76,8 @@ ClientListEntry::ClientListEntry(uint32 in_id, uint32 iAccID, const char* iAccNa
|
||||
pLFGToLevel = 0;
|
||||
pLFGMatchFilter = false;
|
||||
memset(pLFGComments, 0, 64);
|
||||
shared_task_id = 0;
|
||||
m_shared_task = nullptr;
|
||||
}
|
||||
|
||||
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;
|
||||
pLFGMatchFilter = false;
|
||||
memset(pLFGComments, 0, 64);
|
||||
shared_task_id = 0;
|
||||
m_shared_task = nullptr;
|
||||
|
||||
if (iOnline >= CLE_Status_Zoning)
|
||||
Update(iZS, scl, iOnline);
|
||||
@@ -105,6 +114,8 @@ ClientListEntry::~ClientListEntry() {
|
||||
Camp(); // updates zoneserver's numplayers
|
||||
client_list.RemoveCLEReferances(this);
|
||||
}
|
||||
if (m_shared_task != nullptr)
|
||||
m_shared_task->MemberLeftGame(this);
|
||||
for (auto &elem : tell_queue)
|
||||
safe_delete_array(elem);
|
||||
tell_queue.clear();
|
||||
@@ -248,6 +259,8 @@ void ClientListEntry::ClearVars(bool iAll) {
|
||||
pLFG = 0;
|
||||
gm = 0;
|
||||
pClientVersion = 0;
|
||||
shared_task_id = 0;
|
||||
m_shared_task = nullptr;
|
||||
for (auto &elem : tell_queue)
|
||||
safe_delete_array(elem);
|
||||
tell_queue.clear();
|
||||
@@ -261,6 +274,9 @@ void ClientListEntry::Camp(ZoneServer* iZS) {
|
||||
LSUpdate(pzoneserver);
|
||||
}
|
||||
|
||||
if (m_shared_task != nullptr)
|
||||
m_shared_task->MemberLeftGame(this);
|
||||
|
||||
ClearVars();
|
||||
|
||||
stale = 0;
|
||||
@@ -331,3 +347,72 @@ void ClientListEntry::ProcessTellQueue()
|
||||
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/servertalk.h"
|
||||
#include "../common/rulesys.h"
|
||||
#include "../common/global_tasks.h"
|
||||
#include <vector>
|
||||
|
||||
|
||||
@@ -18,6 +19,7 @@
|
||||
|
||||
class ZoneServer;
|
||||
struct ServerClientList_Struct;
|
||||
class SharedTask;
|
||||
|
||||
class ClientListEntry {
|
||||
public:
|
||||
@@ -88,6 +90,17 @@ public:
|
||||
inline void PushToTellQueue(ServerChannelMessage_Struct *scm) { tell_queue.push_back(scm); }
|
||||
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:
|
||||
void ClearVars(bool iAll = false);
|
||||
|
||||
@@ -129,6 +142,13 @@ private:
|
||||
bool pLFGMatchFilter;
|
||||
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
|
||||
std::vector<ServerChannelMessage_Struct *> tell_queue;
|
||||
};
|
||||
|
||||
@@ -72,12 +72,6 @@ void LauncherLink::ProcessMessage(uint16 opcode, EQ::Net::Packet &p)
|
||||
ServerPacket *pack = &tpack;
|
||||
|
||||
switch (opcode) {
|
||||
case 0:
|
||||
break;
|
||||
case ServerOP_KeepAlive: {
|
||||
// ignore this
|
||||
break;
|
||||
}
|
||||
case ServerOP_ZAAuth: {
|
||||
Log(Logs::Detail, Logs::World_Server, "Got authentication from %s when they are already authenticated.", m_name.c_str());
|
||||
break;
|
||||
@@ -296,4 +290,4 @@ void LauncherLink::Shutdown() {
|
||||
auto pack = new ServerPacket(ServerOP_ShutdownAll);
|
||||
SendPacket(pack);
|
||||
delete pack;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,6 +83,8 @@ union semun {
|
||||
#include "queryserv.h"
|
||||
#include "web_interface.h"
|
||||
#include "console.h"
|
||||
#include "shared_tasks.h"
|
||||
#include "router.h"
|
||||
|
||||
#include "../common/net/servertalk_server.h"
|
||||
#include "../zone/data_bucket.h"
|
||||
@@ -103,6 +105,7 @@ bool holdzones = false;
|
||||
const WorldConfig *Config;
|
||||
EQEmuLogSys LogSys;
|
||||
WebInterfaceList web_interface;
|
||||
SharedTaskManager shared_tasks;
|
||||
|
||||
void CatchSignal(int sig_num);
|
||||
void CheckForServerScript(bool force_download = false);
|
||||
@@ -394,6 +397,9 @@ int main(int argc, char** argv) {
|
||||
adventure_manager.Load();
|
||||
adventure_manager.LoadLeaderboardInfo();
|
||||
|
||||
shared_tasks.LoadSharedTasks();
|
||||
shared_tasks.LoadSharedTaskState();
|
||||
|
||||
Log(Logs::General, Logs::World_Server, "Purging expired instances");
|
||||
database.PurgeExpiredInstances();
|
||||
|
||||
@@ -414,6 +420,7 @@ int main(int argc, char** argv) {
|
||||
std::unique_ptr<EQ::Net::ServertalkServer> server_connection;
|
||||
server_connection.reset(new EQ::Net::ServertalkServer());
|
||||
|
||||
Router router;
|
||||
EQ::Net::ServertalkServerOptions server_opts;
|
||||
server_opts.port = Config->WorldTCPPort;
|
||||
server_opts.ipv6 = false;
|
||||
@@ -497,7 +504,26 @@ int main(int argc, char** argv) {
|
||||
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);
|
||||
opts.daybreak_options.resend_delay_ms = RuleI(Network, ResendDelayBaseMS);
|
||||
opts.daybreak_options.resend_delay_factor = RuleR(Network, ResendDelayFactor);
|
||||
opts.daybreak_options.resend_delay_min = RuleI(Network, ResendDelayMinMS);
|
||||
opts.daybreak_options.resend_delay_max = RuleI(Network, ResendDelayMaxMS);
|
||||
|
||||
EQ::Net::EQStreamManager eqsm(opts);
|
||||
|
||||
//register all the patches we have avaliable with the stream identifier.
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
case 0:
|
||||
break;
|
||||
|
||||
case ServerOP_KeepAlive:
|
||||
{
|
||||
// ignore this
|
||||
break;
|
||||
}
|
||||
case ServerOP_ZAAuth:
|
||||
{
|
||||
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));
|
||||
|
||||
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() {
|
||||
@@ -748,9 +747,3 @@ void ZSList::OnTick(EQ::Timer *t)
|
||||
web_interface.SendEvent(out);
|
||||
}
|
||||
|
||||
void ZSList::OnKeepAlive(EQ::Timer *t)
|
||||
{
|
||||
for (auto &zone : list) {
|
||||
zone->SendKeepAlive();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,7 +63,6 @@ public:
|
||||
|
||||
private:
|
||||
void OnTick(EQ::Timer *t);
|
||||
void OnKeepAlive(EQ::Timer *t);
|
||||
uint32 NextID;
|
||||
std::list<std::unique_ptr<ZoneServer>> list;
|
||||
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 "ucs.h"
|
||||
#include "queryserv.h"
|
||||
#include "shared_tasks.h"
|
||||
|
||||
extern ClientList client_list;
|
||||
extern GroupLFPList LFPGroupList;
|
||||
@@ -45,6 +46,7 @@ extern volatile bool UCSServerAvailable_;
|
||||
extern AdventureManager adventure_manager;
|
||||
extern UCSConnection UCSLink;
|
||||
extern QueryServConnection QSLink;
|
||||
extern SharedTaskManager shared_tasks;
|
||||
void CatchSignal(int sig_num);
|
||||
|
||||
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;
|
||||
|
||||
switch (opcode) {
|
||||
case 0:
|
||||
break;
|
||||
case ServerOP_KeepAlive: {
|
||||
// ignore this
|
||||
break;
|
||||
}
|
||||
case ServerOP_ZAAuth: {
|
||||
break;
|
||||
}
|
||||
@@ -1349,6 +1345,16 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
|
||||
cle->ProcessTellQueue();
|
||||
break;
|
||||
}
|
||||
case ServerOP_TaskRequest:
|
||||
{
|
||||
shared_tasks.HandleTaskRequest(pack);
|
||||
break;
|
||||
}
|
||||
case ServerOP_TaskZoneCreated:
|
||||
{
|
||||
shared_tasks.HandleTaskZoneCreated(pack);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
void ZoneServer::SendKeepAlive()
|
||||
{
|
||||
ServerPacket pack(ServerOP_KeepAlive, 0);
|
||||
SendPacket(&pack);
|
||||
}
|
||||
|
||||
void ZoneServer::ChangeWID(uint32 iCharID, uint32 iWID) {
|
||||
auto pack = new ServerPacket(ServerOP_ChangeWID, sizeof(ServerChangeWID_Struct));
|
||||
ServerChangeWID_Struct* scw = (ServerChangeWID_Struct*)pack->pBuffer;
|
||||
|
||||
@@ -39,7 +39,6 @@ public:
|
||||
void SendPacket(ServerPacket* pack) { tcpc->SendPacket(pack); }
|
||||
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 SendKeepAlive();
|
||||
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 Disconnect() { auto handle = tcpc->Handle(); if (handle) { handle->Disconnect(); } }
|
||||
|
||||
+7
-1
@@ -1877,6 +1877,10 @@ bool Client::Death(Mob* killerMob, int32 damage, uint16 spell, EQEmu::skills::Sk
|
||||
if (r)
|
||||
r->MemberZoned(this);
|
||||
|
||||
auto shared_task = GetSharedTask();
|
||||
if (shared_task)
|
||||
shared_task->MemberZoned(this);
|
||||
|
||||
dead_timer.Start(5000, true);
|
||||
m_pp.zone_id = m_pp.binds[0].zoneId;
|
||||
m_pp.zoneInstance = m_pp.binds[0].instance_id;
|
||||
@@ -4514,7 +4518,9 @@ void Mob::ApplyMeleeDamageMods(uint16 skill, int &damage, Mob *defender, ExtraAt
|
||||
if (defender->IsClient() && defender->GetClass() == WARRIOR)
|
||||
dmgbonusmod -= 5;
|
||||
// 168 defensive
|
||||
dmgbonusmod += (defender->spellbonuses.MeleeMitigationEffect + itembonuses.MeleeMitigationEffect + aabonuses.MeleeMitigationEffect);
|
||||
dmgbonusmod += (defender->spellbonuses.MeleeMitigationEffect +
|
||||
defender->itembonuses.MeleeMitigationEffect +
|
||||
defender->aabonuses.MeleeMitigationEffect);
|
||||
}
|
||||
|
||||
damage += damage * dmgbonusmod / 100;
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@
|
||||
|
||||
Aura::Aura(NPCType *type_data, Mob *owner, AuraRecord &record)
|
||||
: NPC(type_data, 0, owner->GetPosition(), GravityBehavior::Flying), spell_id(record.spell_id), distance(record.distance),
|
||||
remove_timer(record.duration), movement_timer(100), process_timer(100), aura_id(-1)
|
||||
remove_timer(record.duration), movement_timer(100), process_timer(1000), aura_id(-1)
|
||||
{
|
||||
GiveNPCTypeData(type_data); // we will delete this later on
|
||||
m_owner = owner->GetID();
|
||||
|
||||
+1
-1
@@ -56,7 +56,7 @@ Beacon::Beacon(Mob *at_mob, int lifetime)
|
||||
:Mob
|
||||
(
|
||||
nullptr, nullptr, 0, 0, 0, INVISIBLE_MAN, 0, BT_NoTarget, 0, 0, 0, 0, 0, at_mob->GetPosition(), 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, EQEmu::TintProfile(), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, EQEmu::TintProfile(), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
),
|
||||
remove_timer(lifetime),
|
||||
spell_timer(0)
|
||||
|
||||
+11
-2
@@ -1472,6 +1472,17 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon)
|
||||
newbon->trap_slots += base1;
|
||||
break;
|
||||
|
||||
case SE_ForageSkill:
|
||||
newbon->GrantForage += base1;
|
||||
// we need to grant a skill point here
|
||||
// I'd rather not do this here, but whatever, probably fine
|
||||
if (IsClient()) {
|
||||
auto client = CastToClient();
|
||||
if (client->GetRawSkill(EQEmu::skills::SkillType::SkillForage) == 0)
|
||||
client->SetSkill(EQEmu::skills::SkillType::SkillForage, 1);
|
||||
}
|
||||
break;
|
||||
|
||||
// to do
|
||||
case SE_PetDiscipline:
|
||||
break;
|
||||
@@ -1479,8 +1490,6 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon)
|
||||
break;
|
||||
case SE_BandolierSlots:
|
||||
break;
|
||||
case SE_ForageSkill:
|
||||
break;
|
||||
case SE_SecondaryForte:
|
||||
break;
|
||||
case SE_ExtendedShielding:
|
||||
|
||||
+26
-23
@@ -163,7 +163,7 @@ Bot::Bot(uint32 botID, uint32 botOwnerCharacterID, uint32 botSpellsID, double to
|
||||
if (!stance_flag && bot_owner)
|
||||
bot_owner->Message(13, "Could not locate stance for '%s'", GetCleanName());
|
||||
|
||||
SetTaunting((GetClass() == WARRIOR || GetClass() == PALADIN || GetClass() == SHADOWKNIGHT) && (GetBotStance() == BotStanceAggressive));
|
||||
SetTaunting((GetClass() == WARRIOR || GetClass() == PALADIN || GetClass() == SHADOWKNIGHT) && (GetBotStance() == EQEmu::constants::stanceAggressive));
|
||||
SetPauseAI(false);
|
||||
|
||||
rest_timer.Disable();
|
||||
@@ -439,6 +439,7 @@ NPCType *Bot::FillNPCTypeStruct(uint32 botSpellsID, std::string botName, std::st
|
||||
bot_npc_type->skip_global_loot = true;
|
||||
//bot_npc_type->rare_spawn = false;
|
||||
bot_npc_type->stuck_behavior = Ground;
|
||||
bot_npc_type->skip_auto_scale = true;
|
||||
|
||||
return bot_npc_type;
|
||||
}
|
||||
@@ -2766,7 +2767,7 @@ void Bot::AI_Process() {
|
||||
// we can't fight if we don't have a target, are stun/mezzed or dead..
|
||||
// Stop attacking if the target is enraged
|
||||
TEST_TARGET();
|
||||
if (GetBotStance() == BotStancePassive || (tar->IsEnraged() && !BehindMob(tar, GetX(), GetY())))
|
||||
if (GetBotStance() == EQEmu::constants::stancePassive || (tar->IsEnraged() && !BehindMob(tar, GetX(), GetY())))
|
||||
return;
|
||||
|
||||
// First, special attack per class (kick, backstab etc..)
|
||||
@@ -2893,7 +2894,7 @@ void Bot::AI_Process() {
|
||||
FaceTarget(GetTarget());
|
||||
|
||||
// This is a mob that is fleeing either because it has been feared or is low on hitpoints
|
||||
if (GetBotStance() != BotStancePassive) {
|
||||
if (GetBotStance() != EQEmu::constants::stancePassive) {
|
||||
AI_PursueCastCheck(); // This appears to always return true..can't trust for success/fail
|
||||
return;
|
||||
}
|
||||
@@ -2901,7 +2902,7 @@ void Bot::AI_Process() {
|
||||
} // end not in combat range
|
||||
|
||||
if (!IsMoving() && !spellend_timer.Enabled()) { // This may actually need work...
|
||||
if (GetBotStance() == BotStancePassive)
|
||||
if (GetBotStance() == EQEmu::constants::stancePassive)
|
||||
return;
|
||||
|
||||
if (GetTarget() && AI_EngagedCastCheck())
|
||||
@@ -2959,7 +2960,7 @@ void Bot::AI_Process() {
|
||||
// Ok to idle
|
||||
if (fm_dist <= GetFollowDistance()) {
|
||||
if (!IsMoving() && AI_think_timer->Check() && !spellend_timer.Enabled()) {
|
||||
if (GetBotStance() != BotStancePassive) {
|
||||
if (GetBotStance() != EQEmu::constants::stancePassive) {
|
||||
if (!AI_IdleCastCheck() && !IsCasting() && GetClass() != BARD)
|
||||
BotMeditate(true);
|
||||
}
|
||||
@@ -3004,7 +3005,7 @@ void Bot::AI_Process() {
|
||||
|
||||
// Basically, bard bots get a chance to cast idle spells while moving
|
||||
if (IsMoving()) {
|
||||
if (GetBotStance() != BotStancePassive) {
|
||||
if (GetBotStance() != EQEmu::constants::stancePassive) {
|
||||
if (GetClass() == BARD && !spellend_timer.Enabled() && AI_think_timer->Check()) {
|
||||
AI_IdleCastCheck();
|
||||
return;
|
||||
@@ -8213,7 +8214,7 @@ bool Bot::CheckLoreConflict(const EQEmu::ItemData* item) {
|
||||
}
|
||||
|
||||
bool EntityList::Bot_AICheckCloseBeneficialSpells(Bot* caster, uint8 iChance, float iRange, uint32 iSpellTypes) {
|
||||
if((iSpellTypes&SpellTypes_Detrimental) != 0) {
|
||||
if((iSpellTypes & SPELL_TYPES_DETRIMENTAL) != 0) {
|
||||
Log(Logs::General, Logs::Error, "Error: detrimental spells requested from AICheckCloseBeneficialSpells!!");
|
||||
return false;
|
||||
}
|
||||
@@ -8268,19 +8269,19 @@ bool EntityList::Bot_AICheckCloseBeneficialSpells(Bot* caster, uint8 iChance, fl
|
||||
Group *g = caster->GetGroup();
|
||||
float hpRatioToHeal = 25.0f;
|
||||
switch(caster->GetBotStance()) {
|
||||
case BotStanceReactive:
|
||||
case BotStanceBalanced:
|
||||
hpRatioToHeal = 50.0f;
|
||||
break;
|
||||
case BotStanceBurn:
|
||||
case BotStanceBurnAE:
|
||||
hpRatioToHeal = 20.0f;
|
||||
break;
|
||||
case BotStanceAggressive:
|
||||
case BotStanceEfficient:
|
||||
default:
|
||||
hpRatioToHeal = 25.0f;
|
||||
break;
|
||||
case EQEmu::constants::stanceReactive:
|
||||
case EQEmu::constants::stanceBalanced:
|
||||
hpRatioToHeal = 50.0f;
|
||||
break;
|
||||
case EQEmu::constants::stanceBurn:
|
||||
case EQEmu::constants::stanceBurnAE:
|
||||
hpRatioToHeal = 20.0f;
|
||||
break;
|
||||
case EQEmu::constants::stanceAggressive:
|
||||
case EQEmu::constants::stanceEfficient:
|
||||
default:
|
||||
hpRatioToHeal = 25.0f;
|
||||
break;
|
||||
}
|
||||
|
||||
if(g) {
|
||||
@@ -8819,11 +8820,11 @@ bool Bot::HasOrMayGetAggro() {
|
||||
}
|
||||
|
||||
void Bot::SetDefaultBotStance() {
|
||||
BotStanceType defaultStance = BotStanceBalanced;
|
||||
EQEmu::constants::StanceType defaultStance = EQEmu::constants::stanceBalanced;
|
||||
if (GetClass() == WARRIOR)
|
||||
defaultStance = BotStanceAggressive;
|
||||
defaultStance = EQEmu::constants::stanceAggressive;
|
||||
|
||||
_baseBotStance = BotStancePassive;
|
||||
_baseBotStance = EQEmu::constants::stancePassive;
|
||||
_botStance = defaultStance;
|
||||
}
|
||||
|
||||
@@ -9096,4 +9097,6 @@ std::string Bot::CreateSayLink(Client* c, const char* message, const char* name)
|
||||
return saylink;
|
||||
}
|
||||
|
||||
uint8 Bot::spell_casting_chances[SPELL_TYPE_COUNT][PLAYER_CLASS_COUNT][EQEmu::constants::STANCE_TYPE_COUNT][cntHSND] = { 0 };
|
||||
|
||||
#endif
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user