Compare commits

..

164 Commits

Author SHA1 Message Date
KimLS b9b2bf0477 Integrating protobuffers 2019-06-13 15:16:12 -07:00
KimLS 0b26c80d8f Merge branch 'shared_tasks' of github.com:EQEmu/Server into shared_tasks_service 2019-06-10 21:53:41 -07:00
KimLS 8497042eef Some changes to routing and boilerplate for task service 2019-06-10 21:51:18 -07:00
Michael Cook (mackal) 1304b9c80f DB scheme changes 2019-06-10 22:40:05 -04:00
KimLS 65c9c86556 Some changes to the tasks service and the general routing strategy 2019-06-10 01:10:28 -07:00
Michael Cook (mackal) ece9251bd6 Merge branch 'master' into shared_tasks 2019-06-10 00:37:57 -04:00
Michael Cook (mackal) 290133803e Add a hard off for NPC scaling for Merc/Bot
They don't need it. We may want to add this to actually be in the DB for
normal NPCs in the future.
2019-06-10 00:36:18 -04:00
Michael Cook (mackal) 4627bfe271 Mercs shouldn't do global loot (I think) 2019-06-10 00:30:04 -04:00
Michael Cook (mackal) 3cbd0fe0f6 Add char_id to SharedTaskMember 2019-06-09 23:10:36 -04:00
Michael Cook (mackal) 8141f831b1 Merge branch 'master' into shared_tasks 2019-06-09 21:42:27 -04:00
KimLS b3a3d9bec5 Shared task service 2019-06-09 18:39:32 -07:00
Uleat c3e10a7409 Merge pull request #853 from dencelle/master
fixed opcode for deleteing a item out of a player's inventory slot
2019-06-09 19:11:06 -04:00
dencelle 65e429a596 fixed opcode for deleteing a item out of a player's inventory slot 2019-06-09 22:36:23 +00:00
Michael Cook (mackal) fa2b5166fb Add in SharedTaskState::MemberZoned hooks
This should be all of them ... at least where raid/group is done ...
2019-06-09 17:59:30 -04:00
Michael Cook (mackal) 8dc25c838b SharedTaskState::MemberZoned find by pointer vale not name 2019-06-09 17:59:20 -04:00
Michael Cook (mackal) 229de34afc Add Client::GetSharedTask 2019-06-09 17:53:45 -04:00
Michael Cook (mackal) 70bdd35b69 Add a Getter for ActiveShareTask 2019-06-09 17:52:11 -04:00
Michael Cook (mackal) e99354223d We need to update the ActiveSharedTask pointer
When we leave, we need to make sure it's managed as well!
2019-06-09 17:51:34 -04:00
Michael Cook (mackal) 8a8e922f46 We need some way to keep track of everyone who needs a lockout
This prevents exploits but is also rather annoying for people who leave
2019-06-09 17:50:33 -04:00
KimLS c1484a698c Comms stuff 2019-06-08 21:49:51 -07:00
Michael Cook (mackal) bd96d676be Work on getting tasks sent to other members
Some stuff just stubbed out for now
2019-06-08 23:43:36 -04:00
Michael Cook (mackal) 2a637a031b Other task stuff in zone is using time not our timer 2019-06-08 23:09:23 -04:00
Michael Cook (mackal) f7c7f5646e Rename PendSharedTask and update comment 2019-06-08 17:38:04 -04:00
Michael Cook (mackal) 577e67f4ee Move stuff around 2019-06-08 17:11:59 -04:00
Michael Cook (mackal) 1084b71d8d Use SQL to fix null 2019-06-08 17:07:41 -04:00
Michael Cook (mackal) 63933f53c8 Merge pull request #851 from fryguy503/lua_stand_crouch
LUA/PERL - IsStanding() and IsCrouching() - Returns as bools
2019-06-08 14:09:44 -04:00
Trust d23a6e646e LUA/PERL - IsStanding() and IsCrouching() - Returns as bools 2019-06-08 04:48:06 +00:00
Michael Cook (mackal) c2ab2a232b Bug fix in SharedTaskManager::LoadSharedTaskState 2019-06-07 01:39:43 -04:00
Michael Cook (mackal) c5f739cbda Add shared_tasks loading in world 2019-06-07 01:16:44 -04:00
Michael Cook (mackal) 385732f403 Remove dead idea in SharedTaskManager::HandleTaskZoneCreated
We'll just load from DB if the task doesn't exist yet
2019-06-03 23:43:11 -04:00
Michael Cook (mackal) b972ec581f Rework accepted_time for shared_tasks 2019-06-02 23:32:53 -04:00
KimLS 32e04cd264 Fix for crash in world from shared tasks 2019-06-02 00:46:11 -07:00
Michael Cook (mackal) b0dff0c006 Some work on world's task activity states 2019-05-30 02:00:29 -04:00
Michael Cook (mackal) c093b3e2ab Stub out some more functions 2019-05-30 01:37:23 -04:00
Uleat 2690e4de4d Redirected bots binaries remote to appveyor artifact repo (thanks Akkadius!) [skip ci] 2019-05-27 20:27:23 -04:00
Chris Miles 1122d29e19 Update system_tables.txt 2019-05-26 03:37:52 -05:00
Michael Cook (mackal) c5bf71f221 The requestor should at least be able to see the new shared task and get
a member list

