Add support for single account login to both world and login server, should also work with eqemu login server, can be turned off in rules if you don't mind the side effects double logins cause. Also lowered the linkdead time to 30s + 90s default (2min)

This commit is contained in:
KimLS 2019-07-13 16:16:15 -07:00
parent 7181b46608
commit 6bdc9b6ba5
9 changed files with 89 additions and 93 deletions

View File

@ -290,14 +290,14 @@ ADD_DEFINITIONS(-DGLM_FORCE_CTOR_INIT)
ADD_DEFINITIONS(-DGLM_ENABLE_EXPERIMENTAL)
#Find everything we need
FIND_PACKAGE(ZLIB REQUIRED)
FIND_PACKAGE(ZLIB)
FIND_PACKAGE(MySQL 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} uv_a fmt RecastNavigation::Detour)
SET(SERVER_LIBS common debug ${MySQL_LIBRARY_DEBUG} optimized ${MySQL_LIBRARY_RELEASE} uv_a fmt RecastNavigation::Detour)
FIND_PACKAGE(Sodium REQUIRED)
IF(SODIUM_FOUND)
@ -320,7 +320,7 @@ IF(ZLIB_FOUND)
SET(SERVER_LIBS ${SERVER_LIBS} ${ZLIB_LIBRARY})
ENDIF()
ELSE()
INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/libs/zlibng")
INCLUDE_DIRECTORIES(BEFORE SYSTEM "${CMAKE_CURRENT_BINARY_DIR}/libs/zlibng" "${CMAKE_CURRENT_SOURCE_DIR}/libs/zlibng")
SET(SERVER_LIBS ${SERVER_LIBS} "zlibstatic")
ENDIF()

View File

@ -257,7 +257,7 @@ namespace EQ
resend_delay_min = 150;
resend_delay_max = 5000;
connect_delay_ms = 500;
stale_connection_ms = 90000;
stale_connection_ms = 30000;
connect_stale_ms = 5000;
crc_length = 2;
max_packet_size = 512;
@ -269,7 +269,7 @@ namespace EQ
simulated_in_packet_loss = 0;
simulated_out_packet_loss = 0;
tic_rate_hertz = 60.0;
resend_timeout = 90000;
resend_timeout = 30000;
connection_close_time = 2000;
outgoing_data_rate = 0.0;
}

View File

@ -225,8 +225,6 @@ RULE_BOOL(World, MaxClientsSetByStatus, false) // If True, IP Limiting will be s
RULE_BOOL(World, EnableIPExemptions, false) // If True, ip_exemptions table is used, if there is no entry for the IP it will default to RuleI(World, MaxClientsPerIP)
RULE_BOOL(World, ClearTempMerchantlist, true) // Clears temp merchant items when world boots.
RULE_BOOL(World, DeleteStaleCorpeBackups, true) // Deletes stale corpse backups older than 2 weeks.
RULE_INT(World, AccountSessionLimit, -1) //Max number of characters allowed on at once from a single account (-1 is disabled)
RULE_INT(World, ExemptAccountLimitStatus, -1) //Min status required to be exempt from multi-session per account limiting (-1 is disabled)
RULE_BOOL(World, GMAccountIPList, false) // Check ip list against GM Accounts, AntiHack GM Accounts.
RULE_INT(World, MinGMAntiHackStatus, 1) //Minimum GM status to check against AntiHack list
RULE_INT(World, SoFStartZoneID, -1) //Sets the Starting Zone for SoF Clients separate from Titanium Clients (-1 is disabled)
@ -241,10 +239,11 @@ RULE_BOOL (World, IPLimitDisconnectAll, false)
RULE_BOOL(World, MaxClientsSimplifiedLogic, false) // New logic that only uses ExemptMaxClientsStatus and MaxClientsPerIP. Done on the loginserver. This mimics the P99-style special IP rules.
RULE_INT (World, TellQueueSize, 20)
RULE_BOOL(World, StartZoneSameAsBindOnCreation, true) //Should the start zone ALWAYS be the same location as your bind?
RULE_BOOL(World, DisallowDuplicateAccountLogins, true)
RULE_CATEGORY_END()
RULE_CATEGORY(Zone)
RULE_INT(Zone, ClientLinkdeadMS, 180000) //the time a client remains link dead on the server after a sudden disconnection
RULE_INT(Zone, ClientLinkdeadMS, 90000) //the time a client remains link dead on the server after a sudden disconnection
RULE_INT(Zone, GraveyardTimeMS, 1200000) //ms time until a player corpse is moved to a zone's graveyard, if one is specified for the zone
RULE_BOOL(Zone, EnableShadowrest, 1) // enables or disables the shadowrest zone feature for player corpses. Default is turned on.
RULE_BOOL(Zone, UsePlayerCorpseBackups, true) // Keeps backups of player corpses.

