diff --git a/common/emu_oplist.h b/common/emu_oplist.h index 2af98de1c..4aef3b27f 100644 --- a/common/emu_oplist.h +++ b/common/emu_oplist.h @@ -303,6 +303,7 @@ N(OP_LockoutTimerInfo), N(OP_Login), N(OP_LoginAccepted), N(OP_LoginComplete), +N(OP_LoginExpansionPacketData), //added for Rof2 client to send expansion data packet. Requires login_opcodes_sod.conf to be updated. N(OP_LoginUnknown1), N(OP_LoginUnknown2), N(OP_Logout), diff --git a/loginserver/client.cpp b/loginserver/client.cpp index eb60d1c68..6e66317bd 100644 --- a/loginserver/client.cpp +++ b/loginserver/client.cpp @@ -563,6 +563,8 @@ void Client::DoSuccessfulLogin( login_reply.web_offer_cooldown_minutes = 0; memcpy(login_reply.key, m_key.c_str(), m_key.size()); + SendExpansionPacketData(login_reply); + char encrypted_buffer[80] = {0}; auto rc = eqcrypt_block((const char*)&login_reply, sizeof(login_reply), encrypted_buffer, 1); if (rc == nullptr) { @@ -583,6 +585,68 @@ void Client::DoSuccessfulLogin( m_client_status = cs_logged_in; } +void Client::SendExpansionPacketData(PlayerLoginReply_Struct& plrs) +{ + SerializeBuffer buf; + //from eqlsstr_us.txt id of each expansion, excluding 'Everquest' + int ExpansionLookup[20] = { 3007, 3008, 3009, 3010, 3012, + 3014, 3031, 3033, 3036, 3040, + 3045, 3046, 3047, 3514, 3516, + 3518, 3520, 3522, 3524 }; + + + if (server.options.IsDisplayExpansions()) { + + int32_t expansion = server.options.GetMaxExpansions(); + int32_t owned_expansion = (expansion << 1) | 1; + + if (m_client_version == cv_sod) { + + // header info of packet. Requires OP_LoginExpansionPacketData=0x0031 to be in login_opcodes_sod.conf + buf.WriteInt32(0x00); + buf.WriteInt32(0x01); + buf.WriteInt16(0x00); + buf.WriteInt32(19); //number of expansions to include in packet + + //generate expansion data + for (int i = 0; i < 19; i++) + { + buf.WriteInt32(i); //sequenctial number + buf.WriteInt32((expansion & (1 << i)) == (1 << i) ? 0x01 : 0x00); //1 own 0 not own + buf.WriteInt8(0x00); + buf.WriteInt32(ExpansionLookup[i]); //from eqlsstr_us.txt + buf.WriteInt32(0x179E); //from eqlsstr_us.txt for buttons/order + buf.WriteInt32(0xFFFFFFFF); //end identification + buf.WriteInt8(0x0); //force order window to appear 1 appear 0 not appear + buf.WriteInt8(0x0); + buf.WriteInt32(0x0000); + buf.WriteInt32(0x0000); + buf.WriteInt32(0xFFFFFFFF); + } + + auto out = std::make_unique(OP_LoginExpansionPacketData, buf); + m_connection->QueuePacket(out.get()); + + } + else if (m_client_version == cv_titanium) + { + if (expansion >= EQ::expansions::bitPoR) + { + // Titanium shipped with 10 expansions. Set owned expansions to be max 10. + plrs.offer_min_days = ((EQ::expansions::bitDoD << 2) | 1) - 2; + } + else + { + plrs.offer_min_days = owned_expansion; + } + // Titanium shipped with 10 expansions. Set owned expansions to be max 10. + plrs.web_offer_min_views = ((EQ::expansions::bitDoD << 2) | 1) - 2; + } + + } + +} + /** * @param username * @param password diff --git a/loginserver/client.h b/loginserver/client.h index 95aa0cfa7..9dd146830 100644 --- a/loginserver/client.h +++ b/loginserver/client.h @@ -51,6 +51,18 @@ public: * @param size */ void Handle_Login(const char *data, unsigned int size); + + /** + * Sends the expansion data packet + * + * Titanium uses the encrypted data block to contact the expansion (You own xxx:) and the max expansions (of yyy) + * Rof uses a seperate data packet specifically for the expansion data + * Live, as of July 2021 uses a similar but slightly different seperate data packet + * + * @param PlayerLoginReply_Struct + * + */ + void SendExpansionPacketData(PlayerLoginReply_Struct& plrs); /** * Sends a packet to the requested server to see if the client is allowed or not diff --git a/loginserver/login_util/login.json b/loginserver/login_util/login.json index c25242f7c..c61b60ce5 100644 --- a/loginserver/login_util/login.json +++ b/loginserver/login_util/login.json @@ -35,6 +35,8 @@ "titanium_port": 5998, "titanium_opcodes": "login_opcodes.conf", "sod_port": 5999, - "sod_opcodes": "login_opcodes_sod.conf" + "sod_opcodes": "login_opcodes_sod.conf", + "display_expansions" : true, + "max_expansions_mask" : 524287 } } diff --git a/loginserver/login_util/login_opcodes_sod.conf b/loginserver/login_util/login_opcodes_sod.conf index fc0d8bb94..cdc856d2c 100644 --- a/loginserver/login_util/login_opcodes_sod.conf +++ b/loginserver/login_util/login_opcodes_sod.conf @@ -8,5 +8,6 @@ OP_ChatMessage=0x0017 OP_LoginAccepted=0x0018 OP_ServerListResponse=0x0019 OP_Poll=0x0029 +OP_LoginExpansionPacketData=0x0031 OP_EnterChat=0x000f OP_PollResponse=0x0011 diff --git a/loginserver/main.cpp b/loginserver/main.cpp index c2975d372..564dfe00b 100644 --- a/loginserver/main.cpp +++ b/loginserver/main.cpp @@ -87,6 +87,12 @@ void LoadServerConfig() ) ); + /** + * Expansion Display Settings + */ + server.options.DisplayExpansions(server.config.GetVariableBool("client_configuration", "display_expansions", false)); //disable by default + server.options.MaxExpansions(server.config.GetVariableInt("client_configuration", "max_expansions_mask", 67108863)); //enable display of all expansions + /** * Account */ @@ -257,6 +263,9 @@ int main(int argc, char **argv) LogInfo("[Config] [Logging] IsDumpInPacketsOn [{0}]", server.options.IsDumpInPacketsOn()); LogInfo("[Config] [Logging] IsDumpOutPacketsOn [{0}]", server.options.IsDumpOutPacketsOn()); LogInfo("[Config] [Account] CanAutoCreateAccounts [{0}]", server.options.CanAutoCreateAccounts()); + LogInfo("[Config] [Client_Configuration] DisplayExpansions [{0}]", server.options.IsDisplayExpansions()); + LogInfo("[Config] [Client_Configuration] MaxExpansions [{0}]", server.options.GetMaxExpansions()); + #ifdef LSPX LogInfo("[Config] [Account] CanAutoLinkAccounts [{0}]", server.options.CanAutoLinkAccounts()); #endif diff --git a/loginserver/options.h b/loginserver/options.h index cf1de76d3..2ccfa5157 100644 --- a/loginserver/options.h +++ b/loginserver/options.h @@ -16,6 +16,8 @@ public: trace(false), dump_in_packets(false), dump_out_packets(false), + display_expansions(false), + max_expansions_mask(0), encryption_mode(5), reject_duplicate_servers(false), allow_password_login(true), @@ -27,6 +29,14 @@ public: */ inline void AllowUnregistered(bool b) { allow_unregistered = b; } + /** + * Returns the value of expansion display settings. + */ + inline void DisplayExpansions(bool b) { display_expansions = b; } + inline void MaxExpansions(int i) { max_expansions_mask = i; } + inline bool IsDisplayExpansions() const { return display_expansions; } + inline int GetMaxExpansions() const { return max_expansions_mask; } + /** * Returns the value of allow_unregistered. */ @@ -142,6 +152,7 @@ private: bool world_trace; bool dump_in_packets; bool dump_out_packets; + bool display_expansions; bool reject_duplicate_servers; bool world_dev_test_servers_list_bottom; bool world_special_character_start_list_bottom; @@ -152,6 +163,7 @@ private: bool auto_link_accounts; bool update_insecure_passwords; int encryption_mode; + int max_expansions_mask; std::string eqemu_loginserver_address; std::string default_loginserver_name; };