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"
|
2022-12-20 14:14:58 +00:00
|
|
|
#include "PacketUtils.h"
|
|
|
|
#include "eGuildRank.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"
|
2023-11-21 20:16:56 +00:00
|
|
|
#include "eObjectBits.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;
|
|
|
|
|
|
|
|
{
|
2023-11-18 00:47:18 +00:00
|
|
|
auto characterIdFetch = Database::Get()->GetCharacterInfo(receiver);
|
2022-07-17 08:40:34 +00:00
|
|
|
|
2023-11-18 00:47:18 +00:00
|
|
|
if (characterIdFetch) {
|
|
|
|
idOfReceiver = characterIdFetch->id;
|
2022-07-17 08:40:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (user->GetIsBestFriendMap().find(receiver) == user->GetIsBestFriendMap().end() && idOfReceiver != LWOOBJID_EMPTY) {
|
2023-11-18 00:47:18 +00:00
|
|
|
auto bffInfo = Database::Get()->GetBestFriendStatus(entity->GetObjectID(), idOfReceiver);
|
2022-07-17 08:40:34 +00:00
|
|
|
|
2023-11-18 00:47:18 +00:00
|
|
|
if (bffInfo) {
|
|
|
|
isBestFriend = bffInfo->bestFriendStatus == 3;
|
2022-07-17 08:40:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (isBestFriend) {
|
|
|
|
auto tmpBestFriendMap = user->GetIsBestFriendMap();
|
|
|
|
tmpBestFriendMap[receiver] = true;
|
|
|
|
user->SetIsBestFriendMap(tmpBestFriendMap);
|
|
|
|
}
|
|
|
|
} 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
|
|
|
}
|
2022-12-20 14:14:58 +00:00
|
|
|
|
2023-11-21 20:16:56 +00:00
|
|
|
void ClientPackets::HandleGuildCreation(Packet* packet) {
|
|
|
|
CINSTREAM_SKIP_HEADER;
|
|
|
|
LUWString guildName(31);
|
|
|
|
inStream.Read(guildName);
|
2022-12-20 14:14:58 +00:00
|
|
|
|
2023-11-21 20:16:56 +00:00
|
|
|
auto user = UserManager::Instance()->GetUser(packet->systemAddress);
|
2022-12-20 14:14:58 +00:00
|
|
|
if (!user) return;
|
|
|
|
|
|
|
|
auto character = user->GetLastUsedChar();
|
|
|
|
if (!character) return;
|
|
|
|
|
2023-11-21 20:16:56 +00:00
|
|
|
LOG("User %s wants to create a guild with name: %s", character->GetName().c_str(), guildName.GetAsString().c_str());
|
2022-12-20 14:14:58 +00:00
|
|
|
|
|
|
|
// First, check to see if there is a guild with that name or not:
|
2023-11-21 20:16:56 +00:00
|
|
|
if (Database::Get()->CheckGuildNameExists(guildName.GetAsString().c_str())) {
|
|
|
|
LOG("But a guild already exists with that name!");
|
|
|
|
SendGuildCreateResponse(packet->systemAddress, eGuildCreationResponse::REJECTED_EXISTS, LWOOBJID_EMPTY, guildName.string);
|
2022-12-20 14:14:58 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-11-21 20:16:56 +00:00
|
|
|
if (!Game::chatFilter->IsSentenceOkay(guildName.GetAsString().c_str(), character->GetGMLevel()).empty()) {
|
|
|
|
LOG("But they used bad words!");
|
|
|
|
SendGuildCreateResponse(packet->systemAddress, eGuildCreationResponse::REJECTED_BAD_NAME, LWOOBJID_EMPTY, guildName.string);
|
2023-11-16 13:12:18 +00:00
|
|
|
return;
|
|
|
|
}
|
2022-12-20 14:14:58 +00:00
|
|
|
|
|
|
|
auto entity = character->GetEntity();
|
|
|
|
if (!entity) return;
|
|
|
|
|
|
|
|
// Check to see if the character is already in a guild or not:
|
|
|
|
auto* characterComp = entity->GetComponent<CharacterComponent>();
|
|
|
|
if (!characterComp) return;
|
|
|
|
|
|
|
|
if (characterComp->GetGuildID() != 0) {
|
2023-11-21 20:16:56 +00:00
|
|
|
ChatPackets::SendSystemMessage(packet->systemAddress, u"You are already in a guild! Leave your current guild first.");
|
2022-12-20 14:14:58 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-11-16 13:12:18 +00:00
|
|
|
LOG("Creating Guild");
|
2023-11-21 20:16:56 +00:00
|
|
|
auto newGuild = Database::Get()->CreateGuild(guildName.GetAsString(), character->GetID(), characterComp->GetUScore());
|
2022-12-20 14:14:58 +00:00
|
|
|
|
2023-11-21 20:16:56 +00:00
|
|
|
if (!newGuild){
|
|
|
|
LOG("Unknown error ocurred while creating a guild! Got %i", newGuild->id);
|
|
|
|
SendGuildCreateResponse(packet->systemAddress, eGuildCreationResponse::UNKNOWN_ERROR, LWOOBJID_EMPTY, guildName.string);
|
2022-12-20 14:14:58 +00:00
|
|
|
return;
|
|
|
|
}
|
2023-11-21 20:16:56 +00:00
|
|
|
|
2023-11-23 12:48:55 +00:00
|
|
|
Database::Get()->InsertGuildMember(newGuild->id, character->GetID(), eGuildRank::LEADER);
|
2023-11-21 20:16:56 +00:00
|
|
|
|
|
|
|
characterComp->SetGuild(newGuild->id, guildName.string);
|
|
|
|
SendGuildCreateResponse(packet->systemAddress, eGuildCreationResponse::CREATED, newGuild->id, guildName.string);
|
|
|
|
AMFArrayValue data;
|
|
|
|
data.Insert("bOn", true);
|
|
|
|
GameMessages::SendUIMessageServerToSingleClient(entity, packet->systemAddress, "ToggleGuildUI", data);
|
2022-12-20 14:14:58 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-11-21 20:16:56 +00:00
|
|
|
void ClientPackets::SendGuildCreateResponse(const SystemAddress& sysAddr, eGuildCreationResponse guildResponse, LWOOBJID guild_id, std::u16string& guildName) {
|
2022-12-21 00:19:21 +00:00
|
|
|
CBITSTREAM;
|
2023-11-21 20:16:56 +00:00
|
|
|
GeneralUtils::SetBit(guild_id, eObjectBits::CHARACTER);
|
|
|
|
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::GUILD_CREATE_RESPONSE);
|
|
|
|
bitStream.Write<uint8_t>(guildResponse);
|
|
|
|
bitStream.Write(guild_id);
|
2023-11-16 06:32:50 +00:00
|
|
|
bitStream.Write(LUWString(guildName));
|
2022-12-21 00:19:21 +00:00
|
|
|
SEND_PACKET;
|
|
|
|
}
|
2023-11-16 03:14:20 +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);
|
|
|
|
|
|
|
|
}
|