View File

@ -213,6 +213,15 @@ enum { QSG_LFGuild_PlayerMatches = 0, QSG_LFGuild_UpdatePlayerInfo, QSG_LFGuild_
#define ServerOP_Speech 0x4513
enum {
UserToWorldStatusWorldUnavail = 0,
UserToWorldStatusSuccess = 1,
UserToWorldStatusSuspended = -1,
UserToWorldStatusBanned = -2,
UserToWorldStatusWorldAtCapacity = -3,
UserToWorldStatusAlreadyOnline = -4
};
/************ PACKET RELATED STRUCT ************/
class ServerPacket
{

View File

@ -165,21 +165,26 @@ void WorldServer::ProcessUsertoWorldResp(uint16_t opcode, const EQ::Net::Packet
switch (utwr->response)
{
case 1:
case UserToWorldStatusSuccess:
per->Message = 101;
break;
case 0:
case UserToWorldStatusWorldUnavail:
per->Message = 326;
break;
case -1:
case UserToWorldStatusSuspended:
per->Message = 337;
break;
case -2:
case UserToWorldStatusBanned:
per->Message = 338;
break;
case -3:
per->Message = 303;
case UserToWorldStatusWorldAtCapacity:
per->Message = 339;
break;
case UserToWorldStatusAlreadyOnline:
per->Message = 111;
break;
default:
per->Message = 102;
}
if (server.options.IsTraceOn())

View File

@ -0,0 +1,2 @@
UPDATE `rule_values` SET `rule_value`='90000' WHERE `rule_name`='Zone:ClientLinkdeadMS';
INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (1, 'DisallowDuplicateAccountLogins', 'true', 'Requires account logins to be unique.');

View File

@ -99,52 +99,6 @@ ClientListEntry* ClientList::GetCLE(uint32 iID) {
return 0;
}
//Account Limiting Code to limit the number of characters allowed on from a single account at once.
void ClientList::EnforceSessionLimit(uint32 iLSAccountID) {
ClientListEntry* ClientEntry = 0;
LinkedListIterator<ClientListEntry*> iterator(clientlist, BACKWARD);
int CharacterCount = 0;
iterator.Reset();
while(iterator.MoreElements()) {
ClientEntry = iterator.GetData();
if ((ClientEntry->LSAccountID() == iLSAccountID) &&
((ClientEntry->Admin() <= (RuleI(World, ExemptAccountLimitStatus))) || (RuleI(World, ExemptAccountLimitStatus) < 0))) {
CharacterCount++;
if (CharacterCount >= (RuleI(World, AccountSessionLimit))){
// If we have a char name, they are in a zone, so send a kick to the zone server
if(strlen(ClientEntry->name())) {
auto pack =
new ServerPacket(ServerOP_KickPlayer, sizeof(ServerKickPlayer_Struct));
ServerKickPlayer_Struct* skp = (ServerKickPlayer_Struct*) pack->pBuffer;
strcpy(skp->adminname, "SessionLimit");
strcpy(skp->name, ClientEntry->name());
skp->adminrank = 255;
zoneserver_list.SendPacket(pack);
safe_delete(pack);
}
ClientEntry->SetOnline(CLE_Status_Offline);
iterator.RemoveCurrent();
continue;
}
}
iterator.Advance();
}
}
//Check current CLE Entry IPs against incoming connection
void ClientList::GetCLEIP(uint32 iIP) {
@ -272,7 +226,7 @@ ClientListEntry* ClientList::FindCharacter(const char* name) {
}
iterator.Advance();
}
return 0;
return nullptr;
}
ClientListEntry* ClientList::FindCLEByAccountID(uint32 iAccID) {
@ -285,7 +239,7 @@ ClientListEntry* ClientList::FindCLEByAccountID(uint32 iAccID) {
}
iterator.Advance();
}
return 0;
return nullptr;
}
ClientListEntry* ClientList::FindCLEByCharacterID(uint32 iCharID) {
@ -298,7 +252,20 @@ ClientListEntry* ClientList::FindCLEByCharacterID(uint32 iCharID) {
}
iterator.Advance();
}
return 0;
return nullptr;
}
ClientListEntry* ClientList::FindCLEByLSID(uint32 iLSID) {
LinkedListIterator<ClientListEntry*> iterator(clientlist);
iterator.Reset();
while (iterator.MoreElements()) {
if (iterator.GetData()->LSID() == iLSID) {
return iterator.GetData();
}
iterator.Advance();
}
return nullptr;
}
void ClientList::SendCLEList(const int16& admin, const char* to, WorldTCPConnection* connection, const char* iName) {

View File

@ -57,11 +57,11 @@ public:
ClientListEntry* FindCharacter(const char* name);
ClientListEntry* FindCLEByAccountID(uint32 iAccID);
ClientListEntry* FindCLEByCharacterID(uint32 iCharID);
ClientListEntry* FindCLEByLSID(uint32 iLSID);
ClientListEntry* GetCLE(uint32 iID);
void GetCLEIP(uint32 iIP);
uint32 GetCLEIPCount(uint32 iLSAccountID);
void DisconnectByIP(uint32 iIP);
void EnforceSessionLimit(uint32 iLSAccountID);
void CLCheckStale();
void CLEKeepAlive(uint32 numupdates, uint32* wid);
void CLEAdd(uint32 iLSID, const char* iLoginName, const char* iLoginKey, int16 iWorldAdmin = 0, uint32 ip = 0, uint8 local=0);

View File

@ -35,6 +35,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "worlddb.h"
#include "zonelist.h"
#include "clientlist.h"
#include "cliententry.h"
#include "world_config.h"
extern ZSList zoneserver_list;
@ -65,38 +66,58 @@ void LoginServer::ProcessUsertoWorldReq(uint16_t opcode, EQ::Net::Packet &p) {
uint32 id = database.GetAccountIDFromLSID(utwr->lsaccountid);
int16 status = database.CheckStatus(id);
auto outpack = new ServerPacket;
outpack->opcode = ServerOP_UsertoWorldResp;
outpack->size = sizeof(UsertoWorldResponse_Struct);
outpack->pBuffer = new uchar[outpack->size];
memset(outpack->pBuffer, 0, outpack->size);
UsertoWorldResponse_Struct* utwrs = (UsertoWorldResponse_Struct*)outpack->pBuffer;
ServerPacket outpack;
outpack.opcode = ServerOP_UsertoWorldResp;
outpack.size = sizeof(UsertoWorldResponse_Struct);
outpack.pBuffer = new uchar[outpack.size];
memset(outpack.pBuffer, 0, outpack.size);
UsertoWorldResponse_Struct* utwrs = (UsertoWorldResponse_Struct*)outpack.pBuffer;
utwrs->lsaccountid = utwr->lsaccountid;
utwrs->ToID = utwr->FromID;
utwrs->worldid = utwr->worldid;
utwrs->response = UserToWorldStatusSuccess;
if (Config->Locked == true)
{
if ((status == 0 || status < 100) && (status != -2 || status != -1))
utwrs->response = 0;
if (status >= 100)
utwrs->response = 1;
}
else {
utwrs->response = 1;
if (status < 100) {
utwrs->response = UserToWorldStatusWorldUnavail;
SendPacket(&outpack);
return;
}
}
int32 x = Config->MaxClients;
if ((int32)numplayers >= x && x != -1 && x != 255 && status < 80)
utwrs->response = -3;
if ((int32)numplayers >= x && x != -1 && x != 255 && status < 80) {
utwrs->response = UserToWorldStatusWorldAtCapacity;
SendPacket(&outpack);
return;
}
if (status == -1)
utwrs->response = -1;
if (status == -2)
utwrs->response = -2;
if (status == -1) {
utwrs->response = UserToWorldStatusSuspended;
SendPacket(&outpack);
return;
}
utwrs->worldid = utwr->worldid;
SendPacket(outpack);
delete outpack;
if (status == -2) {
utwrs->response = UserToWorldStatusBanned;
SendPacket(&outpack);
return;
}
if (RuleB(World, DisallowDuplicateAccountLogins)) {
auto cle = client_list.FindCLEByLSID(utwr->lsaccountid);
if (cle != nullptr) {
auto status = cle->GetOnline();
if (CLE_Status_Never != status && CLE_Status_Offline != status) {
utwrs->response = UserToWorldStatusAlreadyOnline;
SendPacket(&outpack);
return;
}
}
}
SendPacket(&outpack);
}
void LoginServer::ProcessLSClientAuth(uint16_t opcode, EQ::Net::Packet &p) {
@ -105,13 +126,6 @@ void LoginServer::ProcessLSClientAuth(uint16_t opcode, EQ::Net::Packet &p) {
try {
auto slsca = p.GetSerialize<ClientAuth_Struct>(0);
if (RuleI(World, AccountSessionLimit) >= 0) {
// Enforce the limit on the number of characters on the same account that can be
// online at the same time.
client_list.EnforceSessionLimit(slsca.lsaccount_id);
}
client_list.CLEAdd(slsca.lsaccount_id, slsca.name, slsca.key, slsca.worldadmin, slsca.ip, slsca.local);
}
catch (std::exception &ex) {