2021-12-05 17:54:36 +00:00
# include "ChatPacketHandler.h"
# include "PlayerContainer.h"
# include "Database.h"
# include <vector>
2023-09-21 01:06:28 +00:00
# include "BitStreamUtils.h"
2021-12-05 17:54:36 +00:00
# include "Game.h"
# include "dServer.h"
# include "GeneralUtils.h"
2023-10-21 23:31:55 +00:00
# include "Logger.h"
2022-07-13 03:36:06 +00:00
# include "eAddFriendResponseCode.h"
# include "eAddFriendResponseType.h"
# include "RakString.h"
# include "dConfig.h"
2023-04-25 18:17:40 +00:00
# include "eObjectBits.h"
2023-05-03 21:38:32 +00:00
# include "eConnectionType.h"
# include "eChatMessageType.h"
# include "eClientMessageType.h"
# include "eGameMessageType.h"
2024-01-14 07:03:01 +00:00
# include "StringifiedEnum.h"
# include "eGameMasterLevel.h"
2021-12-05 17:54:36 +00:00
void ChatPacketHandler : : HandleFriendlistRequest ( Packet * packet ) {
//Get from the packet which player we want to do something with:
2023-05-08 11:31:10 +00:00
CINSTREAM_SKIP_HEADER ;
2021-12-05 17:54:36 +00:00
LWOOBJID playerID = 0 ;
inStream . Read ( playerID ) ;
2024-01-06 04:42:30 +00:00
auto & player = Game : : playerContainer . GetPlayerDataMutable ( playerID ) ;
2021-12-05 17:54:36 +00:00
if ( ! player ) return ;
2023-11-18 00:47:18 +00:00
auto friendsList = Database : : Get ( ) - > GetFriendsList ( playerID ) ;
for ( const auto & friendData : friendsList ) {
2021-12-05 17:54:36 +00:00
FriendData fd ;
fd . isFTP = false ; // not a thing in DLU
2023-11-18 00:47:18 +00:00
fd . friendID = friendData . friendID ;
2023-04-25 18:17:40 +00:00
GeneralUtils : : SetBit ( fd . friendID , eObjectBits : : PERSISTENT ) ;
GeneralUtils : : SetBit ( fd . friendID , eObjectBits : : CHARACTER ) ;
2021-12-05 17:54:36 +00:00
2023-11-18 00:47:18 +00:00
fd . isBestFriend = friendData . isBestFriend ; //0 = friends, 1 = left_requested, 2 = right_requested, 3 = both_accepted - are now bffs
2024-01-06 04:42:30 +00:00
if ( fd . isBestFriend ) player . countOfBestFriends + = 1 ;
2023-11-18 00:47:18 +00:00
fd . friendName = friendData . friendName ;
2021-12-05 17:54:36 +00:00
//Now check if they're online:
2024-01-06 04:42:30 +00:00
const auto & fr = Game : : playerContainer . GetPlayerData ( fd . friendID ) ;
2022-07-13 03:36:06 +00:00
2021-12-05 17:54:36 +00:00
if ( fr ) {
fd . isOnline = true ;
2024-01-06 04:42:30 +00:00
fd . zoneID = fr . zoneID ;
2021-12-05 17:54:36 +00:00
//Since this friend is online, we need to update them on the fact that we've just logged in:
2022-07-13 03:36:06 +00:00
SendFriendUpdate ( fr , player , 1 , fd . isBestFriend ) ;
2021-12-05 17:54:36 +00:00
} else {
fd . isOnline = false ;
fd . zoneID = LWOZONEID ( ) ;
}
2024-01-06 04:42:30 +00:00
player . friends . push_back ( fd ) ;
2021-12-05 17:54:36 +00:00
}
//Now, we need to send the friendlist to the server they came from:
CBITSTREAM ;
2024-01-15 04:47:59 +00:00
BitStreamUtils : : WriteHeader ( bitStream , eConnectionType : : CHAT , eChatMessageType : : WORLD_ROUTE_PACKET ) ;
2021-12-05 17:54:36 +00:00
bitStream . Write ( playerID ) ;
//portion that will get routed:
2023-09-21 01:06:28 +00:00
BitStreamUtils : : WriteHeader ( bitStream , eConnectionType : : CLIENT , eClientMessageType : : GET_FRIENDS_LIST_RESPONSE ) ;
2021-12-05 17:54:36 +00:00
bitStream . Write < uint8_t > ( 0 ) ;
bitStream . Write < uint16_t > ( 1 ) ; //Length of packet -- just writing one as it doesn't matter, client skips it.
2024-01-06 04:42:30 +00:00
bitStream . Write < uint16_t > ( player . friends . size ( ) ) ;
2022-07-25 02:26:51 +00:00
2024-01-06 04:42:30 +00:00
for ( const auto & data : player . friends ) {
2021-12-05 17:54:36 +00:00
data . Serialize ( bitStream ) ;
}
2024-01-06 04:42:30 +00:00
SystemAddress sysAddr = player . sysAddr ;
2021-12-05 17:54:36 +00:00
SEND_PACKET ;
}
void ChatPacketHandler : : HandleFriendRequest ( Packet * packet ) {
2023-05-08 11:31:10 +00:00
CINSTREAM_SKIP_HEADER ;
2021-12-05 17:54:36 +00:00
2024-01-14 07:03:01 +00:00
LWOOBJID requestorPlayerID ;
LUWString LUplayerName ;
2022-07-13 03:36:06 +00:00
char isBestFriendRequest { } ;
2024-01-14 07:03:01 +00:00
inStream . Read ( requestorPlayerID ) ;
inStream . IgnoreBytes ( 4 ) ;
inStream . Read ( LUplayerName ) ;
2022-07-13 03:36:06 +00:00
inStream . Read ( isBestFriendRequest ) ;
2024-01-14 07:03:01 +00:00
auto playerName = LUplayerName . GetAsString ( ) ;
2024-01-06 04:42:30 +00:00
auto & requestor = Game : : playerContainer . GetPlayerDataMutable ( requestorPlayerID ) ;
2023-10-24 09:26:55 +00:00
if ( ! requestor ) {
LOG ( " No requestor player %llu sent to %s found. " , requestorPlayerID , playerName . c_str ( ) ) ;
return ;
}
2024-01-14 07:03:01 +00:00
// you cannot friend yourself
2024-01-06 04:42:30 +00:00
if ( requestor . playerName = = playerName ) {
2024-01-14 07:03:01 +00:00
SendFriendResponse ( requestor , requestor , eAddFriendResponseType : : GENERALERROR ) ;
2022-10-22 00:35:12 +00:00
return ;
} ;
2024-01-06 04:42:30 +00:00
auto & requestee = Game : : playerContainer . GetPlayerDataMutable ( playerName ) ;
2022-07-13 03:36:06 +00:00
// Check if player is online first
if ( isBestFriendRequest & & ! requestee ) {
2024-01-06 04:42:30 +00:00
for ( auto & friendDataCandidate : requestor . friends ) {
if ( friendDataCandidate . friendName ! = playerName ) continue ;
// Setup the needed info since you can add a best friend offline.
requestee . playerID = friendDataCandidate . friendID ;
requestee . playerName = friendDataCandidate . friendName ;
requestee . zoneID = LWOZONEID ( ) ;
FriendData requesteeFriendData { } ;
requesteeFriendData . friendID = requestor . playerID ;
requesteeFriendData . friendName = requestor . playerName ;
requesteeFriendData . isFTP = false ;
requesteeFriendData . isOnline = false ;
requesteeFriendData . zoneID = requestor . zoneID ;
requestee . friends . push_back ( requesteeFriendData ) ;
requestee . sysAddr = UNASSIGNED_SYSTEM_ADDRESS ;
break ;
2022-07-13 03:36:06 +00:00
}
2021-12-05 17:54:36 +00:00
}
2022-07-13 03:36:06 +00:00
2022-07-25 02:26:51 +00:00
// If at this point we dont have a target, then they arent online and we cant send the request.
2022-07-13 03:36:06 +00:00
// Send the response code that corresponds to what the error is.
if ( ! requestee ) {
2024-01-06 04:42:30 +00:00
requestee . playerName = playerName ;
2023-11-18 00:47:18 +00:00
auto responseType = Database : : Get ( ) - > GetCharacterInfo ( playerName )
? eAddFriendResponseType : : NOTONLINE
: eAddFriendResponseType : : INVALIDCHARACTER ;
2022-07-13 03:36:06 +00:00
2024-01-06 04:42:30 +00:00
SendFriendResponse ( requestor , requestee , responseType ) ;
2022-07-13 03:36:06 +00:00
return ;
}
2024-01-14 07:03:01 +00:00
// Prevent GM friend spam
// If the player we are trying to be friends with is not a civilian and we are a civilian, abort the process
if ( requestee . gmLevel > eGameMasterLevel : : CIVILIAN & & requestor . gmLevel = = eGameMasterLevel : : CIVILIAN ) {
SendFriendResponse ( requestor , requestee , eAddFriendResponseType : : MYTHRAN ) ;
return ;
}
2022-07-13 03:36:06 +00:00
if ( isBestFriendRequest ) {
2023-11-18 00:47:18 +00:00
2022-07-13 03:36:06 +00:00
uint8_t oldBestFriendStatus { } ;
uint8_t bestFriendStatus { } ;
2024-01-06 04:42:30 +00:00
auto bestFriendInfo = Database : : Get ( ) - > GetBestFriendStatus ( requestorPlayerID , requestee . playerID ) ;
2023-11-18 00:47:18 +00:00
if ( bestFriendInfo ) {
2022-07-13 03:36:06 +00:00
// Get the IDs
2023-11-18 00:47:18 +00:00
LWOOBJID queryPlayerID = bestFriendInfo - > playerCharacterId ;
LWOOBJID queryFriendID = bestFriendInfo - > friendCharacterId ;
oldBestFriendStatus = bestFriendInfo - > bestFriendStatus ;
2022-07-13 03:36:06 +00:00
bestFriendStatus = oldBestFriendStatus ;
// Set the bits
2023-04-25 18:17:40 +00:00
GeneralUtils : : SetBit ( queryPlayerID , eObjectBits : : CHARACTER ) ;
GeneralUtils : : SetBit ( queryPlayerID , eObjectBits : : PERSISTENT ) ;
GeneralUtils : : SetBit ( queryFriendID , eObjectBits : : CHARACTER ) ;
GeneralUtils : : SetBit ( queryFriendID , eObjectBits : : PERSISTENT ) ;
2022-07-13 03:36:06 +00:00
// Since this player can either be the friend of someone else or be friends with someone else
// their column in the database determines what bit gets set. When the value hits 3, they
// are now best friends with the other player.
if ( queryPlayerID = = requestorPlayerID ) {
bestFriendStatus | = 1ULL < < 0 ;
} else {
bestFriendStatus | = 1ULL < < 1 ;
}
}
// Only do updates if there was a change in the bff status.
if ( oldBestFriendStatus ! = bestFriendStatus ) {
2023-11-19 01:33:52 +00:00
auto maxBestFriends = Game : : playerContainer . GetMaxNumberOfBestFriends ( ) ;
2024-01-06 04:42:30 +00:00
if ( requestee . countOfBestFriends > = maxBestFriends | | requestor . countOfBestFriends > = maxBestFriends ) {
if ( requestee . countOfBestFriends > = maxBestFriends ) {
SendFriendResponse ( requestor , requestee , eAddFriendResponseType : : THEIRFRIENDLISTFULL , false ) ;
2022-07-13 03:36:06 +00:00
}
2024-01-06 04:42:30 +00:00
if ( requestor . countOfBestFriends > = maxBestFriends ) {
SendFriendResponse ( requestor , requestee , eAddFriendResponseType : : YOURFRIENDSLISTFULL , false ) ;
2022-07-13 03:36:06 +00:00
}
} else {
// Then update the database with this new info.
2024-01-06 04:42:30 +00:00
Database : : Get ( ) - > SetBestFriendStatus ( requestorPlayerID , requestee . playerID , bestFriendStatus ) ;
2022-07-13 03:36:06 +00:00
// Sent the best friend update here if the value is 3
if ( bestFriendStatus = = 3U ) {
2024-01-06 04:42:30 +00:00
requestee . countOfBestFriends + = 1 ;
requestor . countOfBestFriends + = 1 ;
if ( requestee . sysAddr ! = UNASSIGNED_SYSTEM_ADDRESS ) SendFriendResponse ( requestee , requestor , eAddFriendResponseType : : ACCEPTED , false , true ) ;
if ( requestor . sysAddr ! = UNASSIGNED_SYSTEM_ADDRESS ) SendFriendResponse ( requestor , requestee , eAddFriendResponseType : : ACCEPTED , false , true ) ;
for ( auto & friendData : requestor . friends ) {
if ( friendData . friendID = = requestee . playerID ) {
2022-07-13 03:36:06 +00:00
friendData . isBestFriend = true ;
}
}
2024-01-06 04:42:30 +00:00
for ( auto & friendData : requestee . friends ) {
if ( friendData . friendID = = requestor . playerID ) {
2022-07-13 03:36:06 +00:00
friendData . isBestFriend = true ;
}
}
}
}
} else {
2024-01-06 04:42:30 +00:00
if ( requestor . sysAddr ! = UNASSIGNED_SYSTEM_ADDRESS ) SendFriendResponse ( requestor , requestee , eAddFriendResponseType : : WAITINGAPPROVAL , true , true ) ;
2022-07-13 03:36:06 +00:00
}
} else {
2023-11-19 01:33:52 +00:00
auto maxFriends = Game : : playerContainer . GetMaxNumberOfFriends ( ) ;
2024-01-06 04:42:30 +00:00
if ( requestee . friends . size ( ) > = maxFriends ) {
SendFriendResponse ( requestor , requestee , eAddFriendResponseType : : THEIRFRIENDLISTFULL , false ) ;
} else if ( requestor . friends . size ( ) > = maxFriends ) {
SendFriendResponse ( requestor , requestee , eAddFriendResponseType : : YOURFRIENDSLISTFULL , false ) ;
2023-11-18 00:44:48 +00:00
} else {
// Do not send this if we are requesting to be a best friend.
2024-01-06 04:42:30 +00:00
SendFriendRequest ( requestee , requestor ) ;
2023-11-18 00:44:48 +00:00
}
2022-07-13 03:36:06 +00:00
}
2021-12-05 17:54:36 +00:00
}
void ChatPacketHandler : : HandleFriendResponse ( Packet * packet ) {
2023-05-08 11:31:10 +00:00
CINSTREAM_SKIP_HEADER ;
2024-01-14 07:03:01 +00:00
2021-12-05 17:54:36 +00:00
LWOOBJID playerID ;
2024-01-14 07:03:01 +00:00
eAddFriendResponseCode clientResponseCode ;
LUWString friendName ;
2022-07-13 03:36:06 +00:00
2024-01-14 07:03:01 +00:00
inStream . Read ( playerID ) ;
inStream . IgnoreBytes ( 4 ) ;
inStream . Read ( clientResponseCode ) ;
inStream . Read ( friendName ) ;
2021-12-05 17:54:36 +00:00
//Now to try and find both of these:
2024-01-06 04:42:30 +00:00
auto & requestor = Game : : playerContainer . GetPlayerDataMutable ( playerID ) ;
2024-01-14 07:03:01 +00:00
auto & requestee = Game : : playerContainer . GetPlayerDataMutable ( friendName . GetAsString ( ) ) ;
2022-07-13 03:36:06 +00:00
if ( ! requestor | | ! requestee ) return ;
eAddFriendResponseType serverResponseCode { } ;
uint8_t isAlreadyBestFriends = 0U ;
// We need to convert this response code to one we can actually send back to the client.
switch ( clientResponseCode ) {
case eAddFriendResponseCode : : ACCEPTED :
serverResponseCode = eAddFriendResponseType : : ACCEPTED ;
break ;
case eAddFriendResponseCode : : BUSY :
serverResponseCode = eAddFriendResponseType : : BUSY ;
break ;
case eAddFriendResponseCode : : CANCELLED :
serverResponseCode = eAddFriendResponseType : : CANCELLED ;
break ;
case eAddFriendResponseCode : : REJECTED :
serverResponseCode = eAddFriendResponseType : : DECLINED ;
break ;
2022-07-11 00:59:07 +00:00
}
2022-07-13 03:36:06 +00:00
// Now that we have handled the base cases, we need to check the other cases.
if ( serverResponseCode = = eAddFriendResponseType : : ACCEPTED ) {
2024-01-06 04:42:30 +00:00
for ( const auto & friendData : requestor . friends ) {
if ( friendData . friendID = = requestee . playerID ) {
2022-07-13 03:36:06 +00:00
serverResponseCode = eAddFriendResponseType : : ALREADYFRIEND ;
if ( friendData . isBestFriend ) {
isAlreadyBestFriends = 1U ;
}
}
}
2022-07-11 00:59:07 +00:00
}
2022-07-13 03:36:06 +00:00
// This message is NOT sent for best friends and is handled differently for those requests.
if ( serverResponseCode = = eAddFriendResponseType : : ACCEPTED ) {
// Add the each player to the others friend list.
2024-01-06 04:42:30 +00:00
auto & requestorData = requestee . friends . emplace_back ( ) ;
requestorData . zoneID = requestor . zoneID ;
requestorData . friendID = requestor . playerID ;
requestorData . friendName = requestor . playerName ;
2022-07-13 03:36:06 +00:00
requestorData . isBestFriend = false ;
requestorData . isFTP = false ;
requestorData . isOnline = true ;
2024-01-06 04:42:30 +00:00
auto & requesteeData = requestor . friends . emplace_back ( ) ;
requesteeData . zoneID = requestee . zoneID ;
requesteeData . friendID = requestee . playerID ;
requesteeData . friendName = requestee . playerName ;
2022-07-13 03:36:06 +00:00
requesteeData . isBestFriend = false ;
requesteeData . isFTP = false ;
requesteeData . isOnline = true ;
2022-07-25 02:26:51 +00:00
2024-01-06 04:42:30 +00:00
Database : : Get ( ) - > AddFriend ( requestor . playerID , requestee . playerID ) ;
2022-07-13 03:36:06 +00:00
}
2021-12-05 17:54:36 +00:00
2022-07-13 03:36:06 +00:00
if ( serverResponseCode ! = eAddFriendResponseType : : DECLINED ) SendFriendResponse ( requestor , requestee , serverResponseCode , isAlreadyBestFriends ) ;
if ( serverResponseCode ! = eAddFriendResponseType : : ALREADYFRIEND ) SendFriendResponse ( requestee , requestor , serverResponseCode , isAlreadyBestFriends ) ;
2021-12-05 17:54:36 +00:00
}
void ChatPacketHandler : : HandleRemoveFriend ( Packet * packet ) {
2023-05-08 11:31:10 +00:00
CINSTREAM_SKIP_HEADER ;
2021-12-05 17:54:36 +00:00
LWOOBJID playerID ;
2024-01-14 07:03:01 +00:00
LUWString LUFriendName ;
2021-12-05 17:54:36 +00:00
inStream . Read ( playerID ) ;
2024-01-14 07:03:01 +00:00
inStream . IgnoreBytes ( 4 ) ;
inStream . Read ( LUFriendName ) ;
auto friendName = LUFriendName . GetAsString ( ) ;
2021-12-05 17:54:36 +00:00
//we'll have to query the db here to find the user, since you can delete them while they're offline.
//First, we need to find their ID:
LWOOBJID friendID = 0 ;
2023-11-18 00:47:18 +00:00
auto friendIdResult = Database : : Get ( ) - > GetCharacterInfo ( friendName ) ;
if ( friendIdResult ) {
friendID = friendIdResult - > id ;
2021-12-05 17:54:36 +00:00
}
2022-07-11 00:59:07 +00:00
// Convert friendID to LWOOBJID
2023-04-25 18:17:40 +00:00
GeneralUtils : : SetBit ( friendID , eObjectBits : : PERSISTENT ) ;
GeneralUtils : : SetBit ( friendID , eObjectBits : : CHARACTER ) ;
2022-07-11 00:59:07 +00:00
2023-11-18 00:47:18 +00:00
Database : : Get ( ) - > RemoveFriend ( playerID , friendID ) ;
2021-12-05 17:54:36 +00:00
//Now, we need to send an update to notify the sender (and possibly, receiver) that their friendship has been ended:
2024-01-06 04:42:30 +00:00
auto & goonA = Game : : playerContainer . GetPlayerDataMutable ( playerID ) ;
2021-12-05 17:54:36 +00:00
if ( goonA ) {
2022-07-11 00:59:07 +00:00
// Remove the friend from our list of friends
2024-01-06 04:42:30 +00:00
for ( auto friendData = goonA . friends . cbegin ( ) ; friendData ! = goonA . friends . cend ( ) ; friendData + + ) {
if ( friendData - > friendID = = friendID ) {
if ( friendData - > isBestFriend ) - - goonA . countOfBestFriends ;
goonA . friends . erase ( friendData ) ;
2022-07-11 00:59:07 +00:00
break ;
}
}
2021-12-05 17:54:36 +00:00
SendRemoveFriend ( goonA , friendName , true ) ;
}
2022-07-11 00:59:07 +00:00
2024-01-06 04:42:30 +00:00
auto & goonB = Game : : playerContainer . GetPlayerDataMutable ( friendID ) ;
2021-12-05 17:54:36 +00:00
if ( ! goonB ) return ;
2024-01-06 04:42:30 +00:00
2022-07-11 00:59:07 +00:00
// Do it again for other person
2024-01-06 04:42:30 +00:00
for ( auto friendData = goonB . friends . cbegin ( ) ; friendData ! = goonB . friends . cend ( ) ; friendData + + ) {
if ( friendData - > friendID = = playerID ) {
if ( friendData - > isBestFriend ) - - goonB . countOfBestFriends ;
goonB . friends . erase ( friendData ) ;
2022-07-11 00:59:07 +00:00
break ;
}
}
2023-11-19 01:33:52 +00:00
std : : string goonAName = GeneralUtils : : UTF16ToWTF8 ( Game : : playerContainer . GetName ( playerID ) ) ;
2021-12-05 17:54:36 +00:00
SendRemoveFriend ( goonB , goonAName , true ) ;
}
2024-01-14 07:03:01 +00:00
void ChatPacketHandler : : HandleGMLevelUpdate ( Packet * packet ) {
CINSTREAM_SKIP_HEADER ;
LWOOBJID playerID ;
inStream . Read ( playerID ) ;
auto & player = Game : : playerContainer . GetPlayerData ( playerID ) ;
if ( ! player ) return ;
inStream . Read ( player . gmLevel ) ;
}
2024-01-15 04:47:59 +00:00
void ChatPacketHandler : : HandleWho ( Packet * packet ) {
CINSTREAM_SKIP_HEADER ;
LWOOBJID playerID ;
inStream . Read ( playerID ) ;
const auto & sender = Game : : playerContainer . GetPlayerData ( playerID ) ;
if ( ! sender ) return ;
LUWString playerName ;
inStream . Read ( playerName ) ;
const auto & player = Game : : playerContainer . GetPlayerData ( playerName . GetAsString ( ) ) ;
bool online = true ;
if ( ! player ) online = false ;
CBITSTREAM ;
BitStreamUtils : : WriteHeader ( bitStream , eConnectionType : : CHAT , eChatMessageType : : WORLD_ROUTE_PACKET ) ;
bitStream . Write ( playerID ) ;
BitStreamUtils : : WriteHeader ( bitStream , eConnectionType : : CLIENT , eClientMessageType : : WHO_RESPONSE ) ;
bitStream . Write < uint8_t > ( online ) ;
bitStream . Write ( player . zoneID . GetMapID ( ) ) ;
bitStream . Write ( player . zoneID . GetInstanceID ( ) ) ;
bitStream . Write ( player . zoneID . GetCloneID ( ) ) ;
bitStream . Write ( playerName ) ;
SystemAddress sysAddr = sender . sysAddr ;
SEND_PACKET ;
}
void ChatPacketHandler : : HandleShowAll ( Packet * packet ) {
CINSTREAM_SKIP_HEADER ;
LWOOBJID playerID ;
inStream . Read ( playerID ) ;
const auto & sender = Game : : playerContainer . GetPlayerData ( playerID ) ;
if ( ! sender ) return ;
LUString displayZoneData ( 1 ) ;
inStream . Read ( displayZoneData ) ;
LUString displayIndividualPlayers ( 1 ) ;
inStream . Read ( displayIndividualPlayers ) ;
CBITSTREAM ;
BitStreamUtils : : WriteHeader ( bitStream , eConnectionType : : CHAT , eChatMessageType : : WORLD_ROUTE_PACKET ) ;
bitStream . Write ( playerID ) ;
BitStreamUtils : : WriteHeader ( bitStream , eConnectionType : : CLIENT , eClientMessageType : : SHOW_ALL_RESPONSE ) ;
bitStream . Write < uint8_t > ( displayZoneData . string ! = " 1 " & & displayIndividualPlayers . string ! = " 1 " ) ;
bitStream . Write ( Game : : playerContainer . GetPlayerCount ( ) ) ;
bitStream . Write ( Game : : playerContainer . GetSimCount ( ) ) ;
bitStream . Write < uint8_t > ( displayIndividualPlayers . string = = " 1 " ) ;
bitStream . Write < uint8_t > ( displayZoneData . string = = " 1 " ) ;
if ( displayZoneData . string = = " 1 " | | displayIndividualPlayers . string = = " 1 " ) {
for ( auto & [ playerID , playerData ] : Game : : playerContainer . GetAllPlayers ( ) ) {
if ( ! playerData ) continue ;
bitStream . Write < uint8_t > ( 0 ) ; // padding
if ( displayIndividualPlayers . string = = " 1 " ) bitStream . Write ( LUWString ( playerData . playerName ) ) ;
if ( displayZoneData . string = = " 1 " ) {
bitStream . Write ( playerData . zoneID . GetMapID ( ) ) ;
bitStream . Write ( playerData . zoneID . GetInstanceID ( ) ) ;
bitStream . Write ( playerData . zoneID . GetCloneID ( ) ) ;
}
}
}
SystemAddress sysAddr = sender . sysAddr ;
SEND_PACKET ;
}
2024-01-14 07:03:01 +00:00
// the structure the client uses to send this packet is shared in many chat messages
// that are sent to the server. Because of this, there are large gaps of unused data in chat messages
2022-07-25 02:26:51 +00:00
void ChatPacketHandler : : HandleChatMessage ( Packet * packet ) {
2023-05-08 11:31:10 +00:00
CINSTREAM_SKIP_HEADER ;
2024-01-14 07:03:01 +00:00
LWOOBJID playerID ;
2021-12-05 17:54:36 +00:00
inStream . Read ( playerID ) ;
2024-01-06 04:42:30 +00:00
const auto & sender = Game : : playerContainer . GetPlayerData ( playerID ) ;
2024-01-14 07:03:01 +00:00
if ( ! sender | | sender . GetIsMuted ( ) ) return ;
2021-12-05 17:54:36 +00:00
2024-01-14 07:03:01 +00:00
eChatChannel channel ;
uint32_t size ;
inStream . IgnoreBytes ( 4 ) ;
2021-12-05 17:54:36 +00:00
inStream . Read ( channel ) ;
2024-01-14 07:03:01 +00:00
inStream . Read ( size ) ;
inStream . IgnoreBytes ( 77 ) ;
LUWString message ( size ) ;
inStream . Read ( message ) ;
LOG ( " Got a message from (%s) via [%s]: %s " , sender . playerName . c_str ( ) , StringifiedEnum : : ToString ( channel ) . data ( ) , message . GetAsString ( ) . c_str ( ) ) ;
switch ( channel ) {
case eChatChannel : : TEAM : {
auto * team = Game : : playerContainer . GetTeam ( playerID ) ;
if ( team = = nullptr ) return ;
for ( const auto memberId : team - > memberIDs ) {
const auto & otherMember = Game : : playerContainer . GetPlayerData ( memberId ) ;
if ( ! otherMember ) return ;
SendPrivateChatMessage ( sender , otherMember , otherMember , message , eChatChannel : : TEAM , eChatMessageResponseCode : : SENT ) ;
}
break ;
}
default :
LOG ( " Unhandled Chat channel [%s] " , StringifiedEnum : : ToString ( channel ) . data ( ) ) ;
break ;
}
}
2022-07-25 02:26:51 +00:00
2024-01-14 07:03:01 +00:00
// the structure the client uses to send this packet is shared in many chat messages
// that are sent to the server. Because of this, there are large gaps of unused data in chat messages
void ChatPacketHandler : : HandlePrivateChatMessage ( Packet * packet ) {
CINSTREAM_SKIP_HEADER ;
LWOOBJID playerID ;
inStream . Read ( playerID ) ;
2021-12-05 17:54:36 +00:00
2024-01-14 07:03:01 +00:00
const auto & sender = Game : : playerContainer . GetPlayerData ( playerID ) ;
if ( ! sender | | sender . GetIsMuted ( ) ) return ;
2021-12-05 17:54:36 +00:00
2024-01-14 07:03:01 +00:00
eChatChannel channel ;
uint32_t size ;
LUWString LUReceiverName ;
2021-12-05 17:54:36 +00:00
2024-01-14 07:03:01 +00:00
inStream . IgnoreBytes ( 4 ) ;
inStream . Read ( channel ) ;
if ( channel ! = eChatChannel : : PRIVATE_CHAT ) LOG ( " WARNING: Received Private chat with the wrong channel! " ) ;
2021-12-05 17:54:36 +00:00
2024-01-14 07:03:01 +00:00
inStream . Read ( size ) ;
inStream . IgnoreBytes ( 77 ) ;
inStream . Read ( LUReceiverName ) ;
auto receiverName = LUReceiverName . GetAsString ( ) ;
inStream . IgnoreBytes ( 2 ) ;
LUWString message ( size ) ;
inStream . Read ( message ) ;
LOG ( " Got a message from (%s) via [%s]: %s to %s " , sender . playerName . c_str ( ) , StringifiedEnum : : ToString ( channel ) . data ( ) , message . GetAsString ( ) . c_str ( ) , receiverName . c_str ( ) ) ;
const auto & receiver = Game : : playerContainer . GetPlayerData ( receiverName ) ;
if ( ! receiver ) {
PlayerData otherPlayer ;
otherPlayer . playerName = receiverName ;
auto responseType = Database : : Get ( ) - > GetCharacterInfo ( receiverName )
? eChatMessageResponseCode : : NOTONLINE
: eChatMessageResponseCode : : GENERALERROR ;
SendPrivateChatMessage ( sender , otherPlayer , sender , message , eChatChannel : : GENERAL , responseType ) ;
return ;
2021-12-05 17:54:36 +00:00
}
2024-01-14 07:03:01 +00:00
// Check to see if they are friends
// only freinds can whispr each other
for ( const auto & fr : receiver . friends ) {
if ( fr . friendID = = sender . playerID ) {
//To the sender:
SendPrivateChatMessage ( sender , receiver , sender , message , eChatChannel : : PRIVATE_CHAT , eChatMessageResponseCode : : SENT ) ;
//To the receiver:
SendPrivateChatMessage ( sender , receiver , receiver , message , eChatChannel : : PRIVATE_CHAT , eChatMessageResponseCode : : RECEIVEDNEWWHISPER ) ;
return ;
}
2021-12-05 17:54:36 +00:00
}
2024-01-14 07:03:01 +00:00
SendPrivateChatMessage ( sender , receiver , sender , message , eChatChannel : : GENERAL , eChatMessageResponseCode : : NOTFRIENDS ) ;
}
2021-12-05 17:54:36 +00:00
2024-01-14 07:03:01 +00:00
void ChatPacketHandler : : SendPrivateChatMessage ( const PlayerData & sender , const PlayerData & receiver , const PlayerData & routeTo , const LUWString & message , const eChatChannel channel , const eChatMessageResponseCode responseCode ) {
CBITSTREAM ;
2024-01-15 04:47:59 +00:00
BitStreamUtils : : WriteHeader ( bitStream , eConnectionType : : CHAT , eChatMessageType : : WORLD_ROUTE_PACKET ) ;
2024-01-14 07:03:01 +00:00
bitStream . Write ( routeTo . playerID ) ;
BitStreamUtils : : WriteHeader ( bitStream , eConnectionType : : CHAT , eChatMessageType : : PRIVATE_CHAT_MESSAGE ) ;
bitStream . Write ( sender . playerID ) ;
bitStream . Write ( channel ) ;
bitStream . Write < uint32_t > ( 0 ) ; // not used
bitStream . Write ( LUWString ( sender . playerName ) ) ;
bitStream . Write ( sender . playerID ) ;
bitStream . Write < uint16_t > ( 0 ) ; // sourceID
bitStream . Write ( sender . gmLevel ) ;
bitStream . Write ( LUWString ( receiver . playerName ) ) ;
bitStream . Write ( receiver . gmLevel ) ;
bitStream . Write ( responseCode ) ;
bitStream . Write ( message ) ;
SystemAddress sysAddr = routeTo . sysAddr ;
SEND_PACKET ;
2021-12-05 17:54:36 +00:00
}
2024-01-14 07:03:01 +00:00
2021-12-05 17:54:36 +00:00
void ChatPacketHandler : : HandleTeamInvite ( Packet * packet ) {
2023-05-08 11:31:10 +00:00
CINSTREAM_SKIP_HEADER ;
2024-01-14 07:03:01 +00:00
2021-12-05 17:54:36 +00:00
LWOOBJID playerID ;
2024-01-14 07:03:01 +00:00
LUWString invitedPlayer ;
2021-12-05 17:54:36 +00:00
inStream . Read ( playerID ) ;
2024-01-14 07:03:01 +00:00
inStream . IgnoreBytes ( 4 ) ;
inStream . Read ( invitedPlayer ) ;
2021-12-05 17:54:36 +00:00
2024-01-06 04:42:30 +00:00
const auto & player = Game : : playerContainer . GetPlayerData ( playerID ) ;
2021-12-05 17:54:36 +00:00
2024-01-06 04:42:30 +00:00
if ( ! player ) return ;
2021-12-05 17:54:36 +00:00
2023-11-19 01:33:52 +00:00
auto * team = Game : : playerContainer . GetTeam ( playerID ) ;
2021-12-05 17:54:36 +00:00
if ( team = = nullptr ) {
2023-11-19 01:33:52 +00:00
team = Game : : playerContainer . CreateTeam ( playerID ) ;
2021-12-05 17:54:36 +00:00
}
2024-01-14 07:03:01 +00:00
const auto & other = Game : : playerContainer . GetPlayerData ( invitedPlayer . GetAsString ( ) ) ;
2021-12-05 17:54:36 +00:00
2024-01-06 04:42:30 +00:00
if ( ! other ) return ;
2021-12-05 17:54:36 +00:00
2024-01-06 04:42:30 +00:00
if ( Game : : playerContainer . GetTeam ( other . playerID ) ! = nullptr ) {
2021-12-05 17:54:36 +00:00
return ;
}
2021-12-24 00:25:52 +00:00
if ( team - > memberIDs . size ( ) > 3 ) {
// no more teams greater than 4
2023-10-21 23:31:55 +00:00
LOG ( " Someone tried to invite a 5th player to a team " ) ;
2021-12-24 11:57:31 +00:00
return ;
2021-12-24 00:25:52 +00:00
}
2021-12-05 17:54:36 +00:00
SendTeamInvite ( other , player ) ;
2024-01-14 07:03:01 +00:00
LOG ( " Got team invite: %llu -> %s " , playerID , invitedPlayer . GetAsString ( ) . c_str ( ) ) ;
2021-12-05 17:54:36 +00:00
}
2022-07-25 02:26:51 +00:00
void ChatPacketHandler : : HandleTeamInviteResponse ( Packet * packet ) {
2023-05-08 11:31:10 +00:00
CINSTREAM_SKIP_HEADER ;
2021-12-05 17:54:36 +00:00
LWOOBJID playerID = LWOOBJID_EMPTY ;
inStream . Read ( playerID ) ;
uint32_t size = 0 ;
inStream . Read ( size ) ;
char declined = 0 ;
inStream . Read ( declined ) ;
LWOOBJID leaderID = LWOOBJID_EMPTY ;
inStream . Read ( leaderID ) ;
2023-10-21 23:31:55 +00:00
LOG ( " Accepted invite: %llu -> %llu (%d) " , playerID , leaderID , declined ) ;
2021-12-05 17:54:36 +00:00
if ( declined ) {
return ;
}
2023-11-19 01:33:52 +00:00
auto * team = Game : : playerContainer . GetTeam ( leaderID ) ;
2021-12-05 17:54:36 +00:00
if ( team = = nullptr ) {
2023-10-21 23:31:55 +00:00
LOG ( " Failed to find team for leader (%llu) " , leaderID ) ;
2021-12-05 17:54:36 +00:00
2023-11-19 01:33:52 +00:00
team = Game : : playerContainer . GetTeam ( playerID ) ;
2021-12-05 17:54:36 +00:00
}
2022-07-25 02:26:51 +00:00
2021-12-05 17:54:36 +00:00
if ( team = = nullptr ) {
2023-10-21 23:31:55 +00:00
LOG ( " Failed to find team for player (%llu) " , playerID ) ;
2021-12-05 17:54:36 +00:00
return ;
}
2023-11-19 01:33:52 +00:00
Game : : playerContainer . AddMember ( team , playerID ) ;
2021-12-05 17:54:36 +00:00
}
2022-07-25 02:26:51 +00:00
void ChatPacketHandler : : HandleTeamLeave ( Packet * packet ) {
2023-05-08 11:31:10 +00:00
CINSTREAM_SKIP_HEADER ;
2021-12-05 17:54:36 +00:00
LWOOBJID playerID = LWOOBJID_EMPTY ;
inStream . Read ( playerID ) ;
uint32_t size = 0 ;
inStream . Read ( size ) ;
2023-11-19 01:33:52 +00:00
auto * team = Game : : playerContainer . GetTeam ( playerID ) ;
2021-12-05 17:54:36 +00:00
2023-10-21 23:31:55 +00:00
LOG ( " (%llu) leaving team " , playerID ) ;
2021-12-05 17:54:36 +00:00
if ( team ! = nullptr ) {
2023-11-19 01:33:52 +00:00
Game : : playerContainer . RemoveMember ( team , playerID , false , false , true ) ;
2021-12-05 17:54:36 +00:00
}
}
2022-07-25 02:26:51 +00:00
void ChatPacketHandler : : HandleTeamKick ( Packet * packet ) {
2023-05-08 11:31:10 +00:00
CINSTREAM_SKIP_HEADER ;
2024-01-14 07:03:01 +00:00
2021-12-05 17:54:36 +00:00
LWOOBJID playerID = LWOOBJID_EMPTY ;
2024-01-14 07:03:01 +00:00
LUWString kickedPlayer ;
2021-12-05 17:54:36 +00:00
inStream . Read ( playerID ) ;
2024-01-14 07:03:01 +00:00
inStream . IgnoreBytes ( 4 ) ;
inStream . Read ( kickedPlayer ) ;
2022-07-25 02:26:51 +00:00
2021-12-05 17:54:36 +00:00
2024-01-14 07:03:01 +00:00
LOG ( " (%llu) kicking (%s) from team " , playerID , kickedPlayer . GetAsString ( ) . c_str ( ) ) ;
2021-12-05 17:54:36 +00:00
2024-01-14 07:03:01 +00:00
const auto & kicked = Game : : playerContainer . GetPlayerData ( kickedPlayer . GetAsString ( ) ) ;
2021-12-05 17:54:36 +00:00
LWOOBJID kickedId = LWOOBJID_EMPTY ;
2024-01-06 04:42:30 +00:00
if ( kicked ) {
kickedId = kicked . playerID ;
2021-12-05 17:54:36 +00:00
} else {
2024-01-14 07:03:01 +00:00
kickedId = Game : : playerContainer . GetId ( kickedPlayer . string ) ;
2021-12-05 17:54:36 +00:00
}
if ( kickedId = = LWOOBJID_EMPTY ) return ;
2023-11-19 01:33:52 +00:00
auto * team = Game : : playerContainer . GetTeam ( playerID ) ;
2021-12-05 17:54:36 +00:00
if ( team ! = nullptr ) {
if ( team - > leaderID ! = playerID | | team - > leaderID = = kickedId ) return ;
2023-11-19 01:33:52 +00:00
Game : : playerContainer . RemoveMember ( team , kickedId , false , true , false ) ;
2021-12-05 17:54:36 +00:00
}
}
2022-07-25 02:26:51 +00:00
void ChatPacketHandler : : HandleTeamPromote ( Packet * packet ) {
2023-05-08 11:31:10 +00:00
CINSTREAM_SKIP_HEADER ;
2024-01-14 07:03:01 +00:00
2021-12-05 17:54:36 +00:00
LWOOBJID playerID = LWOOBJID_EMPTY ;
2024-01-14 07:03:01 +00:00
LUWString promotedPlayer ;
2022-07-25 02:26:51 +00:00
2024-01-14 07:03:01 +00:00
inStream . Read ( playerID ) ;
inStream . IgnoreBytes ( 4 ) ;
inStream . Read ( promotedPlayer ) ;
2021-12-05 17:54:36 +00:00
2024-01-14 07:03:01 +00:00
LOG ( " (%llu) promoting (%s) to team leader " , playerID , promotedPlayer . GetAsString ( ) . c_str ( ) ) ;
2021-12-05 17:54:36 +00:00
2024-01-14 07:03:01 +00:00
const auto & promoted = Game : : playerContainer . GetPlayerData ( promotedPlayer . GetAsString ( ) ) ;
2021-12-05 17:54:36 +00:00
2024-01-06 04:42:30 +00:00
if ( ! promoted ) return ;
2021-12-05 17:54:36 +00:00
2023-11-19 01:33:52 +00:00
auto * team = Game : : playerContainer . GetTeam ( playerID ) ;
2021-12-05 17:54:36 +00:00
if ( team ! = nullptr ) {
if ( team - > leaderID ! = playerID ) return ;
2024-01-06 04:42:30 +00:00
Game : : playerContainer . PromoteMember ( team , promoted . playerID ) ;
2021-12-05 17:54:36 +00:00
}
}
2022-07-25 02:26:51 +00:00
void ChatPacketHandler : : HandleTeamLootOption ( Packet * packet ) {
2023-05-08 11:31:10 +00:00
CINSTREAM_SKIP_HEADER ;
2021-12-05 17:54:36 +00:00
LWOOBJID playerID = LWOOBJID_EMPTY ;
inStream . Read ( playerID ) ;
uint32_t size = 0 ;
inStream . Read ( size ) ;
2022-07-25 02:26:51 +00:00
2021-12-05 17:54:36 +00:00
char option ;
inStream . Read ( option ) ;
2023-11-19 01:33:52 +00:00
auto * team = Game : : playerContainer . GetTeam ( playerID ) ;
2021-12-05 17:54:36 +00:00
if ( team ! = nullptr ) {
if ( team - > leaderID ! = playerID ) return ;
team - > lootFlag = option ;
2023-11-19 01:33:52 +00:00
Game : : playerContainer . TeamStatusUpdate ( team ) ;
2022-07-25 02:26:51 +00:00
2023-11-19 01:33:52 +00:00
Game : : playerContainer . UpdateTeamsOnWorld ( team , false ) ;
2021-12-05 17:54:36 +00:00
}
}
2022-07-25 02:26:51 +00:00
void ChatPacketHandler : : HandleTeamStatusRequest ( Packet * packet ) {
2023-05-08 11:31:10 +00:00
CINSTREAM_SKIP_HEADER ;
2021-12-05 17:54:36 +00:00
LWOOBJID playerID = LWOOBJID_EMPTY ;
inStream . Read ( playerID ) ;
2023-11-19 01:33:52 +00:00
auto * team = Game : : playerContainer . GetTeam ( playerID ) ;
2024-01-06 04:42:30 +00:00
const auto & data = Game : : playerContainer . GetPlayerData ( playerID ) ;
2021-12-05 17:54:36 +00:00
2024-01-06 04:42:30 +00:00
if ( team ! = nullptr & & data ) {
if ( team - > local & & data . zoneID . GetMapID ( ) ! = team - > zoneId . GetMapID ( ) & & data . zoneID . GetCloneID ( ) ! = team - > zoneId . GetCloneID ( ) ) {
2023-11-19 01:33:52 +00:00
Game : : playerContainer . RemoveMember ( team , playerID , false , false , true , true ) ;
2021-12-05 17:54:36 +00:00
return ;
}
if ( team - > memberIDs . size ( ) < = 1 & & ! team - > local ) {
2023-11-19 01:33:52 +00:00
Game : : playerContainer . DisbandTeam ( team ) ;
2021-12-05 17:54:36 +00:00
return ;
}
if ( ! team - > local ) {
ChatPacketHandler : : SendTeamSetLeader ( data , team - > leaderID ) ;
} else {
ChatPacketHandler : : SendTeamSetLeader ( data , LWOOBJID_EMPTY ) ;
}
2023-11-19 01:33:52 +00:00
Game : : playerContainer . TeamStatusUpdate ( team ) ;
2021-12-05 17:54:36 +00:00
2024-01-06 04:42:30 +00:00
const auto leaderName = GeneralUtils : : UTF8ToUTF16 ( data . playerName ) ;
2021-12-05 17:54:36 +00:00
for ( const auto memberId : team - > memberIDs ) {
2024-01-06 04:42:30 +00:00
const auto & otherMember = Game : : playerContainer . GetPlayerData ( memberId ) ;
2021-12-05 17:54:36 +00:00
if ( memberId = = playerID ) continue ;
2023-11-19 01:33:52 +00:00
const auto memberName = Game : : playerContainer . GetName ( memberId ) ;
2022-07-25 02:26:51 +00:00
2024-01-06 04:42:30 +00:00
if ( otherMember ) {
ChatPacketHandler : : SendTeamSetOffWorldFlag ( otherMember , data . playerID , data . zoneID ) ;
2021-12-05 17:54:36 +00:00
}
2024-01-06 04:42:30 +00:00
ChatPacketHandler : : SendTeamAddPlayer ( data , false , team - > local , false , memberId , memberName , otherMember ? otherMember . zoneID : LWOZONEID ( 0 , 0 , 0 ) ) ;
2021-12-05 17:54:36 +00:00
}
2023-11-19 01:33:52 +00:00
Game : : playerContainer . UpdateTeamsOnWorld ( team , false ) ;
2021-12-05 17:54:36 +00:00
}
}
2024-01-06 04:42:30 +00:00
void ChatPacketHandler : : SendTeamInvite ( const PlayerData & receiver , const PlayerData & sender ) {
2021-12-05 17:54:36 +00:00
CBITSTREAM ;
2024-01-15 04:47:59 +00:00
BitStreamUtils : : WriteHeader ( bitStream , eConnectionType : : CHAT , eChatMessageType : : WORLD_ROUTE_PACKET ) ;
2024-01-06 04:42:30 +00:00
bitStream . Write ( receiver . playerID ) ;
2021-12-05 17:54:36 +00:00
//portion that will get routed:
2023-09-21 01:06:28 +00:00
BitStreamUtils : : WriteHeader ( bitStream , eConnectionType : : CLIENT , eClientMessageType : : TEAM_INVITE ) ;
2021-12-05 17:54:36 +00:00
2024-01-06 04:42:30 +00:00
bitStream . Write ( LUWString ( sender . playerName . c_str ( ) ) ) ;
bitStream . Write ( sender . playerID ) ;
2021-12-05 17:54:36 +00:00
2024-01-06 04:42:30 +00:00
SystemAddress sysAddr = receiver . sysAddr ;
2021-12-05 17:54:36 +00:00
SEND_PACKET ;
}
2024-01-06 04:42:30 +00:00
void ChatPacketHandler : : SendTeamInviteConfirm ( const PlayerData & receiver , bool bLeaderIsFreeTrial , LWOOBJID i64LeaderID , LWOZONEID i64LeaderZoneID , uint8_t ucLootFlag , uint8_t ucNumOfOtherPlayers , uint8_t ucResponseCode , std : : u16string wsLeaderName ) {
2021-12-05 17:54:36 +00:00
CBITSTREAM ;
2024-01-15 04:47:59 +00:00
BitStreamUtils : : WriteHeader ( bitStream , eConnectionType : : CHAT , eChatMessageType : : WORLD_ROUTE_PACKET ) ;
2024-01-06 04:42:30 +00:00
bitStream . Write ( receiver . playerID ) ;
2021-12-05 17:54:36 +00:00
//portion that will get routed:
CMSGHEADER ;
2024-01-06 04:42:30 +00:00
bitStream . Write ( receiver . playerID ) ;
2023-05-03 21:38:32 +00:00
bitStream . Write ( eGameMessageType : : TEAM_INVITE_CONFIRM ) ;
2021-12-05 17:54:36 +00:00
bitStream . Write ( bLeaderIsFreeTrial ) ;
bitStream . Write ( i64LeaderID ) ;
bitStream . Write ( i64LeaderZoneID ) ;
bitStream . Write < uint32_t > ( 0 ) ; // BinaryBuffe, no clue what's in here
bitStream . Write ( ucLootFlag ) ;
bitStream . Write ( ucNumOfOtherPlayers ) ;
bitStream . Write ( ucResponseCode ) ;
2023-12-28 04:18:20 +00:00
bitStream . Write < uint32_t > ( wsLeaderName . size ( ) ) ;
2021-12-05 17:54:36 +00:00
for ( const auto character : wsLeaderName ) {
bitStream . Write ( character ) ;
}
2024-01-06 04:42:30 +00:00
SystemAddress sysAddr = receiver . sysAddr ;
2021-12-05 17:54:36 +00:00
SEND_PACKET ;
}
2024-01-29 18:27:19 +00:00
void ChatPacketHandler : : SendTeamStatus ( const PlayerData & receiver , TeamData * team ) {
2021-12-05 17:54:36 +00:00
CBITSTREAM ;
2024-01-15 04:47:59 +00:00
BitStreamUtils : : WriteHeader ( bitStream , eConnectionType : : CHAT , eChatMessageType : : WORLD_ROUTE_PACKET ) ;
2024-01-06 04:42:30 +00:00
bitStream . Write ( receiver . playerID ) ;
2021-12-05 17:54:36 +00:00
//portion that will get routed:
CMSGHEADER ;
2024-01-06 04:42:30 +00:00
bitStream . Write ( receiver . playerID ) ;
2023-05-03 21:38:32 +00:00
bitStream . Write ( eGameMessageType : : TEAM_GET_STATUS_RESPONSE ) ;
2021-12-05 17:54:36 +00:00
2024-01-29 18:27:19 +00:00
bitStream . Write ( team - > leaderID ) ;
const auto & leader = Game : : playerContainer . GetPlayerData ( team - > leaderID ) ;
bitStream . Write ( leader . zoneID ) ;
bitStream . Write < uint32_t > ( ( team - > memberIDs . size ( ) - 1 ) * ( ( sizeof ( int16_t ) * 33 ) + sizeof ( LWOOBJID ) + sizeof ( LWOZONEID ) ) ) ;
for ( const auto memberid : team - > memberIDs ) {
if ( memberid = = team - > leaderID ) continue ;
const auto & member = Game : : playerContainer . GetPlayerData ( memberid ) ;
bitStream . Write ( LUWString ( member . playerName ) ) ;
bitStream . Write ( memberid ) ;
bitStream . Write ( member . zoneID ) ;
}
bitStream . Write ( team - > lootFlag ) ;
bitStream . Write ( team - > memberIDs . size ( ) ) ;
const std : : u16string wsLeaderName = GeneralUtils : : UTF8ToUTF16 ( leader . playerName ) ;
2023-12-28 04:18:20 +00:00
bitStream . Write < uint32_t > ( wsLeaderName . size ( ) ) ;
2024-01-29 18:27:19 +00:00
bitStream . Write ( wsLeaderName ) ;
2024-01-06 04:42:30 +00:00
SystemAddress sysAddr = receiver . sysAddr ;
2021-12-05 17:54:36 +00:00
SEND_PACKET ;
}
2024-01-06 04:42:30 +00:00
void ChatPacketHandler : : SendTeamSetLeader ( const PlayerData & receiver , LWOOBJID i64PlayerID ) {
2021-12-05 17:54:36 +00:00
CBITSTREAM ;
2024-01-15 04:47:59 +00:00
BitStreamUtils : : WriteHeader ( bitStream , eConnectionType : : CHAT , eChatMessageType : : WORLD_ROUTE_PACKET ) ;
2024-01-06 04:42:30 +00:00
bitStream . Write ( receiver . playerID ) ;
2021-12-05 17:54:36 +00:00
//portion that will get routed:
CMSGHEADER ;
2024-01-06 04:42:30 +00:00
bitStream . Write ( receiver . playerID ) ;
2023-05-03 21:38:32 +00:00
bitStream . Write ( eGameMessageType : : TEAM_SET_LEADER ) ;
2021-12-05 17:54:36 +00:00
bitStream . Write ( i64PlayerID ) ;
2024-01-06 04:42:30 +00:00
SystemAddress sysAddr = receiver . sysAddr ;
2021-12-05 17:54:36 +00:00
SEND_PACKET ;
}
2024-01-06 04:42:30 +00:00
void ChatPacketHandler : : SendTeamAddPlayer ( const PlayerData & receiver , bool bIsFreeTrial , bool bLocal , bool bNoLootOnDeath , LWOOBJID i64PlayerID , std : : u16string wsPlayerName , LWOZONEID zoneID ) {
2021-12-05 17:54:36 +00:00
CBITSTREAM ;
2024-01-15 04:47:59 +00:00
BitStreamUtils : : WriteHeader ( bitStream , eConnectionType : : CHAT , eChatMessageType : : WORLD_ROUTE_PACKET ) ;
2024-01-06 04:42:30 +00:00
bitStream . Write ( receiver . playerID ) ;
2021-12-05 17:54:36 +00:00
//portion that will get routed:
CMSGHEADER ;
2024-01-06 04:42:30 +00:00
bitStream . Write ( receiver . playerID ) ;
2023-05-03 21:38:32 +00:00
bitStream . Write ( eGameMessageType : : TEAM_ADD_PLAYER ) ;
2021-12-05 17:54:36 +00:00
bitStream . Write ( bIsFreeTrial ) ;
bitStream . Write ( bLocal ) ;
bitStream . Write ( bNoLootOnDeath ) ;
bitStream . Write ( i64PlayerID ) ;
2023-12-28 04:18:20 +00:00
bitStream . Write < uint32_t > ( wsPlayerName . size ( ) ) ;
2021-12-05 17:54:36 +00:00
for ( const auto character : wsPlayerName ) {
bitStream . Write ( character ) ;
}
bitStream . Write1 ( ) ;
2024-01-06 04:42:30 +00:00
if ( receiver . zoneID . GetCloneID ( ) = = zoneID . GetCloneID ( ) ) {
2021-12-05 17:54:36 +00:00
zoneID = LWOZONEID ( zoneID . GetMapID ( ) , zoneID . GetInstanceID ( ) , 0 ) ;
}
bitStream . Write ( zoneID ) ;
2024-01-06 04:42:30 +00:00
SystemAddress sysAddr = receiver . sysAddr ;
2021-12-05 17:54:36 +00:00
SEND_PACKET ;
}
2024-01-06 04:42:30 +00:00
void ChatPacketHandler : : SendTeamRemovePlayer ( const PlayerData & receiver , bool bDisband , bool bIsKicked , bool bIsLeaving , bool bLocal , LWOOBJID i64LeaderID , LWOOBJID i64PlayerID , std : : u16string wsPlayerName ) {
2021-12-05 17:54:36 +00:00
CBITSTREAM ;
2024-01-15 04:47:59 +00:00
BitStreamUtils : : WriteHeader ( bitStream , eConnectionType : : CHAT , eChatMessageType : : WORLD_ROUTE_PACKET ) ;
2024-01-06 04:42:30 +00:00
bitStream . Write ( receiver . playerID ) ;
2021-12-05 17:54:36 +00:00
//portion that will get routed:
CMSGHEADER ;
2024-01-06 04:42:30 +00:00
bitStream . Write ( receiver . playerID ) ;
2023-05-03 21:38:32 +00:00
bitStream . Write ( eGameMessageType : : TEAM_REMOVE_PLAYER ) ;
2021-12-05 17:54:36 +00:00
bitStream . Write ( bDisband ) ;
bitStream . Write ( bIsKicked ) ;
bitStream . Write ( bIsLeaving ) ;
bitStream . Write ( bLocal ) ;
bitStream . Write ( i64LeaderID ) ;
bitStream . Write ( i64PlayerID ) ;
2023-12-28 04:18:20 +00:00
bitStream . Write < uint32_t > ( wsPlayerName . size ( ) ) ;
2021-12-05 17:54:36 +00:00
for ( const auto character : wsPlayerName ) {
bitStream . Write ( character ) ;
}
2024-01-06 04:42:30 +00:00
SystemAddress sysAddr = receiver . sysAddr ;
2021-12-05 17:54:36 +00:00
SEND_PACKET ;
}
2024-01-06 04:42:30 +00:00
void ChatPacketHandler : : SendTeamSetOffWorldFlag ( const PlayerData & receiver , LWOOBJID i64PlayerID , LWOZONEID zoneID ) {
2021-12-05 17:54:36 +00:00
CBITSTREAM ;
2024-01-15 04:47:59 +00:00
BitStreamUtils : : WriteHeader ( bitStream , eConnectionType : : CHAT , eChatMessageType : : WORLD_ROUTE_PACKET ) ;
2024-01-06 04:42:30 +00:00
bitStream . Write ( receiver . playerID ) ;
2021-12-05 17:54:36 +00:00
//portion that will get routed:
CMSGHEADER ;
2024-01-06 04:42:30 +00:00
bitStream . Write ( receiver . playerID ) ;
2023-05-03 21:38:32 +00:00
bitStream . Write ( eGameMessageType : : TEAM_SET_OFF_WORLD_FLAG ) ;
2021-12-05 17:54:36 +00:00
bitStream . Write ( i64PlayerID ) ;
2024-01-06 04:42:30 +00:00
if ( receiver . zoneID . GetCloneID ( ) = = zoneID . GetCloneID ( ) ) {
2021-12-05 17:54:36 +00:00
zoneID = LWOZONEID ( zoneID . GetMapID ( ) , zoneID . GetInstanceID ( ) , 0 ) ;
}
bitStream . Write ( zoneID ) ;
2024-01-06 04:42:30 +00:00
SystemAddress sysAddr = receiver . sysAddr ;
2021-12-05 17:54:36 +00:00
SEND_PACKET ;
}
2024-01-06 04:42:30 +00:00
void ChatPacketHandler : : SendFriendUpdate ( const PlayerData & friendData , const PlayerData & playerData , uint8_t notifyType , uint8_t isBestFriend ) {
2021-12-05 17:54:36 +00:00
/*chat notification is displayed if log in / out and friend is updated in friends list
[ u8 ] - update type
Update types
0 - friend logged out
1 - friend logged in
2 - friend changed world / updated
[ wstring ] - Name of friend
[ u16 ] - World ID
[ u16 ] - World Instance
[ u32 ] - World Clone
[ bool ] - is best friend
[ bool ] - is FTP */
CBITSTREAM ;
2024-01-15 04:47:59 +00:00
BitStreamUtils : : WriteHeader ( bitStream , eConnectionType : : CHAT , eChatMessageType : : WORLD_ROUTE_PACKET ) ;
2024-01-06 04:42:30 +00:00
bitStream . Write ( friendData . playerID ) ;
2021-12-05 17:54:36 +00:00
//portion that will get routed:
2023-09-21 01:06:28 +00:00
BitStreamUtils : : WriteHeader ( bitStream , eConnectionType : : CLIENT , eClientMessageType : : UPDATE_FRIEND_NOTIFY ) ;
2021-12-05 17:54:36 +00:00
bitStream . Write < uint8_t > ( notifyType ) ;
2024-01-06 04:42:30 +00:00
std : : string playerName = playerData . playerName . c_str ( ) ;
2021-12-05 17:54:36 +00:00
2023-09-21 01:06:28 +00:00
bitStream . Write ( LUWString ( playerName ) ) ;
2021-12-05 17:54:36 +00:00
2024-01-06 04:42:30 +00:00
bitStream . Write ( playerData . zoneID . GetMapID ( ) ) ;
bitStream . Write ( playerData . zoneID . GetInstanceID ( ) ) ;
2021-12-05 17:54:36 +00:00
2024-01-06 04:42:30 +00:00
if ( playerData . zoneID . GetCloneID ( ) = = friendData . zoneID . GetCloneID ( ) ) {
2021-12-05 17:54:36 +00:00
bitStream . Write ( 0 ) ;
} else {
2024-01-06 04:42:30 +00:00
bitStream . Write ( playerData . zoneID . GetCloneID ( ) ) ;
2021-12-05 17:54:36 +00:00
}
2022-07-13 03:36:06 +00:00
bitStream . Write < uint8_t > ( isBestFriend ) ; //isBFF
2021-12-05 17:54:36 +00:00
bitStream . Write < uint8_t > ( 0 ) ; //isFTP
2024-01-06 04:42:30 +00:00
SystemAddress sysAddr = friendData . sysAddr ;
2021-12-05 17:54:36 +00:00
SEND_PACKET ;
}
2024-01-06 04:42:30 +00:00
void ChatPacketHandler : : SendFriendRequest ( const PlayerData & receiver , const PlayerData & sender ) {
2021-12-05 17:54:36 +00:00
//Make sure people aren't requesting people that they're already friends with:
2024-01-06 04:42:30 +00:00
for ( const auto & fr : receiver . friends ) {
if ( fr . friendID = = sender . playerID ) {
2022-07-13 03:36:06 +00:00
SendFriendResponse ( sender , receiver , eAddFriendResponseType : : ALREADYFRIEND , fr . isBestFriend ) ;
2021-12-05 17:54:36 +00:00
return ; //we have this player as a friend, yeet this function so it doesn't send another request.
}
}
CBITSTREAM ;
2024-01-15 04:47:59 +00:00
BitStreamUtils : : WriteHeader ( bitStream , eConnectionType : : CHAT , eChatMessageType : : WORLD_ROUTE_PACKET ) ;
2024-01-06 04:42:30 +00:00
bitStream . Write ( receiver . playerID ) ;
2021-12-05 17:54:36 +00:00
//portion that will get routed:
2023-09-21 01:06:28 +00:00
BitStreamUtils : : WriteHeader ( bitStream , eConnectionType : : CLIENT , eClientMessageType : : ADD_FRIEND_REQUEST ) ;
2024-01-06 04:42:30 +00:00
bitStream . Write ( LUWString ( sender . playerName ) ) ;
2022-07-13 03:36:06 +00:00
bitStream . Write < uint8_t > ( 0 ) ; // This is a BFF flag however this is unused in live and does not have an implementation client side.
2021-12-05 17:54:36 +00:00
2024-01-06 04:42:30 +00:00
SystemAddress sysAddr = receiver . sysAddr ;
2021-12-05 17:54:36 +00:00
SEND_PACKET ;
}
2024-01-06 04:42:30 +00:00
void ChatPacketHandler : : SendFriendResponse ( const PlayerData & receiver , const PlayerData & sender , eAddFriendResponseType responseCode , uint8_t isBestFriendsAlready , uint8_t isBestFriendRequest ) {
2021-12-05 17:54:36 +00:00
CBITSTREAM ;
2024-01-15 04:47:59 +00:00
BitStreamUtils : : WriteHeader ( bitStream , eConnectionType : : CHAT , eChatMessageType : : WORLD_ROUTE_PACKET ) ;
2024-01-06 04:42:30 +00:00
bitStream . Write ( receiver . playerID ) ;
2021-12-05 17:54:36 +00:00
2022-07-13 03:36:06 +00:00
// Portion that will get routed:
2023-09-21 01:06:28 +00:00
BitStreamUtils : : WriteHeader ( bitStream , eConnectionType : : CLIENT , eClientMessageType : : ADD_FRIEND_RESPONSE ) ;
2022-07-13 03:36:06 +00:00
bitStream . Write ( responseCode ) ;
// For all requests besides accepted, write a flag that says whether or not we are already best friends with the receiver.
2024-01-06 04:42:30 +00:00
bitStream . Write < uint8_t > ( responseCode ! = eAddFriendResponseType : : ACCEPTED ? isBestFriendsAlready : sender . sysAddr ! = UNASSIGNED_SYSTEM_ADDRESS ) ;
2022-07-13 03:36:06 +00:00
// Then write the player name
2024-01-06 04:42:30 +00:00
bitStream . Write ( LUWString ( sender . playerName ) ) ;
2022-07-13 03:36:06 +00:00
// Then if this is an acceptance code, write the following extra info.
if ( responseCode = = eAddFriendResponseType : : ACCEPTED ) {
2024-01-06 04:42:30 +00:00
bitStream . Write ( sender . playerID ) ;
bitStream . Write ( sender . zoneID ) ;
2022-07-13 03:36:06 +00:00
bitStream . Write ( isBestFriendRequest ) ; //isBFF
bitStream . Write < uint8_t > ( 0 ) ; //isFTP
}
2024-01-06 04:42:30 +00:00
SystemAddress sysAddr = receiver . sysAddr ;
2021-12-05 17:54:36 +00:00
SEND_PACKET ;
}
2024-01-06 04:42:30 +00:00
void ChatPacketHandler : : SendRemoveFriend ( const PlayerData & receiver , std : : string & personToRemove , bool isSuccessful ) {
2021-12-05 17:54:36 +00:00
CBITSTREAM ;
2024-01-15 04:47:59 +00:00
BitStreamUtils : : WriteHeader ( bitStream , eConnectionType : : CHAT , eChatMessageType : : WORLD_ROUTE_PACKET ) ;
2024-01-06 04:42:30 +00:00
bitStream . Write ( receiver . playerID ) ;
2021-12-05 17:54:36 +00:00
//portion that will get routed:
2023-09-21 01:06:28 +00:00
BitStreamUtils : : WriteHeader ( bitStream , eConnectionType : : CLIENT , eClientMessageType : : REMOVE_FRIEND_RESPONSE ) ;
2021-12-05 17:54:36 +00:00
bitStream . Write < uint8_t > ( isSuccessful ) ; //isOnline
2023-09-21 01:06:28 +00:00
bitStream . Write ( LUWString ( personToRemove ) ) ;
2021-12-05 17:54:36 +00:00
2024-01-06 04:42:30 +00:00
SystemAddress sysAddr = receiver . sysAddr ;
2021-12-05 17:54:36 +00:00
SEND_PACKET ;
}