mirror of
https://github.com/SapphireServer/Sapphire.git
synced 2025-04-27 06:47:45 +00:00
Merge remote-tracking branch 'remotes/collett/Sapphire5.58' into retail
This commit is contained in:
commit
46295cc7dd
28 changed files with 1452 additions and 184 deletions
|
@ -68,11 +68,20 @@ namespace Sapphire::Common
|
|||
French = 8
|
||||
};
|
||||
|
||||
enum TellFlags : uint8_t
|
||||
enum ChatFromType : uint8_t
|
||||
{
|
||||
GmTellMsg = 0x4,
|
||||
};
|
||||
|
||||
enum ChatChannelType : uint16_t
|
||||
{
|
||||
CWLinkshellChat = 0x0,
|
||||
PartyChat = 0x1,
|
||||
LinkshellChat = 0x2,
|
||||
FreeCompanyChat = 0x3,
|
||||
NoviceNetworkChat = 0x4
|
||||
};
|
||||
|
||||
enum BNpcType : uint8_t
|
||||
{
|
||||
Friendly = 0,
|
||||
|
@ -804,6 +813,22 @@ namespace Sapphire::Common
|
|||
InvincibilityIgnoreDamage,
|
||||
};
|
||||
|
||||
enum InviteReplyType : int32_t
|
||||
{
|
||||
DENY = 0x0,
|
||||
ACCEPT = 0x1,
|
||||
CANCEL = 0x2,
|
||||
};
|
||||
|
||||
enum InviteUpdateType : uint8_t
|
||||
{
|
||||
NEW_INVITE = 0x01,
|
||||
INVITE_CANCEL = 0x02,
|
||||
JOINED_PARTY = 0x03,
|
||||
ACCEPT_INVITE = 0x04,
|
||||
REJECT_INVITE = 0x05,
|
||||
};
|
||||
|
||||
enum PlayerStateFlag : uint8_t
|
||||
{
|
||||
HideUILockChar = 0, // as the name suggests, hides the ui and logs the char...
|
||||
|
@ -1340,6 +1365,12 @@ namespace Sapphire::Common
|
|||
GetGil = 9, // p1: gil
|
||||
EmptyCoffer = 11, // seems like no param
|
||||
};
|
||||
|
||||
enum ItemFlag
|
||||
{
|
||||
FlagNone = 0,
|
||||
FlagHq = 1,
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -241,7 +241,7 @@ void Sapphire::Db::ZoneDbConnection::doPrepareStatements()
|
|||
CONNECTION_BOTH );
|
||||
|
||||
prepareStatement( CHARA_ITEMGLOBAL_UP,
|
||||
"UPDATE charaglobalitem SET stack = ?, durability = ?, stain = ? WHERE ItemId = ?;",
|
||||
"UPDATE charaglobalitem SET stack = ?, durability = ?, flags = ?, reservedFlag = ?, stain = ? WHERE ItemId = ?;",
|
||||
CONNECTION_BOTH );
|
||||
|
||||
prepareStatement( CHARA_ITEMGLOBAL_DELETE,
|
||||
|
|
|
@ -20,6 +20,19 @@ struct FFXIVIpcTell : FFXIVIpcBasePacket< Tell >
|
|||
char msg[1029];
|
||||
};
|
||||
|
||||
struct FFXIVIpcChannelChat : FFXIVIpcBasePacket< ChannelChat >
|
||||
{
|
||||
uint64_t channelId;
|
||||
uint64_t contentId;
|
||||
uint32_t charaId;
|
||||
uint8_t type;
|
||||
uint8_t unknown1;
|
||||
uint8_t unknown2;
|
||||
char name[32];
|
||||
char message[1024];
|
||||
uint8_t padding;
|
||||
};
|
||||
|
||||
/**
|
||||
* Structural representation of the packet sent by the server as response
|
||||
* to a failed tell because of unavailable target player
|
||||
|
|
|
@ -81,15 +81,14 @@ enum ServerZoneIpcType :
|
|||
SocialRequestError = 0xF0AD,
|
||||
|
||||
CFRegistered = 0x029F, // updated 5.58h
|
||||
SocialRequestResponse = 0x373, // updated 6.48
|
||||
SocialMessage = 0x03CB, // updated 5.58h
|
||||
SocialMessage2 = 0x01D7, // updated 5.58h
|
||||
SocialInviteResponse = 0x373, // updated 6.48
|
||||
SocialInviteUpdate = 0x03CB, // updated 5.58h
|
||||
SocialInviteResult = 0x01D7, // updated 5.58h
|
||||
CancelAllianceForming = 0xF0C6, // updated 4.2
|
||||
|
||||
LogMessage = 0x316, // updated 6.48
|
||||
|
||||
Chat = 0x0325, // updated 6.58 hotfix 2
|
||||
PartyChat = 0x0065,
|
||||
|
||||
WorldVisitList = 0xF0FE, // added 4.5
|
||||
|
||||
|
@ -164,7 +163,7 @@ enum ServerZoneIpcType :
|
|||
SomeCustomiseChangePacketProbably = 0x00CD, // added 5.18
|
||||
|
||||
PartyList = 0x16f, // updated 6.48
|
||||
PartyMessage = 0x336, // updated 6.48
|
||||
PartyUpdate = 0x336, // updated 6.48
|
||||
HateRank = 0x2A7, // updated 6.58 hotfix 2
|
||||
HateList = 0x26B, // updated 6.58 hotfix 2
|
||||
ObjectSpawn = 0x03B8, // updated 6.58 hotfix 2
|
||||
|
@ -352,15 +351,15 @@ enum ClientZoneIpcType :
|
|||
CancelLogout = 0x01e3, // updated 6.31h
|
||||
CFDutyInfoHandler = 0xF078, // updated 4.2
|
||||
|
||||
SocialReqSendHandler = 0x00D7, // updated 5.58h
|
||||
SocialResponseHandler = 0x023B, // updated 5.58h
|
||||
SocialInviteHandler = 0x00D7, // updated 5.58h
|
||||
SocialReplyHandler = 0x023B, // updated 5.58h
|
||||
CreateCrossWorldLS = 0x9999, // updated 5.58h
|
||||
|
||||
ChatHandler = 0x246, // updated 6.58 hotfix 2
|
||||
PartyChatHandler = 0x0065, PartySetLeaderHandler = 0x036C, // updated 5.58h
|
||||
LeavePartyHandler = 0x019D, // updated 5.58h
|
||||
KickPartyMemberHandler = 0x0262, // updated 5.58h
|
||||
DisbandPartyHandler = 0x0276, // updated 5.58h
|
||||
PartyChangeLeaderHandler = 0x036C, // updated 5.58h
|
||||
PartyLeaveHandler = 0x019D, // updated 5.58h
|
||||
PartyKickHandler = 0x0262, // updated 5.58h
|
||||
PartyDisbandHandler = 0x0276, // updated 5.58h
|
||||
|
||||
SocialListHandler = 0x10B, // updated 6.58 hotfix 2
|
||||
SetSearchInfoHandler = 0x01A0, // updated 6.58 hotfix 2
|
||||
|
@ -451,6 +450,7 @@ enum ServerChatIpcType :
|
|||
uint16_t
|
||||
{
|
||||
Tell = 0x0064, // updated for sb
|
||||
ChannelChat = 0x0065,
|
||||
PublicContentTell = 0xF0FB, // added 4.5, this is used when receiving a /tell in PublicContent instances such as Eureka or Bozja (prepended F conflicts with TradeReturnEventHandler 6.38)
|
||||
TellErrNotFound = 0x0066,
|
||||
|
||||
|
@ -464,6 +464,7 @@ enum ClientChatIpcType :
|
|||
uint16_t
|
||||
{
|
||||
TellReq = 0x0064,
|
||||
ChannelChatReq = 0x0065,
|
||||
PublicContentTellReq = 0x0326, // updated 5.35 hotfix, this is used when sending a /tell in PublicContent instances such as Eureka or Bozja
|
||||
};
|
||||
|
||||
|
|
|
@ -207,10 +207,10 @@ struct FFXIVIpcChatHandler :
|
|||
/* 001A */ char message[1012];
|
||||
};
|
||||
|
||||
struct FFXIVIpcPartyChatHandler :
|
||||
FFXIVIpcBasePacket< ChatHandler >
|
||||
struct FFXIVIpcChannelChatHandler :
|
||||
FFXIVIpcBasePacket< ChannelChatReq >
|
||||
{
|
||||
uint64_t unknown;
|
||||
uint64_t channelId;
|
||||
char message[1024];
|
||||
};
|
||||
|
||||
|
@ -362,8 +362,8 @@ struct FFXIVIpcWorldInteractionHandler :
|
|||
Common::FFXIVARR_POSITION3 position;
|
||||
};
|
||||
|
||||
struct FFXIVIpcSocialReqSendHandler :
|
||||
FFXIVIpcBasePacket< SocialReqSendHandler >
|
||||
struct FFXIVIpcSocialInviteHandler :
|
||||
FFXIVIpcBasePacket< SocialInviteHandler >
|
||||
{
|
||||
uint64_t unknown;
|
||||
uint8_t p1;
|
||||
|
@ -373,8 +373,8 @@ struct FFXIVIpcSocialReqSendHandler :
|
|||
uint8_t padding[5];
|
||||
};
|
||||
|
||||
struct FFXIVIpcSocialResponseHandler :
|
||||
FFXIVIpcBasePacket< SocialResponseHandler >
|
||||
struct FFXIVIpcSocialReplyHandler :
|
||||
FFXIVIpcBasePacket< SocialReplyHandler >
|
||||
{
|
||||
uint64_t contentId;
|
||||
uint8_t p1;
|
||||
|
@ -384,8 +384,8 @@ struct FFXIVIpcSocialResponseHandler :
|
|||
uint32_t unknown;
|
||||
};
|
||||
|
||||
struct FFXIVIpcPartySetLeaderHandler :
|
||||
FFXIVIpcBasePacket< PartySetLeaderHandler >
|
||||
struct FFXIVIpcPartyChangeLeaderHandler :
|
||||
FFXIVIpcBasePacket< PartyChangeLeaderHandler >
|
||||
{
|
||||
uint64_t contentId;
|
||||
uint8_t p1;
|
||||
|
@ -394,14 +394,14 @@ struct FFXIVIpcPartySetLeaderHandler :
|
|||
uint8_t padding[6];
|
||||
};
|
||||
|
||||
struct FFXIVIpcLeavePartyHandler :
|
||||
FFXIVIpcBasePacket< LeavePartyHandler >
|
||||
struct FFXIVIpcPartyLeaveHandler :
|
||||
FFXIVIpcBasePacket< PartyLeaveHandler >
|
||||
{
|
||||
uint64_t empty;
|
||||
};
|
||||
|
||||
struct FFXIVIpcKickPartyMemberHander :
|
||||
FFXIVIpcBasePacket< KickPartyMemberHandler >
|
||||
struct FFXIVIpcPartyKickHandler :
|
||||
FFXIVIpcBasePacket< PartyKickHandler >
|
||||
{
|
||||
uint64_t contentId;
|
||||
uint8_t p1;
|
||||
|
@ -410,8 +410,8 @@ struct FFXIVIpcKickPartyMemberHander :
|
|||
uint8_t padding[6];
|
||||
};
|
||||
|
||||
struct FFXIVIpcDisbandPartyHandler :
|
||||
FFXIVIpcBasePacket< DisbandPartyHandler >
|
||||
struct FFXIVIpcPartyDisbandHandler :
|
||||
FFXIVIpcBasePacket< PartyDisbandHandler >
|
||||
{
|
||||
uint64_t empty;
|
||||
};
|
||||
|
|
|
@ -47,19 +47,6 @@ namespace Sapphire::Network::Packets::Server
|
|||
uint8_t unknown[12]; //possibly padding?
|
||||
};
|
||||
|
||||
struct FFXIVIpcPartyChat : FFXIVIpcBasePacket< PartyChat >
|
||||
{
|
||||
uint64_t unknown;
|
||||
uint64_t contentId;
|
||||
uint32_t charaId;
|
||||
uint8_t u1;
|
||||
uint8_t u2;
|
||||
uint8_t u3;
|
||||
char name[32];
|
||||
char message[1024];
|
||||
uint8_t padding;
|
||||
};
|
||||
|
||||
struct FFXIVIpcChatBanned : FFXIVIpcBasePacket< ChatBanned >
|
||||
{
|
||||
uint8_t padding[4]; // I was not sure reinterpreting ZST is valid behavior in C++.
|
||||
|
@ -2183,7 +2170,7 @@ namespace Sapphire::Network::Packets::Server
|
|||
uint32_t param7;
|
||||
};
|
||||
|
||||
struct FFXIVIpcSocialMessage : FFXIVIpcBasePacket< SocialMessage >
|
||||
struct FFXIVIpcSocialInviteUpdate : FFXIVIpcBasePacket< SocialInviteUpdate >
|
||||
{
|
||||
uint64_t contentId;
|
||||
uint32_t expireTime;
|
||||
|
@ -2192,12 +2179,12 @@ namespace Sapphire::Network::Packets::Server
|
|||
uint8_t socialType;
|
||||
uint8_t padding;
|
||||
uint8_t type;
|
||||
uint8_t unknown4;
|
||||
uint8_t gender;
|
||||
char name[32];
|
||||
uint8_t padding2[6];
|
||||
};
|
||||
|
||||
struct FFXIVIpcSocialMessage2 : FFXIVIpcBasePacket< SocialMessage2 >
|
||||
struct FFXIVIpcSocialInviteResult : FFXIVIpcBasePacket< SocialInviteResult >
|
||||
{
|
||||
uint64_t contentId;
|
||||
uint32_t unknown3;
|
||||
|
@ -2208,40 +2195,42 @@ namespace Sapphire::Network::Packets::Server
|
|||
char name[32];
|
||||
};
|
||||
|
||||
struct FFXIVIpcSocialRequestResponse : FFXIVIpcBasePacket< SocialRequestResponse >
|
||||
struct FFXIVIpcSocialInviteResponse : FFXIVIpcBasePacket< SocialInviteResponse >
|
||||
{
|
||||
uint64_t contentId;
|
||||
uint32_t unknown3;
|
||||
uint8_t u1AlwaysOne;
|
||||
uint8_t socialType;
|
||||
uint8_t response;
|
||||
uint8_t u2AlwaysOne;
|
||||
uint8_t gender;
|
||||
char name[32];
|
||||
uint8_t padding;
|
||||
};
|
||||
|
||||
struct PartyMember
|
||||
{
|
||||
char name[32];
|
||||
uint64_t contentId;
|
||||
uint32_t charaId;
|
||||
uint32_t u1; // 3.x ParentEntityId?
|
||||
uint32_t u2; // 3.x PetEntityId?
|
||||
uint32_t hp;
|
||||
uint32_t maxHp;
|
||||
uint16_t mp;
|
||||
uint16_t maxMp;
|
||||
uint16_t u3;
|
||||
uint16_t zoneId;
|
||||
uint8_t gposeSelectable; // 3.x Valid?
|
||||
uint8_t classId;
|
||||
uint8_t u5; // 3.x ObjType?
|
||||
uint8_t level;
|
||||
uint8_t isLevelSync;
|
||||
uint8_t unknown[7];
|
||||
Common::StatusEffect effect[30];
|
||||
};
|
||||
|
||||
struct FFXIVIpcPartyList : FFXIVIpcBasePacket< PartyList >
|
||||
{
|
||||
struct
|
||||
{
|
||||
char name[32];
|
||||
uint64_t contentId;
|
||||
uint32_t charaId;
|
||||
uint32_t u1;
|
||||
uint32_t u2;
|
||||
uint32_t hp;
|
||||
uint32_t maxHp;
|
||||
uint16_t mp;
|
||||
uint16_t maxMp;
|
||||
uint16_t u3;
|
||||
uint16_t zoneId;
|
||||
uint8_t gposeSelectable;
|
||||
uint8_t classId;
|
||||
uint8_t u5;
|
||||
uint8_t level;
|
||||
uint8_t isLevelSync;
|
||||
uint8_t unknown[7];
|
||||
Common::StatusEffect effect[30];
|
||||
} member[8];
|
||||
PartyMember member[8];
|
||||
uint64_t partyId;
|
||||
uint64_t channelId;
|
||||
uint8_t leaderIndex;
|
||||
|
@ -2250,16 +2239,16 @@ namespace Sapphire::Network::Packets::Server
|
|||
uint32_t padding2;
|
||||
};
|
||||
|
||||
struct FFXIVIpcPartyMessage : FFXIVIpcBasePacket< PartyMessage >
|
||||
struct FFXIVIpcPartyUpdate : FFXIVIpcBasePacket< PartyUpdate >
|
||||
{
|
||||
uint64_t leaderContentId;
|
||||
uint64_t memberContentId;
|
||||
uint8_t u1;
|
||||
uint8_t u2;
|
||||
uint16_t type;
|
||||
uint8_t partySize; // ?
|
||||
char leaderName[32];
|
||||
char memberName[32];
|
||||
uint64_t executeContentId;
|
||||
uint64_t targetContentId;
|
||||
uint8_t executeGender;
|
||||
uint8_t targetGender;
|
||||
uint16_t updateStatus;
|
||||
uint8_t partySize;
|
||||
char executeName[32];
|
||||
char targetName[32];
|
||||
uint8_t padding[3];
|
||||
};
|
||||
|
||||
|
|
|
@ -67,4 +67,6 @@ void EventItemAction::execute()
|
|||
void EventItemAction::start()
|
||||
{
|
||||
m_startTime = Common::Util::getTimeMs();
|
||||
if( !hasCastTime() )
|
||||
execute();
|
||||
}
|
||||
|
|
|
@ -85,6 +85,7 @@ Sapphire::Entity::Player::Player() :
|
|||
m_onEnterEventDone( false ),
|
||||
m_falling( false ),
|
||||
m_pQueuedAction( nullptr ),
|
||||
m_partyId( 0 ),
|
||||
m_cfNotifiedContent( 0 )
|
||||
{
|
||||
m_id = 0;
|
||||
|
@ -134,7 +135,8 @@ uint32_t Sapphire::Entity::Player::getMaxHp()
|
|||
|
||||
uint32_t Sapphire::Entity::Player::getMaxMp()
|
||||
{
|
||||
return m_baseStats.max_mp;
|
||||
//return m_baseStats.max_mp;
|
||||
return 10000;
|
||||
}
|
||||
|
||||
uint16_t Sapphire::Entity::Player::getZoneId() const
|
||||
|
@ -236,6 +238,10 @@ Sapphire::Common::OnlineStatus Sapphire::Entity::Player::getOnlineStatus() const
|
|||
void Sapphire::Entity::Player::setOnlineStatusMask( uint64_t status )
|
||||
{
|
||||
m_onlineStatus = status;
|
||||
sendToInRangeSet( makeActorControl( getId(), SetStatusIcon, static_cast< uint8_t >( getOnlineStatus() ) ), true );
|
||||
auto statusPacket = makeZonePacket< FFXIVIpcSetOnlineStatus >( getId() );
|
||||
statusPacket->data().onlineStatusFlags = status;
|
||||
queuePacket( statusPacket );
|
||||
}
|
||||
|
||||
uint64_t Sapphire::Entity::Player::getOnlineStatusMask() const
|
||||
|
@ -243,6 +249,47 @@ uint64_t Sapphire::Entity::Player::getOnlineStatusMask() const
|
|||
return m_onlineStatus;
|
||||
}
|
||||
|
||||
void Sapphire::Entity::Player::addOnlineStatus( OnlineStatus status )
|
||||
{
|
||||
uint64_t statusValue = 1ull << static_cast< uint8_t >( status );
|
||||
uint64_t newFlags = getOnlineStatusMask() | statusValue;
|
||||
|
||||
setOnlineStatusMask( newFlags );
|
||||
}
|
||||
|
||||
void Sapphire::Entity::Player::addOnlineStatus( const std::vector< Common::OnlineStatus >& status )
|
||||
{
|
||||
uint64_t newFlags = getOnlineStatusMask();
|
||||
for( const auto& state : status )
|
||||
{
|
||||
uint64_t statusValue = 1ull << static_cast< uint8_t >( state );
|
||||
newFlags |= statusValue;
|
||||
}
|
||||
|
||||
setOnlineStatusMask( newFlags );
|
||||
}
|
||||
|
||||
void Sapphire::Entity::Player::removeOnlineStatus( OnlineStatus status )
|
||||
{
|
||||
uint64_t statusValue = 1ull << static_cast< uint8_t >( status );
|
||||
uint64_t newFlags = getOnlineStatusMask();
|
||||
newFlags &= ~statusValue;
|
||||
|
||||
setOnlineStatusMask( newFlags );
|
||||
}
|
||||
|
||||
void Sapphire::Entity::Player::removeOnlineStatus( const std::vector< Common::OnlineStatus >& status )
|
||||
{
|
||||
uint64_t newFlags = getOnlineStatusMask();
|
||||
for( const auto& state : status )
|
||||
{
|
||||
uint64_t statusValue = 1ull << static_cast< uint8_t >( state );
|
||||
newFlags &= ~statusValue;
|
||||
}
|
||||
|
||||
setOnlineStatusMask( newFlags );
|
||||
}
|
||||
|
||||
void Sapphire::Entity::Player::prepareZoning( uint16_t targetZone, bool fadeOut, uint8_t fadeOutTime, uint16_t animation, uint8_t param4, uint8_t param7, uint8_t unknown )
|
||||
{
|
||||
auto preparePacket = makeZonePacket< FFXIVIpcPrepareZoning >( getId() );
|
||||
|
@ -513,14 +560,15 @@ bool Sapphire::Entity::Player::exitInstance()
|
|||
{
|
||||
auto& teriMgr = Common::Service< TerritoryMgr >::ref();
|
||||
|
||||
auto d = getCurrentTerritory()->getAsDirector();
|
||||
auto d = getCurrentTerritory()->getAsInstanceContent();
|
||||
if( d && d->getContentFinderConditionId() > 0 )
|
||||
{
|
||||
// shows correct name when leaving dungeon
|
||||
auto p = makeZonePacket< FFXIVDirectorUnk4 >( getId() );
|
||||
p->data().param[0] = d->getDirectorId();
|
||||
p->data().param[1] = 1534;
|
||||
p->data().param[2] = 1;
|
||||
p->data().param[3] = d->getContentFinderConditionId();
|
||||
p->data().param[3] = d->getContentId();
|
||||
queuePacket( p );
|
||||
|
||||
prepareZoning( 0, 1, 1, 0, 0, 1, 9 );
|
||||
|
@ -1080,7 +1128,6 @@ bool Sapphire::Entity::Player::hasStateFlag( Common::PlayerStateFlag flag ) cons
|
|||
|
||||
void Sapphire::Entity::Player::setStateFlag( Common::PlayerStateFlag flag )
|
||||
{
|
||||
auto prevOnlineStatus = getOnlineStatus();
|
||||
int32_t iFlag = static_cast< uint32_t >( flag );
|
||||
|
||||
uint16_t index;
|
||||
|
@ -1089,13 +1136,6 @@ void Sapphire::Entity::Player::setStateFlag( Common::PlayerStateFlag flag )
|
|||
|
||||
m_stateFlags[ index ] |= value;
|
||||
sendStateFlags();
|
||||
|
||||
auto newOnlineStatus = getOnlineStatus();
|
||||
|
||||
if( prevOnlineStatus != newOnlineStatus )
|
||||
sendToInRangeSet( makeActorControl( getId(), SetStatusIcon,
|
||||
static_cast< uint8_t >( getOnlineStatus() ) ), true );
|
||||
|
||||
}
|
||||
|
||||
void Sapphire::Entity::Player::setStateFlags( std::vector< Common::PlayerStateFlag > flags )
|
||||
|
@ -1116,8 +1156,6 @@ void Sapphire::Entity::Player::unsetStateFlag( Common::PlayerStateFlag flag )
|
|||
if( !hasStateFlag( flag ) )
|
||||
return;
|
||||
|
||||
auto prevOnlineStatus = getOnlineStatus();
|
||||
|
||||
int32_t iFlag = static_cast< uint32_t >( flag );
|
||||
|
||||
uint16_t index;
|
||||
|
@ -1126,11 +1164,6 @@ void Sapphire::Entity::Player::unsetStateFlag( Common::PlayerStateFlag flag )
|
|||
|
||||
m_stateFlags[ index ] ^= value;
|
||||
sendStateFlags();
|
||||
|
||||
auto newOnlineStatus = getOnlineStatus();
|
||||
|
||||
if( prevOnlineStatus != newOnlineStatus )
|
||||
sendToInRangeSet( makeActorControl( getId(), SetStatusIcon, static_cast< uint8_t >( getOnlineStatus() ) ), true );
|
||||
}
|
||||
|
||||
void Sapphire::Entity::Player::update( uint64_t tickCount )
|
||||
|
@ -1356,6 +1389,14 @@ void Sapphire::Entity::Player::queuePacket( Network::Packets::FFXIVPacketBasePtr
|
|||
|
||||
}
|
||||
|
||||
void Sapphire::Entity::Player::queuePacket( std::vector< Network::Packets::FFXIVPacketBasePtr > packets )
|
||||
{
|
||||
for( auto& packet : packets )
|
||||
{
|
||||
queuePacket( packet );
|
||||
}
|
||||
}
|
||||
|
||||
void Sapphire::Entity::Player::queueChatPacket( Network::Packets::FFXIVPacketBasePtr pPacket )
|
||||
{
|
||||
auto& serverMgr = Common::Service< World::ServerMgr >::ref();
|
||||
|
@ -2334,6 +2375,16 @@ bool Sapphire::Entity::Player::checkAction()
|
|||
return true;
|
||||
}
|
||||
|
||||
uint64_t Sapphire::Entity::Player::getPartyId() const
|
||||
{
|
||||
return m_partyId;
|
||||
}
|
||||
|
||||
void Sapphire::Entity::Player::setPartyId( uint64_t partyId )
|
||||
{
|
||||
m_partyId = partyId;
|
||||
}
|
||||
|
||||
std::vector< Sapphire::Entity::ShopBuyBackEntry >& Sapphire::Entity::Player::getBuyBackListForShop( uint32_t shopId )
|
||||
{
|
||||
return m_shopBuyBackMap[ shopId ];
|
||||
|
|
|
@ -340,7 +340,7 @@ namespace Sapphire::Entity
|
|||
void equipSoulCrystal( ItemPtr pItem, bool updateClass );
|
||||
|
||||
/*! unequip a soul crystal, returning to the base class*/
|
||||
void unequipSoulCrystal( ItemPtr pItem );
|
||||
void unequipSoulCrystal();
|
||||
|
||||
/*! get player ilvl */
|
||||
uint16_t getItemLevel() const;
|
||||
|
@ -543,6 +543,11 @@ namespace Sapphire::Entity
|
|||
/*! returns the current online status */
|
||||
uint64_t getOnlineStatusMask() const;
|
||||
|
||||
void addOnlineStatus( Common::OnlineStatus status );
|
||||
void addOnlineStatus( const std::vector< Common::OnlineStatus >& status );
|
||||
void removeOnlineStatus( Common::OnlineStatus status );
|
||||
void removeOnlineStatus( const std::vector< Common::OnlineStatus >& status );
|
||||
|
||||
/*! perform a teleport of a specified type ( teleport,return,aethernet ) */
|
||||
void teleport( uint16_t aetheryteId, uint8_t type = 1 );
|
||||
|
||||
|
@ -769,6 +774,7 @@ namespace Sapphire::Entity
|
|||
|
||||
/*! queue a packet for the player */
|
||||
void queuePacket( Network::Packets::FFXIVPacketBasePtr pPacket );
|
||||
void queuePacket( std::vector< Network::Packets::FFXIVPacketBasePtr > packets );
|
||||
|
||||
/*! queue a char connection packet for the player */
|
||||
void queueChatPacket( Network::Packets::FFXIVPacketBasePtr pPacket );
|
||||
|
@ -1028,6 +1034,9 @@ namespace Sapphire::Entity
|
|||
|
||||
void updateHuntingLog( uint16_t id );
|
||||
|
||||
uint64_t getPartyId() const;
|
||||
void setPartyId( uint64_t partyId );
|
||||
|
||||
World::SessionPtr getSession();
|
||||
|
||||
uint64_t m_lastMoveTime;
|
||||
|
@ -1181,6 +1190,8 @@ namespace Sapphire::Entity
|
|||
Common::Util::SpawnIndexAllocator< uint8_t > m_objSpawnIndexAllocator;
|
||||
Common::Util::SpawnIndexAllocator< uint8_t > m_actorSpawnIndexAllocator;
|
||||
|
||||
uint64_t m_partyId;
|
||||
|
||||
std::array< Common::HuntingLogEntry, 12 > m_huntingLogEntries;
|
||||
std::unordered_map< uint32_t, std::vector< ShopBuyBackEntry > > m_shopBuyBackMap;
|
||||
};
|
||||
|
|
|
@ -148,9 +148,9 @@ void Sapphire::Entity::Player::equipSoulCrystal( ItemPtr pItem, bool updateJob )
|
|||
|
||||
void Sapphire::Entity::Player::updateModels( GearSetSlot equipSlotId, const Sapphire::ItemPtr& pItem, bool updateClass )
|
||||
{
|
||||
uint64_t model = pItem->getModelId1();
|
||||
uint64_t model2 = pItem->getModelId2();
|
||||
uint64_t stain = pItem->getStain();
|
||||
uint64_t model = pItem ? pItem->getModelId1() : 0;
|
||||
uint64_t model2 = pItem ? pItem->getModelId2() : 0;
|
||||
uint64_t stain = pItem ? pItem->getStain() : 0;
|
||||
|
||||
switch( equipSlotId )
|
||||
{
|
||||
|
@ -172,7 +172,10 @@ void Sapphire::Entity::Player::updateModels( GearSetSlot equipSlotId, const Sapp
|
|||
break;
|
||||
|
||||
case SoulCrystal:
|
||||
equipSoulCrystal( pItem, updateClass );
|
||||
if( pItem )
|
||||
equipSoulCrystal( pItem, updateClass );
|
||||
else
|
||||
unequipSoulCrystal();
|
||||
break;
|
||||
|
||||
case Waist:
|
||||
|
@ -265,15 +268,12 @@ void Sapphire::Entity::Player::unequipItem( Common::GearSetSlot equipSlotId, Ite
|
|||
|
||||
if( sendUpdate )
|
||||
{
|
||||
updateModels( equipSlotId, nullptr, true );
|
||||
sendModel();
|
||||
|
||||
m_itemLevel = calculateEquippedGearItemLevel();
|
||||
sendItemLevel();
|
||||
}
|
||||
|
||||
if ( equipSlotId == SoulCrystal )
|
||||
unequipSoulCrystal( pItem );
|
||||
|
||||
auto baseParams = pItem->getBaseParams();
|
||||
for( auto i = 0; i < 6; ++i )
|
||||
{
|
||||
|
@ -293,7 +293,7 @@ void Sapphire::Entity::Player::unequipItem( Common::GearSetSlot equipSlotId, Ite
|
|||
}
|
||||
}
|
||||
|
||||
void Sapphire::Entity::Player::unequipSoulCrystal( ItemPtr pItem )
|
||||
void Sapphire::Entity::Player::unequipSoulCrystal()
|
||||
{
|
||||
auto& exdData = Common::Service< Sapphire::Data::ExdDataGenerated >::ref();
|
||||
|
||||
|
@ -547,38 +547,6 @@ void Sapphire::Entity::Player::writeInventory( InventoryType type )
|
|||
db.execute( query );
|
||||
}
|
||||
|
||||
void Sapphire::Entity::Player::updateItemDb( Sapphire::ItemPtr pItem ) const
|
||||
{
|
||||
if( pItem->getUId() == 0 )
|
||||
writeItemDb( pItem );
|
||||
|
||||
auto& db = Common::Service< Db::DbWorkerPool< Db::ZoneDbConnection > >::ref();
|
||||
auto stmt = db.getPreparedStatement( Db::CHARA_ITEMGLOBAL_UP );
|
||||
|
||||
// todo: add more fields
|
||||
stmt->setInt( 1, pItem->getStackSize() );
|
||||
stmt->setInt( 2, pItem->getDurability() );
|
||||
stmt->setInt( 3, pItem->getStain() );
|
||||
|
||||
stmt->setInt64( 4, pItem->getUId() );
|
||||
|
||||
db.directExecute( stmt );
|
||||
}
|
||||
|
||||
void Sapphire::Entity::Player::deleteItemDb( Sapphire::ItemPtr item ) const
|
||||
{
|
||||
if( item->getUId() == 0 )
|
||||
return;
|
||||
|
||||
auto& db = Common::Service< Db::DbWorkerPool< Db::ZoneDbConnection > >::ref();
|
||||
auto stmt = db.getPreparedStatement( Db::CHARA_ITEMGLOBAL_DELETE );
|
||||
|
||||
stmt->setInt64( 1, item->getUId() );
|
||||
|
||||
db.directExecute( stmt );
|
||||
}
|
||||
|
||||
|
||||
bool Sapphire::Entity::Player::isObtainable( uint32_t catalogId, uint8_t quantity )
|
||||
{
|
||||
return true;
|
||||
|
@ -748,7 +716,19 @@ Sapphire::Entity::Player::moveItem( uint16_t fromInventoryId, uint8_t fromSlotId
|
|||
auto& itemMap = m_storageMap[ fromInventoryId ]->getItemMap();
|
||||
|
||||
if( tmpItem == nullptr )
|
||||
{
|
||||
sendUrgent( "trying to move EMPTY item from [container{}, slot{}] to [container{}, slot{}], potential client desync, no action is performed.",
|
||||
fromInventoryId, fromSlotId, toInventoryId, toSlot );
|
||||
return;
|
||||
}
|
||||
|
||||
if( auto target = m_storageMap[ toInventoryId ]->getItem( toSlot ) )
|
||||
{
|
||||
sendUrgent( "trying to move item from [container{}, slot{}] to NON-EMPTY [container{}, slot{}], potential client desync, swapItem is performed instead.",
|
||||
fromInventoryId, fromSlotId, toInventoryId, toSlot );
|
||||
swapItem( fromInventoryId, fromSlotId, toInventoryId, toSlot, sendUpdate );
|
||||
return;
|
||||
}
|
||||
|
||||
itemMap[ fromSlotId ].reset();
|
||||
|
||||
|
@ -885,8 +865,28 @@ void Sapphire::Entity::Player::swapItem( uint16_t fromInventoryId, uint8_t fromS
|
|||
auto toItem = m_storageMap[ toInventoryId ]->getItem( toSlot );
|
||||
auto& itemMap = m_storageMap[ fromInventoryId ]->getItemMap();
|
||||
|
||||
if( fromItem == nullptr || toItem == nullptr )
|
||||
if( fromItem == nullptr && toItem == nullptr )
|
||||
{
|
||||
sendUrgent( "trying to swap TWO EMPTY ITEMS from [container{}, slot{}] to [container{}, slot{}], potential client desync, no action is performed.",
|
||||
fromInventoryId, fromSlotId, toInventoryId, toSlot );
|
||||
return;
|
||||
}
|
||||
|
||||
if( fromItem != nullptr && toItem == nullptr )
|
||||
{
|
||||
sendUrgent( "trying to swap item from [container{}, slot{}] to EMPTY [container{}, slot{}], potential client desync, moveItem is performed instead.",
|
||||
fromInventoryId, fromSlotId, toInventoryId, toSlot );
|
||||
moveItem( fromInventoryId, fromSlotId, toInventoryId, toSlot, sendUpdate );
|
||||
return;
|
||||
}
|
||||
|
||||
if( fromItem == nullptr && toItem != nullptr )
|
||||
{
|
||||
sendUrgent( "trying to swap EMPTY item from [container{}, slot{}] to [container{}, slot{}], potential client desync, moveItem is performed instead.",
|
||||
fromInventoryId, fromSlotId, toInventoryId, toSlot );
|
||||
moveItem( toInventoryId, toSlot, fromInventoryId, fromSlotId, sendUpdate ); // we are moving the non-empty toSlot back to fromSlot.
|
||||
return;
|
||||
}
|
||||
|
||||
// An item is being moved from bag0-3 to equippment, meaning
|
||||
// the swapped out item will be placed in the matching armory.
|
||||
|
|
|
@ -650,10 +650,13 @@ void Sapphire::Entity::Player::writeItemDb( Sapphire::ItemPtr pItem ) const
|
|||
auto& itemMgr = Common::Service< World::Manager::ItemMgr >::ref();
|
||||
|
||||
uint8_t flags = 0;
|
||||
if( pItem->isHq() )
|
||||
flags |= Common::ItemFlag::FlagHq;
|
||||
pItem->setUId( itemMgr.getNextUId() );
|
||||
std::string sql = "INSERT INTO charaglobalitem ( CharacterId, itemId, catalogId, stack, flags ) VALUES ( " +
|
||||
std::string sql = "INSERT INTO charaglobalitem ( CharacterId, itemId, reservedFlag, catalogId, stack, flags ) VALUES ( " +
|
||||
std::to_string( getId() ) + ", " +
|
||||
std::to_string( pItem->getUId() ) + ", " +
|
||||
std::to_string( pItem->getReservedFlag() ) + ", " +
|
||||
std::to_string( pItem->getId() ) + ", " +
|
||||
std::to_string( pItem->getStackSize() ) + ", " +
|
||||
std::to_string( flags ) + ");";
|
||||
|
@ -661,6 +664,46 @@ void Sapphire::Entity::Player::writeItemDb( Sapphire::ItemPtr pItem ) const
|
|||
}
|
||||
}
|
||||
|
||||
void Sapphire::Entity::Player::updateItemDb( Sapphire::ItemPtr pItem ) const
|
||||
{
|
||||
if( pItem->getUId() == 0 )
|
||||
{
|
||||
writeItemDb( pItem );
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t flags = 0;
|
||||
if( pItem->isHq() )
|
||||
flags |= Common::ItemFlag::FlagHq;
|
||||
|
||||
auto& db = Common::Service< Db::DbWorkerPool< Db::ZoneDbConnection > >::ref();
|
||||
auto stmt = db.getPreparedStatement( Db::CHARA_ITEMGLOBAL_UP );
|
||||
|
||||
// todo: add more fields
|
||||
stmt->setInt( 1, pItem->getStackSize() );
|
||||
stmt->setInt( 2, pItem->getDurability() );
|
||||
stmt->setInt( 3, flags );
|
||||
stmt->setInt( 4, pItem->getReservedFlag() );
|
||||
stmt->setInt( 5, pItem->getStain() );
|
||||
|
||||
stmt->setInt64( 6, pItem->getUId() );
|
||||
|
||||
db.directExecute( stmt );
|
||||
}
|
||||
|
||||
void Sapphire::Entity::Player::deleteItemDb( Sapphire::ItemPtr item ) const
|
||||
{
|
||||
if( item->getUId() == 0 )
|
||||
return;
|
||||
|
||||
auto& db = Common::Service< Db::DbWorkerPool< Db::ZoneDbConnection > >::ref();
|
||||
auto stmt = db.getPreparedStatement( Db::CHARA_ITEMGLOBAL_DELETE );
|
||||
|
||||
stmt->setInt64( 1, item->getUId() );
|
||||
|
||||
db.directExecute( stmt );
|
||||
}
|
||||
|
||||
bool Sapphire::Entity::Player::loadInventory()
|
||||
{
|
||||
auto& itemMgr = Common::Service< World::Manager::ItemMgr >::ref();
|
||||
|
|
144
src/world/Manager/ChatChannelMgr.cpp
Normal file
144
src/world/Manager/ChatChannelMgr.cpp
Normal file
|
@ -0,0 +1,144 @@
|
|||
#include <Network/PacketWrappers/ChannelChatPacket.h>
|
||||
#include <Logging/Logger.h>
|
||||
#include <Service.h>
|
||||
|
||||
#include "ChatChannelMgr.h"
|
||||
|
||||
#include "Actor/Player.h"
|
||||
#include "ServerMgr.h"
|
||||
#include "Session.h"
|
||||
#include "Network/GameConnection.h"
|
||||
|
||||
using namespace Sapphire;
|
||||
using namespace Sapphire::Network;
|
||||
using namespace Sapphire::Network::Packets;
|
||||
using namespace Sapphire::World::Manager;
|
||||
|
||||
const uint64_t ChatChannelMgr::createChatChannel( Common::ChatChannelType type )
|
||||
{
|
||||
auto& server = Common::Service< World::ServerMgr >::ref();
|
||||
|
||||
// get next id for new channel
|
||||
|
||||
uint32_t cNo = m_lastChatNo;
|
||||
|
||||
m_lastChatNo++;
|
||||
|
||||
uint16_t chatType = static_cast< uint16_t >( type );
|
||||
uint16_t worldId = server.getWorldId();
|
||||
|
||||
Data::ChatChannel cId;
|
||||
|
||||
cId.data.ChannelNo = cNo;
|
||||
cId.data.ChannelType = type;
|
||||
cId.data.WorldId = worldId;
|
||||
|
||||
// create our new chat channel
|
||||
|
||||
Data::ChatChannelMembers newChatChannel = {};
|
||||
|
||||
m_channels[ cId.ChannelID ] = newChatChannel;
|
||||
|
||||
Logger::debug( "Chat channel ID "
|
||||
+ std::to_string( cId.ChannelID )
|
||||
+ " created"
|
||||
);
|
||||
|
||||
return cId.ChannelID;
|
||||
}
|
||||
|
||||
void ChatChannelMgr::addToChannel( uint64_t channelId, Entity::Player& player )
|
||||
{
|
||||
if( !isChannelValid( channelId ) )
|
||||
{
|
||||
// channel id is invalid
|
||||
|
||||
Logger::warn( "Attempted to add player "
|
||||
+ std::to_string( player.getId() )
|
||||
+ " to invalid channel ID "
|
||||
+ std::to_string( channelId )
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
auto& channelMembers = m_channels[ channelId ];
|
||||
auto id = player.getId();
|
||||
|
||||
if( std::find( channelMembers.begin(), channelMembers.end(), id ) == channelMembers.end() )
|
||||
m_channels[ channelId ].emplace_back( id );
|
||||
}
|
||||
|
||||
void ChatChannelMgr::removeFromChannel( uint64_t channelId, Entity::Player& player )
|
||||
{
|
||||
if( !isChannelValid( channelId ) )
|
||||
{
|
||||
// channel id is invalid
|
||||
|
||||
Logger::warn( "Attempted to remove player "
|
||||
+ std::to_string( player.getId() )
|
||||
+ " from invalid channel ID "
|
||||
+ std::to_string( channelId )
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
auto& channelMembers = m_channels[ channelId ];
|
||||
auto id = player.getId();
|
||||
|
||||
auto it = std::find( channelMembers.begin(), channelMembers.end(), id );
|
||||
if( it != channelMembers.end() )
|
||||
channelMembers.erase( it );
|
||||
}
|
||||
|
||||
void ChatChannelMgr::sendMessageToChannel( uint64_t channelId, Entity::Player& sender, const std::string& message )
|
||||
{
|
||||
if( !isChannelValid( channelId ) )
|
||||
{
|
||||
// channel id is invalid
|
||||
|
||||
Logger::warn( "Attempted to send message from player "
|
||||
+ std::to_string( sender.getId() )
|
||||
+ " to invalid channel ID "
|
||||
+ std::to_string( channelId )
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
auto& channelMembers = m_channels[ channelId ];
|
||||
|
||||
auto& server = Common::Service< World::ServerMgr >::ref();
|
||||
|
||||
// send message to all players in chat channel
|
||||
for( const auto id : channelMembers )
|
||||
{
|
||||
// skip sender from getting their own message
|
||||
if( id == sender.getId() )
|
||||
continue;
|
||||
|
||||
auto pPlayer = server.getSession( id )->getPlayer();
|
||||
|
||||
// check if player is online to recv message
|
||||
if( !pPlayer/*->isConnected()*/ )
|
||||
continue;
|
||||
|
||||
// prepare message packet, associating message and sender info with channel data
|
||||
auto chatToChannelPacket = std::make_shared< Packets::Server::ChannelChatPacket >( *pPlayer, sender, channelId, message );
|
||||
pPlayer->queueChatPacket( chatToChannelPacket );
|
||||
}
|
||||
}
|
||||
|
||||
bool ChatChannelMgr::isChannelValid( uint64_t channelId ) const
|
||||
{
|
||||
return !( m_channels.find( channelId ) == m_channels.end() );
|
||||
}
|
||||
|
||||
const Data::ChatChannelMembers& ChatChannelMgr::getChatChannel( uint64_t channelId )
|
||||
{
|
||||
bool channelValid = isChannelValid( channelId );
|
||||
assert( channelValid );
|
||||
|
||||
return m_channels[ channelId ];
|
||||
}
|
45
src/world/Manager/ChatChannelMgr.h
Normal file
45
src/world/Manager/ChatChannelMgr.h
Normal file
|
@ -0,0 +1,45 @@
|
|||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include "ForwardsZone.h"
|
||||
|
||||
namespace Sapphire::Data
|
||||
{
|
||||
using ChatChannelMembers = std::vector< uint32_t >;
|
||||
|
||||
union ChatChannel
|
||||
{
|
||||
uint64_t ChannelID;
|
||||
|
||||
struct ChannelData {
|
||||
uint32_t ChannelNo;
|
||||
uint16_t ChannelType;
|
||||
uint16_t WorldId;
|
||||
} data;
|
||||
};
|
||||
}
|
||||
|
||||
namespace Sapphire::World::Manager
|
||||
{
|
||||
class ChatChannelMgr
|
||||
{
|
||||
public:
|
||||
ChatChannelMgr() = default;
|
||||
~ChatChannelMgr() = default;
|
||||
|
||||
const uint64_t createChatChannel( Common::ChatChannelType type );
|
||||
|
||||
void addToChannel( uint64_t channelId, Entity::Player& player );
|
||||
void removeFromChannel( uint64_t channelId, Entity::Player& player );
|
||||
|
||||
void sendMessageToChannel( uint64_t channelId, Entity::Player& sender, const std::string& message );
|
||||
|
||||
bool isChannelValid( uint64_t channelId ) const;
|
||||
const Data::ChatChannelMembers& getChatChannel( uint64_t channelId );
|
||||
|
||||
private:
|
||||
std::map< uint64_t, Data::ChatChannelMembers > m_channels;
|
||||
uint32_t m_lastChatNo = 0x1000;
|
||||
};
|
||||
}
|
|
@ -132,15 +132,16 @@ Sapphire::ItemPtr Sapphire::World::Manager::ItemMgr::loadItem( uint64_t uId )
|
|||
try
|
||||
{
|
||||
auto itemInfo = exdData.get< Sapphire::Data::Item >( itemRes->getUInt( 1 ) );
|
||||
bool isHq = itemRes->getUInt( 3 ) == 1;
|
||||
bool isHq = itemRes->getUInt( 5 ) & Common::ItemFlag::FlagHq;
|
||||
|
||||
ItemPtr pItem = make_Item( uId,
|
||||
itemRes->getUInt( 1 ),
|
||||
isHq );
|
||||
|
||||
pItem->setStackSize( itemRes->getUInt( 2 ) );
|
||||
pItem->setStain( itemRes->getUInt16( 13 ) );
|
||||
pItem->setReservedFlag( itemRes->getUInt( 3 ) );
|
||||
pItem->setDurability( itemRes->getInt16( 6 ) );
|
||||
pItem->setStain( itemRes->getUInt16( 13 ) );
|
||||
|
||||
return pItem;
|
||||
}
|
||||
|
|
439
src/world/Manager/PartyMgr.cpp
Normal file
439
src/world/Manager/PartyMgr.cpp
Normal file
|
@ -0,0 +1,439 @@
|
|||
#include <Common.h>
|
||||
#include <Exd/ExdDataGenerated.h>
|
||||
#include <Logging/Logger.h>
|
||||
#include <Service.h>
|
||||
|
||||
#include <Network/PacketDef/Zone/ServerZoneDef.h>
|
||||
#include <Network/PacketContainer.h>
|
||||
|
||||
#include "Network/GameConnection.h"
|
||||
|
||||
#include "PartyMgr.h"
|
||||
#include "ServerMgr.h"
|
||||
#include "ChatChannelMgr.h"
|
||||
#include "PlayerMgr.h"
|
||||
|
||||
#include "Session.h"
|
||||
|
||||
#include "Actor/Player.h"
|
||||
|
||||
#include "Network/PacketWrappers/PartyUpdatePacket.h"
|
||||
|
||||
using namespace Sapphire;
|
||||
using namespace Sapphire::World::Manager;
|
||||
using namespace Sapphire::Network::Packets;
|
||||
using namespace Sapphire::Network::Packets::Server;
|
||||
|
||||
void PartyMgr::onJoin( Entity::Player& joiner, Entity::Player& inviter )
|
||||
{
|
||||
auto& server = Common::Service< World::ServerMgr >::ref();
|
||||
auto& ccMgr = Common::Service< World::Manager::ChatChannelMgr >::ref();
|
||||
|
||||
auto& inviteePlayer = joiner;
|
||||
auto& invitingPlayer = inviter;
|
||||
|
||||
if( inviteePlayer.getPartyId() != 0 )
|
||||
{
|
||||
Logger::error( "Player#{} already in a party, cannot be invited!!", inviteePlayer.getId() );
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t partyId;
|
||||
// if there is no party yet, one has to be created
|
||||
PartyPtr party;
|
||||
if( inviteePlayer.getPartyId() == 0 && invitingPlayer.getPartyId() == 0 )
|
||||
{
|
||||
partyId = createParty();
|
||||
party = getParty( partyId );
|
||||
assert( party );
|
||||
|
||||
inviteePlayer.setPartyId( partyId );
|
||||
inviteePlayer.addOnlineStatus( Common::OnlineStatus::PartyMember );
|
||||
invitingPlayer.setPartyId( partyId );
|
||||
invitingPlayer.addOnlineStatus( Common::OnlineStatus::PartyLeader );
|
||||
|
||||
ccMgr.addToChannel( party->ChatChannel, invitingPlayer );
|
||||
ccMgr.addToChannel( party->ChatChannel, inviteePlayer );
|
||||
|
||||
party->MemberId.push_back( invitingPlayer.getId() );
|
||||
party->MemberId.push_back( inviteePlayer.getId() );
|
||||
party->PartyCount = 2;
|
||||
party->LeaderId = invitingPlayer.getId();
|
||||
}
|
||||
else if( inviteePlayer.getPartyId() == 0 )
|
||||
{
|
||||
partyId = invitingPlayer.getPartyId();
|
||||
party = getParty( partyId );
|
||||
|
||||
inviteePlayer.setPartyId( partyId );
|
||||
inviteePlayer.addOnlineStatus( Common::OnlineStatus::PartyMember );
|
||||
|
||||
ccMgr.addToChannel( party->ChatChannel, inviteePlayer );
|
||||
|
||||
party->MemberId.push_back( inviteePlayer.getId() );
|
||||
party->PartyCount++;
|
||||
}
|
||||
|
||||
auto pcUpdateParty = makePartyUpdate( invitingPlayer, inviteePlayer, UpdateStatus::JOINED, party->PartyCount );
|
||||
auto members = getPartyMembers( *party );
|
||||
sendPartyUpdate( *party );
|
||||
for( const auto& member : members )
|
||||
{
|
||||
member->queuePacket( pcUpdateParty );
|
||||
}
|
||||
}
|
||||
|
||||
void PartyMgr::onLeave( Sapphire::Entity::Player &leavingPlayer )
|
||||
{
|
||||
auto& server = Common::Service< World::ServerMgr >::ref();
|
||||
|
||||
auto party = getParty( leavingPlayer.getPartyId() );
|
||||
assert( party );
|
||||
|
||||
auto leadingPlayer = getPartyLeader( *party );
|
||||
assert( leadingPlayer );
|
||||
|
||||
if( !leadingPlayer )
|
||||
return;
|
||||
|
||||
if( party->PartyCount == 2 )
|
||||
{
|
||||
onDisband( *leadingPlayer );
|
||||
}
|
||||
else
|
||||
{
|
||||
auto members = getPartyMembers( *party );
|
||||
removeMember( *party, leavingPlayer.getAsPlayer() );
|
||||
|
||||
uint32_t newLeaderId = 0;
|
||||
for( const auto& member : members )
|
||||
{
|
||||
if( member->getId() == leavingPlayer.getId() )
|
||||
{
|
||||
member->removeOnlineStatus( { Common::OnlineStatus::PartyMember,
|
||||
Common::OnlineStatus::PartyLeader } );
|
||||
|
||||
leavingPlayer.queuePacket( makeZonePacket< FFXIVIpcPartyList >( leavingPlayer.getId() ) );
|
||||
member->queuePacket( makePartyUpdate( leadingPlayer, nullptr, UpdateStatus::KICK_SELF, party->PartyCount ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( leavingPlayer.getId() == party->LeaderId )
|
||||
{
|
||||
newLeaderId = party->MemberId[ 0 ];
|
||||
auto pPlayer = server.getSession( newLeaderId )->getPlayer();
|
||||
if( !pPlayer /*|| !pPlayer->isConnected() */)
|
||||
continue;
|
||||
pPlayer->addOnlineStatus( Common::OnlineStatus::PartyLeader );
|
||||
member->queuePacket( makePartyUpdate( leavingPlayer.getAsPlayer(), pPlayer, UpdateStatus::LEAVELEADER_LEAVED_MEMBER, party->PartyCount ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
member->queuePacket( makePartyUpdate( leavingPlayer.getAsPlayer(), nullptr, UpdateStatus::LEAVE_MEMBER, party->PartyCount ) );
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
if( newLeaderId != 0 )
|
||||
party->LeaderId = newLeaderId;
|
||||
party->PartyCount--;
|
||||
sendPartyUpdate( *party );
|
||||
}
|
||||
}
|
||||
|
||||
void PartyMgr::onDisband( Entity::Player& disbandingPlayer )
|
||||
{
|
||||
auto& server = Common::Service< World::ServerMgr >::ref();
|
||||
auto party = getParty( disbandingPlayer.getPartyId() );
|
||||
assert( party );
|
||||
|
||||
auto members = getPartyMembers( *party );
|
||||
for( const auto& member : members )
|
||||
{
|
||||
removeMember( *party, member );
|
||||
member->removeOnlineStatus( { Common::OnlineStatus::PartyMember, Common::OnlineStatus::PartyLeader } );
|
||||
member->queuePacket( { makePartyUpdate( disbandingPlayer, disbandingPlayer, UpdateStatus::DISBAND, party->PartyCount ), makeZonePacket< FFXIVIpcPartyList >( member->getId() ) } );
|
||||
}
|
||||
|
||||
removeParty( party->PartyID );
|
||||
}
|
||||
|
||||
void PartyMgr::onMoveZone( Sapphire::Entity::Player &movingPlayer )
|
||||
{
|
||||
if( movingPlayer.getPartyId() == 0 )
|
||||
{
|
||||
movingPlayer.queuePacket( makeZonePacket< FFXIVIpcPartyList >( movingPlayer.getId() ) );
|
||||
return;
|
||||
}
|
||||
auto party = getParty( movingPlayer.getPartyId() );
|
||||
assert( party );
|
||||
sendPartyUpdate( *party );
|
||||
}
|
||||
|
||||
void PartyMgr::onMemberDisconnect( Entity::Player& disconnectingPlayer )
|
||||
{
|
||||
if( disconnectingPlayer.getPartyId() == 0 )
|
||||
return;
|
||||
|
||||
auto& server = Common::Service< World::ServerMgr >::ref();
|
||||
auto party = getParty( disconnectingPlayer.getPartyId() );
|
||||
assert( party );
|
||||
auto members = getPartyMembers( *party );
|
||||
auto pLeader = getPartyLeader( *party );
|
||||
|
||||
bool anyMembersOnline = false;
|
||||
|
||||
for( const auto& member : members )
|
||||
{
|
||||
if( member/*->isConnected()*/ )
|
||||
{
|
||||
anyMembersOnline = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// if there are no party members online, destroy the party
|
||||
if( !anyMembersOnline )
|
||||
return onDisband( *pLeader );
|
||||
|
||||
for( const auto& member : members )
|
||||
{
|
||||
// TODO: 2nd argument here makes it automatically send passing leadership message
|
||||
member->queuePacket( { makePartyUpdate( disconnectingPlayer, UpdateStatus::OFFLINE_MEMBER, party->PartyCount ), makeZonePacket< FFXIVIpcPartyList >( member->getId() ) } );
|
||||
}
|
||||
|
||||
sendPartyUpdate( *party );
|
||||
}
|
||||
|
||||
void PartyMgr::onMemberRejoin( Entity::Player& joiningPlayer )
|
||||
{
|
||||
auto party = getParty( joiningPlayer.getPartyId() );
|
||||
assert( party );
|
||||
|
||||
// TODO: do we need a party update here? move zone handler already handles it
|
||||
}
|
||||
|
||||
void PartyMgr::onKick( const std::string& kickPlayerName, Entity::Player& leader )
|
||||
{
|
||||
auto& server = Common::Service< World::ServerMgr >::ref();
|
||||
auto& playerMgr = Common::Service< World::Manager::PlayerMgr >::ref();
|
||||
auto party = getParty( leader.getPartyId() );
|
||||
assert( party );
|
||||
auto pLeader = getPartyLeader( *party );
|
||||
auto members = getPartyMembers( *party );
|
||||
auto pKickedPlayer = server.getSession( kickPlayerName )->getPlayer();
|
||||
if( !pKickedPlayer )
|
||||
{
|
||||
Logger::error( "Target player for kicking not found (\"{t}\")", kickPlayerName );
|
||||
return;
|
||||
}
|
||||
|
||||
if( party->PartyCount == 2 )
|
||||
{
|
||||
onDisband( *pLeader );
|
||||
}
|
||||
else
|
||||
{
|
||||
for( const auto &member: members )
|
||||
{
|
||||
if( kickPlayerName == member->getName() )
|
||||
{
|
||||
removeMember( *party, member );
|
||||
member->removeOnlineStatus( Common::OnlineStatus::PartyMember );
|
||||
|
||||
member->queuePacket( { makePartyUpdate( *pLeader, *member, UpdateStatus::KICK_SELF, party->PartyCount ),
|
||||
makeZonePacket< FFXIVIpcPartyList >( member->getId() ) } );
|
||||
}
|
||||
else
|
||||
{
|
||||
member->queuePacket( makePartyUpdate( *pKickedPlayer, UpdateStatus::KICK_MEMBER, party->PartyCount ) );
|
||||
}
|
||||
}
|
||||
party->PartyCount--;
|
||||
sendPartyUpdate( *party );
|
||||
}
|
||||
}
|
||||
|
||||
void PartyMgr::onChangeLeader( const std::string& newLeaderName, Entity::Player& oldLeader )
|
||||
{
|
||||
auto& server = Common::Service< World::ServerMgr >::ref();
|
||||
auto& playerMgr = Common::Service< World::Manager::PlayerMgr >::ref();
|
||||
auto party = getParty( oldLeader.getPartyId() );
|
||||
|
||||
auto pNewLeader = server.getSession( newLeaderName )->getPlayer();
|
||||
|
||||
if( !pNewLeader )
|
||||
{
|
||||
Logger::error( "Target player for new leader not found (\"{t}\")", newLeaderName );
|
||||
return;
|
||||
}
|
||||
|
||||
for( auto memberId : party->MemberId )
|
||||
{
|
||||
if( memberId == pNewLeader->getId() )
|
||||
{
|
||||
pNewLeader->addOnlineStatus( Common::OnlineStatus::PartyLeader );
|
||||
// this is not ideal, probably better to have a function which can add
|
||||
// and remove at the same time so packets are only triggered once
|
||||
oldLeader.addOnlineStatus( Common::OnlineStatus::PartyMember );
|
||||
oldLeader.removeOnlineStatus( Common::OnlineStatus::PartyLeader );
|
||||
|
||||
party->LeaderId = pNewLeader->getId();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
auto members = getPartyMembers( *party );
|
||||
for( auto& member : members )
|
||||
{
|
||||
auto pcUpdateParty = makePartyUpdate( oldLeader.getAsPlayer(), pNewLeader, UpdateStatus::CHANGELEADER, party->PartyCount );
|
||||
member->queuePacket( pcUpdateParty );
|
||||
}
|
||||
|
||||
sendPartyUpdate( *party );
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
uint64_t PartyMgr::createParty()
|
||||
{
|
||||
auto& chatChannelMgr = Common::Service< ChatChannelMgr >::ref();
|
||||
auto party = std::make_shared< Party >();
|
||||
party->PartyID = getNextPartyId();
|
||||
party->ChatChannel = chatChannelMgr.createChatChannel( Common::ChatChannelType::PartyChat );
|
||||
m_partyIdMap[ party->PartyID ] = party;
|
||||
return party->PartyID;
|
||||
}
|
||||
|
||||
uint64_t PartyMgr::getNextPartyId()
|
||||
{
|
||||
return ++m_maxPartyId;
|
||||
}
|
||||
|
||||
PartyPtr PartyMgr::getParty( uint64_t partyId )
|
||||
{
|
||||
auto it = m_partyIdMap.find( partyId );
|
||||
if( it != m_partyIdMap.end() )
|
||||
return it->second;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector< Entity::PlayerPtr > PartyMgr::getPartyMembers( Party& party )
|
||||
{
|
||||
std::vector< Entity::PlayerPtr > members;
|
||||
|
||||
auto& server = Common::Service< World::ServerMgr >::ref();
|
||||
for( auto& memberId : party.MemberId )
|
||||
{
|
||||
if( memberId == 0 )
|
||||
continue;
|
||||
|
||||
auto pPlayer = server.getSession( memberId )->getPlayer();
|
||||
|
||||
members.push_back( pPlayer );
|
||||
}
|
||||
return members;
|
||||
}
|
||||
|
||||
Entity::PlayerPtr PartyMgr::getPartyLeader( Party& party )
|
||||
{
|
||||
auto& server = Common::Service< World::ServerMgr >::ref();
|
||||
|
||||
if( party.LeaderId == 0 )
|
||||
return nullptr;
|
||||
|
||||
auto pLeader = server.getSession( party.LeaderId )->getPlayer();
|
||||
|
||||
return pLeader;
|
||||
}
|
||||
|
||||
void PartyMgr::sendPartyUpdate( Party& party )
|
||||
{
|
||||
auto& exdData = Common::Service< Data::ExdDataGenerated >::ref();
|
||||
auto partyMembers = getPartyMembers( party );
|
||||
std::vector< PartyMember > entries;
|
||||
auto& server = Common::Service< World::ServerMgr >::ref();
|
||||
|
||||
for( const auto& member : partyMembers )
|
||||
{
|
||||
auto classJob = exdData.get< Data::ClassJob >( static_cast< uint8_t >( member->getClass() ) );
|
||||
if( !classJob )
|
||||
continue;
|
||||
|
||||
PartyMember memberEntry{};
|
||||
|
||||
memberEntry./*ParentEntityId*/u1 = Common::INVALID_GAME_OBJECT_ID;
|
||||
memberEntry./*PetEntityId*/u2 = Common::INVALID_GAME_OBJECT_ID;
|
||||
memberEntry.hp = member->getHp();
|
||||
memberEntry.maxHp = member->getMaxHp();
|
||||
memberEntry.mp = member->getMp();
|
||||
memberEntry.maxMp = member->getMaxMp();
|
||||
memberEntry.classId = static_cast< uint8_t >( member->getClass() );
|
||||
memberEntry.level = member->getLevel();
|
||||
//memberEntry.ObjType = 4; // 1 PC, 2 Buddy ??
|
||||
memberEntry.zoneId = member->getTerritoryTypeId();
|
||||
memberEntry./*Valid*/gposeSelectable = 1;
|
||||
//memberEntry.Tp = member->getTp();
|
||||
//memberEntry.Role = classJob->role;
|
||||
|
||||
entries.push_back( memberEntry );
|
||||
}
|
||||
|
||||
for( const auto& pMember : partyMembers )
|
||||
{
|
||||
size_t idx = 0;
|
||||
|
||||
auto updatePartyPacket = makeZonePacket< FFXIVIpcPartyList >( partyMembers[ 0 ]->getId() );
|
||||
auto& data = updatePartyPacket->data();
|
||||
data.partyId = party.PartyID;
|
||||
data.leaderIndex = getPartyLeaderIndex( party );
|
||||
data.channelId = party.ChatChannel;
|
||||
data.partySize = party.PartyCount;
|
||||
|
||||
for( const auto& member : partyMembers )
|
||||
{
|
||||
bool isConnected = /*member->isConnected()*/true;
|
||||
// if player is online and in the same zone as current member in party, display more data in partylist
|
||||
bool hasInfo = isConnected && member->getTerritoryTypeId() == pMember->getTerritoryTypeId();
|
||||
|
||||
if( hasInfo )
|
||||
{
|
||||
data.member[ idx ] = entries[ idx ];
|
||||
}
|
||||
|
||||
data.member[ idx ].contentId = member->getContentId();
|
||||
data.member[ idx ].charaId = member->getId();
|
||||
strcpy( data.member[ idx ].name, member->getName().c_str() );
|
||||
|
||||
idx++;
|
||||
}
|
||||
|
||||
pMember->queuePacket( updatePartyPacket );
|
||||
}
|
||||
}
|
||||
|
||||
void PartyMgr::removeParty( uint64_t partyId )
|
||||
{
|
||||
m_partyIdMap.erase( partyId );
|
||||
}
|
||||
|
||||
int8_t PartyMgr::getPartyLeaderIndex( const Party &party )
|
||||
{
|
||||
size_t idx = 0;
|
||||
for( const auto& memberId : party.MemberId )
|
||||
{
|
||||
if( memberId == party.LeaderId )
|
||||
return static_cast< int8_t >( idx );
|
||||
idx++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void PartyMgr::removeMember( Party &party, const Entity::PlayerPtr& pMember )
|
||||
{
|
||||
auto& ccMgr = Common::Service< World::Manager::ChatChannelMgr >::ref();
|
||||
pMember->setPartyId( 0 );
|
||||
ccMgr.removeFromChannel( party.ChatChannel, *pMember );
|
||||
party.MemberId.erase( std::remove( party.MemberId.begin(), party.MemberId.end(), pMember->getId() ), party.MemberId.end() );
|
||||
}
|
88
src/world/Manager/PartyMgr.h
Normal file
88
src/world/Manager/PartyMgr.h
Normal file
|
@ -0,0 +1,88 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <ForwardsZone.h>
|
||||
#include <array>
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace Sapphire::World::Manager
|
||||
{
|
||||
|
||||
enum UpdateStatus : int32_t
|
||||
{
|
||||
NONE_8 = 0x0,
|
||||
JOINED = 0x1,
|
||||
CHANGELEADER = 0x2,
|
||||
DISBAND = 0x3,
|
||||
KICK_MEMBER = 0x4,
|
||||
KICK_SELF = 0x5,
|
||||
LEAVE_MEMBER = 0x6,
|
||||
LEAVE_SELF = 0x7,
|
||||
MOVEZONE = 0x8,
|
||||
MOVETERRITORY = 0x9,
|
||||
OFFLINE_MEMBER = 0xA,
|
||||
RECOVERY_MEMBER = 0xB,
|
||||
LEAVELEADER_LEAVED_MEMBER = 0xC,
|
||||
LEAVELEADER_LEAVED_SELF = 0xD,
|
||||
ADDMEMBER_BUDDY = 0xE,
|
||||
REMOVEMEMBER_BUDDY = 0xF,
|
||||
SENDREADYCHECK = 0x10,
|
||||
REPLYREADYCHECK = 0x11,
|
||||
};
|
||||
|
||||
struct Party
|
||||
{
|
||||
std::vector< uint32_t > MemberId;
|
||||
uint64_t PartyID;
|
||||
uint64_t ChatChannel;
|
||||
uint32_t LeaderId;
|
||||
uint8_t PartyCount;
|
||||
};
|
||||
|
||||
using PartyPtr = std::shared_ptr< Party >;
|
||||
|
||||
class PartyMgr
|
||||
{
|
||||
public:
|
||||
PartyMgr() = default;
|
||||
|
||||
/// Perform required actions for events
|
||||
void onJoin( Entity::Player& joiner, Entity::Player& inviter );
|
||||
void onLeave( Entity::Player& leavingPlayer );
|
||||
void onMoveZone( Entity::Player& movingPlayer );
|
||||
void onDisband( Entity::Player& disbandingPlayer );
|
||||
void onKick( const std::string& kickPlayerName, Entity::Player& leader );
|
||||
void onChangeLeader( const std::string& newLeaderName, Entity::Player& oldLeader );
|
||||
|
||||
void onMemberDisconnect( Entity::Player& disconnectingPlayer );
|
||||
void onMemberRejoin( Entity::Player& joiningPlayer );
|
||||
|
||||
void onJoinBuddy( Entity::Player& buddyOwner, Party& party );
|
||||
void onLeaveBuddy( Entity::Player& buddyOwner, Party& party );
|
||||
void onStartReadyCheck( Entity::Player& startingPlayer, Party& party );
|
||||
void onReplyReadyCheck( Entity::Player& replyingPlayer, Party& party );
|
||||
|
||||
///////////////////////////
|
||||
PartyPtr getParty( uint64_t partyId );
|
||||
|
||||
private:
|
||||
// arbitrary start range for party ids
|
||||
uint64_t m_maxPartyId = 0x0000044000000000;
|
||||
|
||||
uint64_t createParty();
|
||||
void removeParty( uint64_t partyId );
|
||||
uint64_t getNextPartyId();
|
||||
std::unordered_map< uint64_t, PartyPtr > m_partyIdMap;
|
||||
|
||||
static void sendPartyUpdate( Party& party );
|
||||
static void removeMember( Party& party, const Entity::PlayerPtr& pMember );
|
||||
static std::vector< Entity::PlayerPtr > getPartyMembers( Party& party );
|
||||
static Entity::PlayerPtr getPartyLeader( Party& party );
|
||||
|
||||
static int8_t getPartyLeaderIndex( const Party& party );
|
||||
|
||||
};
|
||||
|
||||
}
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include <unordered_map>
|
||||
#include <Service.h>
|
||||
#include "Manager/PartyMgr.h"
|
||||
|
||||
#include "Actor/Player.h"
|
||||
|
||||
|
@ -759,6 +760,9 @@ bool Sapphire::World::Manager::TerritoryMgr::movePlayer( TerritoryPtr pZone, Sap
|
|||
|
||||
pPlayer->sendZonePackets();
|
||||
|
||||
auto& partyMgr = Common::Service< World::Manager::PartyMgr >::ref();
|
||||
partyMgr.onMoveZone( *pPlayer );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -143,7 +143,15 @@ Sapphire::Network::GameConnection::GameConnection( Sapphire::Network::HivePtr pH
|
|||
setZoneHandler( ClientZoneIpcType::InventoryEquipRecommendedItems, "InventoryEquipRecommendedItemsHandler", &GameConnection::inventoryEquipRecommendedItemsHandler );
|
||||
|
||||
setChatHandler( ClientChatIpcType::TellReq, "TellReq", &GameConnection::tellHandler );
|
||||
setChatHandler( ClientChatIpcType::ChannelChatReq, "ChannelChatReq", &GameConnection::channelChatHandler );
|
||||
|
||||
setZoneHandler( ClientZoneIpcType::SocialInviteHandler, "SocialInviteHandler", &GameConnection::socialInviteHandler );
|
||||
setZoneHandler( ClientZoneIpcType::SocialReplyHandler, "SocialReplyHandler", &GameConnection::socialReplyHandler );
|
||||
|
||||
setZoneHandler( ClientZoneIpcType::PartyLeaveHandler, "PartyLeaveHandler", &GameConnection::partyLeaveHandler );
|
||||
setZoneHandler( ClientZoneIpcType::PartyDisbandHandler, "PartyDisbandHandler", &GameConnection::partyDisbandHandler );
|
||||
setZoneHandler( ClientZoneIpcType::PartyKickHandler, "PartyKickHandler", &GameConnection::partyKickHandler );
|
||||
setZoneHandler( ClientZoneIpcType::PartyChangeLeaderHandler, "PartyChangeLeaderHandler", &GameConnection::partyChangeLeaderHandler );
|
||||
}
|
||||
|
||||
Sapphire::Network::GameConnection::~GameConnection() = default;
|
||||
|
|
|
@ -179,6 +179,8 @@ namespace Sapphire::Network
|
|||
|
||||
DECLARE_HANDLER( tellHandler );
|
||||
|
||||
DECLARE_HANDLER( channelChatHandler );
|
||||
|
||||
DECLARE_HANDLER( reqPlaceHousingItem );
|
||||
|
||||
DECLARE_HANDLER( reqMoveHousingItem );
|
||||
|
@ -200,6 +202,14 @@ namespace Sapphire::Network
|
|||
DECLARE_HANDLER( eventYieldHandler );
|
||||
|
||||
DECLARE_HANDLER( inventoryEquipRecommendedItemsHandler );
|
||||
|
||||
DECLARE_HANDLER( socialInviteHandler );
|
||||
DECLARE_HANDLER( socialReplyHandler );
|
||||
|
||||
DECLARE_HANDLER( partyLeaveHandler );
|
||||
DECLARE_HANDLER( partyDisbandHandler );
|
||||
DECLARE_HANDLER( partyKickHandler );
|
||||
DECLARE_HANDLER( partyChangeLeaderHandler );
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -256,19 +256,12 @@ void Sapphire::Network::GameConnection::gm1Handler( const Packets::FFXIVARR_PACK
|
|||
{
|
||||
targetPlayer->setOnlineStatusMask( param1 );
|
||||
|
||||
auto statusPacket = makeZonePacket< FFXIVIpcSetOnlineStatus >( player.getId() );
|
||||
statusPacket->data().onlineStatusFlags = param1;
|
||||
queueOutPacket( statusPacket );
|
||||
|
||||
auto searchInfoPacket = makeZonePacket< FFXIVIpcSetSearchInfo >( player.getId() );
|
||||
searchInfoPacket->data().onlineStatusFlags = param1;
|
||||
searchInfoPacket->data().selectRegion = targetPlayer->getSearchSelectRegion();
|
||||
strcpy( searchInfoPacket->data().searchMessage, targetPlayer->getSearchMessage() );
|
||||
targetPlayer->queuePacket( searchInfoPacket );
|
||||
|
||||
targetPlayer->sendToInRangeSet( makeActorControl( player.getId(), SetStatusIcon,
|
||||
static_cast< uint8_t >( player.getOnlineStatus() ) ),
|
||||
true );
|
||||
player.sendNotice( "Icon for {0} was set to {1}", targetPlayer->getName(), param1 );
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -47,6 +47,8 @@
|
|||
#include "Manager/HousingMgr.h"
|
||||
#include "Manager/RNGMgr.h"
|
||||
#include "Manager/ItemMgr.h"
|
||||
#include "Manager/PartyMgr.h"
|
||||
#include "Manager/ChatChannelMgr.h"
|
||||
|
||||
#include "Action/Action.h"
|
||||
#include "Inventory/Item.h"
|
||||
|
@ -91,18 +93,12 @@ void Sapphire::Network::GameConnection::setSearchInfoHandler( const Packets::FFX
|
|||
// mark player as new adventurer
|
||||
player.setNewAdventurer( true );
|
||||
|
||||
auto statusPacket = makeZonePacket< FFXIVIpcSetOnlineStatus >( player.getId() );
|
||||
statusPacket->data().onlineStatusFlags = status;
|
||||
queueOutPacket( statusPacket );
|
||||
|
||||
auto searchInfoPacket = makeZonePacket< FFXIVIpcSetSearchInfo >( player.getId() );
|
||||
searchInfoPacket->data().onlineStatusFlags = status;
|
||||
searchInfoPacket->data().selectRegion = player.getSearchSelectRegion();
|
||||
strcpy( searchInfoPacket->data().searchMessage, player.getSearchMessage() );
|
||||
queueOutPacket( searchInfoPacket );
|
||||
|
||||
player.sendToInRangeSet( makeActorControl( player.getId(), SetStatusIcon,
|
||||
static_cast< uint8_t >( player.getOnlineStatus() ) ), true );
|
||||
}
|
||||
|
||||
void Sapphire::Network::GameConnection::reqSearchInfoHandler( const Packets::FFXIVARR_PACKET_RAW& inPacket,
|
||||
|
@ -444,31 +440,58 @@ void Sapphire::Network::GameConnection::socialListHandler( const Packets::FFXIVA
|
|||
int32_t entrysizes = sizeof( listPacket->data().entries );
|
||||
memset( listPacket->data().entries, 0, sizeof( listPacket->data().entries ) );
|
||||
|
||||
listPacket->data().entries[ 0 ].bytes[ 2 ] = player.getCurrentTerritory()->getTerritoryTypeId();
|
||||
listPacket->data().entries[ 0 ].bytes[ 3 ] = 0x80;
|
||||
listPacket->data().entries[ 0 ].bytes[ 4 ] = 0x02;
|
||||
listPacket->data().entries[ 0 ].bytes[ 6 ] = 0x3B;
|
||||
listPacket->data().entries[ 0 ].bytes[ 11 ] = 0x10;
|
||||
listPacket->data().entries[ 0 ].classJob = static_cast< uint8_t >( player.getClass() );
|
||||
listPacket->data().entries[ 0 ].contentId = player.getContentId();
|
||||
listPacket->data().entries[ 0 ].level = player.getLevel();
|
||||
listPacket->data().entries[ 0 ].zoneId = player.getCurrentTerritory()->getTerritoryTypeId();
|
||||
listPacket->data().entries[ 0 ].zoneId1 = 0x0100;
|
||||
// TODO: no idea what this does
|
||||
//listPacket.data().entries[0].one = 1;
|
||||
auto fillEntryAt = [ &listPacket ]( int i, Entity::PlayerPtr nextPlayer, bool isLeader )
|
||||
{
|
||||
listPacket->data().entries[ i ].bytes[ 2 ] = nextPlayer->getCurrentTerritory()->getTerritoryTypeId();
|
||||
listPacket->data().entries[ i ].bytes[ 3 ] = 0x80;
|
||||
listPacket->data().entries[ i ].bytes[ 4 ] = 0x02;
|
||||
listPacket->data().entries[ i ].bytes[ 6 ] = 0x3B;
|
||||
listPacket->data().entries[ i ].bytes[ 8 ] = isLeader;
|
||||
listPacket->data().entries[ i ].bytes[ 11 ] = 0x10;
|
||||
listPacket->data().entries[ i ].classJob = static_cast< uint8_t >( nextPlayer->getClass() );
|
||||
listPacket->data().entries[ i ].contentId = nextPlayer->getContentId();
|
||||
listPacket->data().entries[ i ].level = nextPlayer->getLevel();
|
||||
listPacket->data().entries[ i ].zoneId = nextPlayer->getCurrentTerritory()->getTerritoryTypeId();
|
||||
listPacket->data().entries[ i ].zoneId1 = 0x0100;
|
||||
// TODO: no idea what this does
|
||||
//listPacket.data().entries[0].one = 1;
|
||||
|
||||
memcpy( listPacket->data().entries[ 0 ].name, player.getName().c_str(), strlen( player.getName().c_str() ) );
|
||||
memcpy( listPacket->data().entries[ i ].name, nextPlayer->getName().c_str(), strlen( nextPlayer->getName().c_str() ) );
|
||||
|
||||
// GC icon
|
||||
listPacket->data().entries[ 0 ].bytes1[ 0 ] = 2;
|
||||
// client language J = 0, E = 1, D = 2, F = 3
|
||||
listPacket->data().entries[ 0 ].bytes1[ 1 ] = 1;
|
||||
// user language settings flag J = 1, E = 2, D = 4, F = 8
|
||||
listPacket->data().entries[ 0 ].bytes1[ 2 ] = 1 + 2;
|
||||
listPacket->data().entries[ 0 ].onlineStatusMask = player.getOnlineStatusMask();
|
||||
// GC icon
|
||||
listPacket->data().entries[ i ].bytes1[ 0 ] = 2;
|
||||
// client language J = 0, E = 1, D = 2, F = 3
|
||||
listPacket->data().entries[ i ].bytes1[ 1 ] = 1;
|
||||
// user language settings flag J = 1, E = 2, D = 4, F = 8
|
||||
listPacket->data().entries[ i ].bytes1[ 2 ] = 1 + 2 + 4 + 8;
|
||||
listPacket->data().entries[ i ].onlineStatusMask = nextPlayer->getOnlineStatusMask();
|
||||
};
|
||||
auto nextPlayer = player.getAsPlayer();
|
||||
fillEntryAt( 0, nextPlayer, false );
|
||||
if( player.getPartyId() != 0 )
|
||||
{
|
||||
// fill party members
|
||||
auto& partyMgr = Common::Service< World::Manager::PartyMgr >::ref();
|
||||
auto& server = Common::Service< World::ServerMgr >::ref();
|
||||
auto pParty = partyMgr.getParty( player.getPartyId() );
|
||||
assert( pParty );
|
||||
|
||||
int i = 1;
|
||||
for( auto id : pParty->MemberId )
|
||||
{
|
||||
nextPlayer = server.getSession( id )->getPlayer();
|
||||
if( nextPlayer->getId() == player.getId() )
|
||||
{
|
||||
// data already in entry 0, only change the leader flag
|
||||
listPacket->data().entries[ 0 ].bytes[ 8 ] = pParty->LeaderId == id;
|
||||
continue;
|
||||
}
|
||||
fillEntryAt( i, nextPlayer, pParty->LeaderId == id );
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
queueOutPacket( listPacket );
|
||||
|
||||
}
|
||||
else if( type == 2 )
|
||||
{ // friend list
|
||||
|
@ -604,12 +627,24 @@ void Sapphire::Network::GameConnection::tellHandler( const Packets::FFXIVARR_PAC
|
|||
|
||||
if( player.isActingAsGm() )
|
||||
{
|
||||
tellPacket->data().flags |= TellFlags::GmTellMsg;
|
||||
tellPacket->data().flags |= ChatFromType::GmTellMsg;
|
||||
}
|
||||
|
||||
pTargetPlayer->queueChatPacket( tellPacket );
|
||||
}
|
||||
|
||||
void Sapphire::Network::GameConnection::channelChatHandler( const Packets::FFXIVARR_PACKET_RAW& inPacket, Entity::Player& player )
|
||||
{
|
||||
const auto packet = ChatChannelPacket< Client::FFXIVIpcChannelChatHandler >( inPacket );
|
||||
auto& data = packet.data();
|
||||
|
||||
auto& chatChannelMgr = Common::Service< ChatChannelMgr >::ref();
|
||||
|
||||
std::string message = std::string( data.message );
|
||||
|
||||
chatChannelMgr.sendMessageToChannel( data.channelId, player, message );
|
||||
}
|
||||
|
||||
void Sapphire::Network::GameConnection::performNoteHandler( const Packets::FFXIVARR_PACKET_RAW& inPacket,
|
||||
Entity::Player& player )
|
||||
{
|
||||
|
|
73
src/world/Network/Handlers/PartyHandlers.cpp
Normal file
73
src/world/Network/Handlers/PartyHandlers.cpp
Normal file
|
@ -0,0 +1,73 @@
|
|||
#include <Common.h>
|
||||
#include <Network/CommonNetwork.h>
|
||||
#include <Network/GamePacket.h>
|
||||
|
||||
#include <Network/PacketContainer.h>
|
||||
#include <Service.h>
|
||||
#include <Network/PacketDef/Zone/ClientZoneDef.h>
|
||||
|
||||
#include "Manager/PartyMgr.h"
|
||||
|
||||
#include "Network/GameConnection.h"
|
||||
|
||||
#include "Session.h"
|
||||
#include "Actor/Player.h"
|
||||
|
||||
using namespace Sapphire::Common;
|
||||
using namespace Sapphire::Network::Packets;
|
||||
using namespace Sapphire::World::Manager;
|
||||
|
||||
|
||||
void Sapphire::Network::GameConnection::partyLeaveHandler( const Packets::FFXIVARR_PACKET_RAW& inPacket,
|
||||
Entity::Player& player )
|
||||
{
|
||||
if( player.getPartyId() == 0 )
|
||||
return;
|
||||
|
||||
auto& partyMgr = Common::Service< Sapphire::World::Manager::PartyMgr >::ref();
|
||||
|
||||
partyMgr.onLeave( player );
|
||||
|
||||
}
|
||||
|
||||
void Sapphire::Network::GameConnection::partyDisbandHandler( const Packets::FFXIVARR_PACKET_RAW& inPacket,
|
||||
Entity::Player& player )
|
||||
{
|
||||
if( player.getPartyId() == 0 )
|
||||
return;
|
||||
|
||||
auto& partyMgr = Common::Service< Sapphire::World::Manager::PartyMgr >::ref();
|
||||
|
||||
partyMgr.onDisband( player );
|
||||
|
||||
}
|
||||
|
||||
void Sapphire::Network::GameConnection::partyKickHandler( const Packets::FFXIVARR_PACKET_RAW& inPacket,
|
||||
Entity::Player& player )
|
||||
{
|
||||
if( player.getPartyId() == 0 )
|
||||
return;
|
||||
|
||||
const auto packet = ZoneChannelPacket< Client::FFXIVIpcPartyKickHandler >( inPacket );
|
||||
const auto& data = packet.data();
|
||||
|
||||
auto& partyMgr = Common::Service< Sapphire::World::Manager::PartyMgr >::ref();
|
||||
|
||||
partyMgr.onKick( std::string( data.name ), player );
|
||||
|
||||
}
|
||||
|
||||
void Sapphire::Network::GameConnection::partyChangeLeaderHandler( const Packets::FFXIVARR_PACKET_RAW& inPacket,
|
||||
Entity::Player& player )
|
||||
{
|
||||
if( player.getPartyId() == 0 )
|
||||
return;
|
||||
|
||||
const auto packet = ZoneChannelPacket< Client::FFXIVIpcPartyChangeLeaderHandler >( inPacket );
|
||||
const auto& data = packet.data();
|
||||
|
||||
auto& partyMgr = Common::Service< Sapphire::World::Manager::PartyMgr >::ref();
|
||||
|
||||
partyMgr.onChangeLeader( std::string( data.name ), player );
|
||||
|
||||
}
|
41
src/world/Network/PacketWrappers/ChannelChatPacket.h
Normal file
41
src/world/Network/PacketWrappers/ChannelChatPacket.h
Normal file
|
@ -0,0 +1,41 @@
|
|||
#pragma once
|
||||
|
||||
#include "Forwards.h"
|
||||
#include "Actor/Player.h"
|
||||
#include <Network/GamePacket.h>
|
||||
#include <Network/PacketDef/Chat/ServerChatDef.h>
|
||||
|
||||
namespace Sapphire::Network::Packets::Server
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief The Chat packet.
|
||||
*/
|
||||
class ChannelChatPacket : public ChatChannelPacket< FFXIVIpcChannelChat >
|
||||
{
|
||||
public:
|
||||
ChannelChatPacket( Entity::Player& target,
|
||||
Entity::Player& sender,
|
||||
uint64_t channelId,
|
||||
const std::string& msg ) :
|
||||
ChatChannelPacket< FFXIVIpcChannelChat >( target.getId(), target.getId() )
|
||||
{
|
||||
initialize( sender, channelId, msg );
|
||||
};
|
||||
|
||||
private:
|
||||
void initialize( Entity::Player& sender, uint64_t channelId, const std::string& msg )
|
||||
{
|
||||
strcpy( m_data.message, msg.c_str() );
|
||||
strcpy( m_data.name, sender.getName().c_str() );
|
||||
|
||||
m_data.channelId = channelId;
|
||||
|
||||
m_data.contentId = sender.getContentId();
|
||||
m_data.charaId = sender.getId();
|
||||
|
||||
m_data.type = 0;
|
||||
};
|
||||
};
|
||||
|
||||
}
|
127
src/world/Network/PacketWrappers/InviteHandlers.cpp
Normal file
127
src/world/Network/PacketWrappers/InviteHandlers.cpp
Normal file
|
@ -0,0 +1,127 @@
|
|||
#include <Common.h>
|
||||
#include <Network/CommonNetwork.h>
|
||||
#include <Network/GamePacket.h>
|
||||
#include <Logging/Logger.h>
|
||||
#include <Network/PacketContainer.h>
|
||||
|
||||
#include <datReader/DatCategories/bg/LgbTypes.h>
|
||||
|
||||
#include <Network/PacketDef/Zone/ClientZoneDef.h>
|
||||
#include <Service.h>
|
||||
|
||||
#include "Network/GameConnection.h"
|
||||
#include "Session.h"
|
||||
|
||||
#include "Territory/Territory.h"
|
||||
|
||||
#include "Network/PacketWrappers/PlayerSetupPacket.h"
|
||||
|
||||
//#include "Manager/FriendListMgr.h"
|
||||
#include "Manager/PartyMgr.h"
|
||||
#include "Manager/PlayerMgr.h"
|
||||
//#include "Manager/FreeCompanyMgr.h"
|
||||
|
||||
#include "Action/Action.h"
|
||||
|
||||
#include "ServerMgr.h"
|
||||
#include "Forwards.h"
|
||||
|
||||
using namespace Sapphire::Common;
|
||||
using namespace Sapphire::Network::Packets;
|
||||
using namespace Sapphire::Network::Packets::Server;
|
||||
using namespace Sapphire::Network::Packets::Client;
|
||||
using namespace Sapphire::World::Manager;
|
||||
|
||||
|
||||
void Sapphire::Network::GameConnection::socialInviteHandler( const FFXIVARR_PACKET_RAW& inPacket, Entity::Player& player )
|
||||
{
|
||||
const auto packet = ZoneChannelPacket< Client::FFXIVIpcSocialInviteHandler >( inPacket );
|
||||
|
||||
player.sendDebug( "Auth Type#{0}", packet.data().socialType );
|
||||
player.sendDebug( "Target Name: {0}", packet.data().name );
|
||||
|
||||
std::string name( packet.data().name );
|
||||
|
||||
auto& playerMgr = Common::Service< World::Manager::PlayerMgr >::ref();
|
||||
auto& server = Common::Service< Sapphire::World::ServerMgr >::ref();
|
||||
auto pTargetPlayer = server.getSession( name )->getPlayer();
|
||||
|
||||
if( !pTargetPlayer )
|
||||
return;
|
||||
|
||||
switch( packet.data().socialType )
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
auto inviteResultPacket = makeZonePacket< Server::FFXIVIpcSocialInviteResult >( player.getId() );
|
||||
auto& data = inviteResultPacket->data();
|
||||
data.contentId = pTargetPlayer->getContentId();
|
||||
data.p1 = packet.data().p1;
|
||||
data.p2 = packet.data().p2;
|
||||
data.socialType = packet.data().socialType;
|
||||
strcpy( data.name, packet.data().name );
|
||||
player.queuePacket( inviteResultPacket );
|
||||
|
||||
auto inviteUpdatePacket = makeZonePacket< Server::FFXIVIpcSocialInviteUpdate >( pTargetPlayer->getId() );
|
||||
inviteUpdatePacket->data().contentId = player.getContentId();
|
||||
inviteUpdatePacket->data().expireTime = Common::Util::getTimeSeconds() + 30;
|
||||
inviteUpdatePacket->data().p1 = packet.data().p1;
|
||||
inviteUpdatePacket->data().p2 = packet.data().p2;
|
||||
inviteUpdatePacket->data().socialType = packet.data().socialType;
|
||||
inviteUpdatePacket->data().type = 1;
|
||||
inviteUpdatePacket->data().gender = player.getGender();
|
||||
strcpy( inviteUpdatePacket->data().name, player.getName().c_str() );
|
||||
pTargetPlayer->queuePacket( inviteUpdatePacket );
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Sapphire::Network::GameConnection::socialReplyHandler( const FFXIVARR_PACKET_RAW& inPacket, Entity::Player& player )
|
||||
{
|
||||
const auto packet = ZoneChannelPacket< Client::FFXIVIpcSocialReplyHandler >( inPacket );
|
||||
const auto& data = packet.data();
|
||||
|
||||
auto& playerMgr = Common::Service< World::Manager::PlayerMgr >::ref();
|
||||
auto& server = Common::Service< Sapphire::World::ServerMgr >::ref();
|
||||
auto pPlayer = server.getSession( data.contentId )->getPlayer();
|
||||
|
||||
if( !pPlayer )
|
||||
return;
|
||||
|
||||
auto inviteReplyPacket = makeZonePacket< Server::FFXIVIpcSocialInviteResponse >( player.getId() );
|
||||
auto& inviteReplyData = inviteReplyPacket->data();
|
||||
inviteReplyData.response = data.response;
|
||||
|
||||
switch( data.socialType )
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
auto& partyMgr = Common::Service< PartyMgr >::ref();
|
||||
|
||||
if( data.response == InviteReplyType::ACCEPT )
|
||||
{
|
||||
partyMgr.onJoin( player, *pPlayer );
|
||||
}
|
||||
|
||||
auto inviteUpPacket = makeZonePacket< Server::FFXIVIpcSocialInviteUpdate >( pPlayer->getId() );
|
||||
inviteUpPacket->data().contentId = player.getContentId();
|
||||
inviteUpPacket->data().expireTime = Common::Util::getTimeSeconds() + 30;
|
||||
inviteUpPacket->data().p1 = packet.data().p1;
|
||||
inviteUpPacket->data().p2 = packet.data().p2;
|
||||
inviteUpPacket->data().socialType = packet.data().socialType;
|
||||
inviteUpPacket->data().type = data.response == InviteReplyType::ACCEPT ? InviteUpdateType::ACCEPT_INVITE : InviteUpdateType::REJECT_INVITE;
|
||||
strcpy( inviteUpPacket->data().name, player.getName().c_str() );
|
||||
pPlayer->queuePacket( inviteUpPacket );
|
||||
|
||||
inviteReplyData.contentId == pPlayer->getContentId();
|
||||
inviteReplyData.socialType = data.socialType;
|
||||
inviteReplyData.gender = pPlayer->getGender();
|
||||
strcpy( inviteReplyData.name, pPlayer->getName().c_str() );
|
||||
player.queuePacket( inviteReplyPacket );
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
83
src/world/Network/PacketWrappers/PartyUpdatePacket.h
Normal file
83
src/world/Network/PacketWrappers/PartyUpdatePacket.h
Normal file
|
@ -0,0 +1,83 @@
|
|||
#pragma once
|
||||
|
||||
#include <Network/GamePacket.h>
|
||||
#include "Actor/Player.h"
|
||||
#include "Forwards.h"
|
||||
|
||||
namespace Sapphire::Network::Packets::Server
|
||||
{
|
||||
class PartyUpdatePacket : public ZoneChannelPacket< FFXIVIpcPartyUpdate >
|
||||
{
|
||||
public:
|
||||
PartyUpdatePacket( Entity::Player& executePlayer, Entity::Player& targetPlayer, uint8_t updateStatus, uint8_t count ) :
|
||||
ZoneChannelPacket< FFXIVIpcPartyUpdate >( executePlayer.getId(), executePlayer.getId() )
|
||||
{
|
||||
initialize( executePlayer, targetPlayer, updateStatus, count );
|
||||
};
|
||||
|
||||
PartyUpdatePacket( Entity::Player& executePlayer, uint8_t updateStatus, uint8_t count ) :
|
||||
ZoneChannelPacket< FFXIVIpcPartyUpdate >( executePlayer.getId(), executePlayer.getId() )
|
||||
{
|
||||
initialize( executePlayer, updateStatus, count );
|
||||
};
|
||||
|
||||
PartyUpdatePacket( const Entity::PlayerPtr& executePlayer, const Entity::PlayerPtr& targetPlayer, uint8_t updateStatus, uint8_t count ) :
|
||||
ZoneChannelPacket< FFXIVIpcPartyUpdate >( executePlayer->getId(), executePlayer->getId() )
|
||||
{
|
||||
initialize( executePlayer, targetPlayer, updateStatus, count );
|
||||
};
|
||||
|
||||
private:
|
||||
void initialize( Entity::Player& executePlayer, Entity::Player& targetPlayer, uint8_t updateStatus, uint8_t partySize )
|
||||
{
|
||||
m_data.executeContentId = executePlayer.getContentId();
|
||||
m_data.targetContentId = targetPlayer.getContentId();
|
||||
m_data.executeGender = executePlayer.getGender();
|
||||
m_data.targetGender = targetPlayer.getGender();
|
||||
m_data.updateStatus = updateStatus;
|
||||
m_data.partySize = partySize;
|
||||
strcpy( m_data.executeName, executePlayer.getName().c_str() );
|
||||
strcpy( m_data.targetName, targetPlayer.getName().c_str() );
|
||||
};
|
||||
|
||||
void initialize( Entity::Player& executePlayer, uint8_t updateStatus, uint8_t partySize )
|
||||
{
|
||||
m_data.executeContentId = executePlayer.getContentId();
|
||||
m_data.targetContentId = 0;
|
||||
m_data.executeGender = executePlayer.getGender();
|
||||
m_data.targetGender = 0;
|
||||
m_data.updateStatus = updateStatus;
|
||||
m_data.partySize = partySize;
|
||||
strcpy( m_data.targetName, executePlayer.getName().c_str() );
|
||||
};
|
||||
|
||||
void initialize( const Entity::PlayerPtr& executePlayer, const Entity::PlayerPtr& targetPlayer, uint8_t updateStatus, uint8_t partySize )
|
||||
{
|
||||
if( targetPlayer )
|
||||
{
|
||||
m_data.targetContentId = targetPlayer->getContentId();
|
||||
m_data.targetGender = targetPlayer->getGender();
|
||||
strcpy( m_data.targetName, targetPlayer->getName().c_str() );
|
||||
}
|
||||
|
||||
if( executePlayer )
|
||||
{
|
||||
m_data.executeContentId = executePlayer->getContentId();
|
||||
m_data.executeGender = executePlayer->getGender();
|
||||
strcpy( m_data.executeName, executePlayer->getName().c_str() );
|
||||
}
|
||||
|
||||
m_data.updateStatus = updateStatus;
|
||||
m_data.partySize = partySize;
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
template< typename... Args >
|
||||
std::shared_ptr< PartyUpdatePacket > makePartyUpdate( Args... args )
|
||||
{
|
||||
return std::make_shared< PartyUpdatePacket >( args... );
|
||||
}
|
||||
|
||||
}
|
|
@ -42,6 +42,8 @@
|
|||
#include "Manager/NaviMgr.h"
|
||||
#include "Manager/ActionMgr.h"
|
||||
#include "Manager/MapMgr.h"
|
||||
#include "Manager/ChatChannelMgr.h"
|
||||
#include "Manager/PartyMgr.h"
|
||||
|
||||
#include "Territory/InstanceObjectCache.h"
|
||||
|
||||
|
@ -153,6 +155,9 @@ void Sapphire::World::ServerMgr::run( int32_t argc, char* argv[] )
|
|||
}
|
||||
Common::Service< Db::DbWorkerPool< Db::ZoneDbConnection > >::set( pDb );
|
||||
|
||||
auto pChatChannelMgr = std::make_shared< Manager::ChatChannelMgr >();
|
||||
Common::Service< Manager::ChatChannelMgr >::set( pChatChannelMgr );
|
||||
|
||||
Logger::info( "LinkshellMgr: Caching linkshells" );
|
||||
auto pLsMgr = std::make_shared< Manager::LinkshellMgr >();
|
||||
if( !pLsMgr->loadLinkshells() )
|
||||
|
@ -227,6 +232,7 @@ void Sapphire::World::ServerMgr::run( int32_t argc, char* argv[] )
|
|||
auto pEventMgr = std::make_shared< Manager::EventMgr >();
|
||||
auto pItemMgr = std::make_shared< Manager::ItemMgr >();
|
||||
auto pRNGMgr = std::make_shared< Manager::RNGMgr >();
|
||||
auto pPartyMgr = std::make_shared< Manager::PartyMgr >();
|
||||
|
||||
Common::Service< DebugCommandMgr >::set( pDebugCom );
|
||||
Common::Service< Manager::PlayerMgr >::set( pPlayerMgr );
|
||||
|
@ -235,6 +241,7 @@ void Sapphire::World::ServerMgr::run( int32_t argc, char* argv[] )
|
|||
Common::Service< Manager::EventMgr >::set( pEventMgr );
|
||||
Common::Service< Manager::ItemMgr >::set( pItemMgr );
|
||||
Common::Service< Manager::RNGMgr >::set( pRNGMgr );
|
||||
Common::Service< Manager::PartyMgr >::set( pPartyMgr );
|
||||
|
||||
Logger::info( "World server running on {0}:{1}", m_ip, m_port );
|
||||
|
||||
|
@ -320,6 +327,7 @@ void Sapphire::World::ServerMgr::mainLoop()
|
|||
{
|
||||
Logger::info( "[{0}] Session removal", it->second->getId() );
|
||||
it = m_sessionMapById.erase( it );
|
||||
removeSession( pPlayer->getContentId() );
|
||||
removeSession( pPlayer->getName() );
|
||||
continue;
|
||||
}
|
||||
|
@ -334,6 +342,7 @@ void Sapphire::World::ServerMgr::mainLoop()
|
|||
// if( it->second.unique() )
|
||||
{
|
||||
it = m_sessionMapById.erase( it );
|
||||
removeSession( pPlayer->getContentId() );
|
||||
removeSession( pPlayer->getName() );
|
||||
}
|
||||
}
|
||||
|
@ -372,17 +381,13 @@ bool Sapphire::World::ServerMgr::createSession( uint32_t sessionId )
|
|||
return false;
|
||||
}
|
||||
|
||||
m_sessionMapByContentId[ newSession->getPlayer()->getContentId() ] = newSession;
|
||||
m_sessionMapByName[ newSession->getPlayer()->getName() ] = newSession;
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
void Sapphire::World::ServerMgr::removeSession( uint32_t sessionId )
|
||||
{
|
||||
m_sessionMapById.erase( sessionId );
|
||||
}
|
||||
|
||||
Sapphire::World::SessionPtr Sapphire::World::ServerMgr::getSession( uint32_t id )
|
||||
{
|
||||
//std::lock_guard<std::mutex> lock( m_sessionMutex );
|
||||
|
@ -394,6 +399,16 @@ Sapphire::World::SessionPtr Sapphire::World::ServerMgr::getSession( uint32_t id
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
Sapphire::World::SessionPtr Sapphire::World::ServerMgr::getSession( uint64_t contentId )
|
||||
{
|
||||
auto it = m_sessionMapByContentId.find( contentId );
|
||||
|
||||
if( it != m_sessionMapByContentId.end() )
|
||||
return ( it->second );
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Sapphire::World::SessionPtr Sapphire::World::ServerMgr::getSession( const std::string& playerName )
|
||||
{
|
||||
//std::lock_guard<std::mutex> lock( m_sessionMutex );
|
||||
|
@ -406,6 +421,16 @@ Sapphire::World::SessionPtr Sapphire::World::ServerMgr::getSession( const std::s
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
void Sapphire::World::ServerMgr::removeSession( uint32_t sessionId )
|
||||
{
|
||||
m_sessionMapById.erase( sessionId );
|
||||
}
|
||||
|
||||
void Sapphire::World::ServerMgr::removeSession( uint64_t contentId )
|
||||
{
|
||||
m_sessionMapByContentId.erase( contentId );
|
||||
}
|
||||
|
||||
void Sapphire::World::ServerMgr::removeSession( const std::string& playerName )
|
||||
{
|
||||
m_sessionMapByName.erase( playerName );
|
||||
|
|
|
@ -24,10 +24,8 @@ namespace Sapphire::World
|
|||
|
||||
bool createSession( uint32_t sessionId );
|
||||
|
||||
void removeSession( uint32_t sessionId );
|
||||
void removeSession( const std::string& playerName );
|
||||
|
||||
World::SessionPtr getSession( uint32_t id );
|
||||
World::SessionPtr getSession( uint64_t contentId );
|
||||
World::SessionPtr getSession( const std::string& playerName );
|
||||
|
||||
size_t getSessionCount() const;
|
||||
|
@ -66,11 +64,15 @@ namespace Sapphire::World
|
|||
Sapphire::Common::Config::WorldConfig m_config;
|
||||
|
||||
std::map< uint32_t, SessionPtr > m_sessionMapById;
|
||||
std::map< uint64_t, SessionPtr > m_sessionMapByContentId;
|
||||
std::map< std::string, SessionPtr > m_sessionMapByName;
|
||||
std::map< uint32_t, std::string > m_playerNameMapById;
|
||||
std::map< uint32_t, uint32_t > m_zones;
|
||||
std::map< std::string, Entity::BNpcTemplatePtr > m_bNpcTemplateMap;
|
||||
|
||||
void removeSession( uint32_t sessionId );
|
||||
void removeSession( uint64_t contentId );
|
||||
void removeSession( const std::string& playerName );
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -8,6 +8,9 @@
|
|||
#include "Network/GameConnection.h"
|
||||
#include "Actor/Player.h"
|
||||
|
||||
#include "Service.h"
|
||||
#include "Manager/PartyMgr.h"
|
||||
|
||||
#include "Session.h"
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
@ -73,6 +76,12 @@ void Sapphire::World::Session::close()
|
|||
if( m_pPlayer )
|
||||
{
|
||||
m_pPlayer->clearBuyBackMap();
|
||||
if( m_pPlayer->getPartyId() != 0 )
|
||||
{
|
||||
// offline player is removed from party for now;
|
||||
auto& partyMgr = Common::Service< World::Manager::PartyMgr >::ref();
|
||||
partyMgr.onLeave( *m_pPlayer );
|
||||
}
|
||||
// do one last update to db
|
||||
m_pPlayer->updateSql();
|
||||
// reset the zone, so the zone handler knows to remove the actor
|
||||
|
|
Loading…
Add table
Reference in a new issue