2021-12-05 17:54:36 +00:00
/*
* Darkflame Universe
* Copyright 2018
*/
# include "ClientPackets.h"
# include "UserManager.h"
# include "User.h"
# include "Character.h"
# include "EntityManager.h"
# include "Entity.h"
# include "ControllablePhysicsComponent.h"
# include "Game.h"
2023-10-21 23:31:55 +00:00
# include "Logger.h"
2021-12-05 17:54:36 +00:00
# include "WorldPackets.h"
# include "NiPoint3.h"
# include "NiQuaternion.h"
# include "dCommonVars.h"
# include "BitStream.h"
# include "dChatFilter.h"
# include "WorldPackets.h"
# include "ChatPackets.h"
# include "dServer.h"
# include "GameMessages.h"
# include "dZoneManager.h"
# include "Player.h"
# include "Zone.h"
# include "PossessorComponent.h"
# include "PossessableComponent.h"
# include "VehiclePhysicsComponent.h"
# include "dConfig.h"
# include "CharacterComponent.h"
2022-07-17 08:40:34 +00:00
# include "Database.h"
2023-03-24 23:16:45 +00:00
# include "eGameMasterLevel.h"
2023-03-04 07:16:37 +00:00
# include "eReplicaComponentType.h"
2023-09-28 17:16:11 +00:00
# include "CheatDetection.h"
2023-11-16 01:30:46 +00:00
# include "Amf3.h"
2021-12-05 17:54:36 +00:00
void ClientPackets : : HandleChatMessage ( const SystemAddress & sysAddr , Packet * packet ) {
User * user = UserManager : : Instance ( ) - > GetUser ( sysAddr ) ;
if ( ! user ) {
2023-10-21 23:31:55 +00:00
LOG ( " Unable to get user to parse chat message " ) ;
2021-12-05 17:54:36 +00:00
return ;
}
if ( user - > GetIsMuted ( ) ) {
user - > GetLastUsedChar ( ) - > SendMuteNotice ( ) ;
return ;
}
2023-05-08 11:31:10 +00:00
CINSTREAM_SKIP_HEADER ;
2021-12-05 17:54:36 +00:00
char chatChannel ;
uint16_t unknown ;
uint32_t messageLength ;
std : : u16string message ;
inStream . Read ( chatChannel ) ;
inStream . Read ( unknown ) ;
inStream . Read ( messageLength ) ;
for ( uint32_t i = 0 ; i < ( messageLength - 1 ) ; + + i ) {
uint16_t character ;
inStream . Read ( character ) ;
message . push_back ( character ) ;
}
std : : string playerName = user - > GetLastUsedChar ( ) - > GetName ( ) ;
2023-03-24 23:16:45 +00:00
bool isMythran = user - > GetLastUsedChar ( ) - > GetGMLevel ( ) > eGameMasterLevel : : CIVILIAN ;
2023-09-28 17:16:11 +00:00
bool isOk = Game : : chatFilter - > IsSentenceOkay ( GeneralUtils : : UTF16ToWTF8 ( message ) , user - > GetLastUsedChar ( ) - > GetGMLevel ( ) ) . empty ( ) ;
2023-10-21 23:31:55 +00:00
LOG_DEBUG ( " Msg: %s was approved previously? %i " , GeneralUtils : : UTF16ToWTF8 ( message ) . c_str ( ) , user - > GetLastChatMessageApproved ( ) ) ;
2023-09-28 17:16:11 +00:00
if ( ! isOk ) {
// Add a limit to the string converted by general utils because it is a user received string and may be a bad actor.
CheatDetection : : ReportCheat (
user ,
sysAddr ,
" Player %s attempted to bypass chat filter with message: %s " ,
playerName . c_str ( ) ,
GeneralUtils : : UTF16ToWTF8 ( message , 512 ) . c_str ( ) ) ;
}
if ( ! isOk & & ! isMythran ) return ;
2021-12-05 17:54:36 +00:00
std : : string sMessage = GeneralUtils : : UTF16ToWTF8 ( message ) ;
2023-10-21 23:31:55 +00:00
LOG ( " %s: %s " , playerName . c_str ( ) , sMessage . c_str ( ) ) ;
2021-12-05 17:54:36 +00:00
ChatPackets : : SendChatMessage ( sysAddr , chatChannel , playerName , user - > GetLoggedInChar ( ) , isMythran , message ) ;
}
void ClientPackets : : HandleClientPositionUpdate ( const SystemAddress & sysAddr , Packet * packet ) {
User * user = UserManager : : Instance ( ) - > GetUser ( sysAddr ) ;
if ( ! user ) {
2023-10-21 23:31:55 +00:00
LOG ( " Unable to get user to parse position update " ) ;
2021-12-05 17:54:36 +00:00
return ;
}
2023-05-08 11:31:10 +00:00
CINSTREAM_SKIP_HEADER ;
2021-12-05 17:54:36 +00:00
2023-07-15 20:56:33 +00:00
Entity * entity = Game : : entityManager - > GetEntity ( user - > GetLastUsedChar ( ) - > GetObjectID ( ) ) ;
2021-12-05 17:54:36 +00:00
if ( ! entity ) return ;
2023-03-04 07:16:37 +00:00
ControllablePhysicsComponent * comp = static_cast < ControllablePhysicsComponent * > ( entity - > GetComponent ( eReplicaComponentType : : CONTROLLABLE_PHYSICS ) ) ;
2021-12-05 17:54:36 +00:00
if ( ! comp ) return ;
/*
//If we didn't move, this will match and stop our velocity
if ( packet - > length = = 37 ) {
NiPoint3 zeroVel ( 0.0f , 0.0f , 0.0f ) ;
comp - > SetVelocity ( zeroVel ) ;
comp - > SetAngularVelocity ( zeroVel ) ;
comp - > SetIsOnGround ( true ) ; //probably8
2023-07-15 20:56:33 +00:00
Game : : entityManager - > SerializeEntity ( entity ) ;
2021-12-05 17:54:36 +00:00
return ;
}
*/
auto * possessorComponent = entity - > GetComponent < PossessorComponent > ( ) ;
NiPoint3 position ;
inStream . Read ( position . x ) ;
inStream . Read ( position . y ) ;
inStream . Read ( position . z ) ;
NiQuaternion rotation ;
inStream . Read ( rotation . x ) ;
inStream . Read ( rotation . y ) ;
inStream . Read ( rotation . z ) ;
inStream . Read ( rotation . w ) ;
bool onGround = false ;
bool onRail = false ;
inStream . Read ( onGround ) ;
inStream . Read ( onRail ) ;
bool velocityFlag = false ;
inStream . Read ( velocityFlag ) ;
NiPoint3 velocity { } ;
if ( velocityFlag ) {
inStream . Read ( velocity . x ) ;
inStream . Read ( velocity . y ) ;
inStream . Read ( velocity . z ) ;
}
bool angVelocityFlag = false ;
inStream . Read ( angVelocityFlag ) ;
NiPoint3 angVelocity { } ;
if ( angVelocityFlag ) {
inStream . Read ( angVelocity . x ) ;
inStream . Read ( angVelocity . y ) ;
inStream . Read ( angVelocity . z ) ;
}
2023-06-20 14:19:21 +00:00
// TODO figure out how to use these. Ignoring for now, but reading in if they exist.
bool hasLocalSpaceInfo { } ;
LWOOBJID objectId { } ;
NiPoint3 localSpacePosition { } ;
bool hasLinearVelocity { } ;
NiPoint3 linearVelocity { } ;
if ( inStream . Read ( hasLocalSpaceInfo ) & & hasLocalSpaceInfo ) {
inStream . Read ( objectId ) ;
inStream . Read ( localSpacePosition . x ) ;
inStream . Read ( localSpacePosition . y ) ;
inStream . Read ( localSpacePosition . z ) ;
if ( inStream . Read ( hasLinearVelocity ) & & hasLinearVelocity ) {
inStream . Read ( linearVelocity . x ) ;
inStream . Read ( linearVelocity . y ) ;
inStream . Read ( linearVelocity . z ) ;
}
}
bool hasRemoteInputInfo { } ;
RemoteInputInfo remoteInput { } ;
if ( inStream . Read ( hasRemoteInputInfo ) & & hasRemoteInputInfo ) {
inStream . Read ( remoteInput . m_RemoteInputX ) ;
inStream . Read ( remoteInput . m_RemoteInputY ) ;
inStream . Read ( remoteInput . m_IsPowersliding ) ;
inStream . Read ( remoteInput . m_IsModified ) ;
}
2022-09-02 18:49:19 +00:00
bool updateChar = true ;
2021-12-05 17:54:36 +00:00
if ( possessorComponent ! = nullptr ) {
2023-07-15 20:56:33 +00:00
auto * possassableEntity = Game : : entityManager - > GetEntity ( possessorComponent - > GetPossessable ( ) ) ;
2021-12-05 17:54:36 +00:00
if ( possassableEntity ! = nullptr ) {
2022-09-02 18:49:19 +00:00
auto * possessableComponent = possassableEntity - > GetComponent < PossessableComponent > ( ) ;
if ( possessableComponent ) {
// While possessing something, only update char if we are attached to the thing we are possessing
if ( possessableComponent - > GetPossessionType ( ) ! = ePossessionType : : ATTACHED_VISIBLE ) updateChar = false ;
}
2021-12-05 17:54:36 +00:00
2022-09-02 18:49:19 +00:00
auto * vehiclePhysicsComponent = possassableEntity - > GetComponent < VehiclePhysicsComponent > ( ) ;
2021-12-05 17:54:36 +00:00
if ( vehiclePhysicsComponent ! = nullptr ) {
vehiclePhysicsComponent - > SetPosition ( position ) ;
vehiclePhysicsComponent - > SetRotation ( rotation ) ;
vehiclePhysicsComponent - > SetIsOnGround ( onGround ) ;
vehiclePhysicsComponent - > SetIsOnRail ( onRail ) ;
vehiclePhysicsComponent - > SetVelocity ( velocity ) ;
vehiclePhysicsComponent - > SetDirtyVelocity ( velocityFlag ) ;
vehiclePhysicsComponent - > SetAngularVelocity ( angVelocity ) ;
vehiclePhysicsComponent - > SetDirtyAngularVelocity ( angVelocityFlag ) ;
2023-06-20 14:19:21 +00:00
vehiclePhysicsComponent - > SetRemoteInputInfo ( remoteInput ) ;
2022-09-02 18:49:19 +00:00
} else {
// Need to get the mount's controllable physics
auto * controllablePhysicsComponent = possassableEntity - > GetComponent < ControllablePhysicsComponent > ( ) ;
if ( ! controllablePhysicsComponent ) return ;
controllablePhysicsComponent - > SetPosition ( position ) ;
controllablePhysicsComponent - > SetRotation ( rotation ) ;
controllablePhysicsComponent - > SetIsOnGround ( onGround ) ;
controllablePhysicsComponent - > SetIsOnRail ( onRail ) ;
controllablePhysicsComponent - > SetVelocity ( velocity ) ;
controllablePhysicsComponent - > SetDirtyVelocity ( velocityFlag ) ;
controllablePhysicsComponent - > SetAngularVelocity ( angVelocity ) ;
controllablePhysicsComponent - > SetDirtyAngularVelocity ( angVelocityFlag ) ;
2021-12-05 17:54:36 +00:00
}
2023-07-15 20:56:33 +00:00
Game : : entityManager - > SerializeEntity ( possassableEntity ) ;
2021-12-05 17:54:36 +00:00
}
}
2022-09-02 18:49:19 +00:00
if ( ! updateChar ) {
2021-12-05 17:54:36 +00:00
velocity = NiPoint3 : : ZERO ;
angVelocity = NiPoint3 : : ZERO ;
}
2022-09-02 18:49:19 +00:00
2021-12-05 17:54:36 +00:00
// Handle statistics
auto * characterComponent = entity - > GetComponent < CharacterComponent > ( ) ;
if ( characterComponent ! = nullptr ) {
characterComponent - > TrackPositionUpdate ( position ) ;
}
comp - > SetPosition ( position ) ;
comp - > SetRotation ( rotation ) ;
comp - > SetIsOnGround ( onGround ) ;
comp - > SetIsOnRail ( onRail ) ;
comp - > SetVelocity ( velocity ) ;
comp - > SetDirtyVelocity ( velocityFlag ) ;
comp - > SetAngularVelocity ( angVelocity ) ;
comp - > SetDirtyAngularVelocity ( angVelocityFlag ) ;
auto * player = static_cast < Player * > ( entity ) ;
player - > SetGhostReferencePoint ( position ) ;
2023-07-15 20:56:33 +00:00
Game : : entityManager - > QueueGhostUpdate ( player - > GetObjectID ( ) ) ;
2021-12-05 17:54:36 +00:00
2023-07-15 20:56:33 +00:00
if ( updateChar ) Game : : entityManager - > SerializeEntity ( entity ) ;
2021-12-05 17:54:36 +00:00
//TODO: add moving platform stuffs
/*bool movingPlatformFlag;
inStream . Read ( movingPlatformFlag ) ;
if ( movingPlatformFlag ) {
LWOOBJID objectID ;
NiPoint3 niData2 ;
inStream . Read ( objectID ) ;
inStream . Read ( niData2 . x ) ;
inStream . Read ( niData2 . y ) ;
inStream . Read ( niData2 . z ) ;
bool niData3Flag ;
inStream . Read ( niData3Flag ) ;
if ( niData3Flag ) {
NiPoint3 niData3 ;
inStream . Read ( niData3 . x ) ;
inStream . Read ( niData3 . y ) ;
inStream . Read ( niData3 . z ) ;
controllablePhysics - > GetLocationData ( ) - > GetMovingPlatformData ( ) - > SetData3 ( niData3 ) ;
}
} */
/*
for ( int i = 0 ; i < Game : : server - > GetReplicaManager ( ) - > GetParticipantCount ( ) ; + + i )
{
const auto & player = Game : : server - > GetReplicaManager ( ) - > GetParticipantAtIndex ( i ) ;
if ( entity - > GetSystemAddress ( ) = = player )
{
continue ;
}
2023-07-15 20:56:33 +00:00
Game : : entityManager - > SerializeEntity ( entity , player ) ;
2021-12-05 17:54:36 +00:00
}
*/
}
void ClientPackets : : HandleChatModerationRequest ( const SystemAddress & sysAddr , Packet * packet ) {
User * user = UserManager : : Instance ( ) - > GetUser ( sysAddr ) ;
if ( ! user ) {
2023-10-21 23:31:55 +00:00
LOG ( " Unable to get user to parse chat moderation request " ) ;
2021-12-05 17:54:36 +00:00
return ;
}
auto * entity = Player : : GetPlayer ( sysAddr ) ;
if ( entity = = nullptr ) {
2023-10-21 23:31:55 +00:00
LOG ( " Unable to get player to parse chat moderation request " ) ;
2021-12-05 17:54:36 +00:00
return ;
}
// Check if the player has restricted chat access
auto * character = entity - > GetCharacter ( ) ;
if ( character - > HasPermission ( ePermissionMap : : RestrictedChatAccess ) ) {
// Send a message to the player
ChatPackets : : SendSystemMessage (
sysAddr ,
u " This character has restricted chat access. "
) ;
return ;
}
RakNet : : BitStream stream ( packet - > data , packet - > length , false ) ;
uint64_t header ;
stream . Read ( header ) ;
// Data
uint8_t chatLevel ;
uint8_t requestID ;
uint16_t messageLength ;
std : : string receiver = " " ;
std : : string message = " " ;
stream . Read ( chatLevel ) ;
stream . Read ( requestID ) ;
for ( uint32_t i = 0 ; i < 42 ; + + i ) {
uint16_t character ;
stream . Read ( character ) ;
receiver . push_back ( static_cast < uint8_t > ( character ) ) ;
}
2022-07-17 08:40:34 +00:00
if ( ! receiver . empty ( ) ) {
2022-07-18 09:01:43 +00:00
if ( std : : string ( receiver . c_str ( ) , 4 ) = = " [GM] " ) { // Shift the string forward if we are speaking to a GM as the client appends "[GM]" if they are
2022-07-17 08:40:34 +00:00
receiver = std : : string ( receiver . c_str ( ) + 4 , receiver . size ( ) - 4 ) ;
}
}
2021-12-05 17:54:36 +00:00
stream . Read ( messageLength ) ;
for ( uint32_t i = 0 ; i < messageLength ; + + i ) {
uint16_t character ;
stream . Read ( character ) ;
message . push_back ( static_cast < uint8_t > ( character ) ) ;
}
2022-07-17 08:40:34 +00:00
bool isBestFriend = false ;
if ( chatLevel = = 1 ) {
// Private chat
LWOOBJID idOfReceiver = LWOOBJID_EMPTY ;
{
sql : : PreparedStatement * stmt = Database : : CreatePreppedStmt ( " SELECT name FROM charinfo WHERE name = ? " ) ;
stmt - > setString ( 1 , receiver ) ;
sql : : ResultSet * res = stmt - > executeQuery ( ) ;
if ( res - > next ( ) ) {
idOfReceiver = res - > getInt ( " id " ) ;
}
2022-07-18 09:01:43 +00:00
delete stmt ;
delete res ;
2022-07-17 08:40:34 +00:00
}
if ( user - > GetIsBestFriendMap ( ) . find ( receiver ) = = user - > GetIsBestFriendMap ( ) . end ( ) & & idOfReceiver ! = LWOOBJID_EMPTY ) {
sql : : PreparedStatement * stmt = Database : : CreatePreppedStmt ( " SELECT * FROM friends WHERE (player_id = ? AND friend_id = ?) OR (player_id = ? AND friend_id = ?) LIMIT 1; " ) ;
stmt - > setInt ( 1 , entity - > GetObjectID ( ) ) ;
stmt - > setInt ( 2 , idOfReceiver ) ;
stmt - > setInt ( 3 , idOfReceiver ) ;
stmt - > setInt ( 4 , entity - > GetObjectID ( ) ) ;
sql : : ResultSet * res = stmt - > executeQuery ( ) ;
if ( res - > next ( ) ) {
isBestFriend = res - > getInt ( " best_friend " ) = = 3 ;
}
if ( isBestFriend ) {
auto tmpBestFriendMap = user - > GetIsBestFriendMap ( ) ;
tmpBestFriendMap [ receiver ] = true ;
user - > SetIsBestFriendMap ( tmpBestFriendMap ) ;
}
delete res ;
delete stmt ;
} else if ( user - > GetIsBestFriendMap ( ) . find ( receiver ) ! = user - > GetIsBestFriendMap ( ) . end ( ) ) {
isBestFriend = true ;
}
}
2022-07-18 09:01:43 +00:00
std : : vector < std : : pair < uint8_t , uint8_t > > segments = Game : : chatFilter - > IsSentenceOkay ( message , entity - > GetGMLevel ( ) , ! ( isBestFriend & & chatLevel = = 1 ) ) ;
2022-07-17 06:54:36 +00:00
bool bAllClean = segments . empty ( ) ;
2021-12-05 17:54:36 +00:00
if ( user - > GetIsMuted ( ) ) {
bAllClean = false ;
}
user - > SetLastChatMessageApproved ( bAllClean ) ;
2022-07-18 09:01:43 +00:00
WorldPackets : : SendChatModerationResponse ( sysAddr , bAllClean , requestID , receiver , segments ) ;
2021-12-05 17:54:36 +00:00
}
2023-11-16 01:30:46 +00:00
void ClientPackets : : SendTop5HelpIssues ( Packet * packet ) {
auto * user = UserManager : : Instance ( ) - > GetUser ( packet - > systemAddress ) ;
if ( ! user ) return ;
auto * character = user - > GetLastUsedChar ( ) ;
if ( ! character ) return ;
auto * entity = character - > GetEntity ( ) ;
if ( ! entity ) return ;
CINSTREAM_SKIP_HEADER ;
int32_t language = 0 ;
inStream . Read ( language ) ;
// TODO: Handle different languages in a nice way
// 0: en_US
// 1: pl_US
// 2: de_DE
// 3: en_GB
AMFArrayValue data ;
// Summaries
data . Insert ( " Summary0 " , Game : : config - > GetValue ( " help_0_summary " ) ) ;
data . Insert ( " Summary1 " , Game : : config - > GetValue ( " help_1_summary " ) ) ;
data . Insert ( " Summary2 " , Game : : config - > GetValue ( " help_2_summary " ) ) ;
data . Insert ( " Summary3 " , Game : : config - > GetValue ( " help_3_summary " ) ) ;
data . Insert ( " Summary4 " , Game : : config - > GetValue ( " help_4_summary " ) ) ;
// Descriptions
data . Insert ( " Description0 " , Game : : config - > GetValue ( " help_0_description " ) ) ;
data . Insert ( " Description1 " , Game : : config - > GetValue ( " help_1_description " ) ) ;
data . Insert ( " Description2 " , Game : : config - > GetValue ( " help_2_description " ) ) ;
data . Insert ( " Description3 " , Game : : config - > GetValue ( " help_3_description " ) ) ;
data . Insert ( " Description4 " , Game : : config - > GetValue ( " help_4_description " ) ) ;
GameMessages : : SendUIMessageServerToSingleClient ( entity , packet - > systemAddress , " UIHelpTop5 " , data ) ;
}