mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-11 21:01:29 +00:00
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:
parent
7181b46608
commit
6bdc9b6ba5
@ -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()
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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
|
||||
{
|
||||
|
||||
@ -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())
|
||||
|
||||
2
utils/sql/git/optional/2019_07_13_linkdead_changes.sql
Normal file
2
utils/sql/git/optional/2019_07_13_linkdead_changes.sql
Normal 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.');
|
||||
@ -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) {
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user