There are still a few issues that need to be solved this way.
We could try searching for the members in zone (by name ...) or we could
just fire off to world and world will have to send a special full
serialization so the new zone could load the state. Or at this point we
could just assume that we have saved the state to the DB (which hasn't
been coded yet) and any out of zone members will have to depend on
loading it up from the DB.
2019-05-26 00:38:28 -04:00
Michael Cook (mackal) 977c3ca3dc Tweak some stuff in world 2019-05-25 21:52:21 -04:00
Michael Cook (mackal) 408ce4650f Implement ClientListEntry::LoadTaskLockouts 2019-05-22 22:38:07 -04:00
Michael Cook (mackal) bc0f705227 Implement SharedTaskManager::LoadSharedTaskState 2019-05-22 15:30:00 -04:00
Michael Cook (mackal) 5c1ab3b24c Move ClientTaskInformation to global task header 2019-05-21 22:03:08 -04:00
Michael Cook (mackal) 85a858fcd6 More comments [skip ci] 2019-05-21 17:10:29 -04:00
Michael Cook (mackal) 6ab2e46f42 Implement SharedTaskManager::LoadSharedTasks 2019-05-21 17:00:34 -04:00
Michael Cook (mackal) 96acb1e638 Finish SharedTaskManager::HandleTaskRequest
Cleaned up some other functions as well
2019-05-21 00:07:14 -04:00
Michael Cook (mackal) eb98eef1b9 Flush out task verification steps 2019-05-18 23:58:36 -04:00
Michael Cook (mackal) e1bb3301a5 World should verify the full task to simplify things 2019-05-18 17:26:09 -04:00
Michael Cook (mackal) 358ce2ca94 Merge branch 'master' into shared_tasks 2019-05-16 22:21:31 -04:00
Alex ad790ac8ef Merge pull request #840 from noudess/master
Roambox patch for navmesh and large roamboxes in hilly zones
2019-05-02 18:38:00 -07:00
Akkadius d7abf3f26c Change compression level in deflate 2019-05-01 16:23:24 -05:00
Akkadius 6739eea78b Change NPC scaling classification order check 2019-05-01 15:26:16 -05:00
Michael Cook (mackal) 6856d1540b Fix spelling 2019-04-30 17:29:30 -04:00
Michael Cook (mackal) cd1306d52c Some tweaks to next ID logic and comment up a load function 2019-04-30 17:25:20 -04:00
Michael Cook (mackal) 20aa1cbe77 Merge branch 'master' into shared_tasks 2019-04-30 17:13:57 -04:00
Uleat cd3125ced0 Added safety to SuspendMinion spell index dereference 2019-04-28 21:20:52 -04:00
Michael Cook (mackal) dfd9a3c714 Merge branch 'master' into shared_tasks 2019-04-26 17:57:31 -04:00
Uleat 72e0320509 Fix for loginserver crashes 2019-04-25 01:11:56 -04:00
Chris Miles 15ff0bf5c3 Merge pull request #843 from noudess/RandomizeFeatures
Expose RandomizeFeatures which supercedes plugin::RandomFeatures in functionality
2019-04-24 16:53:33 -05:00
Paul Coene a402f01514 Update perl_mob.cpp 2019-04-24 17:26:17 -04:00
Paul Coene dfe4bb5b78 Update lua_mob.cpp 2019-04-24 10:32:09 -04:00
Paul Coene c24bfaf35f Update lua_mob.h 2019-04-24 10:30:24 -04:00
Paul Coene 7dc1e10956 Update perl_mob.cpp 2019-04-24 10:10:48 -04:00
Michael Cook (mackal) 54da27424f Implement Foraging AA
Currently this SPA is only checked for AA bonuses since a non-permanent
bonus doesn't make sense. Plus I'm not sure the client is aware of it in
spells/gear
2019-04-14 00:18:23 -04:00
Michael Cook (mackal) 6e1f317c60 Merge pull request #839 from briankinney/rule-based-faction-thresholds
Rule based faction thresholds
2019-04-13 16:01:29 -04:00
Brian Kinney 3e8ef681a3 Change defaults to the values intended by recent update 2019-04-13 15:04:43 -04:00
Michael Cook (mackal) e009e064f3 Merge pull request #842 from noudess/faction_min_max
Fix the auto-correct mechanism on illegal faction
2019-04-13 12:56:58 -04:00
Michael Cook (mackal) 9654beda9f Merge pull request #841 from noudess/use_model
Fix version to match committed manifest
2019-04-13 12:56:48 -04:00
Paul Coene 3105577c1b Fix the auto-correct mechanism on illegal faction
Auto correct was not using the new client_base_data for min/max.
2019-04-13 12:39:45 -04:00
Paul Coene c06774ca61 Fix version to match committed manifest 2019-04-13 07:22:16 -04:00
Noudess e1e3d99a79 Change range of values to accomodate large roamboxes 2019-04-12 20:13:30 -04:00
Noudess 8942c0ea24 Merge remote-tracking branch 'upstream/master' 2019-04-12 20:11:16 -04:00
Chris Miles 1603ea097f Merge pull request #832 from noudess/master
Added model field to npc_types to allow using a diff graphic without losing race
2019-04-12 18:48:04 -05:00
Paul Coene 0426a15fec Update mob.cpp 2019-04-12 19:34:28 -04:00
Paul Coene 5b374927f2 Update mob.cpp 2019-04-12 19:16:00 -04:00
Noudess d59170f84f Fix some formatting and fix some incorrect constants. 2019-04-12 19:09:47 -04:00
Brian Kinney 8aaf39d2d9 Fix incorrect rule categories in SQL 2019-04-12 15:29:05 -04:00
Brian Kinney 2bb305305a Use rules to configure faction thresholds
Default to legacy values. Updated "accurate" values are available in optional database script
2019-04-12 15:25:32 -04:00
Brian Kinney e8127f4b8a Merge pull request #1 from EQEmu/master
Update from Root Repository
2019-04-12 13:51:51 -04:00
Noudess 762de03be7 Merge 2019-04-12 10:50:11 -04:00
Noudess f18b9c99b5 Merge remote-tracking branch 'upstream/master' 2019-04-12 10:35:10 -04:00
Alex 8f9a859c56 Merge pull request #838 from noudess/roamboxfix
Fix SetCurrentWP to allow negatives
2019-04-11 15:02:19 -07:00
Paul Coene 5e008a5a97 Fix SetCurrentWP to allow negatives
Needed to make new roambox constants (that were used instead of 666) actually work.
2019-04-03 15:56:12 -04:00
Michael Cook (mackal) fa2052236c Update some spell immune message colors Fixes #833
Should probably go and do some captures on live, but MQ2Cast's source is
probably correct
2019-03-27 18:20:39 -04:00
Michael Cook (mackal) c04bf79b0f Merge branch 'master' into shared_tasks 2019-03-25 19:42:52 -04:00
Noudess f75c5b6fc8 Fix db version. 2019-03-25 19:32:46 -04:00
Noudess 63045fadd9 Manifest and sql to add model to npc_types to override race if presentwq 2019-03-25 19:29:57 -04:00
Akkadius 850b32f2ca Adjust constants 2019-03-25 18:24:16 -05:00
Noudess 60d5c11c43 Added a use_model field to npc_types to override race-graphics, maintain race. 2019-03-25 19:21:33 -04:00
Chris Miles 03458b88a4 Merge pull request #831 from noudess/master
Fix issue with roambox wait time after switch to new movement code.
2019-03-25 18:12:05 -05:00
Noudess 0852468b88 Add constants for waypoints 2019-03-25 17:54:17 -04:00
Noudess 3d1dda888d Use constants for waypoint values that are not actual waypoints 2019-03-25 14:58:26 -04:00
Noudess a4c171cb1d Fix issue with roambox wait time after switch to navmesh. 2019-03-15 10:28:23 -04:00
Michael Cook (mackal) 20de6acfea Merge pull request #829 from noudess/master
Fix Spin() to use old mechanism so the npc actually spins again.
2019-03-14 12:56:44 -04:00
Michael Cook (mackal) 9c42f28b0d Make Database::CheckStatus() 2038 safe 2019-03-12 14:31:23 -04:00
Noudess 75d3329d37 Fix Spin() to use old mechanism so the npc actually spins again. 2019-03-11 18:24:02 -04:00
Chris Miles 26a95998da Merge pull request #828 from noudess/master
Fix issue with perl script not updating itself correctly
2019-03-11 12:46:26 -07:00
Noudess 6715977a1f Change the system call to an exec. Fix the misnamed argument. 2019-03-11 13:15:55 -04:00
JJ fd990136f7 Fix note in SQL. [skip ci] 2019-03-07 17:46:34 -05:00
Chris Miles 3db3e53f11 Merge pull request #802 from noudess/master
New min/max personal faction per faction.  Use of actual client mods for race/class/deity
2019-03-06 13:17:34 -08:00
Noudess ca4e23695d I hate tabs vs spaces 2019-03-06 16:13:28 -05:00
Noudess 293a18301d More format 2019-03-06 16:10:23 -05:00
Noudess 3eb80e3111 Fixed a line of mixed spaces and tabsy 2019-03-06 15:59:51 -05:00
Noudess 4a0126eec3 Fix some formatting issues. 2019-03-06 15:54:22 -05:00
Akkadius 98e6fcf21c Add individual export options to export_client_files 2019-03-05 02:34:10 -06:00
Noudess ce2e74c9a6 Moved item conversion to optional dir. PEQDB has client values already in items 2019-03-04 14:41:17 -05:00
Noudess 2eb884e9b0 Added code to convert item factions as well 2019-03-04 11:30:55 -05:00
Noudess 84f288d572 Added faction info to changelog.txt 2019-03-01 10:26:00 -05:00
Noudess 88b3d11167 Added code to adjust custom faction bases down due to change in dubious range. 2019-03-01 10:12:21 -05:00
Noudess 96089e1718 Merge branch 'master' of github.com:noudess/Server 2019-02-28 16:11:21 -05:00
Noudess f89a0297b4 Fix so quests are backed up and fixed after faction update (version was wrong) 2019-02-28 16:07:52 -05:00
Paul Coene 6dbd579f4f Merge branch 'master' into master 2019-02-28 15:05:18 -05:00
Noudess aa9611d494 Code added to auto fix quests. Updated manifest and version to current. 2019-02-28 15:01:39 -05:00
Noudess 380e5d5084 Added code for conversion of quests for factions (based on Akkas start)
Made sure a temporary table needed for quest conversion was not removed prior.
2019-02-28 12:00:41 -05:00
Akkadius 726a996a25 Update process timer to be less aggressive 2019-02-27 14:10:22 -06:00
KimLS cb9f0fbe31 Start of a network options interface command 2019-02-24 19:24:10 -08:00
KimLS b156b078ed Revert internal send to old code 2019-02-24 15:20:01 -08:00
Akkadius 37915f5b7e Adjust default rule values 2019-02-17 03:29:23 -06:00
Akkadius 3a8f206841 Merge branch 'master' into resend 2019-02-17 03:25:55 -06:00
Uleat 2af4d3d67d Reworked command and quest api 'traindisc' methods 2019-02-13 07:55:04 -05:00
Uleat 43a488d5b5 Added type conversion to questmgr 'scribespells' 2019-02-11 21:46:20 -05:00
Uleat 0b4dcb4271 Reworked command and quest api 'scribespells' methods 2019-02-11 20:03:02 -05:00
Noudess abf39c4ff7 Added base values for factions that the client does not provide a base, nor mods for, yet we did. 2019-02-11 11:59:55 -05:00
Uleat 3bdd6c20a5 Bot definition clean-up 2019-02-09 06:38:26 -05:00
Uleat bef849b5c1 Definition clean-up 2019-02-09 05:58:49 -05:00
Uleat 146e28f708 Updater criteria fix [ci skip] 2019-02-07 22:13:58 -05:00
Uleat f84fed7335 Merge branch 'master' of https://github.com/EQEmu/Server 2019-02-07 22:09:41 -05:00
Uleat 3cffe5f7ef Put merc and bot classes on the same stance standard (mercs) 2019-02-07 22:09:31 -05:00
Noudess ad97968d5e Fixes for bug wherein illusions other than PC races could be exploited.
Fixed for areas that neglected to take into account alliance and item faction
bonuses.
2019-02-07 14:48:31 -05:00
Michael Cook (mackal) c8b7b3e74f Merge pull request #824 from briankinney/correctly-reference-defender-mitigation
Reference the defender melee mitigation, not attacker
2019-02-06 23:58:27 -05:00
Brian Kinney 1d0b00caf7 Raw numbers are negative so adding is correct 2019-02-06 23:54:38 -05:00
Brian Kinney 93394e0edc Reference the defender melee mitigation, not attacker 2019-02-06 21:52:59 -05:00
Akkadius 230d6ae964 Merge branch 'master' into resend 2019-01-23 19:05:42 -06:00
Noudess 46ead8e29e Move out faction changes to later db version as it is still pending. 2019-01-23 14:54:16 -05:00
KimLS e3d5200310 Redid background task interface, used it to async send client packets 2019-01-07 19:53:23 -08:00
Noudess 5474661e11 Updated manifest to remove extra space, removed comments from sql dumpw 2019-01-05 13:00:33 -05:00
Noudess d7e98bba17 Remove comments. 2019-01-05 12:59:47 -05:00
Noudess ca6bcdb1f9 Updates to match up with db versions that have chwqanges since PR created. 2019-01-05 12:46:52 -05:00
Noudess bd47e2121f Reconstruct faction_list to get rid of obsolete fields. 2019-01-05 12:17:10 -05:00
Noudess 90b46c7bda Change backup table names per Akka
Add commented out secion illustrating what next manifgest might do for
cleanup.
2019-01-05 12:01:40 -05:00
Noudess 4b21f901b9 Performance changes. Now tested on rolath, peq and EZ servers 2019-01-04 13:11:28 -05:00
KimLS 6c1e3ae3d6 Added some rules for network server startup, added a limit on number of resends per connection channel per cycle (default is 10) 2019-01-03 20:04:09 -08:00
KimLS 3cb548f72e Merge branch 'master' into resend 2019-01-03 18:33:55 -08:00
Noudess 37ed923302 Fixed code on insert to not worried about extra fields in target db 2019-01-03 16:42:58 -05:00
KimLS d20ea3852c Some changes to resend logic and default values 2019-01-02 20:57:40 -08:00
Noudess f3608edd62 Merge branch 'master' of github.com:noudess/Server 2018-12-18 11:37:28 -05:00
Noudess b5cc006e46 Update version of db needed for code. 2018-12-18 11:35:15 -05:00
Paul Coene e71eefab50 Merge branch 'master' into master 2018-12-18 11:33:52 -05:00
Noudess 469224cfe7 Update manifest versions 2018-12-18 11:24:10 -05:00
Noudess 3b21d2eb26 Spacing where some spaces crept in. 2018-12-18 11:11:22 -05:00
Noudess 3487086d46 Update version of db needed for faction changes 2018-12-18 11:08:09 -05:00
Noudess 50997ad0ec New sql with new client data tables and a hand create mapping 2018-12-18 11:00:38 -05:00
Noudess 688e37f108 Changes to accomodate the new raw faction data. 2018-12-18 10:58:01 -05:00
Michael Cook (mackal) 7286e6a37f Merge branch 'master' into shared_tasks 2018-12-16 14:46:35 -05:00
Michael Cook (mackal) a244cec9e8 Merge branch 'master' into shared_tasks 2018-10-22 20:29:02 -04:00
Michael Cook (mackal) 7062e2703b Merge branch 'master' into shared_tasks 2018-10-11 20:24:26 -04:00
Michael Cook (mackal) 5f53856fd4 Merge branch 'master' into shared_tasks 2018-10-09 14:22:20 -04:00
Michael Cook (mackal) 17d63bc3f6 Merge branch 'master' into shared_tasks 2018-10-08 12:58:25 -04:00
Michael Cook (mackal) 47fda0f747 Merge branch 'master' into shared_tasks 2018-09-26 23:24:27 -04:00
Michael Cook (mackal) e2c15dbc9e Merge branch 'master' into shared_tasks 2018-09-12 13:34:16 -04:00
Michael Cook (mackal) c089296538 Merge branch 'master' into shared_tasks 2018-09-08 00:25:31 -04:00
Michael Cook (mackal) 94f09e5287 Merge branch 'master' into shared_tasks 2018-09-07 20:18:22 -04:00
Michael Cook (mackal) 93133c289e More shared tasks stuff
Mostly just OOZ checking
2018-09-05 16:04:49 -04:00
Michael Cook (mackal) 8934235030 Merge branch 'master' into shared_tasks 2018-09-03 12:58:47 -04:00
Michael Cook (mackal) ea0a54ed60 More work on shared tasks 2018-09-02 23:14:15 -04:00
Michael Cook (mackal) 39544b4723 Shared Task WIP 2018-09-01 17:32:13 -04:00
147 changed files with 4733 additions and 1791 deletions
+12 -2
View File
@@ -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
View File
@@ -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')
+23
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+34
View File
@@ -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;
}
+26
View File
@@ -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*/
+2
View File
@@ -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),
+9
View File
@@ -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;
+3
View File
@@ -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_*/
+4
View File
@@ -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));
+2
View File
@@ -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.
-42
View File
@@ -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() {
}
};
}
View File
+100
View File
@@ -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
View File
@@ -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
View File
@@ -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];
};
+170
View File
@@ -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 */
+37 -26
View File
@@ -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++;
+13 -5
View File
@@ -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();
+5 -1
View File
@@ -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;
};
}
}
}
+23
View File
@@ -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
View File
@@ -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;
};
}
}
}
+1 -146
View File
@@ -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);
+3 -15
View File
@@ -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);
+28 -5
View File
@@ -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) {
+10 -13
View File
@@ -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;
+1 -149
View File
@@ -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) {
+1 -14
View File
@@ -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
};
}
}
+18
View File
@@ -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;
}
+19
View File
@@ -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
+1
View File
@@ -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
View File
@@ -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()
+75
View File
@@ -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;
}
+43
View File
@@ -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
View File
@@ -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
View File
@@ -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
+75
View File
@@ -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);
}
}
+48
View File
@@ -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);
};
}
+7 -19
View File
@@ -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);
}
}
+4 -9
View File
@@ -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;
+3 -1
View File
@@ -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;
}
}
}
+1 -1
View File
@@ -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)
+2 -3
View File
@@ -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();
+3 -34
View File
@@ -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
View File
@@ -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:
+19
View File
@@ -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)
+17
View File
@@ -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() {
}
+12
View File
@@ -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();
};
+70
View File
@@ -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);
+23
View File
@@ -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;
};
}
+17
View File
@@ -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)
+61
View File
@@ -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);
+19
View File
@@ -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);
};
}
+17
View File
@@ -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)
+40
View File
@@ -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);
+23
View File
@@ -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;
};
}
+5
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
+2
View File
@@ -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
+2
View File
@@ -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
+2
View File
@@ -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
+3 -1
View File
@@ -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 #
+3 -1
View File
@@ -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)
+2
View File
@@ -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
+139 -4
View File
@@ -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();
}
+3
View File
@@ -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`;
+50
View File
@@ -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)
);
+1
View File
@@ -23,6 +23,7 @@ data_buckets
db_str
doors
eqtime
faction_base_data
faction_list
faction_list_mod
fear_hints
+4
View File
@@ -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
+1
View File
@@ -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,
+85
View File
@@ -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;
}
+20
View File
@@ -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;
};
+1 -7
View File
@@ -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;
}
}
+26
View File
@@ -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.
+73
View File
@@ -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);
}
}
}
+19
View File
@@ -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);
};
+535
View File
@@ -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;
}
+117
View File
@@ -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 */
-8
View File
@@ -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.");
-7
View File
@@ -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();
}
}
-1
View File
@@ -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
View File
@@ -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;
-1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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