mirror of
https://github.com/EQEmu/Server.git
synced 2026-05-28 01:26:01 +00:00
Compare commits
109 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b9b2bf0477 | |||
| 0b26c80d8f | |||
| 8497042eef | |||
| 1304b9c80f | |||
| 65c9c86556 | |||
| ece9251bd6 | |||
| 290133803e | |||
| 4627bfe271 | |||
| 3cbd0fe0f6 | |||
| 8141f831b1 | |||
| b3a3d9bec5 | |||
| c3e10a7409 | |||
| 65e429a596 | |||
| fa2b5166fb | |||
| 8dc25c838b | |||
| 229de34afc | |||
| 70bdd35b69 | |||
| e99354223d | |||
| 8a8e922f46 | |||
| c1484a698c | |||
| bd96d676be | |||
| 2a637a031b | |||
| f7c7f5646e | |||
| 577e67f4ee | |||
| 1084b71d8d | |||
| 63933f53c8 | |||
| d23a6e646e | |||
| c2ab2a232b | |||
| c5f739cbda | |||
| 385732f403 | |||
| b972ec581f | |||
| 32e04cd264 | |||
| b0dff0c006 | |||
| c093b3e2ab | |||
| 2690e4de4d | |||
| 1122d29e19 | |||
| c5bf71f221 | |||
| 977c3ca3dc | |||
| 408ce4650f | |||
| bc0f705227 | |||
| 5c1ab3b24c | |||
| 85a858fcd6 | |||
| 6ab2e46f42 | |||
| 96acb1e638 | |||
| eb98eef1b9 | |||
| e1bb3301a5 | |||
| 358ce2ca94 | |||
| ad790ac8ef | |||
| d7abf3f26c | |||
| 6739eea78b | |||
| 6856d1540b | |||
| cd1306d52c | |||
| 20aa1cbe77 | |||
| cd3125ced0 | |||
| dfd9a3c714 | |||
| 72e0320509 | |||
| 15ff0bf5c3 | |||
| a402f01514 | |||
| dfe4bb5b78 | |||
| c24bfaf35f | |||
| 7dc1e10956 | |||
| 54da27424f | |||
| 6e1f317c60 | |||
| 3e8ef681a3 | |||
| e009e064f3 | |||
| 9654beda9f | |||
| 3105577c1b | |||
| c06774ca61 | |||
| e1e3d99a79 | |||
| 8942c0ea24 | |||
| 1603ea097f | |||
| 0426a15fec | |||
| 5b374927f2 | |||
| d59170f84f | |||
| 8aaf39d2d9 | |||
| 2bb305305a | |||
| e8127f4b8a | |||
| 762de03be7 | |||
| f18b9c99b5 | |||
| 8f9a859c56 | |||
| 5e008a5a97 | |||
| fa2052236c | |||
| c04bf79b0f | |||
| f75c5b6fc8 | |||
| 63045fadd9 | |||
| 850b32f2ca | |||
| 60d5c11c43 | |||
| 03458b88a4 | |||
| 0852468b88 | |||
| 3d1dda888d | |||
| a4c171cb1d | |||
| 20de6acfea | |||
| 9c42f28b0d | |||
| 75d3329d37 | |||
| 26a95998da | |||
| 6715977a1f | |||
| 7286e6a37f | |||
| a244cec9e8 | |||
| 7062e2703b | |||
| 5f53856fd4 | |||
| 17d63bc3f6 | |||
| 47fda0f747 | |||
| e2c15dbc9e | |||
| c089296538 | |||
| 94f09e5287 | |||
| 93133c289e | |||
| 8934235030 | |||
| ea0a54ed60 | |||
| 39544b4723 |
+12
-2
@@ -292,16 +292,17 @@ ADD_DEFINITIONS(-DGLM_ENABLE_EXPERIMENTAL)
|
||||
#Find everything we need
|
||||
FIND_PACKAGE(ZLIB REQUIRED)
|
||||
FIND_PACKAGE(MySQL REQUIRED)
|
||||
FIND_PACKAGE(Protobuf REQUIRED)
|
||||
IF(EQEMU_BUILD_PERL)
|
||||
FIND_PACKAGE(PerlLibs REQUIRED)
|
||||
INCLUDE_DIRECTORIES(SYSTEM "${PERL_INCLUDE_PATH}")
|
||||
ENDIF(EQEMU_BUILD_PERL)
|
||||
|
||||
SET(SERVER_LIBS common debug ${MySQL_LIBRARY_DEBUG} optimized ${MySQL_LIBRARY_RELEASE} ${ZLIB_LIBRARY} libuv fmt recast_navigation)
|
||||
SET(SERVER_LIBS common debug ${MySQL_LIBRARY_DEBUG} optimized ${MySQL_LIBRARY_RELEASE} ${ZLIB_LIBRARY} protobuf::libprotoc protobuf::libprotobuf libuv fmt recast_navigation)
|
||||
|
||||
FIND_PACKAGE(Sodium REQUIRED)
|
||||
IF(SODIUM_FOUND)
|
||||
OPTION(EQEMU_ENABLE_SECURITY "Use Encryption For TCP Connections" ON)
|
||||
OPTION(EQEMU_ENABLE_SECURITY "Use Secure Loginserver Hashes" ON)
|
||||
IF(EQEMU_ENABLE_SECURITY)
|
||||
INCLUDE_DIRECTORIES(SYSTEM "${SODIUM_INCLUDE_DIRS}")
|
||||
ADD_DEFINITIONS(-DENABLE_SECURITY)
|
||||
@@ -340,6 +341,7 @@ ENDIF(EQEMU_BUILD_LUA)
|
||||
|
||||
INCLUDE_DIRECTORIES(SYSTEM "${ZLIB_INCLUDE_DIRS}")
|
||||
INCLUDE_DIRECTORIES(SYSTEM "${MySQL_INCLUDE_DIR}")
|
||||
INCLUDE_DIRECTORIES(SYSTEM "${Protobuf_INCLUDE_DIRS}")
|
||||
INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/common/glm")
|
||||
INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/libs/cereal")
|
||||
INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/libs/libuv/include" )
|
||||
@@ -347,6 +349,13 @@ INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/libs/libuv/src")
|
||||
INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/libs/format")
|
||||
INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/libs/recast/detour/include")
|
||||
INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/libs/recast/recast/include")
|
||||
INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_BINARY_DIR}/common")
|
||||
|
||||
IF(VCPKG_TARGET_TRIPLET)
|
||||
MESSAGE(STATUS "Vcpkg Detected")
|
||||
MESSAGE(STATUS "Setting protobuf import dir: ${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/include")
|
||||
SET(Protobuf_IMPORT_DIRS "${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/include")
|
||||
ENDIF()
|
||||
|
||||
IF(EQEMU_BUILD_SERVER OR EQEMU_BUILD_LOGIN OR EQEMU_BUILD_TESTS OR EQEMU_BUILD_HC)
|
||||
ADD_SUBDIRECTORY(common)
|
||||
@@ -359,6 +368,7 @@ IF(EQEMU_BUILD_SERVER)
|
||||
ADD_SUBDIRECTORY(ucs)
|
||||
ADD_SUBDIRECTORY(queryserv)
|
||||
ADD_SUBDIRECTORY(eqlaunch)
|
||||
ADD_SUBDIRECTORY(services/tasks)
|
||||
ENDIF(EQEMU_BUILD_SERVER)
|
||||
IF(EQEMU_BUILD_LOGIN)
|
||||
ADD_SUBDIRECTORY(loginserver)
|
||||
|
||||
+12
-2
@@ -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,8 +73,8 @@ SET(common_sources
|
||||
textures.cpp
|
||||
timer.cpp
|
||||
unix.cpp
|
||||
world_connection.cpp
|
||||
xml_parser.cpp
|
||||
platform.cpp
|
||||
json/jsoncpp.cpp
|
||||
net/console_server.cpp
|
||||
net/console_server_connection.cpp
|
||||
@@ -151,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
|
||||
@@ -195,6 +198,7 @@ SET(common_headers
|
||||
serialize_buffer.h
|
||||
serverinfo.h
|
||||
servertalk.h
|
||||
service.h
|
||||
shareddb.h
|
||||
skills.h
|
||||
spdat.h
|
||||
@@ -206,6 +210,7 @@ SET(common_headers
|
||||
unix.h
|
||||
useperl.h
|
||||
version.h
|
||||
world_connection.h
|
||||
xml_parser.h
|
||||
zone_numbers.h
|
||||
event/event_loop.h
|
||||
@@ -378,7 +383,12 @@ SOURCE_GROUP(Util FILES
|
||||
|
||||
INCLUDE_DIRECTORIES(Patches SocketLib StackWalker TinyXML)
|
||||
|
||||
ADD_LIBRARY(common ${common_sources} ${common_headers})
|
||||
protobuf_generate_cpp(PROTO_TASK_SRCS PROTO_TASK_HDRS "${CMAKE_CURRENT_SOURCE_DIR}/proto/task.proto")
|
||||
|
||||
ADD_LIBRARY(common
|
||||
${common_sources} ${common_headers}
|
||||
${PROTO_TASK_SRCS} ${PROTO_TASK_HDRS}
|
||||
)
|
||||
|
||||
IF(UNIX)
|
||||
SET_SOURCE_FILES_PROPERTIES("SocketLib/Mime.cpp" PROPERTY COMPILE_FLAGS -Wno-unused-result)
|
||||
|
||||
+13
-16
@@ -171,30 +171,27 @@ void Database::LoginIP(uint32 AccountID, const char* LoginIP) {
|
||||
QueryDatabase(query);
|
||||
}
|
||||
|
||||
int16 Database::CheckStatus(uint32 account_id) {
|
||||
std::string query = StringFormat("SELECT `status`, UNIX_TIMESTAMP(`suspendeduntil`) as `suspendeduntil`, UNIX_TIMESTAMP() as `current`"
|
||||
" FROM `account` WHERE `id` = %i", account_id);
|
||||
int16 Database::CheckStatus(uint32 account_id)
|
||||
{
|
||||
std::string query = StringFormat(
|
||||
"SELECT `status`, TIMESTAMPDIFF(SECOND, NOW(), `suspendeduntil`) FROM `account` WHERE `id` = %i",
|
||||
account_id);
|
||||
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (results.RowCount() != 1)
|
||||
return 0;
|
||||
|
||||
auto row = results.begin();
|
||||
int16 status = atoi(row[0]);
|
||||
int32 suspendeduntil = 0;
|
||||
|
||||
// MariaDB initalizes with NULL if unix_timestamp() is out of range
|
||||
if (row[1] != nullptr) {
|
||||
suspendeduntil = atoi(row[1]);
|
||||
}
|
||||
auto row = results.begin();
|
||||
int16 status = atoi(row[0]);
|
||||
int32 date_diff = 0;
|
||||
|
||||
int32 current = atoi(row[2]);
|
||||
if (row[1] != nullptr)
|
||||
date_diff = atoi(row[1]);
|
||||
|
||||
if(suspendeduntil > current)
|
||||
if (date_diff > 0)
|
||||
return -1;
|
||||
|
||||
return status;
|
||||
|
||||
@@ -307,6 +307,12 @@ namespace EQEmu
|
||||
|
||||
} // namespace bug
|
||||
|
||||
enum WaypointStatus : int {
|
||||
RoamBoxPauseInProgress = -3,
|
||||
QuestControlNoGrid = -2,
|
||||
QuestControlGrid = -1
|
||||
};
|
||||
|
||||
} /*EQEmu*/
|
||||
|
||||
#endif /*COMMON_EMU_CONSTANTS_H*/
|
||||
|
||||
@@ -6,6 +6,7 @@ N(OP_0x0347),
|
||||
N(OP_AAAction),
|
||||
N(OP_AAExpUpdate),
|
||||
N(OP_AcceptNewTask),
|
||||
N(OP_AcceptNewSharedTask),
|
||||
N(OP_AckPacket),
|
||||
N(OP_Action),
|
||||
N(OP_Action2),
|
||||
@@ -461,6 +462,7 @@ N(OP_SetServerFilter),
|
||||
N(OP_SetStartCity),
|
||||
N(OP_SetTitle),
|
||||
N(OP_SetTitleReply),
|
||||
N(OP_SharedTaskMemberList),
|
||||
N(OP_Shielding),
|
||||
N(OP_ShopDelItem),
|
||||
N(OP_ShopEnd),
|
||||
|
||||
@@ -3698,6 +3698,7 @@ struct TaskMemberList_Struct {
|
||||
/*12*/ char list_pointer[0];
|
||||
/* list is of the form:
|
||||
char member_name[1] //null terminated string
|
||||
uint32 monster_mission; // class chosen
|
||||
uint8 task_leader //boolean flag
|
||||
*/
|
||||
};
|
||||
@@ -3799,6 +3800,14 @@ struct AcceptNewTask_Struct {
|
||||
uint32 task_master_id; //entity ID
|
||||
};
|
||||
|
||||
struct AcceptNewSharedTask_Struct {
|
||||
uint32 unknown00;
|
||||
uint32 unknown04;
|
||||
uint32 task_master_id;
|
||||
uint32 task_id;
|
||||
float unknown16;
|
||||
};
|
||||
|
||||
//was all 0's from client, server replied with same op, all 0's
|
||||
struct CancelTask_Struct {
|
||||
uint32 SequenceNumber;
|
||||
|
||||
+10
-12
@@ -18,6 +18,7 @@
|
||||
|
||||
#include "faction.h"
|
||||
#include "races.h"
|
||||
#include "rulesys.h"
|
||||
|
||||
const char *FactionValueToString(FACTION_VALUE fv)
|
||||
{
|
||||
@@ -59,34 +60,31 @@ FACTION_VALUE CalculateFaction(FactionMods* fm, int32 tmpCharacter_value)
|
||||
if (fm) {
|
||||
character_value += fm->base + fm->class_mod + fm->race_mod + fm->deity_mod;
|
||||
}
|
||||
if (character_value >= 1100) {
|
||||
if (character_value >= RuleI(Faction, AllyFactionMinimum)) {
|
||||
return FACTION_ALLY;
|
||||
}
|
||||
if (character_value >= 750 && character_value <= 1099) {
|
||||
if (character_value >= RuleI(Faction, WarmlyFactionMinimum)) {
|
||||
return FACTION_WARMLY;
|
||||
}
|
||||
if (character_value >= 500 && character_value <= 749) {
|
||||
if (character_value >= RuleI(Faction, KindlyFactionMinimum)) {
|
||||
return FACTION_KINDLY;
|
||||
}
|
||||
if (character_value >= 100 && character_value <= 499) {
|
||||
if (character_value >= RuleI(Faction, AmiablyFactionMinimum)) {
|
||||
return FACTION_AMIABLE;
|
||||
}
|
||||
if (character_value >= 0 && character_value <= 99) {
|
||||
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 >= -500 && character_value <= -101) {
|
||||
if (character_value >= RuleI(Faction, DubiouslyFactionMinimum)) {
|
||||
return FACTION_DUBIOUS;
|
||||
}
|
||||
if (character_value >= -750 && character_value <= -501) {
|
||||
if (character_value >= RuleI(Faction, ThreateninglyFactionMinimum)) {
|
||||
return FACTION_THREATENLY;
|
||||
}
|
||||
if (character_value <= -751) {
|
||||
return FACTION_SCOWLS;
|
||||
}
|
||||
return FACTION_INDIFFERENT;
|
||||
return FACTION_SCOWLS;
|
||||
}
|
||||
|
||||
// this function should check if some races have more than one race define
|
||||
|
||||
@@ -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 */
|
||||
@@ -942,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;
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "endian.h"
|
||||
#include <fmt/format.h>
|
||||
#include <cctype>
|
||||
#include <google/protobuf/message.h>
|
||||
|
||||
void EQ::Net::Packet::PutInt8(size_t offset, int8_t value)
|
||||
{
|
||||
@@ -167,6 +168,23 @@ void EQ::Net::Packet::PutData(size_t offset, void *data, size_t length)
|
||||
memcpy(((char*)Data() + offset), data, length);
|
||||
}
|
||||
|
||||
void EQ::Net::Packet::PutProtobuf(size_t offset, const google::protobuf::Message *msg)
|
||||
{
|
||||
auto length = msg->ByteSizeLong();
|
||||
|
||||
if (length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Length() < offset + length) {
|
||||
if (!Resize(offset + length)) {
|
||||
throw std::out_of_range("Packet::PutProtobuf(), could not resize packet and would of written past the end.");
|
||||
}
|
||||
}
|
||||
|
||||
msg->SerializeToArray((void*)((char*)Data() + offset), (int)length);
|
||||
}
|
||||
|
||||
int8_t EQ::Net::Packet::GetInt8(size_t offset) const
|
||||
{
|
||||
if (Length() < offset + 1) {
|
||||
@@ -276,6 +294,11 @@ std::string EQ::Net::Packet::GetCString(size_t offset) const
|
||||
return std::string(str);
|
||||
}
|
||||
|
||||
EQ::Net::StaticPacket EQ::Net::Packet::GetPacket(size_t offset, size_t length) const
|
||||
{
|
||||
return EQ::Net::StaticPacket((char*)Data() + offset, length);
|
||||
}
|
||||
|
||||
char ToSafePrint(unsigned char in) {
|
||||
if (std::isprint(in)) {
|
||||
return in;
|
||||
|
||||
+13
-1
@@ -8,8 +8,17 @@
|
||||
#include <cereal/cereal.hpp>
|
||||
#include <cereal/archives/binary.hpp>
|
||||
|
||||
namespace google
|
||||
{
|
||||
namespace protobuf
|
||||
{
|
||||
class Message;
|
||||
}
|
||||
}
|
||||
|
||||
namespace EQ {
|
||||
namespace Net {
|
||||
class StaticPacket;
|
||||
class Packet
|
||||
{
|
||||
public:
|
||||
@@ -64,6 +73,7 @@ namespace EQ {
|
||||
void PutCString(size_t offset, const char *str);
|
||||
void PutPacket(size_t offset, const Packet &p);
|
||||
void PutData(size_t offset, void *data, size_t length);
|
||||
void PutProtobuf(size_t offset, const google::protobuf::Message *msg);
|
||||
|
||||
int8_t GetInt8(size_t offset) const;
|
||||
int16_t GetInt16(size_t offset) const;
|
||||
@@ -77,6 +87,8 @@ namespace EQ {
|
||||
double GetDouble(size_t offset) const;
|
||||
std::string GetString(size_t offset, size_t length) const;
|
||||
std::string GetCString(size_t offset) const;
|
||||
StaticPacket GetPacket(size_t offset, size_t length) const;
|
||||
google::protobuf::Message* GetProtobuf(size_t offset);
|
||||
|
||||
std::string ToString() const;
|
||||
std::string ToString(size_t line_length) const;
|
||||
@@ -127,4 +139,4 @@ namespace EQ {
|
||||
std::vector<char> m_data;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,34 +19,12 @@ EQ::Net::ServertalkClient::~ServertalkClient()
|
||||
{
|
||||
}
|
||||
|
||||
void EQ::Net::ServertalkClient::Send(uint16_t opcode, EQ::Net::Packet &p)
|
||||
void EQ::Net::ServertalkClient::Send(uint16_t opcode, const EQ::Net::Packet &p)
|
||||
{
|
||||
EQ::Net::DynamicPacket out;
|
||||
#ifdef ENABLE_SECURITY
|
||||
if (m_encrypted) {
|
||||
if (p.Length() == 0) {
|
||||
p.PutUInt8(0, 0);
|
||||
}
|
||||
|
||||
out.PutUInt32(0, p.Length() + crypto_secretbox_MACBYTES);
|
||||
out.PutUInt16(4, opcode);
|
||||
|
||||
std::unique_ptr<unsigned char[]> cipher(new unsigned char[p.Length() + crypto_secretbox_MACBYTES]);
|
||||
|
||||
crypto_box_easy_afternm(&cipher[0], (unsigned char*)p.Data(), p.Length(), m_nonce_ours, m_shared_key);
|
||||
(*(uint64_t*)&m_nonce_ours[0])++;
|
||||
out.PutData(6, &cipher[0], p.Length() + crypto_secretbox_MACBYTES);
|
||||
}
|
||||
else {
|
||||
out.PutUInt32(0, p.Length());
|
||||
out.PutUInt16(4, opcode);
|
||||
out.PutPacket(6, p);
|
||||
}
|
||||
#else
|
||||
out.PutUInt32(0, p.Length());
|
||||
out.PutUInt16(4, opcode);
|
||||
out.PutPacket(6, p);
|
||||
#endif
|
||||
InternalSend(ServertalkMessage, out);
|
||||
}
|
||||
|
||||
@@ -188,51 +166,6 @@ void EQ::Net::ServertalkClient::ProcessReadBuffer()
|
||||
|
||||
void EQ::Net::ServertalkClient::ProcessHello(EQ::Net::Packet &p)
|
||||
{
|
||||
#ifdef ENABLE_SECURITY
|
||||
memset(m_public_key_ours, 0, crypto_box_PUBLICKEYBYTES);
|
||||
memset(m_public_key_theirs, 0, crypto_box_PUBLICKEYBYTES);
|
||||
memset(m_private_key_ours, 0, crypto_box_SECRETKEYBYTES);
|
||||
memset(m_nonce_ours, 0, crypto_box_NONCEBYTES);
|
||||
memset(m_nonce_theirs, 0, crypto_box_NONCEBYTES);
|
||||
memset(m_shared_key, 0, crypto_box_BEFORENMBYTES);
|
||||
m_encrypted = false;
|
||||
|
||||
try {
|
||||
bool enc = p.GetInt8(0) == 1 ? true : false;
|
||||
|
||||
if (enc) {
|
||||
if (p.Length() == (1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES)) {
|
||||
memcpy(m_public_key_theirs, (char*)p.Data() + 1, crypto_box_PUBLICKEYBYTES);
|
||||
memcpy(m_nonce_theirs, (char*)p.Data() + 1 + crypto_box_PUBLICKEYBYTES, crypto_box_NONCEBYTES);
|
||||
m_encrypted = true;
|
||||
|
||||
SendHandshake();
|
||||
|
||||
if (m_on_connect_cb) {
|
||||
m_on_connect_cb(this);
|
||||
}
|
||||
}
|
||||
else {
|
||||
LogF(Logs::General, Logs::Error, "Could not process hello, size != {0}", 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES);
|
||||
}
|
||||
}
|
||||
else {
|
||||
SendHandshake();
|
||||
|
||||
if (m_on_connect_cb) {
|
||||
m_on_connect_cb(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (std::exception &ex) {
|
||||
LogF(Logs::General, Logs::Error, "Error parsing hello from server: {0}", ex.what());
|
||||
m_connection->Disconnect();
|
||||
|
||||
if (m_on_connect_cb) {
|
||||
m_on_connect_cb(nullptr);
|
||||
}
|
||||
}
|
||||
#else
|
||||
try {
|
||||
bool enc = p.GetInt8(0) == 1 ? true : false;
|
||||
|
||||
@@ -259,7 +192,6 @@ void EQ::Net::ServertalkClient::ProcessHello(EQ::Net::Packet &p)
|
||||
m_on_connect_cb(nullptr);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void EQ::Net::ServertalkClient::ProcessMessage(EQ::Net::Packet &p)
|
||||
@@ -269,45 +201,6 @@ void EQ::Net::ServertalkClient::ProcessMessage(EQ::Net::Packet &p)
|
||||
auto opcode = p.GetUInt16(4);
|
||||
if (length > 0) {
|
||||
auto data = p.GetString(6, length);
|
||||
#ifdef ENABLE_SECURITY
|
||||
if (m_encrypted) {
|
||||
size_t message_len = length - crypto_secretbox_MACBYTES;
|
||||
std::unique_ptr<unsigned char[]> decrypted_text(new unsigned char[message_len]);
|
||||
if (crypto_box_open_easy_afternm(&decrypted_text[0], (unsigned char*)&data[0], length, m_nonce_theirs, m_shared_key))
|
||||
{
|
||||
LogF(Logs::General, Logs::Error, "Error decrypting message from server");
|
||||
(*(uint64_t*)&m_nonce_theirs[0])++;
|
||||
return;
|
||||
}
|
||||
|
||||
EQ::Net::StaticPacket decrypted_packet(&decrypted_text[0], message_len);
|
||||
|
||||
(*(uint64_t*)&m_nonce_theirs[0])++;
|
||||
|
||||
auto cb = m_message_callbacks.find(opcode);
|
||||
if (cb != m_message_callbacks.end()) {
|
||||
cb->second(opcode, decrypted_packet);
|
||||
}
|
||||
|
||||
if (m_message_callback) {
|
||||
m_message_callback(opcode, decrypted_packet);
|
||||
}
|
||||
}
|
||||
else {
|
||||
size_t message_len = length;
|
||||
EQ::Net::StaticPacket packet(&data[0], message_len);
|
||||
|
||||
auto cb = m_message_callbacks.find(opcode);
|
||||
if (cb != m_message_callbacks.end()) {
|
||||
cb->second(opcode, packet);
|
||||
}
|
||||
|
||||
if (m_message_callback) {
|
||||
m_message_callback(opcode, packet);
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
size_t message_len = length;
|
||||
EQ::Net::StaticPacket packet(&data[0], message_len);
|
||||
|
||||
@@ -319,7 +212,6 @@ void EQ::Net::ServertalkClient::ProcessMessage(EQ::Net::Packet &p)
|
||||
if (m_message_callback) {
|
||||
m_message_callback(opcode, packet);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
catch (std::exception &ex) {
|
||||
@@ -330,46 +222,9 @@ void EQ::Net::ServertalkClient::ProcessMessage(EQ::Net::Packet &p)
|
||||
void EQ::Net::ServertalkClient::SendHandshake(bool downgrade)
|
||||
{
|
||||
EQ::Net::DynamicPacket handshake;
|
||||
#ifdef ENABLE_SECURITY
|
||||
if (m_encrypted) {
|
||||
crypto_box_keypair(m_public_key_ours, m_private_key_ours);
|
||||
randombytes_buf(m_nonce_ours, crypto_box_NONCEBYTES);
|
||||
|
||||
crypto_box_beforenm(m_shared_key, m_public_key_theirs, m_private_key_ours);
|
||||
|
||||
handshake.PutData(0, m_public_key_ours, crypto_box_PUBLICKEYBYTES);
|
||||
handshake.PutData(crypto_box_PUBLICKEYBYTES, m_nonce_ours, crypto_box_NONCEBYTES);
|
||||
|
||||
memset(m_public_key_ours, 0, crypto_box_PUBLICKEYBYTES);
|
||||
memset(m_public_key_theirs, 0, crypto_box_PUBLICKEYBYTES);
|
||||
memset(m_private_key_ours, 0, crypto_box_SECRETKEYBYTES);
|
||||
|
||||
size_t cipher_length = m_identifier.length() + 1 + m_credentials.length() + 1 + crypto_secretbox_MACBYTES;
|
||||
size_t data_length = m_identifier.length() + 1 + m_credentials.length() + 1;
|
||||
|
||||
std::unique_ptr<unsigned char[]> signed_buffer(new unsigned char[cipher_length]);
|
||||
std::unique_ptr<unsigned char[]> data_buffer(new unsigned char[data_length]);
|
||||
|
||||
memset(&data_buffer[0], 0, data_length);
|
||||
memcpy(&data_buffer[0], m_identifier.c_str(), m_identifier.length());
|
||||
memcpy(&data_buffer[1 + m_identifier.length()], m_credentials.c_str(), m_credentials.length());
|
||||
|
||||
crypto_box_easy_afternm(&signed_buffer[0], &data_buffer[0], data_length, m_nonce_ours, m_shared_key);
|
||||
|
||||
(*(uint64_t*)&m_nonce_ours[0])++;
|
||||
|
||||
handshake.PutData(crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES, &signed_buffer[0], cipher_length);
|
||||
}
|
||||
else {
|
||||
handshake.PutString(0, m_identifier);
|
||||
handshake.PutString(m_identifier.length() + 1, m_credentials);
|
||||
handshake.PutUInt8(m_identifier.length() + 1 + m_credentials.length(), 0);
|
||||
}
|
||||
#else
|
||||
handshake.PutString(0, m_identifier);
|
||||
handshake.PutString(m_identifier.length() + 1, m_credentials);
|
||||
handshake.PutUInt8(m_identifier.length() + 1 + m_credentials.length(), 0);
|
||||
#endif
|
||||
|
||||
if (downgrade) {
|
||||
InternalSend(ServertalkClientDowngradeSecurityHandshake, handshake);
|
||||
|
||||
@@ -4,9 +4,6 @@
|
||||
#include "../event/timer.h"
|
||||
#include "servertalk_common.h"
|
||||
#include "packet.h"
|
||||
#ifdef ENABLE_SECURITY
|
||||
#include <sodium.h>
|
||||
#endif
|
||||
|
||||
namespace EQ
|
||||
{
|
||||
@@ -18,7 +15,7 @@ namespace EQ
|
||||
ServertalkClient(const std::string &addr, int port, bool ipv6, const std::string &identifier, const std::string &credentials);
|
||||
~ServertalkClient();
|
||||
|
||||
void Send(uint16_t opcode, EQ::Net::Packet &p);
|
||||
void Send(uint16_t opcode, const EQ::Net::Packet &p);
|
||||
void SendPacket(ServerPacket *p);
|
||||
void OnConnect(std::function<void(ServertalkClient*)> cb) { m_on_connect_cb = cb; }
|
||||
void OnMessage(uint16_t opcode, std::function<void(uint16_t, EQ::Net::Packet&)> cb);
|
||||
@@ -26,6 +23,8 @@ namespace EQ
|
||||
bool Connected() const { return m_connecting != true; }
|
||||
|
||||
std::shared_ptr<EQ::Net::TCPConnection> Handle() { return m_connection; }
|
||||
|
||||
std::string GetIdentifier() const { return m_identifier; }
|
||||
private:
|
||||
void Connect();
|
||||
void ProcessData(EQ::Net::TCPConnection *c, const unsigned char *data, size_t length);
|
||||
@@ -51,17 +50,6 @@ namespace EQ
|
||||
std::unordered_map<uint16_t, std::function<void(uint16_t, EQ::Net::Packet&)>> m_message_callbacks;
|
||||
std::function<void(uint16_t, EQ::Net::Packet&)> m_message_callback;
|
||||
std::function<void(ServertalkClient*)> m_on_connect_cb;
|
||||
|
||||
#ifdef ENABLE_SECURITY
|
||||
unsigned char m_public_key_ours[crypto_box_PUBLICKEYBYTES];
|
||||
unsigned char m_private_key_ours[crypto_box_SECRETKEYBYTES];
|
||||
unsigned char m_nonce_ours[crypto_box_NONCEBYTES];
|
||||
|
||||
unsigned char m_public_key_theirs[crypto_box_PUBLICKEYBYTES];
|
||||
unsigned char m_nonce_theirs[crypto_box_NONCEBYTES];
|
||||
|
||||
unsigned char m_shared_key[crypto_box_BEFORENMBYTES];
|
||||
#endif
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ EQ::Net::ServertalkLegacyClient::~ServertalkLegacyClient()
|
||||
{
|
||||
}
|
||||
|
||||
void EQ::Net::ServertalkLegacyClient::Send(uint16_t opcode, EQ::Net::Packet &p)
|
||||
void EQ::Net::ServertalkLegacyClient::Send(uint16_t opcode, const EQ::Net::Packet &p)
|
||||
{
|
||||
if (!m_connection)
|
||||
return;
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace EQ
|
||||
ServertalkLegacyClient(const std::string &addr, int port, bool ipv6);
|
||||
~ServertalkLegacyClient();
|
||||
|
||||
void Send(uint16_t opcode, EQ::Net::Packet &p);
|
||||
void Send(uint16_t opcode, const EQ::Net::Packet &p);
|
||||
void SendPacket(ServerPacket *p);
|
||||
void OnConnect(std::function<void(ServertalkLegacyClient*)> cb) { m_on_connect_cb = cb; }
|
||||
void OnMessage(uint16_t opcode, std::function<void(uint16_t, EQ::Net::Packet&)> cb);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "servertalk_server.h"
|
||||
#include <regex>
|
||||
|
||||
EQ::Net::ServertalkServer::ServertalkServer()
|
||||
{
|
||||
@@ -19,16 +20,26 @@ void EQ::Net::ServertalkServer::Listen(const ServertalkServerOptions& opts)
|
||||
});
|
||||
}
|
||||
|
||||
void EQ::Net::ServertalkServer::OnConnectionIdentified(const std::string &type, std::function<void(std::shared_ptr<ServertalkServerConnection>)> cb)
|
||||
void EQ::Net::ServertalkServer::OnConnectionIdentified(const std::string &type, IdentityCallback cb)
|
||||
{
|
||||
m_on_ident.insert(std::make_pair(type, cb));
|
||||
}
|
||||
|
||||
void EQ::Net::ServertalkServer::OnConnectionRemoved(const std::string &type, std::function<void(std::shared_ptr<ServertalkServerConnection>)> cb)
|
||||
void EQ::Net::ServertalkServer::OnConnectionRemoved(const std::string &type, IdentityCallback cb)
|
||||
{
|
||||
m_on_disc.insert(std::make_pair(type, cb));
|
||||
}
|
||||
|
||||
void EQ::Net::ServertalkServer::OnConnectionIdentified(IdentityCallback cb)
|
||||
{
|
||||
m_on_any_ident = cb;
|
||||
}
|
||||
|
||||
void EQ::Net::ServertalkServer::OnConnectionRemoved(IdentityCallback cb)
|
||||
{
|
||||
m_on_any_disc = cb;
|
||||
}
|
||||
|
||||
void EQ::Net::ServertalkServer::ConnectionDisconnected(ServertalkServerConnection *conn)
|
||||
{
|
||||
if (conn->GetIdentifier().empty()) {
|
||||
@@ -51,6 +62,11 @@ void EQ::Net::ServertalkServer::ConnectionDisconnected(ServertalkServerConnectio
|
||||
if (on_disc != m_on_disc.end()) {
|
||||
on_disc->second(*iter);
|
||||
}
|
||||
|
||||
if (m_on_any_disc) {
|
||||
m_on_any_disc(*iter);
|
||||
}
|
||||
|
||||
type->second.erase(iter);
|
||||
return;
|
||||
}
|
||||
@@ -65,9 +81,16 @@ void EQ::Net::ServertalkServer::ConnectionIdentified(ServertalkServerConnection
|
||||
auto iter = m_unident_connections.begin();
|
||||
while (iter != m_unident_connections.end()) {
|
||||
if (conn == iter->get()) {
|
||||
auto on_ident = m_on_ident.find(conn->GetIdentifier());
|
||||
if (on_ident != m_on_ident.end()) {
|
||||
on_ident->second(*iter);
|
||||
for (auto &ident : m_on_ident) {
|
||||
std::regex ident_regex(ident.first);
|
||||
|
||||
if (std::regex_match(conn->GetIdentifier(), ident_regex)) {
|
||||
ident.second(*iter);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_on_any_ident) {
|
||||
m_on_any_ident(*iter);
|
||||
}
|
||||
|
||||
if (m_ident_connections.count(conn->GetIdentifier()) > 0) {
|
||||
|
||||
@@ -5,10 +5,6 @@
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#ifdef ENABLE_SECURITY
|
||||
#include <sodium.h>
|
||||
#endif
|
||||
|
||||
namespace EQ
|
||||
{
|
||||
namespace Net
|
||||
@@ -22,13 +18,8 @@ namespace EQ
|
||||
std::string credentials;
|
||||
|
||||
ServertalkServerOptions() {
|
||||
#ifdef ENABLE_SECURITY
|
||||
encrypted = true;
|
||||
allow_downgrade = true;
|
||||
#else
|
||||
encrypted = false;
|
||||
allow_downgrade = true;
|
||||
#endif
|
||||
ipv6 = false;
|
||||
}
|
||||
};
|
||||
@@ -36,12 +27,16 @@ namespace EQ
|
||||
class ServertalkServer
|
||||
{
|
||||
public:
|
||||
typedef std::function<void(std::shared_ptr<ServertalkServerConnection>)> IdentityCallback;
|
||||
|
||||
ServertalkServer();
|
||||
~ServertalkServer();
|
||||
|
||||
void Listen(const ServertalkServerOptions& opts);
|
||||
void OnConnectionIdentified(const std::string &type, std::function<void(std::shared_ptr<ServertalkServerConnection>)> cb);
|
||||
void OnConnectionRemoved(const std::string &type, std::function<void(std::shared_ptr<ServertalkServerConnection>)> cb);
|
||||
void OnConnectionIdentified(const std::string &type, IdentityCallback cb);
|
||||
void OnConnectionRemoved(const std::string &type, IdentityCallback cb);
|
||||
void OnConnectionIdentified(IdentityCallback cb);
|
||||
void OnConnectionRemoved(IdentityCallback cb);
|
||||
|
||||
private:
|
||||
void ConnectionDisconnected(ServertalkServerConnection *conn);
|
||||
@@ -52,8 +47,10 @@ namespace EQ
|
||||
std::vector<std::shared_ptr<ServertalkServerConnection>> m_unident_connections;
|
||||
std::map<std::string, std::vector<std::shared_ptr<ServertalkServerConnection>>> m_ident_connections;
|
||||
|
||||
std::map<std::string, std::function<void(std::shared_ptr<ServertalkServerConnection>)>> m_on_ident;
|
||||
std::map<std::string, std::function<void(std::shared_ptr<ServertalkServerConnection>)>> m_on_disc;
|
||||
std::map<std::string, IdentityCallback> m_on_ident;
|
||||
std::map<std::string, IdentityCallback> m_on_disc;
|
||||
IdentityCallback m_on_any_ident;
|
||||
IdentityCallback m_on_any_disc;
|
||||
bool m_encrypted;
|
||||
bool m_allow_downgrade;
|
||||
std::string m_credentials;
|
||||
|
||||
@@ -19,33 +19,12 @@ EQ::Net::ServertalkServerConnection::~ServertalkServerConnection()
|
||||
{
|
||||
}
|
||||
|
||||
void EQ::Net::ServertalkServerConnection::Send(uint16_t opcode, EQ::Net::Packet & p)
|
||||
void EQ::Net::ServertalkServerConnection::Send(uint16_t opcode, const EQ::Net::Packet & p)
|
||||
{
|
||||
EQ::Net::DynamicPacket out;
|
||||
#ifdef ENABLE_SECURITY
|
||||
if (m_encrypted) {
|
||||
if (p.Length() == 0) {
|
||||
p.PutUInt8(0, 0);
|
||||
}
|
||||
|
||||
out.PutUInt32(0, p.Length() + crypto_secretbox_MACBYTES);
|
||||
out.PutUInt16(4, opcode);
|
||||
|
||||
std::unique_ptr<unsigned char[]> cipher(new unsigned char[p.Length() + crypto_secretbox_MACBYTES]);
|
||||
crypto_box_easy_afternm(&cipher[0], (unsigned char*)p.Data(), p.Length(), m_nonce_ours, m_shared_key);
|
||||
(*(uint64_t*)&m_nonce_ours[0])++;
|
||||
out.PutData(6, &cipher[0], p.Length() + crypto_secretbox_MACBYTES);
|
||||
}
|
||||
else {
|
||||
out.PutUInt32(0, p.Length());
|
||||
out.PutUInt16(4, opcode);
|
||||
out.PutPacket(6, p);
|
||||
}
|
||||
#else
|
||||
out.PutUInt32(0, p.Length());
|
||||
out.PutUInt16(4, opcode);
|
||||
out.PutPacket(6, p);
|
||||
#endif
|
||||
InternalSend(ServertalkMessage, out);
|
||||
}
|
||||
|
||||
@@ -155,29 +134,7 @@ void EQ::Net::ServertalkServerConnection::OnDisconnect(TCPConnection *c)
|
||||
void EQ::Net::ServertalkServerConnection::SendHello()
|
||||
{
|
||||
EQ::Net::DynamicPacket hello;
|
||||
|
||||
#ifdef ENABLE_SECURITY
|
||||
memset(m_public_key_ours, 0, crypto_box_PUBLICKEYBYTES);
|
||||
memset(m_public_key_theirs, 0, crypto_box_PUBLICKEYBYTES);
|
||||
memset(m_private_key_ours, 0, crypto_box_SECRETKEYBYTES);
|
||||
memset(m_nonce_ours, 0, crypto_box_NONCEBYTES);
|
||||
memset(m_nonce_theirs, 0, crypto_box_NONCEBYTES);
|
||||
|
||||
if (m_encrypted) {
|
||||
hello.PutInt8(0, 1);
|
||||
|
||||
crypto_box_keypair(m_public_key_ours, m_private_key_ours);
|
||||
randombytes_buf(m_nonce_ours, crypto_box_NONCEBYTES);
|
||||
|
||||
hello.PutData(1, m_public_key_ours, crypto_box_PUBLICKEYBYTES);
|
||||
hello.PutData(1 + crypto_box_PUBLICKEYBYTES, m_nonce_ours, crypto_box_NONCEBYTES);
|
||||
}
|
||||
else {
|
||||
hello.PutInt8(0, 0);
|
||||
}
|
||||
#else
|
||||
hello.PutInt8(0, 0);
|
||||
#endif
|
||||
|
||||
InternalSend(ServertalkServerHello, hello);
|
||||
}
|
||||
@@ -199,69 +156,6 @@ void EQ::Net::ServertalkServerConnection::InternalSend(ServertalkPacketType type
|
||||
|
||||
void EQ::Net::ServertalkServerConnection::ProcessHandshake(EQ::Net::Packet &p, bool downgrade_security)
|
||||
{
|
||||
#ifdef ENABLE_SECURITY
|
||||
if (downgrade_security && m_allow_downgrade && m_encrypted) {
|
||||
LogF(Logs::General, Logs::TCP_Connection, "Downgraded encrypted connection to plaintext because otherside didn't support encryption {0}:{1}",
|
||||
m_connection->RemoteIP(), m_connection->RemotePort());
|
||||
m_encrypted = false;
|
||||
}
|
||||
|
||||
if (m_encrypted) {
|
||||
try {
|
||||
if (p.Length() > (crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES)) {
|
||||
memcpy(m_public_key_theirs, (char*)p.Data(), crypto_box_PUBLICKEYBYTES);
|
||||
memcpy(m_nonce_theirs, (char*)p.Data() + crypto_box_PUBLICKEYBYTES, crypto_box_NONCEBYTES);
|
||||
|
||||
crypto_box_beforenm(m_shared_key, m_public_key_theirs, m_private_key_ours);
|
||||
|
||||
size_t cipher_len = p.Length() - crypto_box_PUBLICKEYBYTES - crypto_box_NONCEBYTES;
|
||||
size_t message_len = cipher_len - crypto_secretbox_MACBYTES;
|
||||
std::unique_ptr<unsigned char[]> decrypted_text(new unsigned char[message_len]);
|
||||
|
||||
if (crypto_box_open_easy_afternm(&decrypted_text[0], (unsigned char*)p.Data() + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES, cipher_len, m_nonce_theirs, m_shared_key))
|
||||
{
|
||||
LogF(Logs::General, Logs::Error, "Error decrypting handshake from client, dropping connection.");
|
||||
m_connection->Disconnect();
|
||||
return;
|
||||
}
|
||||
|
||||
m_identifier = (const char*)&decrypted_text[0];
|
||||
std::string credentials = (const char*)&decrypted_text[0] + (m_identifier.length() + 1);
|
||||
|
||||
if (!m_parent->CheckCredentials(credentials)) {
|
||||
LogF(Logs::General, Logs::Error, "Got incoming connection with invalid credentials during handshake, dropping connection.");
|
||||
m_connection->Disconnect();
|
||||
return;
|
||||
}
|
||||
|
||||
m_parent->ConnectionIdentified(this);
|
||||
(*(uint64_t*)&m_nonce_theirs[0])++;
|
||||
}
|
||||
}
|
||||
catch (std::exception &ex) {
|
||||
LogF(Logs::General, Logs::Error, "Error parsing handshake from client: {0}", ex.what());
|
||||
m_connection->Disconnect();
|
||||
}
|
||||
}
|
||||
else {
|
||||
try {
|
||||
m_identifier = p.GetCString(0);
|
||||
auto credentials = p.GetCString(m_identifier.length() + 1);
|
||||
|
||||
if (!m_parent->CheckCredentials(credentials)) {
|
||||
LogF(Logs::General, Logs::Error, "Got incoming connection with invalid credentials during handshake, dropping connection.");
|
||||
m_connection->Disconnect();
|
||||
return;
|
||||
}
|
||||
|
||||
m_parent->ConnectionIdentified(this);
|
||||
}
|
||||
catch (std::exception &ex) {
|
||||
LogF(Logs::General, Logs::Error, "Error parsing handshake from client: {0}", ex.what());
|
||||
m_connection->Disconnect();
|
||||
}
|
||||
}
|
||||
#else
|
||||
try {
|
||||
m_identifier = p.GetCString(0);
|
||||
auto credentials = p.GetCString(m_identifier.length() + 1);
|
||||
@@ -278,7 +172,6 @@ void EQ::Net::ServertalkServerConnection::ProcessHandshake(EQ::Net::Packet &p, b
|
||||
LogF(Logs::General, Logs::Error, "Error parsing handshake from client: {0}", ex.what());
|
||||
m_connection->Disconnect();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void EQ::Net::ServertalkServerConnection::ProcessMessage(EQ::Net::Packet &p)
|
||||
@@ -288,46 +181,6 @@ void EQ::Net::ServertalkServerConnection::ProcessMessage(EQ::Net::Packet &p)
|
||||
auto opcode = p.GetUInt16(4);
|
||||
if (length > 0) {
|
||||
auto data = p.GetString(6, length);
|
||||
#ifdef ENABLE_SECURITY
|
||||
if (m_encrypted) {
|
||||
size_t message_len = length - crypto_secretbox_MACBYTES;
|
||||
std::unique_ptr<unsigned char[]> decrypted_text(new unsigned char[message_len]);
|
||||
|
||||
if (crypto_box_open_easy_afternm(&decrypted_text[0], (unsigned char*)&data[0], length, m_nonce_theirs, m_shared_key))
|
||||
{
|
||||
LogF(Logs::General, Logs::Error, "Error decrypting message from client");
|
||||
(*(uint64_t*)&m_nonce_theirs[0])++;
|
||||
return;
|
||||
}
|
||||
|
||||
EQ::Net::StaticPacket decrypted_packet(&decrypted_text[0], message_len);
|
||||
|
||||
(*(uint64_t*)&m_nonce_theirs[0])++;
|
||||
|
||||
auto cb = m_message_callbacks.find(opcode);
|
||||
if (cb != m_message_callbacks.end()) {
|
||||
cb->second(opcode, decrypted_packet);
|
||||
}
|
||||
|
||||
if (m_message_callback) {
|
||||
m_message_callback(opcode, decrypted_packet);
|
||||
}
|
||||
}
|
||||
else {
|
||||
size_t message_len = length;
|
||||
EQ::Net::StaticPacket packet(&data[0], message_len);
|
||||
|
||||
auto cb = m_message_callbacks.find(opcode);
|
||||
if (cb != m_message_callbacks.end()) {
|
||||
cb->second(opcode, packet);
|
||||
}
|
||||
|
||||
if (m_message_callback) {
|
||||
m_message_callback(opcode, packet);
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
size_t message_len = length;
|
||||
EQ::Net::StaticPacket packet(&data[0], message_len);
|
||||
|
||||
@@ -339,7 +192,6 @@ void EQ::Net::ServertalkServerConnection::ProcessMessage(EQ::Net::Packet &p)
|
||||
if (m_message_callback) {
|
||||
m_message_callback(opcode, packet);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
catch (std::exception &ex) {
|
||||
|
||||
@@ -4,9 +4,6 @@
|
||||
#include "servertalk_common.h"
|
||||
#include "packet.h"
|
||||
#include <vector>
|
||||
#ifdef ENABLE_SECURITY
|
||||
#include <sodium.h>
|
||||
#endif
|
||||
|
||||
namespace EQ
|
||||
{
|
||||
@@ -19,7 +16,7 @@ namespace EQ
|
||||
ServertalkServerConnection(std::shared_ptr<EQ::Net::TCPConnection> c, ServertalkServer *parent, bool encrypted, bool allow_downgrade);
|
||||
~ServertalkServerConnection();
|
||||
|
||||
void Send(uint16_t opcode, EQ::Net::Packet &p);
|
||||
void Send(uint16_t opcode, const EQ::Net::Packet &p);
|
||||
void SendPacket(ServerPacket *p);
|
||||
void OnMessage(uint16_t opcode, std::function<void(uint16_t, EQ::Net::Packet&)> cb);
|
||||
void OnMessage(std::function<void(uint16_t, EQ::Net::Packet&)> cb);
|
||||
@@ -48,16 +45,6 @@ namespace EQ
|
||||
|
||||
bool m_encrypted;
|
||||
bool m_allow_downgrade;
|
||||
#ifdef ENABLE_SECURITY
|
||||
unsigned char m_public_key_ours[crypto_box_PUBLICKEYBYTES];
|
||||
unsigned char m_private_key_ours[crypto_box_SECRETKEYBYTES];
|
||||
unsigned char m_nonce_ours[crypto_box_NONCEBYTES];
|
||||
|
||||
unsigned char m_public_key_theirs[crypto_box_PUBLICKEYBYTES];
|
||||
unsigned char m_nonce_theirs[crypto_box_NONCEBYTES];
|
||||
|
||||
unsigned char m_shared_key[crypto_box_BEFORENMBYTES];
|
||||
#endif
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
syntax = "proto3";
|
||||
import "google/protobuf/any.proto";
|
||||
|
||||
package EQ.Proto;
|
||||
|
||||
message TaskMessage {
|
||||
int32 message = 1;
|
||||
google.protobuf.Any details = 2;
|
||||
}
|
||||
|
||||
message ClientTaskStateRequest {
|
||||
int32 client_id = 1;
|
||||
}
|
||||
|
||||
message ClientTaskStateResponse {
|
||||
int32 client_id = 1;
|
||||
}
|
||||
|
||||
@@ -758,6 +758,17 @@ RULE_BOOL(Bugs, UseOldReportingMethod, true) // Forces the use of the old bug re
|
||||
RULE_BOOL(Bugs, DumpTargetEntity, false) // Dumps the target entity, if one is provided
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(Faction)
|
||||
RULE_INT(Faction, AllyFactionMinimum, 1100)
|
||||
RULE_INT(Faction, WarmlyFactionMinimum, 750)
|
||||
RULE_INT(Faction, KindlyFactionMinimum, 500)
|
||||
RULE_INT(Faction, AmiablyFactionMinimum, 100)
|
||||
RULE_INT(Faction, IndifferentlyFactionMinimum, 0)
|
||||
RULE_INT(Faction, ApprehensivelyFactionMinimum, -100)
|
||||
RULE_INT(Faction, DubiouslyFactionMinimum, -500)
|
||||
RULE_INT(Faction, ThreateninglyFactionMinimum, -750)
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
#undef RULE_CATEGORY
|
||||
#undef RULE_INT
|
||||
#undef RULE_REAL
|
||||
|
||||
@@ -187,6 +187,7 @@ public:
|
||||
const unsigned char *buffer() const { return m_buffer; }
|
||||
|
||||
friend class BasePacket;
|
||||
friend class ServerPacket;
|
||||
|
||||
private:
|
||||
void Grow(size_t new_size);
|
||||
|
||||
+233
-197
@@ -1,218 +1,220 @@
|
||||
#ifndef EQ_SOPCODES_H
|
||||
#define EQ_SOPCODES_H
|
||||
#pragma once
|
||||
|
||||
#include "../common/types.h"
|
||||
#include "../common/packet_functions.h"
|
||||
#include "../common/eq_packet_structs.h"
|
||||
#include "../common/serialize_buffer.h"
|
||||
#include "../net/packet.h"
|
||||
#include <cereal/cereal.hpp>
|
||||
#include <cereal/types/string.hpp>
|
||||
|
||||
#define SERVER_TIMEOUT 45000 // how often keepalive gets sent
|
||||
#define INTERSERVER_TIMER 10000
|
||||
#define LoginServer_StatusUpdateInterval 15000
|
||||
#define LoginServer_AuthStale 60000
|
||||
#define AUTHCHANGE_TIMEOUT 900 // in seconds
|
||||
constexpr auto INTERSERVER_TIMER = 10000;
|
||||
constexpr auto LoginServer_StatusUpdateInterval = 15000;
|
||||
|
||||
#define ServerOP_KeepAlive 0x0001 // packet to test if port is still open
|
||||
#define ServerOP_ChannelMessage 0x0002 // broadcast/guildsay
|
||||
#define ServerOP_SetZone 0x0003 // client -> server zoneinfo
|
||||
#define ServerOP_ShutdownAll 0x0004 // exit(0);
|
||||
#define ServerOP_ZoneShutdown 0x0005 // unload all data, goto sleep mode
|
||||
#define ServerOP_ZoneBootup 0x0006 // come out of sleep mode and load zone specified
|
||||
#define ServerOP_ZoneStatus 0x0007 // Shows status of all zones
|
||||
#define ServerOP_SetConnectInfo 0x0008 // Tells server address and port #
|
||||
#define ServerOP_EmoteMessage 0x0009 // Worldfarts
|
||||
#define ServerOP_ClientList 0x000A // Update worldserver's client list, for #whos
|
||||
#define ServerOP_Who 0x000B // #who
|
||||
#define ServerOP_ZonePlayer 0x000C // #zone, or #summon
|
||||
#define ServerOP_KickPlayer 0x000D // #kick
|
||||
//Certain ops needed for backwards compat with old LS can't enum without being really annoying.
|
||||
constexpr auto ServerOP_UsertoWorldReq = 0xAB00;
|
||||
constexpr auto ServerOP_UsertoWorldResp = 0xAB01;
|
||||
constexpr auto ServerOP_LSClientAuth = 0x1002;
|
||||
constexpr auto ServerOP_LSFatalError = 0x1003;
|
||||
constexpr auto ServerOP_SystemwideMessage = 0x1005;
|
||||
constexpr auto ServerOP_LSRemoteAddr = 0x1009;
|
||||
constexpr auto ServerOP_LSAccountUpdate = 0x100A;
|
||||
constexpr auto ServerOP_NewLSInfo = 0x1008;
|
||||
constexpr auto ServerOP_LSInfo = 0x1000;
|
||||
constexpr auto ServerOP_LSStatus = 0x1001;
|
||||
|
||||
#define ServerOP_RefreshGuild 0x000E // Notice to all zoneservers to refresh their guild cache for ID# in packet (ServerGuildRefresh_Struct)
|
||||
#define ServerOP_VoiceMacro 0x000F
|
||||
//#define ServerOP_GuildInvite 0x0010
|
||||
#define ServerOP_DeleteGuild 0x0011 // ServerGuildID_Struct
|
||||
#define ServerOP_GuildRankUpdate 0x0012
|
||||
#define ServerOP_GuildCharRefresh 0x0013
|
||||
#define ServerOP_GuildMemberUpdate 0x0014
|
||||
#define ServerOP_RequestOnlineGuildMembers 0x0015
|
||||
#define ServerOP_OnlineGuildMembersResponse 0x0016
|
||||
#define ServerOP_LFGuildUpdate 0x0017
|
||||
enum ServerOpcode : int
|
||||
{
|
||||
ServerOP_ChannelMessage,
|
||||
ServerOP_SetZone,
|
||||
ServerOP_ShutdownAll,
|
||||
ServerOP_ZoneShutdown,
|
||||
ServerOP_ZoneBootup,
|
||||
ServerOP_ZoneStatus,
|
||||
ServerOP_SetConnectInfo,
|
||||
ServerOP_EmoteMessage,
|
||||
ServerOP_ClientList,
|
||||
ServerOP_Who,
|
||||
ServerOP_ZonePlayer,
|
||||
ServerOP_KickPlayer,
|
||||
ServerOP_RefreshGuild,
|
||||
ServerOP_VoiceMacro,
|
||||
//ServerOP_GuildInvite,
|
||||
ServerOP_DeleteGuild,
|
||||
ServerOP_GuildRankUpdate,
|
||||
ServerOP_GuildCharRefresh,
|
||||
ServerOP_GuildMemberUpdate,
|
||||
ServerOP_RequestOnlineGuildMembers,
|
||||
ServerOP_OnlineGuildMembersResponse,
|
||||
ServerOP_LFGuildUpdate,
|
||||
ServerOP_FlagUpdate,
|
||||
ServerOP_GMGoto,
|
||||
ServerOP_MultiLineMsg,
|
||||
ServerOP_Lock,
|
||||
ServerOP_Motd,
|
||||
ServerOP_Uptime,
|
||||
ServerOP_Petition,
|
||||
ServerOP_KillPlayer,
|
||||
ServerOP_UpdateGM,
|
||||
ServerOP_RezzPlayer,
|
||||
ServerOP_ZoneReboot,
|
||||
ServerOP_ZoneToZoneRequest,
|
||||
ServerOP_AcceptWorldEntrance,
|
||||
ServerOP_ZAAuth,
|
||||
ServerOP_ZAAuthFailed,
|
||||
ServerOP_ZoneIncClient,
|
||||
ServerOP_ClientListKA,
|
||||
ServerOP_ChangeWID,
|
||||
ServerOP_IPLookup,
|
||||
ServerOP_LockZone,
|
||||
ServerOP_ItemStatus,
|
||||
ServerOP_OOCMute,
|
||||
ServerOP_Revoke,
|
||||
ServerOP_WebInterfaceCall,
|
||||
ServerOP_GroupIDReq,
|
||||
ServerOP_GroupIDReply,
|
||||
ServerOP_GroupLeave,
|
||||
ServerOP_RezzPlayerAccept,
|
||||
ServerOP_SpawnCondition,
|
||||
ServerOP_SpawnEvent,
|
||||
ServerOP_SetLaunchName,
|
||||
ServerOP_RezzPlayerReject,
|
||||
ServerOP_SpawnPlayerCorpse,
|
||||
ServerOP_Consent,
|
||||
ServerOP_Consent_Response,
|
||||
ServerOP_ForceGroupUpdate,
|
||||
ServerOP_OOZGroupMessage,
|
||||
ServerOP_DisbandGroup,
|
||||
ServerOP_GroupJoin,
|
||||
ServerOP_UpdateSpawn,
|
||||
ServerOP_SpawnStatusChange,
|
||||
ServerOP_ReloadTasks,
|
||||
ServerOP_DepopAllPlayersCorpses,
|
||||
ServerOP_ReloadTitles,
|
||||
ServerOP_QGlobalUpdate,
|
||||
ServerOP_QGlobalDelete,
|
||||
ServerOP_DepopPlayerCorpse,
|
||||
ServerOP_RequestTellQueue,
|
||||
ServerOP_ChangeSharedMem,
|
||||
ServerOP_WebInterfaceEvent,
|
||||
ServerOP_WebInterfaceSubscribe,
|
||||
ServerOP_WebInterfaceUnsubscribe,
|
||||
ServerOP_RaidAdd,
|
||||
ServerOP_RaidRemove,
|
||||
ServerOP_RaidDisband,
|
||||
ServerOP_RaidLockFlag,
|
||||
ServerOP_RaidGroupLeader,
|
||||
ServerOP_RaidLeader,
|
||||
ServerOP_RaidGroupSay,
|
||||
ServerOP_RaidSay,
|
||||
ServerOP_DetailsChange,
|
||||
ServerOP_UpdateGroup,
|
||||
ServerOP_RaidGroupDisband,
|
||||
ServerOP_RaidChangeGroup,
|
||||
ServerOP_RaidGroupAdd,
|
||||
ServerOP_RaidGroupRemove,
|
||||
ServerOP_GroupInvite,
|
||||
ServerOP_GroupFollow,
|
||||
ServerOP_GroupFollowAck,
|
||||
ServerOP_GroupCancelInvite,
|
||||
ServerOP_RaidMOTD,
|
||||
ServerOP_InstanceUpdateTime,
|
||||
ServerOP_AdventureRequest,
|
||||
ServerOP_AdventureRequestAccept,
|
||||
ServerOP_AdventureRequestDeny,
|
||||
ServerOP_AdventureRequestCreate,
|
||||
ServerOP_AdventureData,
|
||||
ServerOP_AdventureDataClear,
|
||||
ServerOP_AdventureCreateDeny,
|
||||
ServerOP_AdventureDataRequest,
|
||||
ServerOP_AdventureClickDoor,
|
||||
ServerOP_AdventureClickDoorReply,
|
||||
ServerOP_AdventureClickDoorError,
|
||||
ServerOP_AdventureLeave,
|
||||
ServerOP_AdventureLeaveReply,
|
||||
ServerOP_AdventureLeaveDeny,
|
||||
ServerOP_AdventureCountUpdate,
|
||||
ServerOP_AdventureZoneData,
|
||||
ServerOP_AdventureAssaCountUpdate,
|
||||
ServerOP_AdventureFinish,
|
||||
ServerOP_AdventureLeaderboard,
|
||||
ServerOP_WhoAll,
|
||||
ServerOP_FriendsWho,
|
||||
ServerOP_LFGMatches,
|
||||
ServerOP_LFPUpdate,
|
||||
ServerOP_LFPMatches,
|
||||
ServerOP_ClientVersionSummary,
|
||||
ServerOP_ListWorlds,
|
||||
ServerOP_PeerConnect,
|
||||
ServerOP_TaskRequest,
|
||||
ServerOP_TaskGrant,
|
||||
ServerOP_TaskReject,
|
||||
ServerOP_TaskAddPlayer,
|
||||
ServerOP_TaskRemovePlayer,
|
||||
ServerOP_TaskZoneCreated,
|
||||
ServerOP_TaskZoneFailed,
|
||||
ServerOP_EncapPacket,
|
||||
ServerOP_WorldListUpdate,
|
||||
ServerOP_WorldListRemove,
|
||||
ServerOP_TriggerWorldListRefresh,
|
||||
ServerOP_WhoAllReply,
|
||||
ServerOP_SetWorldTime,
|
||||
ServerOP_GetWorldTime,
|
||||
ServerOP_SyncWorldTime,
|
||||
ServerOP_RefreshCensorship,
|
||||
ServerOP_LSZoneInfo,
|
||||
ServerOP_LSZoneStart,
|
||||
ServerOP_LSZoneBoot,
|
||||
ServerOP_LSZoneShutdown,
|
||||
ServerOP_LSZoneSleep,
|
||||
ServerOP_LSPlayerLeftWorld,
|
||||
ServerOP_LSPlayerJoinWorld,
|
||||
ServerOP_LSPlayerZoneChange,
|
||||
ServerOP_LauncherConnectInfo,
|
||||
ServerOP_LauncherZoneRequest,
|
||||
ServerOP_LauncherZoneStatus,
|
||||
ServerOP_DoZoneCommand,
|
||||
ServerOP_UCSMessage,
|
||||
ServerOP_UCSMailMessage,
|
||||
ServerOP_ReloadRules,
|
||||
ServerOP_ReloadRulesWorld,
|
||||
ServerOP_CameraShake,
|
||||
ServerOP_QueryServGeneric,
|
||||
ServerOP_CZSignalClient,
|
||||
ServerOP_CZSignalClientByName,
|
||||
ServerOP_CZMessagePlayer,
|
||||
ServerOP_ReloadWorld,
|
||||
ServerOP_ReloadLogs,
|
||||
ServerOP_ReloadPerlExportSettings,
|
||||
ServerOP_CZSetEntityVariableByClientName,
|
||||
ServerOP_UCSServerStatusRequest,
|
||||
ServerOP_UCSServerStatusReply,
|
||||
ServerOP_Speech,
|
||||
ServerOP_QSPlayerLogTrades,
|
||||
ServerOP_QSPlayerLogHandins,
|
||||
ServerOP_QSPlayerLogNPCKills,
|
||||
ServerOP_QSPlayerLogDeletes,
|
||||
ServerOP_QSPlayerLogMoves,
|
||||
ServerOP_QSPlayerLogMerchantTransactions,
|
||||
ServerOP_QSSendQuery,
|
||||
ServerOP_CZSignalNPC,
|
||||
ServerOP_CZSetEntityVariableByNPCTypeID,
|
||||
ServerOP_WWMarquee,
|
||||
ServerOP_QSPlayerDropItem,
|
||||
ServerOP_RouteTo,
|
||||
|
||||
#define ServerOP_FlagUpdate 0x0018 // GM Flag updated for character, refresh the memory cache
|
||||
#define ServerOP_GMGoto 0x0019
|
||||
#define ServerOP_MultiLineMsg 0x001A
|
||||
#define ServerOP_Lock 0x001B // For #lock/#unlock inside server
|
||||
#define ServerOP_Motd 0x001C // For changing MoTD inside server.
|
||||
#define ServerOP_Uptime 0x001D
|
||||
#define ServerOP_Petition 0x001E
|
||||
#define ServerOP_KillPlayer 0x001F
|
||||
#define ServerOP_UpdateGM 0x0020
|
||||
#define ServerOP_RezzPlayer 0x0021
|
||||
#define ServerOP_ZoneReboot 0x0022
|
||||
#define ServerOP_ZoneToZoneRequest 0x0023
|
||||
#define ServerOP_AcceptWorldEntrance 0x0024
|
||||
#define ServerOP_ZAAuth 0x0025
|
||||
#define ServerOP_ZAAuthFailed 0x0026
|
||||
#define ServerOP_ZoneIncClient 0x0027 // Incoming client
|
||||
#define ServerOP_ClientListKA 0x0028
|
||||
#define ServerOP_ChangeWID 0x0029
|
||||
#define ServerOP_IPLookup 0x002A
|
||||
#define ServerOP_LockZone 0x002B
|
||||
#define ServerOP_ItemStatus 0x002C
|
||||
#define ServerOP_OOCMute 0x002D
|
||||
#define ServerOP_Revoke 0x002E
|
||||
#define ServerOP_WebInterfaceCall 0x002F
|
||||
#define ServerOP_GroupIDReq 0x0030
|
||||
#define ServerOP_GroupIDReply 0x0031
|
||||
#define ServerOP_GroupLeave 0x0032 // for disbanding out of zone folks
|
||||
#define ServerOP_RezzPlayerAccept 0x0033
|
||||
#define ServerOP_SpawnCondition 0x0034
|
||||
#define ServerOP_SpawnEvent 0x0035
|
||||
#define ServerOP_SetLaunchName 0x0036
|
||||
#define ServerOP_RezzPlayerReject 0x0037
|
||||
#define ServerOP_SpawnPlayerCorpse 0x0038
|
||||
#define ServerOP_Consent 0x0039
|
||||
#define ServerOP_Consent_Response 0x003a
|
||||
#define ServerOP_ForceGroupUpdate 0x003b
|
||||
#define ServerOP_OOZGroupMessage 0x003c
|
||||
#define ServerOP_DisbandGroup 0x003d //for disbanding a whole group cross zone
|
||||
#define ServerOP_GroupJoin 0x003e //for joining ooz folks
|
||||
#define ServerOP_UpdateSpawn 0x003f
|
||||
#define ServerOP_SpawnStatusChange 0x0040
|
||||
#define ServerOP_ReloadTasks 0x0060
|
||||
#define ServerOP_DepopAllPlayersCorpses 0x0061
|
||||
#define ServerOP_ReloadTitles 0x0062
|
||||
#define ServerOP_QGlobalUpdate 0x0063
|
||||
#define ServerOP_QGlobalDelete 0x0064
|
||||
#define ServerOP_DepopPlayerCorpse 0x0065
|
||||
#define ServerOP_RequestTellQueue 0x0066 // client asks for it's tell queues
|
||||
#define ServerOP_ChangeSharedMem 0x0067
|
||||
#define ServerOP_WebInterfaceEvent 0x0068
|
||||
#define ServerOP_WebInterfaceSubscribe 0x0069
|
||||
#define ServerOP_WebInterfaceUnsubscribe 0x0070
|
||||
/*Tasks*/
|
||||
ServerOP_GetClientTaskState
|
||||
};
|
||||
|
||||
#define ServerOP_RaidAdd 0x0100 //in use
|
||||
#define ServerOP_RaidRemove 0x0101 //in use
|
||||
#define ServerOP_RaidDisband 0x0102 //in use
|
||||
#define ServerOP_RaidLockFlag 0x0103 //in use
|
||||
#define ServerOP_RaidGroupLeader 0x0104 //in use
|
||||
#define ServerOP_RaidLeader 0x0105 //in use
|
||||
#define ServerOP_RaidGroupSay 0x0106 //in use
|
||||
#define ServerOP_RaidSay 0x0107 //in use
|
||||
#define ServerOP_DetailsChange 0x0108 //in use
|
||||
|
||||
#define ServerOP_UpdateGroup 0x010A //in use
|
||||
#define ServerOP_RaidGroupDisband 0x010B //in use
|
||||
#define ServerOP_RaidChangeGroup 0x010C //in use
|
||||
#define ServerOP_RaidGroupAdd 0x010D
|
||||
#define ServerOP_RaidGroupRemove 0x010E
|
||||
#define ServerOP_GroupInvite 0x010F
|
||||
#define ServerOP_GroupFollow 0x0110
|
||||
#define ServerOP_GroupFollowAck 0x0111
|
||||
#define ServerOP_GroupCancelInvite 0x0112
|
||||
#define ServerOP_RaidMOTD 0x0113
|
||||
|
||||
#define ServerOP_InstanceUpdateTime 0x014F
|
||||
#define ServerOP_AdventureRequest 0x0150
|
||||
#define ServerOP_AdventureRequestAccept 0x0151
|
||||
#define ServerOP_AdventureRequestDeny 0x0152
|
||||
#define ServerOP_AdventureRequestCreate 0x0153
|
||||
#define ServerOP_AdventureData 0x0154
|
||||
#define ServerOP_AdventureDataClear 0x0155
|
||||
#define ServerOP_AdventureCreateDeny 0x0156
|
||||
#define ServerOP_AdventureDataRequest 0x0157
|
||||
#define ServerOP_AdventureClickDoor 0x0158
|
||||
#define ServerOP_AdventureClickDoorReply 0x0159
|
||||
#define ServerOP_AdventureClickDoorError 0x015a
|
||||
#define ServerOP_AdventureLeave 0x015b
|
||||
#define ServerOP_AdventureLeaveReply 0x015c
|
||||
#define ServerOP_AdventureLeaveDeny 0x015d
|
||||
#define ServerOP_AdventureCountUpdate 0x015e
|
||||
#define ServerOP_AdventureZoneData 0x015f
|
||||
#define ServerOP_AdventureAssaCountUpdate 0x0160
|
||||
#define ServerOP_AdventureFinish 0x0161
|
||||
#define ServerOP_AdventureLeaderboard 0x0162
|
||||
|
||||
#define ServerOP_WhoAll 0x0210
|
||||
#define ServerOP_FriendsWho 0x0211
|
||||
#define ServerOP_LFGMatches 0x0212
|
||||
#define ServerOP_LFPUpdate 0x0213
|
||||
#define ServerOP_LFPMatches 0x0214
|
||||
#define ServerOP_ClientVersionSummary 0x0215
|
||||
#define ServerOP_LSInfo 0x1000
|
||||
#define ServerOP_LSStatus 0x1001
|
||||
#define ServerOP_LSClientAuth 0x1002
|
||||
#define ServerOP_LSFatalError 0x1003
|
||||
#define ServerOP_SystemwideMessage 0x1005
|
||||
#define ServerOP_ListWorlds 0x1006
|
||||
#define ServerOP_PeerConnect 0x1007
|
||||
#define ServerOP_NewLSInfo 0x1008
|
||||
#define ServerOP_LSRemoteAddr 0x1009
|
||||
#define ServerOP_LSAccountUpdate 0x100A
|
||||
|
||||
#define ServerOP_EncapPacket 0x2007 // Packet within a packet
|
||||
#define ServerOP_WorldListUpdate 0x2008
|
||||
#define ServerOP_WorldListRemove 0x2009
|
||||
#define ServerOP_TriggerWorldListRefresh 0x200A
|
||||
#define ServerOP_WhoAllReply 0x2010
|
||||
#define ServerOP_SetWorldTime 0x200B
|
||||
#define ServerOP_GetWorldTime 0x200C
|
||||
#define ServerOP_SyncWorldTime 0x200E
|
||||
#define ServerOP_RefreshCensorship 0x200F
|
||||
|
||||
#define ServerOP_LSZoneInfo 0x3001
|
||||
#define ServerOP_LSZoneStart 0x3002
|
||||
#define ServerOP_LSZoneBoot 0x3003
|
||||
#define ServerOP_LSZoneShutdown 0x3004
|
||||
#define ServerOP_LSZoneSleep 0x3005
|
||||
#define ServerOP_LSPlayerLeftWorld 0x3006
|
||||
#define ServerOP_LSPlayerJoinWorld 0x3007
|
||||
#define ServerOP_LSPlayerZoneChange 0x3008
|
||||
|
||||
#define ServerOP_UsertoWorldReq 0xAB00
|
||||
#define ServerOP_UsertoWorldResp 0xAB01
|
||||
|
||||
#define ServerOP_LauncherConnectInfo 0x3000
|
||||
#define ServerOP_LauncherZoneRequest 0x3001
|
||||
#define ServerOP_LauncherZoneStatus 0x3002
|
||||
#define ServerOP_DoZoneCommand 0x3003
|
||||
|
||||
#define ServerOP_UCSMessage 0x4000
|
||||
#define ServerOP_UCSMailMessage 0x4001
|
||||
#define ServerOP_ReloadRules 0x4002
|
||||
#define ServerOP_ReloadRulesWorld 0x4003
|
||||
#define ServerOP_CameraShake 0x4004
|
||||
#define ServerOP_QueryServGeneric 0x4005
|
||||
#define ServerOP_CZSignalClient 0x4006
|
||||
#define ServerOP_CZSignalClientByName 0x4007
|
||||
#define ServerOP_CZMessagePlayer 0x4008
|
||||
#define ServerOP_ReloadWorld 0x4009
|
||||
#define ServerOP_ReloadLogs 0x4010
|
||||
#define ServerOP_ReloadPerlExportSettings 0x4011
|
||||
#define ServerOP_CZSetEntityVariableByClientName 0x4012
|
||||
#define ServerOP_UCSServerStatusRequest 0x4013
|
||||
#define ServerOP_UCSServerStatusReply 0x4014
|
||||
/* Query Server OP Codes */
|
||||
#define ServerOP_QSPlayerLogTrades 0x5010
|
||||
#define ServerOP_QSPlayerLogHandins 0x5011
|
||||
#define ServerOP_QSPlayerLogNPCKills 0x5012
|
||||
#define ServerOP_QSPlayerLogDeletes 0x5013
|
||||
#define ServerOP_QSPlayerLogMoves 0x5014
|
||||
#define ServerOP_QSPlayerLogMerchantTransactions 0x5015
|
||||
#define ServerOP_QSSendQuery 0x5016
|
||||
#define ServerOP_CZSignalNPC 0x5017
|
||||
#define ServerOP_CZSetEntityVariableByNPCTypeID 0x5018
|
||||
#define ServerOP_WWMarquee 0x5019
|
||||
#define ServerOP_QSPlayerDropItem 0x5020
|
||||
|
||||
/* Query Serv Generic Packet Flag/Type Enumeration */
|
||||
enum { QSG_LFGuild = 0 };
|
||||
enum { QSG_LFGuild_PlayerMatches = 0, QSG_LFGuild_UpdatePlayerInfo, QSG_LFGuild_RequestPlayerInfo, QSG_LFGuild_UpdateGuildInfo, QSG_LFGuild_GuildMatches,
|
||||
QSG_LFGuild_RequestGuildInfo };
|
||||
|
||||
#define ServerOP_Speech 0x4513
|
||||
|
||||
/************ PACKET RELATED STRUCT ************/
|
||||
class ServerPacket
|
||||
{
|
||||
@@ -248,6 +250,19 @@ public:
|
||||
_rpos = 0;
|
||||
}
|
||||
|
||||
ServerPacket(uint16 in_opcode, SerializeBuffer &buf)
|
||||
{
|
||||
compressed = false;
|
||||
size = buf.m_pos;
|
||||
buf.m_pos = 0;
|
||||
opcode = in_opcode;
|
||||
pBuffer = buf.m_buffer;
|
||||
buf.m_buffer = 0;
|
||||
buf.m_capacity = 0;
|
||||
_wpos = 0;
|
||||
_rpos = 0;
|
||||
}
|
||||
|
||||
ServerPacket* Copy() {
|
||||
if (this == 0) {
|
||||
return 0;
|
||||
@@ -1314,6 +1329,27 @@ struct UCSServerStatus_Struct {
|
||||
};
|
||||
};
|
||||
|
||||
#pragma pack()
|
||||
// shared task related communications
|
||||
struct ServerSharedTaskMember_Struct { // used for various things we just need the ID and a name (add, remove, etc)
|
||||
uint32 id;
|
||||
char name[64];
|
||||
};
|
||||
// error constants
|
||||
#define TASKJOINOOZ_CAN 0
|
||||
#define TASKJOINOOZ_NOTASK 1
|
||||
#define TASKJOINOOZ_HAVEONE 2
|
||||
#define TASKJOINOOZ_LEVEL 3
|
||||
#define TASKJOINOOZ_TIMER 4
|
||||
|
||||
#endif
|
||||
/*
|
||||
* Routing
|
||||
*/
|
||||
|
||||
struct RouteToMessage
|
||||
{
|
||||
char filter[32];
|
||||
char identifier[32];
|
||||
char id[32];
|
||||
};
|
||||
|
||||
#pragma pack()
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
#include "service.h"
|
||||
#include "event/event_loop.h"
|
||||
#include "event/timer.h"
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
|
||||
struct EQ::Service::Impl
|
||||
{
|
||||
bool running;
|
||||
std::string identifier;
|
||||
size_t heartbeat_duration_ms;
|
||||
size_t sleep_duration_ms;
|
||||
std::unique_ptr<EQ::WorldConnection> world_connection;
|
||||
std::unique_ptr<EQ::Timer> heartbeat_timer;
|
||||
std::chrono::steady_clock::time_point last_time;
|
||||
};
|
||||
|
||||
EQ::Service::Service(const std::string &identifier, size_t heartbeat_duration_ms, size_t sleep_duration_ms)
|
||||
{
|
||||
_impl.reset(new Impl());
|
||||
_impl->running = false;
|
||||
_impl->identifier = identifier;
|
||||
_impl->heartbeat_duration_ms = heartbeat_duration_ms;
|
||||
_impl->sleep_duration_ms = sleep_duration_ms;
|
||||
}
|
||||
|
||||
EQ::Service::~Service()
|
||||
{
|
||||
}
|
||||
|
||||
void EQ::Service::Run()
|
||||
{
|
||||
_impl->running = true;
|
||||
|
||||
OnStart();
|
||||
|
||||
//If start canceled our run then just quit, dont bother initializing everything else
|
||||
if (!_impl->running) {
|
||||
return;
|
||||
}
|
||||
|
||||
_impl->world_connection.reset(new EQ::WorldConnection(_impl->identifier));
|
||||
_impl->world_connection->SetOnRoutedMessageHandler([this](const std::string& filter, const std::string& identifier, const std::string& id, const EQ::Net::Packet& payload) {
|
||||
OnRoutedMessage(filter, identifier, id, payload);
|
||||
});
|
||||
_impl->last_time = std::chrono::steady_clock::now();
|
||||
|
||||
_impl->heartbeat_timer.reset(new EQ::Timer(_impl->heartbeat_duration_ms, true, [this](EQ::Timer *t) {
|
||||
auto now = std::chrono::steady_clock::now();
|
||||
auto time_since = std::chrono::duration_cast<std::chrono::duration<double>>(now - _impl->last_time);
|
||||
OnHeartbeat(time_since.count());
|
||||
_impl->last_time = now;
|
||||
}));
|
||||
|
||||
auto &loop = EQ::EventLoop::Get();
|
||||
auto sleep_duration = _impl->sleep_duration_ms;
|
||||
while (_impl->running) {
|
||||
loop.Process();
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(sleep_duration));
|
||||
}
|
||||
|
||||
_impl->heartbeat_timer.release();
|
||||
_impl->world_connection.release();
|
||||
|
||||
OnStop();
|
||||
}
|
||||
|
||||
void EQ::Service::RouteMessage(const std::string &filter, const std::string &id, const EQ::Net::Packet &p)
|
||||
{
|
||||
_impl->world_connection->RouteMessage(filter, id, p);
|
||||
}
|
||||
|
||||
void EQ::Service::Stop() {
|
||||
_impl->running = false;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
#include "world_connection.h"
|
||||
#include "net/packet.h"
|
||||
#include "eqemu_logsys.h"
|
||||
#include "platform.h"
|
||||
#include "crash.h"
|
||||
|
||||
#define EQRegisterService(type) EQEmuLogSys LogSys; \
|
||||
int main(int argc, char **argv) { \
|
||||
LogSys.LoadLogSettingsDefaults(); \
|
||||
set_exception_handler(); \
|
||||
type srv; \
|
||||
srv.Run(); \
|
||||
return 0; \
|
||||
} \
|
||||
|
||||
namespace EQ
|
||||
{
|
||||
class Service
|
||||
{
|
||||
public:
|
||||
Service(const std::string &identifier, size_t heartbeat_duration_ms, size_t sleep_duration);
|
||||
virtual ~Service();
|
||||
|
||||
void Run();
|
||||
|
||||
protected:
|
||||
virtual void OnStart() = 0;
|
||||
virtual void OnStop() = 0;
|
||||
virtual void OnHeartbeat(double time_since_last) = 0;
|
||||
virtual void OnRoutedMessage(const std::string& filter, const std::string& identifier, const std::string& id, const EQ::Net::Packet& payload) = 0;
|
||||
|
||||
void RouteMessage(const std::string &filter, const std::string &id, const EQ::Net::Packet& p);
|
||||
void Stop();
|
||||
private:
|
||||
struct Impl;
|
||||
std::unique_ptr<Impl> _impl;
|
||||
};
|
||||
}
|
||||
+1
-1
@@ -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
|
||||
|
||||
+1
-1
@@ -31,7 +31,7 @@
|
||||
*/
|
||||
|
||||
|
||||
#define CURRENT_BINARY_DATABASE_VERSION 9138
|
||||
#define CURRENT_BINARY_DATABASE_VERSION 9139
|
||||
|
||||
#ifdef BOTS
|
||||
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9022
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
#include "world_connection.h"
|
||||
#include "eqemu_config.h"
|
||||
#include "string_util.h"
|
||||
|
||||
EQ::WorldConnection::WorldConnection(const std::string &type) {
|
||||
auto config = EQEmuConfig::get();
|
||||
|
||||
m_connection.reset(new EQ::Net::ServertalkClient(config->WorldIP, config->WorldTCPPort, false, type, config->SharedKey));
|
||||
m_connection->OnConnect([this](EQ::Net::ServertalkClient *client) {
|
||||
if (m_on_connected) {
|
||||
m_on_connected();
|
||||
}
|
||||
});
|
||||
|
||||
m_connection->OnMessage(std::bind(&WorldConnection::_HandleMessage, this, std::placeholders::_1, std::placeholders::_2));
|
||||
m_connection->OnMessage(ServerOP_RouteTo, std::bind(&WorldConnection::_HandleRoutedMessage, this, std::placeholders::_1, std::placeholders::_2));
|
||||
}
|
||||
|
||||
EQ::WorldConnection::~WorldConnection() {
|
||||
|
||||
}
|
||||
|
||||
void EQ::WorldConnection::SendPacket(ServerPacket* pack) {
|
||||
m_connection->SendPacket(pack);
|
||||
}
|
||||
|
||||
std::string EQ::WorldConnection::GetIP() const {
|
||||
return m_connection->Handle()->RemoteIP();
|
||||
}
|
||||
|
||||
uint16 EQ::WorldConnection::GetPort() const {
|
||||
return m_connection->Handle()->RemotePort();
|
||||
}
|
||||
|
||||
bool EQ::WorldConnection::Connected() const {
|
||||
return m_connection->Connected();
|
||||
}
|
||||
|
||||
void EQ::WorldConnection::RouteMessage(const std::string &filter, const std::string &id, const EQ::Net::Packet& payload)
|
||||
{
|
||||
if (!m_connection->Connected()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto identifier = m_connection->GetIdentifier();
|
||||
|
||||
RouteToMessage msg;
|
||||
strn0cpy(msg.filter, filter.c_str(), 32);
|
||||
strn0cpy(msg.identifier, identifier.c_str(), 32);
|
||||
strn0cpy(msg.id, id.c_str(), 32);
|
||||
|
||||
EQ::Net::DynamicPacket out;
|
||||
out.Reserve(sizeof(RouteToMessage) + payload.Length());
|
||||
out.PutData(0, &msg, sizeof(RouteToMessage));
|
||||
out.PutPacket(sizeof(RouteToMessage), payload);
|
||||
|
||||
m_connection->Send(ServerOP_RouteTo, out);
|
||||
}
|
||||
|
||||
void EQ::WorldConnection::_HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
|
||||
{
|
||||
if (m_on_message) {
|
||||
m_on_message(opcode, p);
|
||||
}
|
||||
}
|
||||
|
||||
void EQ::WorldConnection::_HandleRoutedMessage(uint16 opcode, const EQ::Net::Packet &p)
|
||||
{
|
||||
if (m_on_routed_message) {
|
||||
auto msg = (RouteToMessage*)p.Data();
|
||||
auto payload = p.GetPacket(sizeof(RouteToMessage), p.Length() - sizeof(RouteToMessage));
|
||||
|
||||
m_on_routed_message(msg->filter, msg->identifier, msg->id, payload);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
#pragma once
|
||||
|
||||
#include "eq_packet_structs.h"
|
||||
#include "net/servertalk_client_connection.h"
|
||||
#include <functional>
|
||||
|
||||
namespace EQ
|
||||
{
|
||||
class WorldConnection
|
||||
{
|
||||
public:
|
||||
typedef std::function<void()> OnConnectedHandler;
|
||||
typedef std::function<void(uint16, const EQ::Net::Packet&)> OnMessageHandler;
|
||||
typedef std::function<void(const std::string&, const std::string&, const std::string&, const EQ::Net::Packet&)> OnRoutedMessageHandler;
|
||||
|
||||
WorldConnection(const std::string &type);
|
||||
virtual ~WorldConnection();
|
||||
|
||||
void SendPacket(ServerPacket* pack);
|
||||
std::string GetIP() const;
|
||||
uint16 GetPort() const;
|
||||
bool Connected() const;
|
||||
|
||||
void SetOnConnectedHandler(OnConnectedHandler handler) {
|
||||
m_on_connected = handler;
|
||||
};
|
||||
|
||||
void SetOnMessageHandler(OnMessageHandler handler) {
|
||||
m_on_message = handler;
|
||||
};
|
||||
|
||||
void SetOnRoutedMessageHandler(OnRoutedMessageHandler handler) {
|
||||
m_on_routed_message = handler;
|
||||
}
|
||||
|
||||
void RouteMessage(const std::string &filter, const std::string &id, const EQ::Net::Packet& payload);
|
||||
|
||||
protected:
|
||||
OnConnectedHandler m_on_connected;
|
||||
OnMessageHandler m_on_message;
|
||||
OnRoutedMessageHandler m_on_routed_message;
|
||||
std::unique_ptr<EQ::Net::ServertalkClient> m_connection;
|
||||
|
||||
private:
|
||||
void _HandleMessage(uint16 opcode, const EQ::Net::Packet& p);
|
||||
void _HandleRoutedMessage(uint16 opcode, const EQ::Net::Packet& p);
|
||||
};
|
||||
}
|
||||
@@ -25,16 +25,14 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#include "zone_launch.h"
|
||||
|
||||
WorldServer::WorldServer(std::map<std::string, ZoneLaunch *> &zones, const char *name, const EQEmuConfig *config)
|
||||
: m_name(name),
|
||||
:
|
||||
WorldConnection::WorldConnection("Launcher"),
|
||||
m_name(name),
|
||||
m_config(config),
|
||||
m_zones(zones)
|
||||
{
|
||||
m_connection.reset(new EQ::Net::ServertalkClient(config->WorldIP, config->WorldTCPPort, false, "Launcher", config->SharedKey));
|
||||
m_connection->OnConnect([this](EQ::Net::ServertalkClient *client) {
|
||||
OnConnected();
|
||||
});
|
||||
|
||||
m_connection->OnMessage(std::bind(&WorldServer::HandleMessage, this, std::placeholders::_1, std::placeholders::_2));
|
||||
SetOnConnectedHandler(std::bind(&WorldServer::OnConnected, this));
|
||||
SetOnMessageHandler(std::bind(&WorldServer::HandleMessage, this, std::placeholders::_1, std::placeholders::_2));
|
||||
}
|
||||
|
||||
WorldServer::~WorldServer() {
|
||||
@@ -57,19 +55,11 @@ void WorldServer::OnConnected() {
|
||||
}
|
||||
}
|
||||
|
||||
void WorldServer::HandleMessage(uint16 opcode, EQ::Net::Packet &p) {
|
||||
void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
|
||||
ServerPacket tpack(opcode, p);
|
||||
ServerPacket *pack = &tpack;
|
||||
|
||||
switch (opcode) {
|
||||
case 0: {
|
||||
break;
|
||||
}
|
||||
case ServerOP_EmoteMessage:
|
||||
case ServerOP_KeepAlive: {
|
||||
// ignore this
|
||||
break;
|
||||
}
|
||||
case ServerOP_LauncherZoneRequest: {
|
||||
if (pack->size != sizeof(LauncherZoneRequest)) {
|
||||
Log(Logs::Detail, Logs::Launcher, "Invalid size of LauncherZoneRequest: %d", pack->size);
|
||||
@@ -126,8 +116,6 @@ void WorldServer::HandleMessage(uint16 opcode, EQ::Net::Packet &p) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void WorldServer::SendStatus(const char *short_name, uint32 start_count, bool running) {
|
||||
auto pack = new ServerPacket(ServerOP_LauncherZoneStatus, sizeof(LauncherZoneStatus));
|
||||
LauncherZoneStatus* it = (LauncherZoneStatus*)pack->pBuffer;
|
||||
@@ -138,4 +126,4 @@ void WorldServer::SendStatus(const char *short_name, uint32 start_count, bool ru
|
||||
|
||||
m_connection->SendPacket(pack);
|
||||
safe_delete(pack);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,28 +18,23 @@
|
||||
#ifndef WORLDSERVER_H
|
||||
#define WORLDSERVER_H
|
||||
|
||||
#include "../common/net/servertalk_client_connection.h"
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include "../common/world_connection.h"
|
||||
#include <queue>
|
||||
#include <map>
|
||||
|
||||
class ZoneLaunch;
|
||||
class EQEmuConfig;
|
||||
|
||||
class WorldServer {
|
||||
class WorldServer : public EQ::WorldConnection {
|
||||
public:
|
||||
WorldServer(std::map<std::string, ZoneLaunch *> &zones, const char *name, const EQEmuConfig *config);
|
||||
~WorldServer();
|
||||
|
||||
void HandleMessage(uint16 opcode, EQ::Net::Packet &p);
|
||||
|
||||
void SendStatus(const char *short_name, uint32 start_count, bool running);
|
||||
|
||||
private:
|
||||
virtual void OnConnected();
|
||||
void HandleMessage(uint16 opcode, const EQ::Net::Packet &p);
|
||||
void OnConnected();
|
||||
|
||||
std::unique_ptr<EQ::Net::ServertalkClient> m_connection;
|
||||
const char *const m_name;
|
||||
const EQEmuConfig *const m_config;
|
||||
std::map<std::string, ZoneLaunch *> &m_zones;
|
||||
|
||||
@@ -256,13 +256,15 @@ void ServerManager::DestroyServerByName(std::string l_name, std::string s_name,
|
||||
while (iter != world_servers.end()) {
|
||||
if ((*iter).get() == ignore) {
|
||||
++iter;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((*iter)->GetLongName().compare(l_name) == 0 && (*iter)->GetShortName().compare(s_name) == 0) {
|
||||
(*iter)->GetConnection()->Handle()->Disconnect();
|
||||
iter = world_servers.erase(iter);
|
||||
continue;
|
||||
}
|
||||
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include "../common/packet_dump.h"
|
||||
#include "../common/rulesys.h"
|
||||
|
||||
extern WorldServer *worldserver;
|
||||
extern std::unique_ptr<WorldServer> worldserver;
|
||||
extern Database database;
|
||||
|
||||
PlayerLookingForGuild::PlayerLookingForGuild(char *Name, char *Comments, uint32 Level, uint32 Class, uint32 AACount, uint32 Timezone, uint32 TimePosted)
|
||||
|
||||
@@ -39,7 +39,7 @@ Database database;
|
||||
LFGuildManager lfguildmanager;
|
||||
std::string WorldShortName;
|
||||
const queryservconfig *Config;
|
||||
WorldServer *worldserver = 0;
|
||||
std::unique_ptr<WorldServer> worldserver;
|
||||
EQEmuLogSys LogSys;
|
||||
|
||||
void CatchSignal(int sig_num) {
|
||||
@@ -88,8 +88,7 @@ int main() {
|
||||
}
|
||||
|
||||
/* Initial Connection to Worldserver */
|
||||
worldserver = new WorldServer;
|
||||
worldserver->Connect();
|
||||
worldserver.reset(new WorldServer());
|
||||
|
||||
/* Load Looking For Guild Manager */
|
||||
lfguildmanager.LoadDatabase();
|
||||
|
||||
@@ -43,49 +43,18 @@ extern Database database;
|
||||
extern LFGuildManager lfguildmanager;
|
||||
|
||||
WorldServer::WorldServer()
|
||||
: WorldConnection::WorldConnection("QueryServ")
|
||||
{
|
||||
SetOnMessageHandler(std::bind(&WorldServer::HandleMessage, this, std::placeholders::_1, std::placeholders::_2));
|
||||
}
|
||||
|
||||
WorldServer::~WorldServer()
|
||||
{
|
||||
}
|
||||
|
||||
void WorldServer::Connect()
|
||||
{
|
||||
m_connection.reset(new EQ::Net::ServertalkClient(Config->WorldIP, Config->WorldTCPPort, false, "QueryServ", Config->SharedKey));
|
||||
m_connection->OnMessage(std::bind(&WorldServer::HandleMessage, this, std::placeholders::_1, std::placeholders::_2));
|
||||
}
|
||||
|
||||
bool WorldServer::SendPacket(ServerPacket *pack)
|
||||
{
|
||||
m_connection->SendPacket(pack);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string WorldServer::GetIP() const
|
||||
{
|
||||
return m_connection->Handle()->RemoteIP();
|
||||
}
|
||||
|
||||
uint16 WorldServer::GetPort() const
|
||||
{
|
||||
return m_connection->Handle()->RemotePort();
|
||||
}
|
||||
|
||||
bool WorldServer::Connected() const
|
||||
{
|
||||
return m_connection->Connected();
|
||||
}
|
||||
|
||||
void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
|
||||
{
|
||||
switch (opcode) {
|
||||
case 0: {
|
||||
break;
|
||||
}
|
||||
case ServerOP_KeepAlive: {
|
||||
break;
|
||||
}
|
||||
case ServerOP_Speech: {
|
||||
Server_Speech_Struct *SSS = (Server_Speech_Struct*)p.Data();
|
||||
std::string tmp1 = SSS->from;
|
||||
@@ -185,4 +154,4 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-10
@@ -18,20 +18,13 @@
|
||||
#ifndef WORLDSERVER_H
|
||||
#define WORLDSERVER_H
|
||||
|
||||
#include "../common/eq_packet_structs.h"
|
||||
#include "../common/net/servertalk_client_connection.h"
|
||||
#include "../common/world_connection.h"
|
||||
|
||||
class WorldServer
|
||||
class WorldServer : public EQ::WorldConnection
|
||||
{
|
||||
public:
|
||||
WorldServer();
|
||||
~WorldServer();
|
||||
|
||||
void Connect();
|
||||
bool SendPacket(ServerPacket* pack);
|
||||
std::string GetIP() const;
|
||||
uint16 GetPort() const;
|
||||
bool Connected() const;
|
||||
virtual ~WorldServer();
|
||||
|
||||
void HandleMessage(uint16 opcode, const EQ::Net::Packet &p);
|
||||
private:
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
|
||||
|
||||
SET(service_sources
|
||||
tasks_database.cpp
|
||||
tasks_service.cpp
|
||||
)
|
||||
|
||||
SET(service_headers
|
||||
tasks_database.h
|
||||
tasks_service.h
|
||||
)
|
||||
|
||||
ADD_EXECUTABLE(tasks_service ${service_sources} ${service_headers})
|
||||
|
||||
INSTALL(TARGETS tasks_service RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
|
||||
|
||||
TARGET_LINK_LIBRARIES(tasks_service ${SERVER_LIBS})
|
||||
|
||||
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
|
||||
@@ -0,0 +1,17 @@
|
||||
#include "tasks_database.h"
|
||||
|
||||
TasksDatabase::TasksDatabase()
|
||||
: Database()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
TasksDatabase::TasksDatabase(const char* host, const char* user, const char* passwd, const char* database, uint32 port)
|
||||
: Database(host, user, passwd, database, port)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
TasksDatabase::~TasksDatabase() {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../common/global_define.h"
|
||||
#include "../../common/types.h"
|
||||
#include "../../common/database.h"
|
||||
|
||||
class TasksDatabase : public Database {
|
||||
public:
|
||||
TasksDatabase();
|
||||
TasksDatabase(const char* host, const char* user, const char* passwd, const char* database, uint32 port);
|
||||
~TasksDatabase();
|
||||
};
|
||||
@@ -0,0 +1,70 @@
|
||||
#include "tasks_service.h"
|
||||
#include "../../common/eqemu_logsys.h"
|
||||
#include "../../common/eqemu_config.h"
|
||||
|
||||
EQ::TasksService::TasksService()
|
||||
: EQ::Service("Tasks", 100, 1)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
EQ::TasksService::~TasksService() {
|
||||
|
||||
}
|
||||
|
||||
void EQ::TasksService::OnStart() {
|
||||
Log(Logs::General, Logs::Status, "Connecting to database...");
|
||||
|
||||
auto config = EQEmuConfig::get();
|
||||
|
||||
m_db.reset(new TasksDatabase());
|
||||
|
||||
auto r = m_db->Connect(
|
||||
config->DatabaseHost.c_str(),
|
||||
config->DatabaseUsername.c_str(),
|
||||
config->DatabasePassword.c_str(),
|
||||
config->DatabaseDB.c_str(),
|
||||
config->DatabasePort);
|
||||
|
||||
if (false == r) {
|
||||
Log(Logs::General, Logs::Status, "Unable to connect to database.");
|
||||
Stop();
|
||||
return;
|
||||
}
|
||||
|
||||
Log(Logs::General, Logs::Status, "Connected to database.");
|
||||
|
||||
m_db->LoadLogSettings(LogSys.log_settings);
|
||||
LogSys.StartFileLogs();
|
||||
|
||||
//Load task info here
|
||||
}
|
||||
|
||||
void EQ::TasksService::OnStop() {
|
||||
m_db.release();
|
||||
}
|
||||
|
||||
void EQ::TasksService::OnHeartbeat(double time_since_last) {
|
||||
|
||||
}
|
||||
|
||||
void EQ::TasksService::OnRoutedMessage(const std::string& filter, const std::string& identifier, const std::string& id, const EQ::Net::Packet& payload)
|
||||
{
|
||||
LogF(Logs::General, Logs::Status, "On routed message with payload size {0}", payload.Length());
|
||||
|
||||
//auto msg_type = payload.GetInt32(0);
|
||||
//
|
||||
//switch (msg_type) {
|
||||
//case TaskGetClientTaskState:
|
||||
//{
|
||||
// Log(Logs::General, Logs::Status, "Task state request");
|
||||
// auto req = payload.GetSerialize<GetClientTaskStateRequest>(4);
|
||||
// //Get the task state request
|
||||
// break;
|
||||
//}
|
||||
//default:
|
||||
// break;
|
||||
//}
|
||||
}
|
||||
|
||||
EQRegisterService(EQ::TasksService);
|
||||
@@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../common/service.h"
|
||||
#include "tasks_database.h"
|
||||
|
||||
namespace EQ
|
||||
{
|
||||
class TasksService : public EQ::Service
|
||||
{
|
||||
public:
|
||||
TasksService();
|
||||
virtual ~TasksService();
|
||||
|
||||
protected:
|
||||
virtual void OnStart();
|
||||
virtual void OnStop();
|
||||
virtual void OnHeartbeat(double time_since_last);
|
||||
virtual void OnRoutedMessage(const std::string& filter, const std::string& identifier, const std::string& id, const EQ::Net::Packet& payload);
|
||||
|
||||
private:
|
||||
std::unique_ptr<TasksDatabase> m_db;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
|
||||
|
||||
SET(service_sources
|
||||
test1_service.cpp
|
||||
)
|
||||
|
||||
SET(service_headers
|
||||
test1_service.h
|
||||
)
|
||||
|
||||
ADD_EXECUTABLE(test1_service ${service_sources} ${service_headers})
|
||||
|
||||
INSTALL(TARGETS test1_service RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
|
||||
|
||||
TARGET_LINK_LIBRARIES(test1_service ${SERVER_LIBS})
|
||||
|
||||
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
|
||||
@@ -0,0 +1,61 @@
|
||||
#include "test1_service.h"
|
||||
#include "../../common/eqemu_logsys.h"
|
||||
#include "../../common/eqemu_config.h"
|
||||
|
||||
EQ::Test1Service::Test1Service()
|
||||
: EQ::Service("Test1", 1, 1)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
struct TestPacket
|
||||
{
|
||||
int64_t f1;
|
||||
int64_t f2;
|
||||
int64_t f3;
|
||||
int64_t f4;
|
||||
int64_t f5;
|
||||
int64_t f6;
|
||||
int64_t f7;
|
||||
char f8[4092];
|
||||
|
||||
template <class Archive>
|
||||
void serialize(Archive &ar)
|
||||
{
|
||||
ar(f1, f2, f3, f4, f5, f6, f7, f8);
|
||||
}
|
||||
};
|
||||
|
||||
EQ::Test1Service::~Test1Service() {
|
||||
|
||||
}
|
||||
|
||||
void EQ::Test1Service::OnStart() {
|
||||
|
||||
}
|
||||
|
||||
void EQ::Test1Service::OnStop() {
|
||||
}
|
||||
|
||||
void EQ::Test1Service::OnHeartbeat(double time_since_last) {
|
||||
TestPacket p;
|
||||
p.f1 = 33;
|
||||
p.f2 = 43;
|
||||
p.f3 = 56;
|
||||
p.f4 = 90;
|
||||
|
||||
EQ::Net::DynamicPacket out;
|
||||
out.PutInt32(0, 1234);
|
||||
out.PutSerialize(4, p);
|
||||
|
||||
for (int i = 0; i < 250; ++i) {
|
||||
RouteMessage("Test2", "", out);
|
||||
}
|
||||
}
|
||||
|
||||
void EQ::Test1Service::OnRoutedMessage(const std::string& filter, const std::string& identifier, const std::string& id, const EQ::Net::Packet& payload)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
EQRegisterService(EQ::Test1Service);
|
||||
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../common/service.h"
|
||||
|
||||
namespace EQ
|
||||
{
|
||||
class Test1Service : public EQ::Service
|
||||
{
|
||||
public:
|
||||
Test1Service();
|
||||
virtual ~Test1Service();
|
||||
|
||||
protected:
|
||||
virtual void OnStart();
|
||||
virtual void OnStop();
|
||||
virtual void OnHeartbeat(double time_since_last);
|
||||
virtual void OnRoutedMessage(const std::string& filter, const std::string& identifier, const std::string& id, const EQ::Net::Packet& payload);
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
|
||||
|
||||
SET(service_sources
|
||||
test2_service.cpp
|
||||
)
|
||||
|
||||
SET(service_headers
|
||||
test2_service.h
|
||||
)
|
||||
|
||||
ADD_EXECUTABLE(test2_service ${service_sources} ${service_headers})
|
||||
|
||||
INSTALL(TARGETS test2_service RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
|
||||
|
||||
TARGET_LINK_LIBRARIES(test2_service ${SERVER_LIBS})
|
||||
|
||||
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
|
||||
@@ -0,0 +1,40 @@
|
||||
#include "test2_service.h"
|
||||
#include "../../common/eqemu_logsys.h"
|
||||
#include "../../common/eqemu_config.h"
|
||||
|
||||
EQ::Test2Service::Test2Service()
|
||||
: EQ::Service("Test2", 3000, 1)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
EQ::Test2Service::~Test2Service() {
|
||||
|
||||
}
|
||||
|
||||
void EQ::Test2Service::OnStart() {
|
||||
bytes = 0;
|
||||
packets = 0;
|
||||
}
|
||||
|
||||
void EQ::Test2Service::OnStop() {
|
||||
}
|
||||
|
||||
void EQ::Test2Service::OnHeartbeat(double time_since_last) {
|
||||
|
||||
auto bytes_per_sec = bytes / time_since_last;
|
||||
auto packets_per_sec = packets / time_since_last;
|
||||
printf("Transfer rate %.2f KB/sec %.2f Packets/sec\n", bytes_per_sec / 1000.0, packets_per_sec);
|
||||
|
||||
bytes = 0;
|
||||
packets = 0;
|
||||
}
|
||||
|
||||
void EQ::Test2Service::OnRoutedMessage(const std::string& filter, const std::string& identifier, const std::string& id, const EQ::Net::Packet& payload)
|
||||
{
|
||||
bytes += sizeof(RouteToMessage);
|
||||
bytes += payload.Length();
|
||||
packets++;
|
||||
}
|
||||
|
||||
EQRegisterService(EQ::Test2Service);
|
||||
@@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../common/service.h"
|
||||
|
||||
namespace EQ
|
||||
{
|
||||
class Test2Service : public EQ::Service
|
||||
{
|
||||
public:
|
||||
Test2Service();
|
||||
virtual ~Test2Service();
|
||||
|
||||
protected:
|
||||
virtual void OnStart();
|
||||
virtual void OnStop();
|
||||
virtual void OnHeartbeat(double time_since_last);
|
||||
virtual void OnRoutedMessage(const std::string& filter, const std::string& identifier, const std::string& id, const EQ::Net::Packet& payload);
|
||||
|
||||
private:
|
||||
size_t bytes;
|
||||
size_t packets;
|
||||
};
|
||||
}
|
||||
+2
-2
@@ -40,7 +40,7 @@ ChatChannelList *ChannelList;
|
||||
Clientlist *g_Clientlist;
|
||||
EQEmuLogSys LogSys;
|
||||
Database database;
|
||||
WorldServer *worldserver = nullptr;
|
||||
std::unique_ptr<WorldServer> worldserver;
|
||||
|
||||
const ucsconfig *Config;
|
||||
|
||||
@@ -142,7 +142,7 @@ int main() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
worldserver = new WorldServer;
|
||||
worldserver.reset(new WorldServer());
|
||||
|
||||
while(RunLoops) {
|
||||
|
||||
|
||||
+3
-10
@@ -47,16 +47,16 @@ void Client50ToServerSayLink(std::string& serverSayLink, const std::string& clie
|
||||
void Client55ToServerSayLink(std::string& serverSayLink, const std::string& clientSayLink);
|
||||
|
||||
WorldServer::WorldServer()
|
||||
: WorldConnection::WorldConnection("UCS")
|
||||
{
|
||||
m_connection.reset(new EQ::Net::ServertalkClient(Config->WorldIP, Config->WorldTCPPort, false, "UCS", Config->SharedKey));
|
||||
m_connection->OnMessage(std::bind(&WorldServer::ProcessMessage, this, std::placeholders::_1, std::placeholders::_2));
|
||||
SetOnMessageHandler(std::bind(&WorldServer::ProcessMessage, this, std::placeholders::_1, std::placeholders::_2));
|
||||
}
|
||||
|
||||
WorldServer::~WorldServer()
|
||||
{
|
||||
}
|
||||
|
||||
void WorldServer::ProcessMessage(uint16 opcode, EQ::Net::Packet &p)
|
||||
void WorldServer::ProcessMessage(uint16 opcode, const EQ::Net::Packet &p)
|
||||
{
|
||||
ServerPacket tpack(opcode, p);
|
||||
ServerPacket *pack = &tpack;
|
||||
@@ -65,13 +65,6 @@ void WorldServer::ProcessMessage(uint16 opcode, EQ::Net::Packet &p)
|
||||
|
||||
switch (opcode)
|
||||
{
|
||||
case 0: {
|
||||
break;
|
||||
}
|
||||
case ServerOP_KeepAlive:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case ServerOP_UCSMessage:
|
||||
{
|
||||
char *Buffer = (char *)pack->pBuffer;
|
||||
|
||||
+3
-9
@@ -18,20 +18,14 @@
|
||||
#ifndef WORLDSERVER_H
|
||||
#define WORLDSERVER_H
|
||||
|
||||
#include "../net/servertalk_client_connection.h"
|
||||
#include "../common/eq_packet_structs.h"
|
||||
#include <memory>
|
||||
#include "../world_connection.h"
|
||||
|
||||
class WorldServer
|
||||
class WorldServer : public EQ::WorldConnection
|
||||
{
|
||||
public:
|
||||
WorldServer();
|
||||
~WorldServer();
|
||||
void ProcessMessage(uint16 opcode, EQ::Net::Packet &);
|
||||
|
||||
private:
|
||||
|
||||
std::unique_ptr<EQ::Net::ServertalkClient> m_connection;
|
||||
void ProcessMessage(uint16 opcode, const EQ::Net::Packet &p);
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
@@ -563,6 +563,8 @@ OP_TaskHistoryRequest=0x6cf6
|
||||
OP_TaskHistoryReply=0x25eb
|
||||
OP_DeclineAllTasks=0x0000
|
||||
OP_TaskRequestTimer=0x4b76
|
||||
OP_AcceptNewSharedTask=0x3e5e
|
||||
OP_SharedTaskMemberList=0x4ddb
|
||||
|
||||
# Title opcodes
|
||||
OP_NewTitlesAvailable=0x45d1
|
||||
|
||||
@@ -568,6 +568,8 @@ OP_TaskHistoryRequest=0x5f1c
|
||||
OP_TaskHistoryReply=0x3d05
|
||||
OP_DeclineAllTasks=0x0000
|
||||
OP_TaskRequestTimer=0x7a48
|
||||
OP_AcceptNewSharedTask=0x6646
|
||||
OP_SharedTaskMemberList=0x1e7d
|
||||
|
||||
# Title opcodes
|
||||
OP_NewTitlesAvailable=0x0d32
|
||||
|
||||
@@ -534,6 +534,8 @@ OP_TaskHistoryReply=0x3d2a # C
|
||||
OP_CancelTask=0x726b # C
|
||||
OP_DeclineAllTasks=0x0000 #
|
||||
OP_TaskRequestTimer=0x2e70
|
||||
OP_AcceptNewSharedTask=0x4751
|
||||
OP_SharedTaskMemberList=0x55f4
|
||||
|
||||
|
||||
OP_Shroud=0x6d1f
|
||||
|
||||
@@ -500,7 +500,7 @@ OP_TaskHistoryRequest=0x3035 #
|
||||
OP_TaskHistoryReply=0x3A60 #
|
||||
OP_CancelTask=0x4db6 #Xinu or 0x2c8c or 0x4db6
|
||||
OP_DeclineAllTasks=0x0000 #not sure, 12 bytes
|
||||
OP_TaskMemberList=0x3713
|
||||
#OP_TaskMemberList=0x3713
|
||||
OP_TaskMemberInvite=0x3cde
|
||||
OP_TaskMemberInviteResponse=0x6cab
|
||||
OP_TaskMemberChange=0x354a
|
||||
@@ -510,6 +510,8 @@ OP_TaskRemovePlayer=0x516f
|
||||
OP_TaskPlayerList=0x0ad6
|
||||
OP_TaskQuit=0x2c8c
|
||||
OP_TaskRequestTimer=0x0b08
|
||||
OP_AcceptNewSharedTask=0x5bed
|
||||
OP_SharedTaskMemberList=0x3713
|
||||
|
||||
#Title opcodes
|
||||
OP_NewTitlesAvailable=0x179c #
|
||||
|
||||
@@ -458,7 +458,7 @@ OP_TaskActivityComplete=0x54eb
|
||||
OP_CompletedTasks=0x76a2 # ShowEQ 10/27/05
|
||||
OP_TaskDescription=0x5ef7 # ShowEQ 10/27/05
|
||||
OP_TaskActivity=0x682d # ShowEQ 10/27/05
|
||||
OP_TaskMemberList=0x722f #not sure
|
||||
#OP_TaskMemberList=0x722f #not sure
|
||||
OP_OpenNewTasksWindow=0x5e7c #combined with OP_AvaliableTask I think
|
||||
OP_AvaliableTask=0x0000
|
||||
OP_AcceptNewTask=0x207f
|
||||
@@ -475,6 +475,8 @@ OP_TaskRemovePlayer=0x37b9
|
||||
OP_TaskPlayerList=0x3961
|
||||
OP_TaskQuit=0x35dd
|
||||
OP_TaskRequestTimer=0x6a1d
|
||||
OP_AcceptNewSharedTask=0x194d
|
||||
OP_SharedTaskMemberList=0x722f
|
||||
#task complete related: 0x0000 (24 bytes), 0x0000 (8 bytes), 0x0000 (4 bytes)
|
||||
|
||||
|
||||
|
||||
@@ -557,6 +557,8 @@ OP_TaskHistoryReply=0x4524 # C
|
||||
OP_CancelTask=0x3bf5 # C
|
||||
OP_DeclineAllTasks=0x0000 #
|
||||
OP_TaskRequestTimer=0x719e
|
||||
OP_AcceptNewSharedTask=0x6ded
|
||||
OP_SharedTaskMemberList=0x584e
|
||||
|
||||
# Title opcodes
|
||||
OP_NewTitlesAvailable=0x4b49 # C
|
||||
|
||||
@@ -637,7 +637,7 @@ sub do_self_update_check_routine {
|
||||
if ($OS eq "Linux") {
|
||||
system("chmod 755 eqemu_server.pl");
|
||||
}
|
||||
system("perl eqemu_server.pl start_from_world");
|
||||
exec("perl eqemu_server.pl ran_from_world");
|
||||
}
|
||||
}
|
||||
print "[Install] Done\n";
|
||||
@@ -1393,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(
|
||||
|
||||
@@ -392,6 +392,7 @@
|
||||
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
|
||||
|
||||
@@ -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)
|
||||
;
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE `npc_types` ADD COLUMN `model` SMALLINT(5) NOT NULL DEFAULT '0' AFTER `stuck_behavior`;
|
||||
@@ -0,0 +1,50 @@
|
||||
ALTER TABLE `tasks` ADD `reward_points` INT NOT NULL DEFAULT '0' AFTER `rewardmethod`;
|
||||
ALTER TABLE `tasks` ADD `reward_type` INT NOT NULL DEFAULT '0' AFTER `reward_points`;
|
||||
ALTER TABLE `tasks` ADD `replay_group` INT NOT NULL DEFAULT '0';
|
||||
ALTER TABLE `tasks` ADD `min_players` INT NOT NULL DEFAULT '0';
|
||||
ALTER TABLE `tasks` ADD `max_players` INT NOT NULL DEFAULT '0';
|
||||
ALTER TABLE `tasks` ADD `task_lock_step` INT NOT NULL DEFAULT '0';
|
||||
ALTER TABLE `tasks` ADD `instance_zone_id` INT NOT NULL DEFAULT '0';
|
||||
ALTER TABLE `tasks` ADD `zone_version` INT NOT NULL DEFAULT '0';
|
||||
ALTER TABLE `tasks` ADD `zone_in_zone_id` INT NOT NULL DEFAULT '0';
|
||||
ALTER TABLE `tasks` ADD `zone_in_x` FLOAT NOT NULL DEFAULT '0';
|
||||
ALTER TABLE `tasks` ADD `zone_in_y` FLOAT NOT NULL DEFAULT '0';
|
||||
ALTER TABLE `tasks` ADD `zone_in_object_id` TINYINT NOT NULL DEFAULT '0';
|
||||
ALTER TABLE `tasks` ADD `dest_x` FLOAT NOT NULL DEFAULT '0';
|
||||
ALTER TABLE `tasks` ADD `dest_y` FLOAT NOT NULL DEFAULT '0';
|
||||
ALTER TABLE `tasks` ADD `dest_z` FLOAT NOT NULL DEFAULT '0';
|
||||
ALTER TABLE `tasks` ADD `dest_h` FLOAT NOT NULL DEFAULT '0';
|
||||
CREATE TABLE `task_replay_groups` (
|
||||
`id` INT NOT NULL,
|
||||
`duration` INT NOT NULL,
|
||||
`name` VARCHAR(128) NOT NULL DEFAULT '',
|
||||
PRIMARY KEY(`id`)
|
||||
);
|
||||
CREATE TABLE `character_task_lockouts` (
|
||||
`character_id` INT NOT NULL,
|
||||
`replay_group` INT NOT NULL,
|
||||
`original_id` INT NOT NULL,
|
||||
`timestamp` INT NOT NULL,
|
||||
PRIMARY KEY(`character_id`, `replay_group`)
|
||||
);
|
||||
CREATE TABLE `shared_task_state` (
|
||||
`id` INT NOT NULL,
|
||||
`task_id` INT NOT NULL,
|
||||
`accepted_time` INT NOT NULL,
|
||||
`is_locked` TINYINT NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY(`id`)
|
||||
);
|
||||
CREATE TABLE `shared_task_activities` (
|
||||
`shared_task_id` INT NOT NULL,
|
||||
`activity_id` INT NOT NULL,
|
||||
`done_count` INT NOT NULL,
|
||||
`completed` TINYINT,
|
||||
PRIMARY KEY(`shared_task_id`, `activity_id`)
|
||||
);
|
||||
CREATE TABLE `shared_task_members` (
|
||||
`shared_task_id` INT NOT NULL,
|
||||
`character_id` INT NOT NULL,
|
||||
`character_name` VARCHAR(64) NOT NULL,
|
||||
`is_leader` TINYINT DEFAULT 0,
|
||||
PRIMARY KEY(shared_task_id, character_id)
|
||||
);
|
||||
@@ -23,6 +23,7 @@ data_buckets
|
||||
db_str
|
||||
doors
|
||||
eqtime
|
||||
faction_base_data
|
||||
faction_list
|
||||
faction_list_mod
|
||||
fear_hints
|
||||
|
||||
@@ -15,6 +15,8 @@ SET(world_sources
|
||||
login_server_list.cpp
|
||||
net.cpp
|
||||
queryserv.cpp
|
||||
router.cpp
|
||||
shared_tasks.cpp
|
||||
ucs.cpp
|
||||
web_interface.cpp
|
||||
web_interface_eqw.cpp
|
||||
@@ -42,6 +44,8 @@ SET(world_headers
|
||||
login_server_list.h
|
||||
net.h
|
||||
queryserv.h
|
||||
router.h
|
||||
shared_tasks.h
|
||||
sof_char_create_data.h
|
||||
ucs.h
|
||||
web_interface.h
|
||||
|
||||
@@ -1221,6 +1221,7 @@ void Client::EnterWorld(bool TryBootup) {
|
||||
}
|
||||
|
||||
cle->SetChar(charid, char_name);
|
||||
cle->LoadTaskLockouts();
|
||||
database.UpdateLiveChar(char_name, GetAccountID());
|
||||
|
||||
Log(Logs::General, Logs::World_Server,
|
||||
|
||||
@@ -25,6 +25,9 @@
|
||||
#include "world_config.h"
|
||||
#include "../common/guilds.h"
|
||||
#include "../common/string_util.h"
|
||||
#include "shared_tasks.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
extern uint32 numplayers;
|
||||
extern LoginServerList loginserverlist;
|
||||
@@ -50,6 +53,8 @@ ClientListEntry::ClientListEntry(uint32 in_id, uint32 iLSID, const char* iLoginN
|
||||
pLFGToLevel = 0;
|
||||
pLFGMatchFilter = false;
|
||||
memset(pLFGComments, 0, 64);
|
||||
shared_task_id = 0;
|
||||
m_shared_task = nullptr;
|
||||
}
|
||||
|
||||
ClientListEntry::ClientListEntry(uint32 in_id, uint32 iAccID, const char* iAccName, MD5& iMD5Pass, int16 iAdmin)
|
||||
@@ -71,6 +76,8 @@ ClientListEntry::ClientListEntry(uint32 in_id, uint32 iAccID, const char* iAccNa
|
||||
pLFGToLevel = 0;
|
||||
pLFGMatchFilter = false;
|
||||
memset(pLFGComments, 0, 64);
|
||||
shared_task_id = 0;
|
||||
m_shared_task = nullptr;
|
||||
}
|
||||
|
||||
ClientListEntry::ClientListEntry(uint32 in_id, ZoneServer* iZS, ServerClientList_Struct* scl, int8 iOnline)
|
||||
@@ -93,6 +100,8 @@ ClientListEntry::ClientListEntry(uint32 in_id, ZoneServer* iZS, ServerClientList
|
||||
pLFGToLevel = 0;
|
||||
pLFGMatchFilter = false;
|
||||
memset(pLFGComments, 0, 64);
|
||||
shared_task_id = 0;
|
||||
m_shared_task = nullptr;
|
||||
|
||||
if (iOnline >= CLE_Status_Zoning)
|
||||
Update(iZS, scl, iOnline);
|
||||
@@ -105,6 +114,8 @@ ClientListEntry::~ClientListEntry() {
|
||||
Camp(); // updates zoneserver's numplayers
|
||||
client_list.RemoveCLEReferances(this);
|
||||
}
|
||||
if (m_shared_task != nullptr)
|
||||
m_shared_task->MemberLeftGame(this);
|
||||
for (auto &elem : tell_queue)
|
||||
safe_delete_array(elem);
|
||||
tell_queue.clear();
|
||||
@@ -248,6 +259,8 @@ void ClientListEntry::ClearVars(bool iAll) {
|
||||
pLFG = 0;
|
||||
gm = 0;
|
||||
pClientVersion = 0;
|
||||
shared_task_id = 0;
|
||||
m_shared_task = nullptr;
|
||||
for (auto &elem : tell_queue)
|
||||
safe_delete_array(elem);
|
||||
tell_queue.clear();
|
||||
@@ -261,6 +274,9 @@ void ClientListEntry::Camp(ZoneServer* iZS) {
|
||||
LSUpdate(pzoneserver);
|
||||
}
|
||||
|
||||
if (m_shared_task != nullptr)
|
||||
m_shared_task->MemberLeftGame(this);
|
||||
|
||||
ClearVars();
|
||||
|
||||
stale = 0;
|
||||
@@ -331,3 +347,72 @@ void ClientListEntry::ProcessTellQueue()
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* returns expire timestamp
|
||||
*/
|
||||
|
||||
int ClientListEntry::GetTaskLockoutExpire(int id) const
|
||||
{
|
||||
auto it = std::find_if(m_task_replay_timers.begin(), m_task_replay_timers.end(),
|
||||
[id](const TaskTimer &a) { return a.ID == id; });
|
||||
|
||||
if (it != m_task_replay_timers.end())
|
||||
return it->expires;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* returns seconds until expires
|
||||
* returns <= 0 if expired
|
||||
*/
|
||||
|
||||
int ClientListEntry::GetTaskLockoutTimeLeft(int id) const
|
||||
{
|
||||
auto it = std::find_if(m_task_replay_timers.begin(), m_task_replay_timers.end(),
|
||||
[id](const TaskTimer &a) { return a.ID == id; });
|
||||
|
||||
if (it != m_task_replay_timers.end())
|
||||
return it->expires - time(nullptr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Cleans up expired lockouts from the DB
|
||||
*/
|
||||
bool ClientListEntry::CleanExpiredTaskLockouts() const
|
||||
{
|
||||
std::string query =
|
||||
StringFormat("DELETE FROM `character_task_lockouts` WHERE `character_id` = %i AND `timestamp` > %i", pcharid,
|
||||
Timer::GetCurrentTime());
|
||||
auto results = database.QueryDatabase(query);
|
||||
return results.Success();
|
||||
}
|
||||
|
||||
/*
|
||||
* Loads task lockouts
|
||||
*/
|
||||
bool ClientListEntry::LoadTaskLockouts()
|
||||
{
|
||||
CleanExpiredTaskLockouts();
|
||||
std::string query = StringFormat(
|
||||
"SELECT `replay_group`, `original_id`, `timestamp` FROM `character_task_lockouts` WHERE `character_id` = %i",
|
||||
pcharid);
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
return false;
|
||||
|
||||
if (results.RowCount() > 0) {
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
TaskTimer t;
|
||||
t.ID = atoi(row[0]);
|
||||
t.original_id = atoi(row[1]);
|
||||
t.expires = atoi(row[2]);
|
||||
m_task_replay_timers.push_back(t);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
//#include "../common/eq_packet_structs.h"
|
||||
#include "../common/servertalk.h"
|
||||
#include "../common/rulesys.h"
|
||||
#include "../common/global_tasks.h"
|
||||
#include <vector>
|
||||
|
||||
|
||||
@@ -18,6 +19,7 @@
|
||||
|
||||
class ZoneServer;
|
||||
struct ServerClientList_Struct;
|
||||
class SharedTask;
|
||||
|
||||
class ClientListEntry {
|
||||
public:
|
||||
@@ -88,6 +90,17 @@ public:
|
||||
inline void PushToTellQueue(ServerChannelMessage_Struct *scm) { tell_queue.push_back(scm); }
|
||||
void ProcessTellQueue();
|
||||
|
||||
// shared task stuff
|
||||
bool CleanExpiredTaskLockouts() const;
|
||||
bool LoadTaskLockouts();
|
||||
int GetTaskLockoutExpire(int id) const;
|
||||
int GetTaskLockoutTimeLeft(int id) const;
|
||||
inline int GetCurrentSharedTaskID() const { return shared_task_id; }
|
||||
inline void SetCurrentSharedTaskID(int in) { shared_task_id = in; }
|
||||
inline bool HasFreeSharedTaskSlot() const { return shared_task_id == 0; }
|
||||
inline void SetSharedTask(SharedTask *in) { m_shared_task = in; }
|
||||
inline SharedTask *GetSharedTask() const { return m_shared_task; }
|
||||
|
||||
private:
|
||||
void ClearVars(bool iAll = false);
|
||||
|
||||
@@ -129,6 +142,13 @@ private:
|
||||
bool pLFGMatchFilter;
|
||||
char pLFGComments[64];
|
||||
|
||||
// shared task stuff
|
||||
// stub for now
|
||||
int shared_task_id; // ID in the TaskManager
|
||||
SharedTask *m_shared_task; // just for quick reference so we can tell it to clean up our pointer
|
||||
|
||||
std::vector<TaskTimer> m_task_replay_timers;
|
||||
|
||||
// Tell Queue -- really a vector :D
|
||||
std::vector<ServerChannelMessage_Struct *> tell_queue;
|
||||
};
|
||||
|
||||
@@ -72,12 +72,6 @@ void LauncherLink::ProcessMessage(uint16 opcode, EQ::Net::Packet &p)
|
||||
ServerPacket *pack = &tpack;
|
||||
|
||||
switch (opcode) {
|
||||
case 0:
|
||||
break;
|
||||
case ServerOP_KeepAlive: {
|
||||
// ignore this
|
||||
break;
|
||||
}
|
||||
case ServerOP_ZAAuth: {
|
||||
Log(Logs::Detail, Logs::World_Server, "Got authentication from %s when they are already authenticated.", m_name.c_str());
|
||||
break;
|
||||
@@ -296,4 +290,4 @@ void LauncherLink::Shutdown() {
|
||||
auto pack = new ServerPacket(ServerOP_ShutdownAll);
|
||||
SendPacket(pack);
|
||||
delete pack;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,6 +83,8 @@ union semun {
|
||||
#include "queryserv.h"
|
||||
#include "web_interface.h"
|
||||
#include "console.h"
|
||||
#include "shared_tasks.h"
|
||||
#include "router.h"
|
||||
|
||||
#include "../common/net/servertalk_server.h"
|
||||
#include "../zone/data_bucket.h"
|
||||
@@ -103,6 +105,7 @@ bool holdzones = false;
|
||||
const WorldConfig *Config;
|
||||
EQEmuLogSys LogSys;
|
||||
WebInterfaceList web_interface;
|
||||
SharedTaskManager shared_tasks;
|
||||
|
||||
void CatchSignal(int sig_num);
|
||||
void CheckForServerScript(bool force_download = false);
|
||||
@@ -394,6 +397,9 @@ int main(int argc, char** argv) {
|
||||
adventure_manager.Load();
|
||||
adventure_manager.LoadLeaderboardInfo();
|
||||
|
||||
shared_tasks.LoadSharedTasks();
|
||||
shared_tasks.LoadSharedTaskState();
|
||||
|
||||
Log(Logs::General, Logs::World_Server, "Purging expired instances");
|
||||
database.PurgeExpiredInstances();
|
||||
|
||||
@@ -414,6 +420,7 @@ int main(int argc, char** argv) {
|
||||
std::unique_ptr<EQ::Net::ServertalkServer> server_connection;
|
||||
server_connection.reset(new EQ::Net::ServertalkServer());
|
||||
|
||||
Router router;
|
||||
EQ::Net::ServertalkServerOptions server_opts;
|
||||
server_opts.port = Config->WorldTCPPort;
|
||||
server_opts.ipv6 = false;
|
||||
@@ -497,6 +504,20 @@ 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);
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
#include "router.h"
|
||||
#include "../common/string_util.h"
|
||||
|
||||
Router::Router()
|
||||
{
|
||||
}
|
||||
|
||||
Router::~Router()
|
||||
{
|
||||
}
|
||||
|
||||
void Router::AddConnection(std::shared_ptr<EQ::Net::ServertalkServerConnection> connection)
|
||||
{
|
||||
m_connections.push_back(connection);
|
||||
connection->OnMessage(ServerOP_RouteTo, std::bind(&Router::OnRouterMessage, this, connection, std::placeholders::_1, std::placeholders::_2));
|
||||
}
|
||||
|
||||
void Router::RemoveConnection(std::shared_ptr<EQ::Net::ServertalkServerConnection> connection)
|
||||
{
|
||||
auto iter = m_connections.begin();
|
||||
while (iter != m_connections.end()) {
|
||||
if ((*iter) == connection) {
|
||||
m_connections.erase(iter);
|
||||
return;
|
||||
}
|
||||
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
|
||||
void Router::OnRouterMessage(std::shared_ptr<EQ::Net::ServertalkServerConnection> connection, uint16 opcode, const EQ::Net::Packet &p)
|
||||
{
|
||||
auto msg = (RouteToMessage*)p.Data();
|
||||
char to_id[32];
|
||||
strn0cpy(to_id, msg->id, 32);
|
||||
|
||||
strn0cpy(msg->id, connection->GetUUID().c_str(), 32);
|
||||
|
||||
|
||||
if (to_id[0] != '\0' && msg->filter[0] != '\0') {
|
||||
for (auto &connection : m_connections) {
|
||||
auto id = connection->GetUUID();
|
||||
auto identifier = connection->GetIdentifier();
|
||||
if (strcmp(to_id, id.c_str()) == 0) {
|
||||
connection->Send(ServerOP_RouteTo, p);
|
||||
}
|
||||
else if (strcmp(msg->filter, identifier.c_str()) == 0) {
|
||||
connection->Send(ServerOP_RouteTo, p);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (msg->filter[0] != '\0') {
|
||||
for (auto &connection : m_connections) {
|
||||
auto identifier = connection->GetIdentifier();
|
||||
if (strcmp(msg->filter, identifier.c_str()) == 0) {
|
||||
connection->Send(ServerOP_RouteTo, p);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (to_id[0] != '\0') {
|
||||
for (auto &connection : m_connections) {
|
||||
auto id = connection->GetUUID();
|
||||
if (strcmp(to_id, id.c_str()) == 0) {
|
||||
connection->Send(ServerOP_RouteTo, p);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (auto &connection : m_connections) {
|
||||
connection->Send(ServerOP_RouteTo, p);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include "../common/net/servertalk_server_connection.h"
|
||||
#include <memory>
|
||||
#include <list>
|
||||
|
||||
class Router
|
||||
{
|
||||
public:
|
||||
Router();
|
||||
~Router();
|
||||
|
||||
void AddConnection(std::shared_ptr<EQ::Net::ServertalkServerConnection> connection);
|
||||
void RemoveConnection(std::shared_ptr<EQ::Net::ServertalkServerConnection> connection);
|
||||
private:
|
||||
std::list<std::shared_ptr<EQ::Net::ServertalkServerConnection>> m_connections;
|
||||
|
||||
void OnRouterMessage(std::shared_ptr<EQ::Net::ServertalkServerConnection> connection, uint16 opcode, const EQ::Net::Packet &p);
|
||||
};
|
||||
@@ -0,0 +1,535 @@
|
||||
#include "../common/string_util.h"
|
||||
#include "cliententry.h"
|
||||
#include "clientlist.h"
|
||||
#include "shared_tasks.h"
|
||||
#include "worlddb.h"
|
||||
#include "zonelist.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
extern ClientList client_list;
|
||||
extern ZSList zoneserver_list;
|
||||
extern SharedTaskManager shared_tasks;
|
||||
|
||||
void SharedTaskManager::HandleTaskRequest(ServerPacket *pack)
|
||||
{
|
||||
if (!pack)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Things done in zone:
|
||||
* Verified we were requesting a shared task
|
||||
* Verified leader has a slot available (guess we should double check this one)
|
||||
* Verified leader met level reqs
|
||||
* Verified repeatable or not completed (not doing that here?)
|
||||
* Verified leader doesn't have a lock out
|
||||
* Verified the group/raid met min/max player counts
|
||||
*/
|
||||
|
||||
char tmp_str[64] = { 0 };
|
||||
int task_id = pack->ReadUInt32();
|
||||
int npc_id = pack->ReadUInt32();
|
||||
pack->ReadString(tmp_str);
|
||||
std::string leader_name = tmp_str;
|
||||
int player_count = pack->ReadUInt32();
|
||||
std::vector<std::string> players;
|
||||
for (int i = 0; i < player_count; ++i) {
|
||||
pack->ReadString(tmp_str);
|
||||
players.push_back(tmp_str);
|
||||
}
|
||||
|
||||
// check if the task exist, we only load shared tasks in world, so we know the type is correct if found
|
||||
auto it = task_information.find(task_id);
|
||||
if (it == task_information.end()) { // not loaded! bad id or not shared task
|
||||
auto pc = client_list.FindCharacter(leader_name.c_str());
|
||||
if (pc) {
|
||||
// failure TODO: appropriate message
|
||||
auto pack = new ServerPacket(ServerOP_TaskReject, leader_name.size() + 1 + 8);
|
||||
pack->WriteUInt32(0); // string ID or just generic fail message
|
||||
pack->WriteUInt32(npc_id);
|
||||
pack->WriteString(leader_name.c_str());
|
||||
zoneserver_list.SendPacket(pc->zone(), pc->instance(), pack);
|
||||
safe_delete(pack);
|
||||
} // oh well
|
||||
return;
|
||||
}
|
||||
|
||||
int id = GetNextID();
|
||||
auto ret = tasks.insert({id, {id, task_id}});
|
||||
if (!ret.second) {
|
||||
auto pc = client_list.FindCharacter(leader_name.c_str());
|
||||
if (pc) {
|
||||
// failure TODO: appropriate message
|
||||
auto pack = new ServerPacket(ServerOP_TaskReject, leader_name.size() + 1 + 8);
|
||||
pack->WriteUInt32(0); // string ID or just generic fail message
|
||||
pack->WriteUInt32(npc_id);
|
||||
pack->WriteString(leader_name.c_str());
|
||||
zoneserver_list.SendPacket(pc->zone(), pc->instance(), pack);
|
||||
safe_delete(pack);
|
||||
} // oh well
|
||||
return;
|
||||
}
|
||||
|
||||
auto cle_leader = client_list.FindCharacter(leader_name.c_str());
|
||||
if (cle_leader == nullptr) {// something went wrong
|
||||
tasks.erase(ret.first);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!cle_leader->HasFreeSharedTaskSlot()) { // they have a task already ...
|
||||
tasks.erase(ret.first);
|
||||
return;
|
||||
}
|
||||
|
||||
auto &task = ret.first->second;
|
||||
task.AddMember(leader_name, cle_leader, cle_leader->CharID(), true);
|
||||
|
||||
if (players.empty()) {
|
||||
// send instant success to leader
|
||||
SerializeBuffer buf(10);
|
||||
buf.WriteInt32(id); // shared task's ID
|
||||
buf.WriteInt32(task_id); // ID of the task's data
|
||||
buf.WriteInt32(npc_id); // NPC we're requesting from
|
||||
buf.WriteString(leader_name); // leader's name
|
||||
buf.WriteInt32(0); // member list minus leader
|
||||
|
||||
auto pack = new ServerPacket(ServerOP_TaskGrant, buf);
|
||||
zoneserver_list.SendPacket(cle_leader->zone(), cle_leader->instance(), pack);
|
||||
safe_delete(pack);
|
||||
|
||||
task.SetCLESharedTasks();
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto &&name : players) {
|
||||
// look up CLEs by name, tell them we need to know if they can be added
|
||||
auto cle = client_list.FindCharacter(name.c_str());
|
||||
if (cle) {
|
||||
// make sure we don't have a shared task already
|
||||
if (!cle->HasFreeSharedTaskSlot()) {
|
||||
// failure TODO: appropriate message
|
||||
auto pack = new ServerPacket(ServerOP_TaskReject, leader_name.size() + 1 + 8);
|
||||
pack->WriteUInt32(0); // string ID or just generic fail message
|
||||
pack->WriteUInt32(npc_id);
|
||||
pack->WriteString(leader_name.c_str());
|
||||
zoneserver_list.SendPacket(cle_leader->zone(), cle_leader->instance(), pack);
|
||||
safe_delete(pack);
|
||||
tasks.erase(ret.first);
|
||||
return;
|
||||
}
|
||||
|
||||
// make sure our level is right
|
||||
if (!AppropriateLevel(task_id, cle->level())) {
|
||||
// failure TODO: appropriate message
|
||||
auto pack = new ServerPacket(ServerOP_TaskReject, leader_name.size() + 1 + 8);
|
||||
pack->WriteUInt32(0); // string ID or just generic fail message
|
||||
pack->WriteUInt32(npc_id);
|
||||
pack->WriteString(leader_name.c_str());
|
||||
zoneserver_list.SendPacket(cle_leader->zone(), cle_leader->instance(), pack);
|
||||
safe_delete(pack);
|
||||
tasks.erase(ret.first);
|
||||
return;
|
||||
}
|
||||
|
||||
// check our lock out timer
|
||||
int expires = cle->GetTaskLockoutExpire(task_id);
|
||||
if ((expires - time(nullptr)) >= 0) {
|
||||
// failure TODO: appropriate message, we need to send the timestamp here
|
||||
auto pack = new ServerPacket(ServerOP_TaskReject, leader_name.size() + 1 + 8);
|
||||
pack->WriteUInt32(0); // string ID or just generic fail message
|
||||
pack->WriteUInt32(npc_id);
|
||||
pack->WriteString(leader_name.c_str());
|
||||
zoneserver_list.SendPacket(cle_leader->zone(), cle_leader->instance(), pack);
|
||||
safe_delete(pack);
|
||||
tasks.erase(ret.first);
|
||||
return;
|
||||
}
|
||||
|
||||
// we're good, add to task
|
||||
task.AddMember(name, cle, cle->CharID());
|
||||
}
|
||||
}
|
||||
|
||||
// this will also prevent any of these clients from requesting or being added to another, lets do it now before we tell zone
|
||||
task.SetCLESharedTasks();
|
||||
task.InitActivities();
|
||||
// fire off to zone we're done!
|
||||
SerializeBuffer buf(10 + 10 * players.size());
|
||||
buf.WriteInt32(id); // shared task's ID
|
||||
buf.WriteInt32(task_id); // ID of the task's data
|
||||
buf.WriteInt32(npc_id); // NPC we're requesting from
|
||||
buf.WriteInt32(task.GetAcceptedTime()); // time we accepted it
|
||||
buf.WriteString(leader_name); // leader's name
|
||||
task.SerializeMembers(buf, false); // everyone but leader
|
||||
|
||||
auto reply = new ServerPacket(ServerOP_TaskGrant, buf);
|
||||
zoneserver_list.SendPacket(cle_leader->zone(), cle_leader->instance(), reply);
|
||||
safe_delete(reply);
|
||||
|
||||
task.Save();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Just sends the ID of the task that was successfully created zone side
|
||||
* We now need to tell all the other clients to join the task
|
||||
* We could probably try to find all the clients already in the zone and not
|
||||
* worry about them here, but it's simpler this way
|
||||
*/
|
||||
void SharedTaskManager::HandleTaskZoneCreated(ServerPacket *pack)
|
||||
{
|
||||
if (!pack)
|
||||
return;
|
||||
|
||||
int id = pack->ReadUInt32();
|
||||
|
||||
auto task = GetSharedTask(id);
|
||||
|
||||
if (!task) // hmm guess we should tell zone something is broken TODO
|
||||
return;
|
||||
|
||||
// we reuse this, easier this way
|
||||
auto outpack = new ServerPacket(ServerOP_TaskZoneCreated, sizeof(ServerSharedTaskMember_Struct));
|
||||
auto stm = (ServerSharedTaskMember_Struct *)outpack->pBuffer;
|
||||
stm->id = id;
|
||||
|
||||
for (auto &&m : task->members) {
|
||||
if (m.leader) // leader done!
|
||||
continue;
|
||||
|
||||
if (!m.cle) // hmmm
|
||||
continue;
|
||||
|
||||
if (!m.cle->Server()) // hmm
|
||||
continue;
|
||||
|
||||
strn0cpy(stm->name, m.name.c_str(), 64);
|
||||
zoneserver_list.SendPacket(m.cle->zone(), m.cle->instance(), outpack);
|
||||
}
|
||||
|
||||
safe_delete(outpack);
|
||||
}
|
||||
|
||||
/*
|
||||
* Loads in the tasks and task_activity tables
|
||||
* We limit to shared to save some memory
|
||||
* This can be called while reloading tasks (because deving etc)
|
||||
* This data is loaded into the task_information map
|
||||
*/
|
||||
|
||||
bool SharedTaskManager::LoadSharedTasks(int single_task)
|
||||
{
|
||||
std::string query;
|
||||
|
||||
if (single_task == 0) {
|
||||
query =
|
||||
StringFormat("SELECT `id`, `type`, `duration`, `duration_code`, `title`, `description`, `reward`, "
|
||||
"`rewardid`, `cashreward`, `xpreward`, `rewardmethod`, `faction_reward`, `minlevel`, "
|
||||
"`maxlevel`, `repeatable`, `completion_emote`, `reward_points`, `reward_type`, "
|
||||
"`replay_group`, `min_players`, `max_players`, `task_lock_step`, `instance_zone_id`, "
|
||||
"`zone_version`, `zone_in_zone_id`, `zone_in_x`, `zone_in_y`, `zone_in_object_id`, "
|
||||
"`dest_x`, `dest_y`, `dest_z`, `dest_h` FROM `tasks` WHERE `type` = %i",
|
||||
static_cast<int>(TaskType::Shared));
|
||||
} else {
|
||||
query =
|
||||
StringFormat("SELECT `id`, `type`, `duration`, `duration_code`, `title`, `description`, `reward`, "
|
||||
"`rewardid`, `cashreward`, `xpreward`, `rewardmethod`, `faction_reward`, `minlevel`, "
|
||||
"`maxlevel`, `repeatable`, `completion_emote`, `reward_points`, `reward_type`, "
|
||||
"`replay_group`, `min_players`, `max_players`, `task_lock_step`, `instance_zone_id`, "
|
||||
"`zone_version`, `zone_in_zone_id`, `zone_in_x`, `zone_in_y`, `zone_in_object_id`, "
|
||||
"`dest_x`, `dest_y`, `dest_z`, `dest_h` FROM `tasks` WHERE `id` = %i AND `type` = %i",
|
||||
single_task, static_cast<int>(TaskType::Shared));
|
||||
}
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
int task_id = atoi(row[0]);
|
||||
|
||||
auto &task = task_information[task_id];
|
||||
task.type = static_cast<TaskType>(atoi(row[1]));
|
||||
task.Duration = atoi(row[2]);
|
||||
task.dur_code = static_cast<DurationCode>(atoi(row[3]));
|
||||
task.Title = row[4];
|
||||
task.Description = row[5];
|
||||
task.Reward = row[6];
|
||||
task.RewardID = atoi(row[7]);
|
||||
task.CashReward = atoi(row[8]);
|
||||
task.XPReward = atoi(row[9]);
|
||||
task.RewardMethod = (TaskMethodType)atoi(row[10]);
|
||||
task.faction_reward = atoi(row[11]);
|
||||
task.MinLevel = atoi(row[12]);
|
||||
task.MaxLevel = atoi(row[13]);
|
||||
task.Repeatable = atoi(row[14]);
|
||||
task.completion_emote = row[15];
|
||||
task.reward_points = atoi(row[16]);
|
||||
task.reward_type = static_cast<PointType>(atoi(row[17]));
|
||||
task.replay_group = atoi(row[18]);
|
||||
task.min_players = atoi(row[19]);
|
||||
task.max_players = atoi(row[20]);
|
||||
task.task_lock_step = atoi(row[21]);
|
||||
task.instance_zone_id = atoi(row[22]);
|
||||
task.zone_version = atoi(row[23]);
|
||||
task.zone_in_zone_id = atoi(row[24]);
|
||||
task.zone_in_x = atof(row[25]);
|
||||
task.zone_in_y = atof(row[26]);
|
||||
task.zone_in_object_id = atoi(row[27]);
|
||||
task.dest_x = atof(row[28]);
|
||||
task.dest_y = atof(row[29]);
|
||||
task.dest_z = atof(row[30]);
|
||||
task.dest_h = atof(row[31]);
|
||||
task.ActivityCount = 0;
|
||||
task.SequenceMode = ActivitiesSequential;
|
||||
task.LastStep = 0;
|
||||
}
|
||||
|
||||
// hmm need to limit to shared tasks only ...
|
||||
if (single_task == 0)
|
||||
query = StringFormat(
|
||||
"SELECT `taskid`, `step`, `activityid`, `activitytype`, `target_name`, `item_list`, `skill_list`, "
|
||||
"`spell_list`, `description_override`, `goalid`, `goalmethod`, `goalcount`, `delivertonpc`, "
|
||||
"`zones`, `optional` FROM `task_activities` WHERE `activityid` < %i AND `taskid` IN (SELECT `id` "
|
||||
"FROM `tasks` WHERE `type` = %i) ORDER BY taskid, activityid ASC",
|
||||
MAXACTIVITIESPERTASK, static_cast<int>(TaskType::Shared));
|
||||
else
|
||||
query = StringFormat(
|
||||
"SELECT `taskid`, `step`, `activityid`, `activitytype`, `target_name`, `item_list`, `skill_list`, "
|
||||
"`spell_list`, `description_override`, `goalid`, `goalmethod`, `goalcount`, `delivertonpc`, "
|
||||
"`zones`, `optional` FROM `task_activities` WHERE `taskid` = %i AND `activityid` < %i AND `taskid` "
|
||||
"IN (SELECT `id` FROM `tasks` WHERE `type` = %i) ORDER BY taskid, activityid ASC",
|
||||
single_task, MAXACTIVITIESPERTASK, static_cast<int>(TaskType::Shared));
|
||||
results = database.QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
int task_id = atoi(row[0]);
|
||||
int step = atoi(row[1]);
|
||||
|
||||
int activity_id = atoi(row[2]);
|
||||
|
||||
if (activity_id < 0 || activity_id >= MAXACTIVITIESPERTASK) {
|
||||
// This shouldn't happen, as the SELECT is bounded by MAXTASKS
|
||||
continue;
|
||||
}
|
||||
|
||||
if (task_information.count(task_id) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto &task = task_information[task_id];
|
||||
|
||||
task.Activity[task.ActivityCount].StepNumber = step;
|
||||
|
||||
if (step != 0)
|
||||
task.SequenceMode = ActivitiesStepped;
|
||||
|
||||
if (step > task.LastStep)
|
||||
task.LastStep = step;
|
||||
|
||||
// Task Activities MUST be numbered sequentially from 0. If not, log an error
|
||||
// and set the task to nullptr. Subsequent activities for this task will raise
|
||||
// ERR_NOTASK errors.
|
||||
// Change to (activityID != (task.ActivityCount + 1)) to index from 1
|
||||
if (activity_id != task.ActivityCount) {
|
||||
task_information.erase(task_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
task.Activity[task.ActivityCount].Type = atoi(row[3]);
|
||||
|
||||
task.Activity[task.ActivityCount].target_name = row[4];
|
||||
task.Activity[task.ActivityCount].item_list = row[5];
|
||||
task.Activity[task.ActivityCount].skill_list = row[6];
|
||||
task.Activity[task.ActivityCount].skill_id = atoi(row[6]); // for older clients
|
||||
task.Activity[task.ActivityCount].spell_list = row[7];
|
||||
task.Activity[task.ActivityCount].spell_id = atoi(row[7]); // for older clients
|
||||
task.Activity[task.ActivityCount].desc_override = row[8];
|
||||
|
||||
task.Activity[task.ActivityCount].GoalID = atoi(row[9]);
|
||||
task.Activity[task.ActivityCount].GoalMethod = (TaskMethodType)atoi(row[10]);
|
||||
task.Activity[task.ActivityCount].GoalCount = atoi(row[11]);
|
||||
task.Activity[task.ActivityCount].DeliverToNPC = atoi(row[12]);
|
||||
task.Activity[task.ActivityCount].zones = row[13];
|
||||
auto zones = SplitString(task.Activity[task.ActivityCount].zones, ';');
|
||||
for (auto && e : zones)
|
||||
task.Activity[task.ActivityCount].ZoneIDs.push_back(std::stoi(e));
|
||||
task.Activity[task.ActivityCount].Optional = atoi(row[14]);
|
||||
|
||||
task.ActivityCount++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is called once during boot of world
|
||||
* We need to load next_id, clean up expired tasks (?), and populate the map
|
||||
*/
|
||||
bool SharedTaskManager::LoadSharedTaskState()
|
||||
{
|
||||
// one may think we should clean up expired tasks, but we don't just in case world is booting back up after a crash
|
||||
// we will clean them up in the normal process loop so zones get told to clean up
|
||||
std::string query = "SELECT `id`, `task_id`, `accepted_time`, `is_locked` FROM `shared_task_state`";
|
||||
auto results = database.QueryDatabase(query);
|
||||
|
||||
if (results.Success() && results.RowCount() > 0) {
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
int id = atoi(row[0]);
|
||||
|
||||
auto &task = tasks[id];
|
||||
task.SetID(id);
|
||||
task.SetTaskID(atoi(row[1]));
|
||||
task.SetAcceptedTime(atoi(row[2]));
|
||||
task.SetLocked(atoi(row[3]) != 0);
|
||||
}
|
||||
}
|
||||
|
||||
query = "SELECT `shared_task_id`, `character_id`, `character_name`, `is_leader` FROM `shared_task_members` ORDER BY shared_task_id ASC";
|
||||
results = database.QueryDatabase(query);
|
||||
if (results.Success() && results.RowCount() > 0) {
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
int task_id = atoi(row[0]);
|
||||
// hmm not sure best way to do this, fine for now
|
||||
if (tasks.count(task_id) == 1)
|
||||
tasks[task_id].AddMember(row[2], nullptr, atoi(row[1]), atoi(row[3]) != 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Load existing tasks. We may not want to actually do this here and wait for a client to log in
|
||||
// But the crash case may actually dictate we should :P
|
||||
|
||||
// set next_id to highest used ID
|
||||
query = "SELECT IFNULL(MAX(id), 0) FROM shared_task_state";
|
||||
results = database.QueryDatabase(query);
|
||||
if (results.Success() && results.RowCount() == 1) {
|
||||
auto row = results.begin();
|
||||
next_id = atoi(row[0]);
|
||||
} else {
|
||||
next_id = 0; // oh well
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the next unused ID
|
||||
* Hopefully this does not grow too large.
|
||||
*/
|
||||
int SharedTaskManager::GetNextID()
|
||||
{
|
||||
next_id++;
|
||||
// let's not be extra clever here ...
|
||||
while (tasks.count(next_id) != 0)
|
||||
next_id++;
|
||||
|
||||
return next_id;
|
||||
}
|
||||
|
||||
/*
|
||||
* returns true if the level fits in the task's defined range
|
||||
*/
|
||||
bool SharedTaskManager::AppropriateLevel(int id, int level) const
|
||||
{
|
||||
auto it = task_information.find(id);
|
||||
// doesn't exist
|
||||
if (it == task_information.end())
|
||||
return false;
|
||||
|
||||
auto &task = it->second;
|
||||
|
||||
if (task.MinLevel && level < task.MinLevel)
|
||||
return false;
|
||||
|
||||
if (task.MaxLevel && level > task.MaxLevel)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* This will check if any tasks have expired
|
||||
*/
|
||||
void SharedTaskManager::Process()
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* When a player leaves world they will tell us to clean up their pointer
|
||||
* This is NOT leaving the shared task, just crashed or something
|
||||
*/
|
||||
|
||||
void SharedTask::MemberLeftGame(ClientListEntry *cle)
|
||||
{
|
||||
auto it = std::find_if(members.begin(), members.end(), [cle](SharedTaskMember &m) { return m.cle == cle; });
|
||||
|
||||
// ahh okay ...
|
||||
if (it == members.end())
|
||||
return;
|
||||
|
||||
it->cle = nullptr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Serializes Members into the SerializeBuffer
|
||||
* Starts with count then followed by names null-termed
|
||||
* In the future this will include monster mission shit
|
||||
* This should probably send the SharedMember struct or something more like it, fine for now
|
||||
*/
|
||||
void SharedTask::SerializeMembers(SerializeBuffer &buf, bool include_leader) const
|
||||
{
|
||||
buf.WriteInt32(include_leader ? members.size() : members.size() - 1);
|
||||
|
||||
for (auto && m : members) {
|
||||
if (!include_leader && m.leader)
|
||||
continue;
|
||||
|
||||
buf.WriteString(m.name);
|
||||
// TODO: live also has monster mission class choice in here
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This sets the CLE's quick look up shared task stuff
|
||||
*/
|
||||
void SharedTask::SetCLESharedTasks()
|
||||
{
|
||||
for (auto &&m : members) {
|
||||
if (m.cle == nullptr) // shouldn't happen ....
|
||||
continue;
|
||||
|
||||
m.cle->SetSharedTask(this);
|
||||
m.cle->SetCurrentSharedTaskID(id);
|
||||
}
|
||||
}
|
||||
|
||||
void SharedTask::Save() const
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* sets up activity stuff
|
||||
*/
|
||||
void SharedTask::InitActivities()
|
||||
{
|
||||
task_state.TaskID = task_id;
|
||||
task_state.AcceptedTime = time(nullptr);
|
||||
task_state.Updated = true;
|
||||
task_state.CurrentStep = -1;
|
||||
|
||||
for (int i = 0; i < shared_tasks.GetTaskActivityCount(task_id); i++) {
|
||||
task_state.Activity[i].ActivityID = i;
|
||||
task_state.Activity[i].DoneCount = 0;
|
||||
task_state.Activity[i].State = ActivityHidden;
|
||||
task_state.Activity[i].Updated = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool SharedTask::UnlockActivities()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
#ifndef SHARED_TASKS_H
|
||||
#define SHARED_TASKS_H
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "../common/servertalk.h"
|
||||
#include "../common/global_tasks.h"
|
||||
#include "cliententry.h"
|
||||
|
||||
class ClientListEntry;
|
||||
|
||||
struct SharedTaskMember {
|
||||
std::string name;
|
||||
ClientListEntry *cle;
|
||||
int char_id;
|
||||
bool leader;
|
||||
// TODO: monster mission stuff
|
||||
SharedTaskMember() : cle(nullptr), char_id(0), leader(false) {}
|
||||
SharedTaskMember(std::string name, ClientListEntry *cle, int char_id, bool leader)
|
||||
: name(name), cle(cle), char_id(char_id), leader(leader)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class SharedTask {
|
||||
public:
|
||||
SharedTask() : id(0), task_id(0), locked(false) {}
|
||||
SharedTask(int id, int task_id) : id(id), task_id(task_id), locked(false) {}
|
||||
~SharedTask() {}
|
||||
|
||||
void AddMember(std::string name, ClientListEntry *cle = nullptr, int char_id = 0, bool leader = false)
|
||||
{
|
||||
members.push_back({name, cle, char_id, leader});
|
||||
if (leader)
|
||||
leader_name = name;
|
||||
if (char_id == 0)
|
||||
return;
|
||||
auto it = std::find(char_ids.begin(), char_ids.end(), char_id);
|
||||
if (it == char_ids.end())
|
||||
char_ids.push_back(char_id);
|
||||
}
|
||||
void MemberLeftGame(ClientListEntry *cle);
|
||||
inline const std::string &GetLeaderName() const { return leader_name; }
|
||||
inline SharedTaskMember *GetLeader() {
|
||||
auto it = std::find_if(members.begin(), members.end(), [](const SharedTaskMember &m) { return m.leader; });
|
||||
if (it != members.end())
|
||||
return &(*it);
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void SerializeMembers(SerializeBuffer &buf, bool include_leader = true) const;
|
||||
void SetCLESharedTasks();
|
||||
void InitActivities();
|
||||
bool UnlockActivities();
|
||||
|
||||
void Save() const; // save to database
|
||||
|
||||
private:
|
||||
inline void SetID(int in) { id = in; }
|
||||
inline void SetTaskID(int in) { task_id = in; }
|
||||
inline void SetAcceptedTime(int in) { task_state.AcceptedTime = in; }
|
||||
inline void SetLocked(bool in) { locked = in; }
|
||||
|
||||
inline int GetAcceptedTime() const { return task_state.AcceptedTime; }
|
||||
int id; // id we have in our map
|
||||
int task_id; // ID of the task we're on
|
||||
bool locked;
|
||||
std::string leader_name;
|
||||
std::vector<SharedTaskMember> members;
|
||||
std::vector<int> char_ids; // every char id of someone to be locked out, different in case they leave/removed
|
||||
ClientTaskInformation task_state; // book keeping
|
||||
|
||||
friend class SharedTaskManager;
|
||||
};
|
||||
|
||||
class SharedTaskManager {
|
||||
public:
|
||||
SharedTaskManager() : next_id(0) {}
|
||||
~SharedTaskManager() {}
|
||||
|
||||
bool LoadSharedTaskState();
|
||||
bool LoadSharedTasks(int single_task = 0);
|
||||
|
||||
bool AppropriateLevel(int id, int level) const;
|
||||
|
||||
inline SharedTask *GetSharedTask(int id) {
|
||||
auto it = tasks.find(id);
|
||||
if (it != tasks.end())
|
||||
return &it->second;
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
inline int GetTaskActivityCount(int task_id) const {
|
||||
auto it = task_information.find(task_id);
|
||||
if (it != task_information.end())
|
||||
return it->second.ActivityCount;
|
||||
else
|
||||
return 0; // hmm
|
||||
}
|
||||
|
||||
// IPC packet processing
|
||||
void HandleTaskRequest(ServerPacket *pack);
|
||||
void HandleTaskZoneCreated(ServerPacket *pack);
|
||||
|
||||
void Process();
|
||||
|
||||
private:
|
||||
int GetNextID();
|
||||
int next_id;
|
||||
std::unordered_map<int, SharedTask> tasks; // current active shared task states
|
||||
std::unordered_map<int, TaskInformation> task_information; // task info shit
|
||||
};
|
||||
|
||||
#endif /* !SHARED_TASKS_H */
|
||||
@@ -36,14 +36,6 @@ void UCSConnection::ProcessPacket(uint16 opcode, EQ::Net::Packet &p)
|
||||
|
||||
switch (opcode)
|
||||
{
|
||||
case 0:
|
||||
break;
|
||||
|
||||
case ServerOP_KeepAlive:
|
||||
{
|
||||
// ignore this
|
||||
break;
|
||||
}
|
||||
case ServerOP_ZAAuth:
|
||||
{
|
||||
Log(Logs::Detail, Logs::UCS_Server, "Got authentication from UCS when they are already authenticated.");
|
||||
|
||||
@@ -43,7 +43,6 @@ ZSList::ZSList()
|
||||
memset(pLockedZones, 0, sizeof(pLockedZones));
|
||||
|
||||
m_tick.reset(new EQ::Timer(5000, true, std::bind(&ZSList::OnTick, this, std::placeholders::_1)));
|
||||
m_keepalive.reset(new EQ::Timer(2500, true, std::bind(&ZSList::OnKeepAlive, this, std::placeholders::_1)));
|
||||
}
|
||||
|
||||
ZSList::~ZSList() {
|
||||
@@ -748,9 +747,3 @@ void ZSList::OnTick(EQ::Timer *t)
|
||||
web_interface.SendEvent(out);
|
||||
}
|
||||
|
||||
void ZSList::OnKeepAlive(EQ::Timer *t)
|
||||
{
|
||||
for (auto &zone : list) {
|
||||
zone->SendKeepAlive();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,7 +63,6 @@ public:
|
||||
|
||||
private:
|
||||
void OnTick(EQ::Timer *t);
|
||||
void OnKeepAlive(EQ::Timer *t);
|
||||
uint32 NextID;
|
||||
std::list<std::unique_ptr<ZoneServer>> list;
|
||||
uint16 pLockedZones[MaxLockedZones];
|
||||
|
||||
+12
-13
@@ -35,6 +35,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#include "adventure_manager.h"
|
||||
#include "ucs.h"
|
||||
#include "queryserv.h"
|
||||
#include "shared_tasks.h"
|
||||
|
||||
extern ClientList client_list;
|
||||
extern GroupLFPList LFPGroupList;
|
||||
@@ -45,6 +46,7 @@ extern volatile bool UCSServerAvailable_;
|
||||
extern AdventureManager adventure_manager;
|
||||
extern UCSConnection UCSLink;
|
||||
extern QueryServConnection QSLink;
|
||||
extern SharedTaskManager shared_tasks;
|
||||
void CatchSignal(int sig_num);
|
||||
|
||||
ZoneServer::ZoneServer(std::shared_ptr<EQ::Net::ServertalkServerConnection> connection, EQ::Net::ConsoleServer *console)
|
||||
@@ -186,12 +188,6 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
|
||||
ServerPacket *pack = &tpack;
|
||||
|
||||
switch (opcode) {
|
||||
case 0:
|
||||
break;
|
||||
case ServerOP_KeepAlive: {
|
||||
// ignore this
|
||||
break;
|
||||
}
|
||||
case ServerOP_ZAAuth: {
|
||||
break;
|
||||
}
|
||||
@@ -1349,6 +1345,16 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
|
||||
cle->ProcessTellQueue();
|
||||
break;
|
||||
}
|
||||
case ServerOP_TaskRequest:
|
||||
{
|
||||
shared_tasks.HandleTaskRequest(pack);
|
||||
break;
|
||||
}
|
||||
case ServerOP_TaskZoneCreated:
|
||||
{
|
||||
shared_tasks.HandleTaskZoneCreated(pack);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
Log(Logs::Detail, Logs::World_Server, "Unknown ServerOPcode from zone 0x%04x, size %d", pack->opcode, pack->size);
|
||||
@@ -1405,13 +1411,6 @@ void ZoneServer::SendGroupIDs() {
|
||||
delete pack;
|
||||
}
|
||||
|
||||
|
||||
void ZoneServer::SendKeepAlive()
|
||||
{
|
||||
ServerPacket pack(ServerOP_KeepAlive, 0);
|
||||
SendPacket(&pack);
|
||||
}
|
||||
|
||||
void ZoneServer::ChangeWID(uint32 iCharID, uint32 iWID) {
|
||||
auto pack = new ServerPacket(ServerOP_ChangeWID, sizeof(ServerChangeWID_Struct));
|
||||
ServerChangeWID_Struct* scw = (ServerChangeWID_Struct*)pack->pBuffer;
|
||||
|
||||
@@ -39,7 +39,6 @@ public:
|
||||
void SendPacket(ServerPacket* pack) { tcpc->SendPacket(pack); }
|
||||
void SendEmoteMessage(const char* to, uint32 to_guilddbid, int16 to_minstatus, uint32 type, const char* message, ...);
|
||||
void SendEmoteMessageRaw(const char* to, uint32 to_guilddbid, int16 to_minstatus, uint32 type, const char* message);
|
||||
void SendKeepAlive();
|
||||
bool SetZone(uint32 iZoneID, uint32 iInstanceID = 0, bool iStaticZone = false);
|
||||
void TriggerBootup(uint32 iZoneID = 0, uint32 iInstanceID = 0, const char* iAdminName = 0, bool iMakeStatic = false);
|
||||
void Disconnect() { auto handle = tcpc->Handle(); if (handle) { handle->Disconnect(); } }
|
||||
|
||||
@@ -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;
|
||||
|
||||
+1
-1
@@ -56,7 +56,7 @@ Beacon::Beacon(Mob *at_mob, int lifetime)
|
||||
:Mob
|
||||
(
|
||||
nullptr, nullptr, 0, 0, 0, INVISIBLE_MAN, 0, BT_NoTarget, 0, 0, 0, 0, 0, at_mob->GetPosition(), 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, EQEmu::TintProfile(), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, EQEmu::TintProfile(), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
),
|
||||
remove_timer(lifetime),
|
||||
spell_timer(0)
|
||||
|
||||
+11
-2
@@ -1472,6 +1472,17 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon)
|
||||
newbon->trap_slots += base1;
|
||||
break;
|
||||
|
||||
case SE_ForageSkill:
|
||||
newbon->GrantForage += base1;
|
||||
// we need to grant a skill point here
|
||||
// I'd rather not do this here, but whatever, probably fine
|
||||
if (IsClient()) {
|
||||
auto client = CastToClient();
|
||||
if (client->GetRawSkill(EQEmu::skills::SkillType::SkillForage) == 0)
|
||||
client->SetSkill(EQEmu::skills::SkillType::SkillForage, 1);
|
||||
}
|
||||
break;
|
||||
|
||||
// to do
|
||||
case SE_PetDiscipline:
|
||||
break;
|
||||
@@ -1479,8 +1490,6 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon)
|
||||
break;
|
||||
case SE_BandolierSlots:
|
||||
break;
|
||||
case SE_ForageSkill:
|
||||
break;
|
||||
case SE_SecondaryForte:
|
||||
break;
|
||||
case SE_ExtendedShielding:
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
+20
-5
@@ -119,6 +119,7 @@ Client::Client(EQStreamInterface* ieqs)
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
),
|
||||
hpupdate_timer(2000),
|
||||
@@ -2603,9 +2604,12 @@ uint16 Client::GetMaxSkillAfterSpecializationRules(EQEmu::skills::SkillType skil
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Result += spellbonuses.RaiseSkillCap[skillid] + itembonuses.RaiseSkillCap[skillid] + aabonuses.RaiseSkillCap[skillid];
|
||||
|
||||
if (skillid == EQEmu::skills::SkillType::SkillForage)
|
||||
Result += aabonuses.GrantForage;
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
@@ -3392,6 +3396,11 @@ void Client::LinkDead()
|
||||
if(raid){
|
||||
raid->MemberZoned(this);
|
||||
}
|
||||
|
||||
auto shared_task = GetSharedTask();
|
||||
if (shared_task)
|
||||
shared_task->MemberZoned(this);
|
||||
|
||||
// save_timer.Start(2500);
|
||||
linkdead_timer.Start(RuleI(Zone,ClientLinkdeadMS));
|
||||
SendAppearancePacket(AT_Linkdead, 1);
|
||||
@@ -5608,6 +5617,12 @@ void Client::SuspendMinion()
|
||||
{
|
||||
if(m_suspendedminion.SpellID > 0)
|
||||
{
|
||||
if (m_suspendedminion.SpellID >= SPDAT_RECORDS) {
|
||||
Message(13, "Invalid suspended minion spell id (%u).", m_suspendedminion.SpellID);
|
||||
memset(&m_suspendedminion, 0, sizeof(PetInfo));
|
||||
return;
|
||||
}
|
||||
|
||||
MakePoweredPet(m_suspendedminion.SpellID, spells[m_suspendedminion.SpellID].teleport_zone,
|
||||
m_suspendedminion.petpower, m_suspendedminion.Name, m_suspendedminion.size);
|
||||
|
||||
@@ -7809,9 +7824,9 @@ void Client::SetFactionLevel(uint32 char_id, uint32 npc_id, uint8 char_class, ui
|
||||
//
|
||||
// Adjust these values for cases where starting faction is below
|
||||
// min or above max by not allowing any earn in those directions.
|
||||
this_faction_min = MIN_PERSONAL_FACTION - fm.base;
|
||||
this_faction_min = fm.min - fm.base;
|
||||
this_faction_min = std::min(0, this_faction_min);
|
||||
this_faction_max = MAX_PERSONAL_FACTION - fm.base;
|
||||
this_faction_max = fm.max - fm.base;
|
||||
this_faction_max = std::max(0, this_faction_max);
|
||||
|
||||
// Get the characters current value with that faction
|
||||
@@ -7852,9 +7867,9 @@ void Client::SetFactionLevel2(uint32 char_id, int32 faction_id, uint8 char_class
|
||||
// min or above max by not allowing any earn/loss in those directions.
|
||||
// At least one faction starts out way below min, so we don't want
|
||||
// to allow loses in those cases, just massive gains.
|
||||
this_faction_min = MIN_PERSONAL_FACTION - fm.base;
|
||||
this_faction_min = fm.min - fm.base;
|
||||
this_faction_min = std::min(0, this_faction_min);
|
||||
this_faction_max = MAX_PERSONAL_FACTION - fm.base;
|
||||
this_faction_max = fm.max - fm.base;
|
||||
this_faction_max = std::max(0, this_faction_max);
|
||||
|
||||
//Get the faction modifiers
|
||||
|
||||
+9
-2
@@ -791,7 +791,9 @@ public:
|
||||
uint32 GetCharMaxLevelFromQGlobal();
|
||||
uint32 GetCharMaxLevelFromBucket();
|
||||
|
||||
inline bool IsStanding() const {return (playeraction == 0);}
|
||||
inline bool IsSitting() const {return (playeraction == 1);}
|
||||
inline bool IsCrouching() const {return (playeraction == 2);}
|
||||
inline bool IsBecomeNPC() const { return npcflag; }
|
||||
inline uint8 GetBecomeNPCLevel() const { return npclevel; }
|
||||
inline void SetBecomeNPC(bool flag) { npcflag = flag; }
|
||||
@@ -1019,13 +1021,15 @@ public:
|
||||
inline void UpdateTasksOnExplore(int ExploreID) { if(taskstate) taskstate->UpdateTasksOnExplore(this, ExploreID); }
|
||||
inline bool UpdateTasksOnSpeakWith(int NPCTypeID) { if(taskstate) return taskstate->UpdateTasksOnSpeakWith(this, NPCTypeID); else return false; }
|
||||
inline bool UpdateTasksOnDeliver(std::list<EQEmu::ItemInstance*>& Items, int Cash, int NPCTypeID) { if (taskstate) return taskstate->UpdateTasksOnDeliver(this, Items, Cash, NPCTypeID); else return false; }
|
||||
inline void TaskSetSelector(Mob *mob, int TaskSetID) { if(taskmanager) taskmanager->TaskSetSelector(this, taskstate, mob, TaskSetID); }
|
||||
inline void TaskQuestSetSelector(Mob *mob, int count, int *tasks) { if(taskmanager) taskmanager->TaskQuestSetSelector(this, taskstate, mob, count, tasks); }
|
||||
inline void TaskSetSelector(Mob *mob, int TaskSetID, bool shared = false) { if(taskmanager) taskmanager->TaskSetSelector(this, taskstate, mob, TaskSetID, shared); }
|
||||
inline void TaskQuestSetSelector(Mob *mob, int count, int *tasks, bool shared = false) { if(taskmanager) taskmanager->TaskQuestSetSelector(this, taskstate, mob, count, tasks, shared); }
|
||||
inline void EnableTask(int TaskCount, int *TaskList) { if(taskstate) taskstate->EnableTask(CharacterID(), TaskCount, TaskList); }
|
||||
inline void DisableTask(int TaskCount, int *TaskList) { if(taskstate) taskstate->DisableTask(CharacterID(), TaskCount, TaskList); }
|
||||
inline bool IsTaskEnabled(int TaskID) { return (taskstate ? taskstate->IsTaskEnabled(TaskID) : false); }
|
||||
inline void ProcessTaskProximities(float X, float Y, float Z) { if(taskstate) taskstate->ProcessTaskProximities(this, X, Y, Z); }
|
||||
inline void AssignTask(int TaskID, int NPCID, bool enforce_level_requirement = false) { if (taskstate) taskstate->AcceptNewTask(this, TaskID, NPCID, enforce_level_requirement); }
|
||||
inline void AssignSharedTask(int TaskID, int NPCID, int id, int accepted_time, std::vector<std::string> &members) { if (taskstate) taskstate->AcceptNewSharedTask(this, TaskID, NPCID, id, accepted_time, members); }
|
||||
inline void AddToSharedTask(int TaskID) { if (taskstate) taskstate->AddToSharedTask(this, TaskID); }
|
||||
inline int ActiveSpeakTask(int NPCID) { if(taskstate) return taskstate->ActiveSpeakTask(NPCID); else return 0; }
|
||||
inline int ActiveSpeakActivity(int NPCID, int TaskID) { if(taskstate) return taskstate->ActiveSpeakActivity(NPCID, TaskID); else return 0; }
|
||||
inline void FailTask(int TaskID) { if(taskstate) taskstate->FailTask(this, TaskID); }
|
||||
@@ -1042,6 +1046,9 @@ public:
|
||||
inline int GetTaskActivityDoneCountFromTaskID(int TaskID, int ActivityID) { return (taskstate ? taskstate->GetTaskActivityDoneCountFromTaskID(TaskID, ActivityID) :0); }
|
||||
inline int ActiveTasksInSet(int TaskSet) { return (taskstate ? taskstate->ActiveTasksInSet(TaskSet) :0); }
|
||||
inline int CompletedTasksInSet(int TaskSet) { return (taskstate ? taskstate->CompletedTasksInSet(TaskSet) :0); }
|
||||
inline int GetTaskLockoutExpire(int id) { return 0; } // stub
|
||||
inline int GetTaskLockoutTimeLeft(int id) { return 0; } // stub
|
||||
inline SharedTaskState *GetSharedTask() { return taskstate ? taskstate->GetSharedTask() : nullptr; }
|
||||
|
||||
inline const EQEmu::versions::ClientVersion ClientVersion() const { return m_ClientVersion; }
|
||||
inline const uint32 ClientVersionBit() const { return m_ClientVersionBit; }
|
||||
|
||||
@@ -115,6 +115,7 @@ void MapOpcodes()
|
||||
ConnectedOpcodes[OP_0x0193] = &Client::Handle_0x0193;
|
||||
ConnectedOpcodes[OP_AAAction] = &Client::Handle_OP_AAAction;
|
||||
ConnectedOpcodes[OP_AcceptNewTask] = &Client::Handle_OP_AcceptNewTask;
|
||||
ConnectedOpcodes[OP_AcceptNewSharedTask] = &Client::Handle_OP_AcceptNewSharedTask;
|
||||
ConnectedOpcodes[OP_AdventureInfoRequest] = &Client::Handle_OP_AdventureInfoRequest;
|
||||
ConnectedOpcodes[OP_AdventureLeaderboardRequest] = &Client::Handle_OP_AdventureLeaderboardRequest;
|
||||
ConnectedOpcodes[OP_AdventureMerchantPurchase] = &Client::Handle_OP_AdventureMerchantPurchase;
|
||||
@@ -1787,6 +1788,20 @@ void Client::Handle_OP_AcceptNewTask(const EQApplicationPacket *app)
|
||||
taskstate->AcceptNewTask(this, ant->task_id, ant->task_master_id);
|
||||
}
|
||||
|
||||
void Client::Handle_OP_AcceptNewSharedTask(const EQApplicationPacket *app)
|
||||
{
|
||||
if (app->size != sizeof(AcceptNewSharedTask_Struct)) {
|
||||
Log(Logs::General, Logs::None, "Size mismatch in OP_AcceptNewSharedTask expected %i got %i",
|
||||
sizeof(AcceptNewSharedTask_Struct), app->size);
|
||||
DumpPacket(app);
|
||||
return;
|
||||
}
|
||||
auto *ant = (AcceptNewSharedTask_Struct*)app->pBuffer;
|
||||
|
||||
if (ant->task_id > 0 && RuleB(TaskSystem, EnableTaskSystem) && taskstate)
|
||||
taskstate->RequestSharedTask(this, ant->task_id, ant->task_master_id);
|
||||
}
|
||||
|
||||
void Client::Handle_OP_AdventureInfoRequest(const EQApplicationPacket *app)
|
||||
{
|
||||
if (app->size < sizeof(EntityId_Struct))
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
void Handle_0x01e7(const EQApplicationPacket *app);
|
||||
void Handle_OP_AAAction(const EQApplicationPacket *app);
|
||||
void Handle_OP_AcceptNewTask(const EQApplicationPacket *app);
|
||||
void Handle_OP_AcceptNewSharedTask(const EQApplicationPacket *app);
|
||||
void Handle_OP_AdventureInfoRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_AdventureLeaderboardRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_AdventureMerchantPurchase(const EQApplicationPacket *app);
|
||||
|
||||
@@ -149,6 +149,9 @@ bool Client::Process() {
|
||||
{
|
||||
myraid->MemberZoned(this);
|
||||
}
|
||||
auto shared_task = GetSharedTask();
|
||||
if (shared_task)
|
||||
shared_task->MemberZoned(this);
|
||||
return(false);
|
||||
}
|
||||
|
||||
@@ -171,6 +174,9 @@ bool Client::Process() {
|
||||
if (myraid) {
|
||||
myraid->MemberZoned(this);
|
||||
}
|
||||
auto shared_task = GetSharedTask();
|
||||
if (shared_task)
|
||||
shared_task->MemberZoned(this);
|
||||
return false; //delete client
|
||||
}
|
||||
|
||||
@@ -653,6 +659,9 @@ bool Client::Process() {
|
||||
myraid->MemberZoned(this);
|
||||
}
|
||||
}
|
||||
auto shared_task = GetSharedTask();
|
||||
if (shared_task)
|
||||
shared_task->MemberZoned(this);
|
||||
OnDisconnect(false);
|
||||
return false;
|
||||
}
|
||||
@@ -694,6 +703,10 @@ void Client::OnDisconnect(bool hard_disconnect) {
|
||||
if (MyRaid)
|
||||
MyRaid->MemberZoned(this);
|
||||
|
||||
auto shared_task = GetSharedTask();
|
||||
if (shared_task)
|
||||
shared_task->MemberZoned(this);
|
||||
|
||||
parse->EventPlayer(EVENT_DISCONNECT, this, "", 0);
|
||||
|
||||
/* QS: PlayerLogConnectDisconnect */
|
||||
@@ -2101,6 +2114,10 @@ void Client::HandleRespawnFromHover(uint32 Option)
|
||||
if(r)
|
||||
r->MemberZoned(this);
|
||||
|
||||
auto shared_task = GetSharedTask();
|
||||
if (shared_task)
|
||||
shared_task->MemberZoned(this);
|
||||
|
||||
m_pp.zone_id = chosen->zone_id;
|
||||
m_pp.zoneInstance = chosen->instance_id;
|
||||
database.MoveCharacterToZone(CharacterID(), database.GetZoneName(chosen->zone_id));
|
||||
|
||||
+17
-7
@@ -39,6 +39,8 @@
|
||||
#include <ctime>
|
||||
#include <thread>
|
||||
|
||||
#include <task.pb.h>
|
||||
|
||||
#ifdef _WINDOWS
|
||||
#define strcasecmp _stricmp
|
||||
#endif
|
||||
@@ -2831,14 +2833,22 @@ void command_spawn(Client *c, const Seperator *sep)
|
||||
|
||||
void command_test(Client *c, const Seperator *sep)
|
||||
{
|
||||
c->Message(15, "Triggering test command");
|
||||
EQ::Proto::ClientTaskStateRequest req;
|
||||
req.set_client_id(123);
|
||||
|
||||
if (sep->arg[1]) {
|
||||
c->SetPrimaryWeaponOrnamentation(atoi(sep->arg[1]));
|
||||
}
|
||||
if (sep->arg[2]) {
|
||||
c->SetSecondaryWeaponOrnamentation(atoi(sep->arg[2]));
|
||||
}
|
||||
EQ::Net::DynamicPacket p;
|
||||
p.PutProtobuf(0, &req);
|
||||
|
||||
worldserver.RouteMessage("Tasks", "", p);
|
||||
|
||||
//c->Message(15, "Triggering test command");
|
||||
//
|
||||
//if (sep->arg[1]) {
|
||||
// c->SetPrimaryWeaponOrnamentation(atoi(sep->arg[1]));
|
||||
//}
|
||||
//if (sep->arg[2]) {
|
||||
// c->SetSecondaryWeaponOrnamentation(atoi(sep->arg[2]));
|
||||
//}
|
||||
}
|
||||
|
||||
void command_texture(Client *c, const Seperator *sep)
|
||||
|
||||
@@ -558,6 +558,7 @@ struct StatBonuses {
|
||||
int16 FeignedCastOnChance; // Percent Value
|
||||
bool PetCommands[PET_MAXCOMMANDS]; // SPA 267
|
||||
int FeignedMinionChance; // SPA 281 base1 = chance, just like normal FD
|
||||
int GrantForage; // affects max skill of forage as well as granting non-forage classes forage
|
||||
int aura_slots;
|
||||
int trap_slots;
|
||||
bool hunger; // Song of Sustenance -- min caps to 3500
|
||||
|
||||
+4
-1
@@ -152,7 +152,8 @@ Corpse::Corpse(NPC* in_npc, ItemList* in_itemlist, uint32 in_npctypeid, const NP
|
||||
in_npc->GetDeity(),in_npc->GetLevel(),in_npc->GetNPCTypeID(),in_npc->GetSize(),0,
|
||||
in_npc->GetPosition(), in_npc->GetInnateLightType(), in_npc->GetTexture(),in_npc->GetHelmTexture(),
|
||||
0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,EQEmu::TintProfile(),0xff,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(),0xff,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
(*in_npctypedata)->use_model),
|
||||
corpse_decay_timer(in_decaytime),
|
||||
corpse_rez_timer(0),
|
||||
corpse_delay_timer(RuleI(NPC, CorpseUnlockTimer)),
|
||||
@@ -258,6 +259,7 @@ Corpse::Corpse(Client* client, int32 in_rezexp) : Mob (
|
||||
0, // uint8 in_bracertexture,
|
||||
0, // uint8 in_handtexture,
|
||||
0, // uint8 in_legtexture,
|
||||
0,
|
||||
0 // uint8 in_feettexture,
|
||||
),
|
||||
corpse_decay_timer(RuleI(Character, CorpseDecayTimeMS)),
|
||||
@@ -484,6 +486,7 @@ EQEmu::TintProfile(),
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0),
|
||||
corpse_decay_timer(RuleI(Character, CorpseDecayTimeMS)),
|
||||
corpse_rez_timer(RuleI(Character, CorpseResTimeMS)),
|
||||
|
||||
@@ -2127,6 +2127,23 @@ XS(XS__taskselector) {
|
||||
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS__sharedtaskselector);
|
||||
XS(XS__sharedtaskselector) {
|
||||
dXSARGS;
|
||||
if ((items >= 1) && (items <= MAXCHOOSERENTRIES)) {
|
||||
int tasks[MAXCHOOSERENTRIES];
|
||||
for (int i = 0; i < items; i++) {
|
||||
tasks[i] = (int) SvIV(ST(i));
|
||||
}
|
||||
quest_manager.taskselector(items, tasks, true);
|
||||
} else {
|
||||
Perl_croak(aTHX_ "Usage: quest::sharedtaskselector(int task_id, 2, 3, 4, 5 [up to 40])");
|
||||
}
|
||||
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS__task_setselector);
|
||||
XS(XS__task_setselector) {
|
||||
dXSARGS;
|
||||
@@ -3942,6 +3959,7 @@ EXTERN_C XS(boot_quest) {
|
||||
newXS(strcpy(buf, "targlobal"), XS__targlobal, file);
|
||||
newXS(strcpy(buf, "taskexploredarea"), XS__taskexploredarea, file);
|
||||
newXS(strcpy(buf, "taskselector"), XS__taskselector, file);
|
||||
newXS(strcpy(buf, "sharedtaskselector"), XS__sharedtaskselector, file);
|
||||
newXS(strcpy(buf, "task_setselector"), XS__task_setselector, file);
|
||||
newXS(strcpy(buf, "tasktimeleft"), XS__tasktimeleft, file);
|
||||
newXS(strcpy(buf, "toggle_spawn_event"), XS__toggle_spawn_event, file);
|
||||
|
||||
+1
-1
@@ -36,7 +36,7 @@ Encounter::Encounter(const char* enc_name)
|
||||
:Mob
|
||||
(
|
||||
nullptr, nullptr, 0, 0, 0, INVISIBLE_MAN, 0, BT_NoTarget, 0, 0, 0, 0, 0, glm::vec4(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, 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
|
||||
)
|
||||
{
|
||||
encounter_name[0] = 0;
|
||||
|
||||
@@ -537,6 +537,9 @@ void EntityList::MobProcess()
|
||||
Log(Logs::General, Logs::Error, "About to delete a client still in a raid.");
|
||||
r->MemberZoned(mob->CastToClient());
|
||||
}
|
||||
auto shared_task = mob->CastToClient()->GetSharedTask();
|
||||
if (shared_task)
|
||||
shared_task->MemberZoned(mob);
|
||||
entity_list.RemoveClient(id);
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -972,8 +972,8 @@ void Client::DeleteItemInInventory(int16 slot_id, int8 quantity, bool client_upd
|
||||
safe_delete(outapp);
|
||||
}
|
||||
else {
|
||||
outapp = new EQApplicationPacket(OP_MoveItem, sizeof(MoveItem_Struct));
|
||||
MoveItem_Struct* delitem = (MoveItem_Struct*)outapp->pBuffer;
|
||||
outapp = new EQApplicationPacket(OP_DeleteItem, sizeof(DeleteItem_Struct));
|
||||
DeleteItem_Struct* delitem = (DeleteItem_Struct*)outapp->pBuffer;
|
||||
delitem->from_slot = slot_id;
|
||||
delitem->to_slot = 0xFFFFFFFF;
|
||||
delitem->number_in_stack = 0xFFFFFFFF;
|
||||
|
||||
@@ -615,11 +615,21 @@ void Lua_Client::UntrainDiscAll(bool update_client) {
|
||||
self->UntrainDiscAll(update_client);
|
||||
}
|
||||
|
||||
bool Lua_Client::IsStanding() {
|
||||
Lua_Safe_Call_Bool();
|
||||
return self->IsStanding();
|
||||
}
|
||||
|
||||
bool Lua_Client::IsSitting() {
|
||||
Lua_Safe_Call_Bool();
|
||||
return self->IsSitting();
|
||||
}
|
||||
|
||||
bool Lua_Client::IsCrouching() {
|
||||
Lua_Safe_Call_Bool();
|
||||
return self->IsCrouching();
|
||||
}
|
||||
|
||||
void Lua_Client::SetFeigned(bool v) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->SetFeigned(v);
|
||||
@@ -1621,7 +1631,9 @@ luabind::scope lua_register_client() {
|
||||
.def("UntrainDisc", (void(Lua_Client::*)(int,bool))&Lua_Client::UntrainDisc)
|
||||
.def("UntrainDiscAll", (void(Lua_Client::*)(void))&Lua_Client::UntrainDiscAll)
|
||||
.def("UntrainDiscAll", (void(Lua_Client::*)(bool))&Lua_Client::UntrainDiscAll)
|
||||
.def("IsStanding", (bool(Lua_Client::*)(void))&Lua_Client::IsStanding)
|
||||
.def("IsSitting", (bool(Lua_Client::*)(void))&Lua_Client::IsSitting)
|
||||
.def("IsCrouching", (bool(Lua_Client::*)(void))&Lua_Client::IsCrouching)
|
||||
.def("SetFeigned", (void(Lua_Client::*)(bool))&Lua_Client::SetFeigned)
|
||||
.def("GetFeigned", (bool(Lua_Client::*)(void))&Lua_Client::GetFeigned)
|
||||
.def("AutoSplitEnabled", (bool(Lua_Client::*)(void))&Lua_Client::AutoSplitEnabled)
|
||||
|
||||
@@ -148,7 +148,9 @@ public:
|
||||
void UntrainDisc(int slot, bool update_client);
|
||||
void UntrainDiscAll();
|
||||
void UntrainDiscAll(bool update_client);
|
||||
bool IsStanding();
|
||||
bool IsSitting();
|
||||
bool IsCrouching();
|
||||
void SetFeigned(bool v);
|
||||
bool GetFeigned();
|
||||
bool AutoSplitEnabled();
|
||||
|
||||
+28
-1
@@ -581,6 +581,32 @@ void lua_task_selector(luabind::adl::object table) {
|
||||
quest_manager.taskselector(count, tasks);
|
||||
}
|
||||
|
||||
void lua_task_selector(luabind::adl::object table, bool shared) {
|
||||
if(luabind::type(table) != LUA_TTABLE) {
|
||||
return;
|
||||
}
|
||||
|
||||
int tasks[MAXCHOOSERENTRIES] = { 0 };
|
||||
int count = 0;
|
||||
|
||||
for(int i = 1; i <= MAXCHOOSERENTRIES; ++i) {
|
||||
auto cur = table[i];
|
||||
int cur_value = 0;
|
||||
if(luabind::type(cur) != LUA_TNIL) {
|
||||
try {
|
||||
cur_value = luabind::object_cast<int>(cur);
|
||||
} catch(luabind::cast_failed) {
|
||||
}
|
||||
} else {
|
||||
count = i - 1;
|
||||
break;
|
||||
}
|
||||
|
||||
tasks[i - 1] = cur_value;
|
||||
}
|
||||
quest_manager.taskselector(count, tasks, shared);
|
||||
}
|
||||
|
||||
void lua_task_set_selector(int task_set) {
|
||||
quest_manager.tasksetselector(task_set);
|
||||
}
|
||||
@@ -1652,7 +1678,8 @@ luabind::scope lua_register_general() {
|
||||
luabind::def("summon_all_player_corpses", &lua_summon_all_player_corpses),
|
||||
luabind::def("get_player_buried_corpse_count", &lua_get_player_buried_corpse_count),
|
||||
luabind::def("bury_player_corpse", &lua_bury_player_corpse),
|
||||
luabind::def("task_selector", &lua_task_selector),
|
||||
luabind::def("task_selector", (void(*)(luabind::adl::object))&lua_task_selector),
|
||||
luabind::def("task_selector", (void(*)(luabind::adl::object,bool))&lua_task_selector),
|
||||
luabind::def("task_set_selector", &lua_task_set_selector),
|
||||
luabind::def("enable_task", &lua_enable_task),
|
||||
luabind::def("disable_task", &lua_disable_task),
|
||||
|
||||
@@ -267,6 +267,11 @@ void Lua_Mob::ChangeSize(double in_size, bool no_restriction) {
|
||||
self->ChangeSize(static_cast<float>(in_size), no_restriction);
|
||||
}
|
||||
|
||||
void Lua_Mob::RandomizeFeatures(bool send_illusion, bool save_variables) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->RandomizeFeatures(send_illusion, save_variables);
|
||||
}
|
||||
|
||||
void Lua_Mob::GMMove(double x, double y, double z) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->GMMove(static_cast<float>(x), static_cast<float>(y), static_cast<float>(z));
|
||||
@@ -2202,6 +2207,7 @@ luabind::scope lua_register_mob() {
|
||||
.def("DoAnim", (void(Lua_Mob::*)(int,int,bool,int))&Lua_Mob::DoAnim)
|
||||
.def("ChangeSize", (void(Lua_Mob::*)(double))&Lua_Mob::ChangeSize)
|
||||
.def("ChangeSize", (void(Lua_Mob::*)(double,bool))&Lua_Mob::ChangeSize)
|
||||
.def("RandomizeFeatures", (void(Lua_Mob::*)(bool,bool))&Lua_Mob::RandomizeFeatures)
|
||||
.def("GMMove", (void(Lua_Mob::*)(double,double,double))&Lua_Mob::GMMove)
|
||||
.def("GMMove", (void(Lua_Mob::*)(double,double,double,double))&Lua_Mob::GMMove)
|
||||
.def("GMMove", (void(Lua_Mob::*)(double,double,double,double,bool))&Lua_Mob::GMMove)
|
||||
|
||||
@@ -71,6 +71,7 @@ public:
|
||||
void DoAnim(int anim_num, int type, bool ackreq, int filter);
|
||||
void ChangeSize(double in_size);
|
||||
void ChangeSize(double in_size, bool no_restriction);
|
||||
void RandomizeFeatures(bool send_illusion, bool save_variables);
|
||||
void GMMove(double x, double y, double z);
|
||||
void GMMove(double x, double y, double z, double heading);
|
||||
void GMMove(double x, double y, double z, double heading, bool send_update);
|
||||
|
||||
+85
-160
@@ -92,7 +92,8 @@ Mob::Mob(
|
||||
uint8 in_bracertexture,
|
||||
uint8 in_handtexture,
|
||||
uint8 in_legtexture,
|
||||
uint8 in_feettexture
|
||||
uint8 in_feettexture,
|
||||
uint16 in_usemodel
|
||||
) :
|
||||
attack_timer(2000),
|
||||
attack_dw_timer(2000),
|
||||
@@ -147,6 +148,7 @@ Mob::Mob(
|
||||
race = in_race;
|
||||
base_gender = in_gender;
|
||||
base_race = in_race;
|
||||
use_model = in_usemodel;
|
||||
class_ = in_class;
|
||||
bodytype = in_bodytype;
|
||||
orig_bodytype = in_bodytype;
|
||||
@@ -1112,7 +1114,7 @@ void Mob::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho)
|
||||
ns->spawn.spawnId = GetID();
|
||||
ns->spawn.curHp = static_cast<uint8>(GetHPRatio());
|
||||
ns->spawn.max_hp = 100; //this field needs a better name
|
||||
ns->spawn.race = race;
|
||||
ns->spawn.race = (use_model) ? use_model : race;
|
||||
ns->spawn.runspeed = runspeed;
|
||||
ns->spawn.walkspeed = walkspeed;
|
||||
ns->spawn.class_ = class_;
|
||||
@@ -1692,151 +1694,74 @@ void Mob::SendIllusionPacket(
|
||||
float in_size
|
||||
)
|
||||
{
|
||||
uint8 new_texture = in_texture;
|
||||
uint8 new_helmtexture = in_helmtexture;
|
||||
uint8 new_haircolor;
|
||||
uint8 new_beardcolor;
|
||||
uint8 new_eyecolor1;
|
||||
uint8 new_eyecolor2;
|
||||
uint8 new_hairstyle;
|
||||
uint8 new_luclinface;
|
||||
uint8 new_beard;
|
||||
uint8 new_aa_title;
|
||||
uint32 new_drakkin_heritage;
|
||||
uint32 new_drakkin_tattoo;
|
||||
uint32 new_drakkin_details;
|
||||
|
||||
uint16 BaseRace = GetBaseRace();
|
||||
race = (in_race) ? in_race : GetBaseRace();
|
||||
|
||||
if (in_race == 0) {
|
||||
race = BaseRace;
|
||||
if (in_gender == 0xFF) {
|
||||
gender = GetBaseGender();
|
||||
if (in_gender != 0xFF)
|
||||
{
|
||||
gender = in_gender;
|
||||
}
|
||||
else {
|
||||
gender = in_gender;
|
||||
else
|
||||
{
|
||||
gender = (in_race) ? GetDefaultGender(race, gender) : GetBaseGender();
|
||||
}
|
||||
}
|
||||
else {
|
||||
race = in_race;
|
||||
if (in_gender == 0xFF) {
|
||||
gender = GetDefaultGender(race, gender);
|
||||
|
||||
if (in_texture == 0xFF && !IsPlayerRace(in_race))
|
||||
{
|
||||
new_texture = GetTexture();
|
||||
}
|
||||
else {
|
||||
gender = in_gender;
|
||||
|
||||
if (in_helmtexture == 0xFF && !IsPlayerRace(in_race))
|
||||
{
|
||||
new_helmtexture = GetHelmTexture();
|
||||
}
|
||||
}
|
||||
|
||||
if (in_texture == 0xFF) {
|
||||
if (IsPlayerRace(in_race)) {
|
||||
texture = 0xFF;
|
||||
}
|
||||
else {
|
||||
texture = GetTexture();
|
||||
}
|
||||
}
|
||||
else {
|
||||
texture = in_texture;
|
||||
}
|
||||
|
||||
if (in_helmtexture == 0xFF) {
|
||||
if (IsPlayerRace(in_race)) {
|
||||
helmtexture = 0xFF;
|
||||
}
|
||||
else if (in_texture != 0xFF) {
|
||||
helmtexture = in_texture;
|
||||
}
|
||||
else {
|
||||
helmtexture = GetHelmTexture();
|
||||
}
|
||||
}
|
||||
else {
|
||||
helmtexture = in_helmtexture;
|
||||
}
|
||||
|
||||
if (in_haircolor == 0xFF) {
|
||||
haircolor = GetHairColor();
|
||||
}
|
||||
else {
|
||||
haircolor = in_haircolor;
|
||||
}
|
||||
|
||||
if (in_beardcolor == 0xFF) {
|
||||
beardcolor = GetBeardColor();
|
||||
}
|
||||
else {
|
||||
beardcolor = in_beardcolor;
|
||||
}
|
||||
|
||||
if (in_eyecolor1 == 0xFF) {
|
||||
eyecolor1 = GetEyeColor1();
|
||||
}
|
||||
else {
|
||||
eyecolor1 = in_eyecolor1;
|
||||
}
|
||||
|
||||
if (in_eyecolor2 == 0xFF) {
|
||||
eyecolor2 = GetEyeColor2();
|
||||
}
|
||||
else {
|
||||
eyecolor2 = in_eyecolor2;
|
||||
}
|
||||
|
||||
if (in_hairstyle == 0xFF) {
|
||||
hairstyle = GetHairStyle();
|
||||
}
|
||||
else {
|
||||
hairstyle = in_hairstyle;
|
||||
}
|
||||
|
||||
if (in_luclinface == 0xFF) {
|
||||
luclinface = GetLuclinFace();
|
||||
}
|
||||
else {
|
||||
luclinface = in_luclinface;
|
||||
}
|
||||
|
||||
if (in_beard == 0xFF) {
|
||||
beard = GetBeard();
|
||||
}
|
||||
else {
|
||||
beard = in_beard;
|
||||
}
|
||||
|
||||
aa_title = in_aa_title;
|
||||
|
||||
if (in_drakkin_heritage == 0xFFFFFFFF) {
|
||||
drakkin_heritage = GetDrakkinHeritage();
|
||||
}
|
||||
else {
|
||||
drakkin_heritage = in_drakkin_heritage;
|
||||
}
|
||||
|
||||
if (in_drakkin_tattoo == 0xFFFFFFFF) {
|
||||
drakkin_tattoo = GetDrakkinTattoo();
|
||||
}
|
||||
else {
|
||||
drakkin_tattoo = in_drakkin_tattoo;
|
||||
}
|
||||
|
||||
if (in_drakkin_details == 0xFFFFFFFF) {
|
||||
drakkin_details = GetDrakkinDetails();
|
||||
}
|
||||
else {
|
||||
drakkin_details = in_drakkin_details;
|
||||
}
|
||||
|
||||
if (in_size <= 0.0f) {
|
||||
size = GetSize();
|
||||
}
|
||||
else {
|
||||
size = in_size;
|
||||
}
|
||||
new_haircolor = (in_haircolor == 0xFF) ? GetHairColor() : in_haircolor;
|
||||
new_beardcolor = (in_beardcolor == 0xFF) ? GetBeardColor() : in_beardcolor;
|
||||
new_eyecolor1 = (in_eyecolor1 == 0xFF) ? GetEyeColor1() : in_eyecolor1;
|
||||
new_eyecolor2 = (in_eyecolor2 == 0xFF) ? GetEyeColor2() : in_eyecolor2;
|
||||
new_hairstyle = (in_hairstyle == 0xFF) ? GetHairStyle() : in_hairstyle;
|
||||
new_luclinface = (in_luclinface == 0xFF) ? GetLuclinFace() : in_luclinface;
|
||||
new_beard = (in_beard == 0xFF) ? GetBeard() : in_beard;
|
||||
new_drakkin_heritage =
|
||||
(in_drakkin_heritage == 0xFFFFFFFF) ? GetDrakkinHeritage() : in_drakkin_heritage;
|
||||
new_drakkin_tattoo =
|
||||
(in_drakkin_tattoo == 0xFFFFFFFF) ? GetDrakkinTattoo() : in_drakkin_tattoo;
|
||||
new_drakkin_details =
|
||||
(in_drakkin_details == 0xFFFFFFFF) ? GetDrakkinDetails() : in_drakkin_details;
|
||||
new_aa_title = in_aa_title;
|
||||
size = (in_size <= 0.0f) ? GetSize() : in_size;
|
||||
|
||||
// Reset features to Base from the Player Profile
|
||||
if (IsClient() && in_race == 0) {
|
||||
race = CastToClient()->GetBaseRace();
|
||||
gender = CastToClient()->GetBaseGender();
|
||||
texture = 0xFF;
|
||||
helmtexture = 0xFF;
|
||||
haircolor = CastToClient()->GetBaseHairColor();
|
||||
beardcolor = CastToClient()->GetBaseBeardColor();
|
||||
eyecolor1 = CastToClient()->GetBaseEyeColor();
|
||||
eyecolor2 = CastToClient()->GetBaseEyeColor();
|
||||
hairstyle = CastToClient()->GetBaseHairStyle();
|
||||
luclinface = CastToClient()->GetBaseFace();
|
||||
beard = CastToClient()->GetBaseBeard();
|
||||
aa_title = 0xFF;
|
||||
drakkin_heritage = CastToClient()->GetBaseHeritage();
|
||||
drakkin_tattoo = CastToClient()->GetBaseTattoo();
|
||||
drakkin_details = CastToClient()->GetBaseDetails();
|
||||
race = CastToClient()->GetBaseRace();
|
||||
gender = CastToClient()->GetBaseGender();
|
||||
new_texture = texture = 0xFF;
|
||||
new_helmtexture = helmtexture = 0xFF;
|
||||
new_haircolor = haircolor = CastToClient()->GetBaseHairColor();
|
||||
new_beardcolor = beardcolor = CastToClient()->GetBaseBeardColor();
|
||||
new_eyecolor1 = eyecolor1 = CastToClient()->GetBaseEyeColor();
|
||||
new_eyecolor2 = eyecolor2 = CastToClient()->GetBaseEyeColor();
|
||||
new_hairstyle = hairstyle = CastToClient()->GetBaseHairStyle();
|
||||
new_luclinface = luclinface = CastToClient()->GetBaseFace();
|
||||
new_beard = beard = CastToClient()->GetBaseBeard();
|
||||
new_aa_title = aa_title = 0xFF;
|
||||
new_drakkin_heritage = drakkin_heritage = CastToClient()->GetBaseHeritage();
|
||||
new_drakkin_tattoo = drakkin_tattoo = CastToClient()->GetBaseTattoo();
|
||||
new_drakkin_details = drakkin_details = CastToClient()->GetBaseDetails();
|
||||
switch (race) {
|
||||
case OGRE:
|
||||
size = 9;
|
||||
@@ -1873,18 +1798,18 @@ void Mob::SendIllusionPacket(
|
||||
strcpy(is->charname, GetCleanName());
|
||||
is->race = race;
|
||||
is->gender = gender;
|
||||
is->texture = texture;
|
||||
is->helmtexture = helmtexture;
|
||||
is->haircolor = haircolor;
|
||||
is->beardcolor = beardcolor;
|
||||
is->beard = beard;
|
||||
is->eyecolor1 = eyecolor1;
|
||||
is->eyecolor2 = eyecolor2;
|
||||
is->hairstyle = hairstyle;
|
||||
is->face = luclinface;
|
||||
is->drakkin_heritage = drakkin_heritage;
|
||||
is->drakkin_tattoo = drakkin_tattoo;
|
||||
is->drakkin_details = drakkin_details;
|
||||
is->texture = new_texture;
|
||||
is->helmtexture = new_helmtexture;
|
||||
is->haircolor = new_haircolor;
|
||||
is->beardcolor = new_beardcolor;
|
||||
is->beard = new_beard;
|
||||
is->eyecolor1 = new_eyecolor1;
|
||||
is->eyecolor2 = new_eyecolor2;
|
||||
is->hairstyle = new_hairstyle;
|
||||
is->face = new_luclinface;
|
||||
is->drakkin_heritage = new_drakkin_heritage;
|
||||
is->drakkin_tattoo = new_drakkin_tattoo;
|
||||
is->drakkin_details = new_drakkin_details;
|
||||
is->size = size;
|
||||
|
||||
entity_list.QueueClients(this, outapp);
|
||||
@@ -1898,17 +1823,17 @@ void Mob::SendIllusionPacket(
|
||||
"Illusion: Race = %i, Gender = %i, Texture = %i, HelmTexture = %i, HairColor = %i, BeardColor = %i, EyeColor1 = %i, EyeColor2 = %i, HairStyle = %i, Face = %i, DrakkinHeritage = %i, DrakkinTattoo = %i, DrakkinDetails = %i, Size = %f",
|
||||
race,
|
||||
gender,
|
||||
texture,
|
||||
helmtexture,
|
||||
haircolor,
|
||||
beardcolor,
|
||||
eyecolor1,
|
||||
eyecolor2,
|
||||
hairstyle,
|
||||
luclinface,
|
||||
drakkin_heritage,
|
||||
drakkin_tattoo,
|
||||
drakkin_details,
|
||||
new_texture,
|
||||
new_helmtexture,
|
||||
new_haircolor,
|
||||
new_beardcolor,
|
||||
new_eyecolor1,
|
||||
new_eyecolor2,
|
||||
new_hairstyle,
|
||||
new_luclinface,
|
||||
new_drakkin_heritage,
|
||||
new_drakkin_tattoo,
|
||||
new_drakkin_details,
|
||||
size);
|
||||
}
|
||||
|
||||
|
||||
+4
-2
@@ -159,7 +159,8 @@ public:
|
||||
uint8 in_bracertexture,
|
||||
uint8 in_handtexture,
|
||||
uint8 in_legtexture,
|
||||
uint8 in_feettexture
|
||||
uint8 in_feettexture,
|
||||
uint16 in_usemodel
|
||||
);
|
||||
virtual ~Mob();
|
||||
|
||||
@@ -1091,7 +1092,7 @@ public:
|
||||
inline glm::vec4 GetCurrentWayPoint() const { return m_CurrentWayPoint; }
|
||||
inline float GetCWPP() const { return(static_cast<float>(cur_wp_pause)); }
|
||||
inline int GetCWP() const { return(cur_wp); }
|
||||
void SetCurrentWP(uint16 waypoint) { cur_wp = waypoint; }
|
||||
void SetCurrentWP(int waypoint) { cur_wp = waypoint; }
|
||||
virtual FACTION_VALUE GetReverseFactionCon(Mob* iOther) { return FACTION_INDIFFERENT; }
|
||||
|
||||
virtual const bool IsUnderwaterOnly() const { return false; }
|
||||
@@ -1280,6 +1281,7 @@ protected:
|
||||
|
||||
uint8 gender;
|
||||
uint16 race;
|
||||
uint16 use_model;
|
||||
uint8 base_gender;
|
||||
uint16 base_race;
|
||||
uint8 class_;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user