no crashes
This commit is contained in:
Aaron Kimbre 2023-11-21 14:16:56 -06:00
parent e5f62e870b
commit a4bf11502f
17 changed files with 286 additions and 94 deletions

View File

@ -18,6 +18,7 @@
#include "eChatInternalMessageType.h" #include "eChatInternalMessageType.h"
#include "eClientMessageType.h" #include "eClientMessageType.h"
#include "eGameMessageType.h" #include "eGameMessageType.h"
#include "eGuildLeaveReason.h"
extern PlayerContainer playerContainer; extern PlayerContainer playerContainer;
@ -676,8 +677,25 @@ void ChatPacketHandler::HandleGuildLeave(Packet* packet){
CINSTREAM_SKIP_HEADER; CINSTREAM_SKIP_HEADER;
LWOOBJID playerID = LWOOBJID_EMPTY; LWOOBJID playerID = LWOOBJID_EMPTY;
inStream.Read(playerID); inStream.Read(playerID);
LOG("HandleGuildLeave %llu", playerID); auto* player = playerContainer.GetPlayerData(playerID);
if (!player) return;
auto guild_id = Database::Get()->GetMembersGuild(playerID);
Database::Get()->DeleteGuildMember(player->playerID);
auto members = Database::Get()->GetGuildMembers(guild_id);
if (members.empty()) Database::Get()->DeleteGuild(guild_id);
// Send the removal, need to send this to all players in guild TODO
CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
bitStream.Write(player->playerID);
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::GUILD_REMOVE_PLAYER);
bitStream.Write(eGuildLeaveReason::LEFT);
bitStream.Write(LUWString(player->playerName));
bitStream.Write(player->playerID);
SystemAddress sysAddr = player->sysAddr;
SEND_PACKET;
} }
void ChatPacketHandler::HandleGuildGetAll(Packet* packet){ void ChatPacketHandler::HandleGuildGetAll(Packet* packet){
@ -685,7 +703,42 @@ void ChatPacketHandler::HandleGuildGetAll(Packet* packet){
LWOOBJID playerID = LWOOBJID_EMPTY; LWOOBJID playerID = LWOOBJID_EMPTY;
inStream.Read(playerID); inStream.Read(playerID);
LOG("HandleGuildGetAll %llu", playerID); LOG("HandleGuildGetAll %llu", playerID);
auto player = playerContainer.GetPlayerData(playerID);
if (!player) return;
auto guild_id = Database::Get()->GetMembersGuild(player->playerID);
if (!guild_id) return;
auto guild = Database::Get()->GetGuild(guild_id);
if (!guild) return;
auto members = Database::Get()->GetGuildMembers(guild_id);
CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
bitStream.Write(playerID);
//portion that will get routed:
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::GUILD_DATA);
bitStream.Write0();
bitStream.Write(LUWString(guild->name, 31));
bitStream.Write(LUWString("test1", 11));
bitStream.Write(LUWString("test2", 11));
bitStream.Write<uint32_t>(69);
bitStream.Write<uint32_t>(0);
bitStream.Write<uint32_t>(1);
bitStream.Write<uint8_t>(0);
bitStream.Write<uint8_t>(members.size());
//Member data
bitStream.Write1();
bitStream.Write1();
bitStream.Write<uint16_t>(1200);
bitStream.Write<uint16_t>(1);
bitStream.Write<uint16_t>(1);
bitStream.Write<uint16_t>(1);
bitStream.Write<uint32_t>(1);
bitStream.Write(LUWString(player->playerName, 25));
bitStream.Write<uint8_t>(0); //???
SystemAddress sysAddr = packet->systemAddress;
SEND_PACKET;
} }
void ChatPacketHandler::SendTeamInvite(PlayerData* receiver, PlayerData* sender) { void ChatPacketHandler::SendTeamInvite(PlayerData* receiver, PlayerData* sender) {

View File

@ -19,6 +19,7 @@
#include "eChatMessageType.h" #include "eChatMessageType.h"
#include "eChatInternalMessageType.h" #include "eChatInternalMessageType.h"
#include "eWorldMessageType.h" #include "eWorldMessageType.h"
#include "PacketUtils.h"
#include "Game.h" #include "Game.h"
@ -293,10 +294,16 @@ void HandlePacket(Packet* packet) {
// Guild messages // Guild messages
case eChatMessageType::GUILD_CREATE: case eChatMessageType::GUILD_CREATE:
PacketUtils::SavePacket("GUILD_CREATE", (const char*) packet->data, packet->length);
LOG("GUILD_CREATE"); LOG("GUILD_CREATE");
break; break;
case eChatMessageType::GUILD_INVITE:
PacketUtils::SavePacket("GUILD_INVITE", (const char*) packet->data, packet->length);
break;
case eChatMessageType::GUILD_INVITE_RESPONSE: case eChatMessageType::GUILD_INVITE_RESPONSE:
PacketUtils::SavePacket("GUILD_INVITE_RESPONSE", (const char*) packet->data, packet->length);
LOG("GUILD_INVITE_RESPONSE"); LOG("GUILD_INVITE_RESPONSE");
break; break;
@ -305,14 +312,17 @@ void HandlePacket(Packet* packet) {
break; break;
case eChatMessageType::GUILD_KICK: case eChatMessageType::GUILD_KICK:
PacketUtils::SavePacket("GUILD_KICK", (const char*) packet->data, packet->length);
LOG("GUILD_KICK"); LOG("GUILD_KICK");
break; break;
case eChatMessageType::GUILD_GET_STATUS: case eChatMessageType::GUILD_GET_STATUS:
PacketUtils::SavePacket("GUILD_GET_STATUS", (const char*) packet->data, packet->length);
LOG("GUILD_GET_STATUS"); LOG("GUILD_GET_STATUS");
break; break;
case eChatMessageType::GUILD_GET_ALL: case eChatMessageType::GUILD_GET_ALL:
PacketUtils::SavePacket("GUILD_GET_ALL", (const char*) packet->data, packet->length);
LOG("GUILD_GET_ALL"); LOG("GUILD_GET_ALL");
ChatPacketHandler::HandleGuildGetAll(packet); ChatPacketHandler::HandleGuildGetAll(packet);
break; break;

View File

@ -0,0 +1,12 @@
#pragma once
#include <cstdint>
#ifndef __EGUILDLEAVEREASON__H__
#define __EGUILDLEAVEREASON__H__
enum class eGuildLeaveReason : uint8_t {
LEFT = 0,
KICKED
};
#endif //!__EGUILDLEAVEREASON__H__

View File

@ -8,6 +8,7 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include <map> #include <map>
#include <cstdint>
// CPPLinq // CPPLinq
#ifdef _WIN32 #ifdef _WIN32

View File

@ -21,12 +21,13 @@
#include "ICharInfo.h" #include "ICharInfo.h"
#include "IAccounts.h" #include "IAccounts.h"
#include "IActivityLog.h" #include "IActivityLog.h"
#include "IGuilds.h"
#include "IGuildMembers.h"
namespace sql { namespace sql {
class Statement; class Statement;
class PreparedStatement; class PreparedStatement;
}; };
#define _DEBUG
#ifdef _DEBUG #ifdef _DEBUG
# define DLU_SQL_TRY_CATCH_RETHROW(x) do { try { x; } catch (sql::SQLException& ex) { LOG("SQL Error: %s", ex.what()); throw; } } while(0) # define DLU_SQL_TRY_CATCH_RETHROW(x) do { try { x; } catch (sql::SQLException& ex) { LOG("SQL Error: %s", ex.what()); throw; } } while(0)
#else #else
@ -38,7 +39,7 @@ class GameDatabase :
public IMail, public ICommandLog, public IPlayerCheatDetections, public IBugReports, public IMail, public ICommandLog, public IPlayerCheatDetections, public IBugReports,
public IPropertyContents, public IProperty, public IPetNames, public ICharXml, public IPropertyContents, public IProperty, public IPetNames, public ICharXml,
public IMigrationHistory, public IUgc, public IFriends, public ICharInfo, public IMigrationHistory, public IUgc, public IFriends, public ICharInfo,
public IAccounts, public IActivityLog { public IAccounts, public IActivityLog, public IGuilds, public IGuildMembers {
public: public:
virtual ~GameDatabase() = default; virtual ~GameDatabase() = default;
// TODO: These should be made private. // TODO: These should be made private.

View File

@ -0,0 +1,20 @@
#ifndef __IGUILDMEMBERS__H__
#define __IGUILDMEMBERS__H__
#include <cstdint>
#include <optional>
class IGuildMembers {
public:
struct GuildMember {
uint32_t id;
uint16_t rank;
};
virtual void InsertGuildMember(const uint32_t guild_id, const uint32_t member_id, const uint16_t rank = 4) = 0;
virtual void DeleteGuildMember(const uint32_t member_id) = 0;
virtual uint32_t GetMembersGuild(const uint32_t member_id) = 0;
virtual std::vector<GuildMember> GetGuildMembers(const uint32_t guild_id) = 0;
virtual bool CheckIsInGuild(const uint32_t guild_id, const uint32_t character_id) = 0;
};
#endif //!__IGUILDMEMBERS__H__

View File

@ -0,0 +1,25 @@
#ifndef __IGUILDS__H__
#define __IGUILDS__H__
#include <cstdint>
#include <optional>
#include <string>
class IGuilds {
public:
struct Guild {
uint32_t id;
uint32_t owner_id;
std::string name;
std::string motd;
int64_t reputation;
};
virtual std::optional<Guild> CreateGuild(const std::string_view name, const int32_t owner_id, const uint64_t reputation) = 0;
virtual std::optional<Guild> GetGuild(const uint32_t guild_id) = 0;
virtual std::optional<Guild> GetGuildByName(const std::string_view name) = 0;
virtual bool CheckGuildNameExists(const std::string_view name) = 0;
virtual void SetMOTD(const uint32_t guild_id, const std::string_view motd) = 0;
virtual void DeleteGuild(const uint32_t guild_id) = 0;
};
#endif //!__IGUILDS__H__

View File

@ -103,6 +103,17 @@ public:
std::optional<uint32_t> GetDonationTotal(const uint32_t activityId) override; std::optional<uint32_t> GetDonationTotal(const uint32_t activityId) override;
std::optional<bool> IsPlaykeyActive(const int32_t playkeyId) override; std::optional<bool> IsPlaykeyActive(const int32_t playkeyId) override;
std::vector<IUgc::Model> GetUgcModels(const LWOOBJID& propertyId) override; std::vector<IUgc::Model> GetUgcModels(const LWOOBJID& propertyId) override;
std::optional<IGuilds::Guild> CreateGuild(const std::string_view name, const int32_t owner_id, const uint64_t reputation) override;
std::optional<IGuilds::Guild> GetGuild(const uint32_t guild_id) override;
std::optional<IGuilds::Guild> GetGuildByName(const std::string_view name) override;
bool CheckGuildNameExists(const std::string_view name) override;
void SetMOTD(const uint32_t guild_id, const std::string_view motd) override;
void DeleteGuild(const uint32_t guild_id) override;
void InsertGuildMember(const uint32_t guild_id, const uint32_t member_id, const uint16_t rank) override;
void DeleteGuildMember(const uint32_t member_id) override;
uint32_t GetMembersGuild(const uint32_t member_id) override;
std::vector<GuildMember> GetGuildMembers(const uint32_t guild_id) override;
bool CheckIsInGuild(const uint32_t guild_id, const uint32_t character_id) override;
private: private:
// Generic query functions that can be used for any query. // Generic query functions that can be used for any query.

View File

@ -6,6 +6,8 @@ set(DDATABASES_DATABASES_MYSQL_TABLES_SOURCES
"CharXml.cpp" "CharXml.cpp"
"CommandLog.cpp" "CommandLog.cpp"
"Friends.cpp" "Friends.cpp"
"Guilds.cpp"
"GuildMembers.cpp"
"Leaderboard.cpp" "Leaderboard.cpp"
"Mail.cpp" "Mail.cpp"
"MigrationHistory.cpp" "MigrationHistory.cpp"

View File

@ -0,0 +1,35 @@
#include "MySQLDatabase.h"
void MySQLDatabase::InsertGuildMember(const uint32_t guild_id, const uint32_t member_id, const uint16_t rank){
ExecuteInsert("INSERT INTO guild_members (guild_id, character_id, rank) VALUES (?, ?, ?);", guild_id, member_id, rank);
}
void MySQLDatabase::DeleteGuildMember(const uint32_t member_id){
ExecuteDelete("DELETE FROM guild_members WHERE character_id = ?;", member_id);
}
uint32_t MySQLDatabase::GetMembersGuild(const uint32_t member_id){
auto res = ExecuteSelect("SELECT * FROM guild_members WHERE character_id = ?;", member_id);
if (!res->next()) return 0;
return res->getUInt("guild_id");
}
std::vector<IGuildMembers::GuildMember> MySQLDatabase::GetGuildMembers(const uint32_t guild_id){
auto res = ExecuteSelect("SELECT * FROM guild_members WHERE guild_id = ?;", guild_id);
std::vector<GuildMember> toReturn;
toReturn.reserve(res->rowsCount());
while (res->next()) {
GuildMember member;
member.id = res->getUInt("character_id");
member.rank = res->getUInt("rank");
toReturn.push_back(member);
}
return toReturn;
}
bool MySQLDatabase::CheckIsInGuild(const uint32_t guild_id, const uint32_t character_id) {
auto res = ExecuteSelect("SELECT * FROM guild_members WHERE guild_id = ? AND character_id = ?;", guild_id, character_id);
if (res->next()) return true;
return false;
}

View File

@ -0,0 +1,46 @@
#include "MySQLDatabase.h"
std::optional<IGuilds::Guild> MySQLDatabase::CreateGuild(const std::string_view name, const int32_t owner_id, const uint64_t reputation) {
ExecuteInsert("INSERT INTO guilds (name, owner_id, reputation) VALUES (?, ?, ?);", name, owner_id, reputation);
return GetGuildByName(name);
}
std::optional<IGuilds::Guild> MySQLDatabase::GetGuild(const uint32_t guild_id) {
auto return_res = ExecuteSelect("SELECT * from guilds where id = ?", guild_id);
if (!return_res->next()) return std::nullopt;
IGuilds::Guild toReturn;
toReturn.id = return_res->getInt64("id");
toReturn.owner_id = return_res->getUInt("owner_id");
toReturn.name = return_res->getString("name").c_str();
toReturn.motd = return_res->getString("motd").c_str();
toReturn.reputation = return_res->getUInt64("reputation");
return toReturn;
}
std::optional<IGuilds::Guild> MySQLDatabase::GetGuildByName(const std::string_view name) {
auto return_res = ExecuteSelect("SELECT * from guilds where name = ?", name);
if (!return_res->next()) return std::nullopt;
IGuilds::Guild toReturn;
toReturn.id = return_res->getUInt("id");
toReturn.owner_id = return_res->getUInt("owner_id");
toReturn.name = return_res->getString("name").c_str();
toReturn.motd = return_res->getString("motd").c_str();
toReturn.reputation = return_res->getUInt64("reputation");
return toReturn;
}
bool MySQLDatabase::CheckGuildNameExists(const std::string_view name) {
auto res = ExecuteSelect("SELECT * FROM guilds WHERE name = ?;", name);
return res->next();
}
void MySQLDatabase::SetMOTD(const uint32_t guild_id, const std::string_view motd) {
auto res = ExecuteUpdate("Update guilds SET motd = ? WHERE id = ?;", motd, guild_id);
if (res != 1) throw res;
}
void MySQLDatabase::DeleteGuild(const uint32_t guild_id) {
ExecuteDelete("DELETE FROM guilds where id = ?;", guild_id);
}

View File

@ -17,6 +17,8 @@
#include "eGameMasterLevel.h" #include "eGameMasterLevel.h"
#include "eGameActivity.h" #include "eGameActivity.h"
#include <ctime> #include <ctime>
#include "Database.h"
#include "eObjectBits.h"
CharacterComponent::CharacterComponent(Entity* parent, Character* character) : Component(parent) { CharacterComponent::CharacterComponent(Entity* parent, Character* character) : Component(parent) {
m_Character = character; m_Character = character;
@ -40,10 +42,7 @@ CharacterComponent::CharacterComponent(Entity* parent, Character* character) : C
m_CurrentActivity = eGameActivity::NONE; m_CurrentActivity = eGameActivity::NONE;
m_CountryCode = 0; m_CountryCode = 0;
m_LastUpdateTimestamp = std::time(nullptr); m_LastUpdateTimestamp = std::time(nullptr);
m_GuildID = LWOOBJID_EMPTY;
m_GuildID = 0;
m_GuildName = u"";
} }
bool CharacterComponent::LandingAnimDisabled(int zoneID) { bool CharacterComponent::LandingAnimDisabled(int zoneID) {
@ -153,11 +152,9 @@ void CharacterComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInit
outBitStream->Write(m_DirtySocialInfo); outBitStream->Write(m_DirtySocialInfo);
if (m_DirtySocialInfo) { if (m_DirtySocialInfo) {
outBitStream->Write(m_GuildID); outBitStream->Write<uint64_t>(m_GuildID);
outBitStream->Write<unsigned char>(static_cast<unsigned char>(m_GuildName.size())); outBitStream->Write<uint16_t>(m_GuildName.size());
if (!m_GuildName.empty()) if (!m_GuildName.empty()) outBitStream->Write(m_GuildName);
outBitStream->WriteBits(reinterpret_cast<const unsigned char*>(m_GuildName.c_str()), static_cast<unsigned char>(m_GuildName.size()) * sizeof(wchar_t) * 8);
outBitStream->Write(m_IsLEGOClubMember); outBitStream->Write(m_IsLEGOClubMember);
outBitStream->Write(m_CountryCode); outBitStream->Write(m_CountryCode);
m_DirtySocialInfo = false; m_DirtySocialInfo = false;
@ -180,9 +177,15 @@ void CharacterComponent::SetGMLevel(eGameMasterLevel gmlevel) {
m_GMLevel = gmlevel; m_GMLevel = gmlevel;
} }
void CharacterComponent::SetGuild(LWOOBJID& guildID, std::u16string guildName) { void CharacterComponent::SetGuild(uint32_t guild_id, std::u16string guildName) {
m_GuildID = guildID; if (guild_id == 0 || guildName.empty()){
m_GuildID = LWOOBJID_EMPTY;
m_GuildName.clear();
} else {
m_GuildID = guild_id;
GeneralUtils::SetBit(m_GuildID, eObjectBits::CHARACTER);
m_GuildName = guildName; m_GuildName = guildName;
}
m_DirtySocialInfo = true; m_DirtySocialInfo = true;
} }
@ -261,16 +264,20 @@ void CharacterComponent::LoadFromXml(tinyxml2::XMLDocument* doc) {
} }
// Guild Stuff: // Guild Stuff:
const tinyxml2::XMLAttribute* guildName = character->FindAttribute("gn"); // Ensure the guild they are a part of still exists
if (guildName) { // Update the guild name if it has changed
const char* gn = guildName->Value();
int64_t gid = 0; int64_t gid = 0;
character->QueryInt64Attribute("gid", &gid); character->QueryInt64Attribute("gid", &gid);
if (gid != 0) { if (gid != 0) {
std::string guildname(gn); auto guild = Database::Get()->GetGuild(gid);
m_GuildName = GeneralUtils::UTF8ToUTF16(guildname); if (guild && Database::Get()->CheckIsInGuild(guild->id, m_Parent->GetCharacter()->GetID())) {
LOG("Found Guild %i name %s", guild->id, guild->name.c_str());
m_GuildName = GeneralUtils::UTF8ToUTF16(guild->name);
m_GuildID = gid; m_GuildID = gid;
m_DirtySocialInfo = true; m_DirtySocialInfo = true;
} else {
LOG("Unalbe to find Guild %i name %s", guild->id, guild->name.c_str());
SetGuild(0, u"");
} }
} }
@ -362,7 +369,7 @@ void CharacterComponent::UpdateXml(tinyxml2::XMLDocument* doc) {
// End custom attributes // End custom attributes
// //
if (m_GuildID != 0 || m_GuildName != u"") { if (m_GuildID != 0 || !m_GuildName.empty()) {
character->SetAttribute("gn", GeneralUtils::UTF16ToWTF8(m_GuildName).c_str()); character->SetAttribute("gn", GeneralUtils::UTF16ToWTF8(m_GuildName).c_str());
character->SetAttribute("gid", m_GuildID); character->SetAttribute("gid", m_GuildID);
} }

View File

@ -197,10 +197,10 @@ public:
/** /**
* @brief Set the character's Guild * @brief Set the character's Guild
* *
* @param guildID * @param guild_id
* @param guildName * @param guildName
*/ */
void SetGuild(LWOOBJID& guildID, std::u16string guildName); void SetGuild(uint32_t guild_id, std::u16string guildName);
/** /**
* Initializes the player statistics from the string stored in the XML * Initializes the player statistics from the string stored in the XML

View File

@ -37,6 +37,7 @@
#include "eReplicaComponentType.h" #include "eReplicaComponentType.h"
#include "CheatDetection.h" #include "CheatDetection.h"
#include "Amf3.h" #include "Amf3.h"
#include "eObjectBits.h"
void ClientPackets::HandleChatMessage(const SystemAddress& sysAddr, Packet* packet) { void ClientPackets::HandleChatMessage(const SystemAddress& sysAddr, Packet* packet) {
User* user = UserManager::Instance()->GetUser(sysAddr); User* user = UserManager::Instance()->GetUser(sysAddr);
@ -391,36 +392,29 @@ void ClientPackets::HandleChatModerationRequest(const SystemAddress& sysAddr, Pa
WorldPackets::SendChatModerationResponse(sysAddr, bAllClean, requestID, receiver, segments); WorldPackets::SendChatModerationResponse(sysAddr, bAllClean, requestID, receiver, segments);
} }
void ClientPackets::HandleGuildCreation(const SystemAddress& sysAddr, Packet* packet) { void ClientPackets::HandleGuildCreation(Packet* packet) {
std::string guildName = PacketUtils::ReadString(8, packet, true); CINSTREAM_SKIP_HEADER;
LUWString guildName(31);
inStream.Read(guildName);
auto user = UserManager::Instance()->GetUser(sysAddr); auto user = UserManager::Instance()->GetUser(packet->systemAddress);
if (!user) return; if (!user) return;
auto character = user->GetLastUsedChar(); auto character = user->GetLastUsedChar();
if (!character) return; if (!character) return;
Game::logger->Log("ClientPackets", "User %s wants to create a guild with name: %s", character->GetName().c_str(), guildName.c_str()); LOG("User %s wants to create a guild with name: %s", character->GetName().c_str(), guildName.GetAsString().c_str());
// First, check to see if there is a guild with that name or not: // First, check to see if there is a guild with that name or not:
auto stmt = Database::CreatePreppedStmt("SELECT * FROM guilds WHERE name=?"); if (Database::Get()->CheckGuildNameExists(guildName.GetAsString().c_str())) {
stmt->setString(1, guildName.c_str()); LOG("But a guild already exists with that name!");
SendGuildCreateResponse(packet->systemAddress, eGuildCreationResponse::REJECTED_EXISTS, LWOOBJID_EMPTY, guildName.string);
auto res = stmt->executeQuery();
if (res->rowsCount() > 0) {
Game::logger->Log("ClientPackets", "But a guild already exists with that name!");
auto usedName = GeneralUtils::UTF8ToUTF16(guildName);
SendGuildCreateResponse(sysAddr, eGuildCreationResponse::REJECTED_EXISTS, LWOOBJID_EMPTY, usedName);
return; return;
} }
delete res; if (!Game::chatFilter->IsSentenceOkay(guildName.GetAsString().c_str(), character->GetGMLevel()).empty()) {
delete stmt; LOG("But they used bad words!");
SendGuildCreateResponse(packet->systemAddress, eGuildCreationResponse::REJECTED_BAD_NAME, LWOOBJID_EMPTY, guildName.string);
if (!Game::chatFilter->IsSentenceOkay(guildName, character->GetGMLevel()).empty()) {
Game::logger->Log("ClientPackets", "But they used bad words!");
auto usedName = GeneralUtils::UTF8ToUTF16(guildName);
SendGuildCreateResponse(sysAddr, eGuildCreationResponse::REJECTED_BAD_NAME, LWOOBJID_EMPTY, usedName);
return; return;
} }
@ -432,61 +426,36 @@ void ClientPackets::HandleGuildCreation(const SystemAddress& sysAddr, Packet* pa
if (!characterComp) return; if (!characterComp) return;
if (characterComp->GetGuildID() != 0) { if (characterComp->GetGuildID() != 0) {
ChatPackets::SendSystemMessage(sysAddr, u"You are already in a guild! Leave your current guild first."); ChatPackets::SendSystemMessage(packet->systemAddress, u"You are already in a guild! Leave your current guild first.");
return; return;
} }
auto creation = (uint32_t)time(nullptr);
LOG("Creating Guild"); LOG("Creating Guild");
// If not, insert our newly created guild: auto newGuild = Database::Get()->CreateGuild(guildName.GetAsString(), character->GetID(), characterComp->GetUScore());
auto insertGuild = Database::CreatePreppedStmt("INSERT INTO `guilds`(`name`, `owner_id`, `reputation`, `created`) VALUES (?,?,?,?)");
insertGuild->setString(1, guildName.c_str());
insertGuild->setUInt(2, character->GetID());
insertGuild->setUInt(3, characterComp->GetUScore());
insertGuild->setUInt(4, creation);
insertGuild->execute();
delete insertGuild;
// Enable the guild on their character component: if (!newGuild){
auto get = Database::CreatePreppedStmt("SELECT id, name FROM guilds WHERE owner_id=?"); LOG("Unknown error ocurred while creating a guild! Got %i", newGuild->id);
get->setInt(1, character->GetID()); SendGuildCreateResponse(packet->systemAddress, eGuildCreationResponse::UNKNOWN_ERROR, LWOOBJID_EMPTY, guildName.string);
auto* results = get->executeQuery();
LWOOBJID guildId = LWOOBJID_EMPTY;
std::u16string name;
while (results->next()) {
guildId = results->getInt(1);
name = GeneralUtils::UTF8ToUTF16(results->getString(2).c_str());
characterComp->SetGuild(guildId, name);
}
if (guildId == LWOOBJID_EMPTY){
Game::logger->Log("ClientPackets", "Unknown error ocurred while creating a guild!");
auto usedName = GeneralUtils::UTF8ToUTF16(guildName);
SendGuildCreateResponse(sysAddr, eGuildCreationResponse::UNKNOWN_ERROR, LWOOBJID_EMPTY, usedName);
return; return;
} }
auto insertOwner = Database::CreatePreppedStmt("INSERT INTO `guild_members`(`guild_id`, `character_id`, `rank`, `joined`) VALUES (?,?,?,?)"); Database::Get()->InsertGuildMember(newGuild->id, character->GetID(), eGuildRank::FOUNDER);
insertOwner->setUInt(1, guildId);
insertOwner->setUInt(2, character->GetID()); characterComp->SetGuild(newGuild->id, guildName.string);
insertOwner->setUInt(3, eGuildRank::FOUNDER); SendGuildCreateResponse(packet->systemAddress, eGuildCreationResponse::CREATED, newGuild->id, guildName.string);
insertOwner->setUInt(4, creation); AMFArrayValue data;
insertOwner->execute(); data.Insert("bOn", true);
delete insertOwner; GameMessages::SendUIMessageServerToSingleClient(entity, packet->systemAddress, "ToggleGuildUI", data);
//Send the guild create response:
SendGuildCreateResponse(sysAddr, eGuildCreationResponse::CREATED, guildId, name);
// TODO: enable guild ui here
} }
void ClientPackets::SendGuildCreateResponse(const SystemAddress& sysAddr, eGuildCreationResponse guildResponse, LWOOBJID guildID, std::u16string& guildName) { void ClientPackets::SendGuildCreateResponse(const SystemAddress& sysAddr, eGuildCreationResponse guildResponse, LWOOBJID guild_id, std::u16string& guildName) {
CBITSTREAM; CBITSTREAM;
CMSGHEADER; GeneralUtils::SetBit(guild_id, eObjectBits::CHARACTER);
bitStream.Write(eClientMessageType::GUILD_CREATE_RESPONSE); BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::GUILD_CREATE_RESPONSE);
bitStream.Write(guildResponse); bitStream.Write<uint8_t>(guildResponse);
bitStream.Write(guildID); bitStream.Write(guild_id);
bitStream.Write(LUWString(guildName)); bitStream.Write(LUWString(guildName));
SEND_PACKET; SEND_PACKET;
} }

View File

@ -17,8 +17,8 @@ namespace ClientPackets {
void SendTop5HelpIssues(Packet* packet); void SendTop5HelpIssues(Packet* packet);
// Guild stuff // Guild stuff
void HandleGuildCreation(const SystemAddress& sysAddr, Packet* packet); void HandleGuildCreation(Packet* packet);
void SendGuildCreateResponse(const SystemAddress& sysAddr, eGuildCreationResponse guildResponse, LWOOBJID guildID, std::u16string& guildName); void SendGuildCreateResponse(const SystemAddress& sysAddr, eGuildCreationResponse guildResponse, LWOOBJID guild_id, std::u16string& guildName);
}; };
#endif // CLIENTPACKETS_H #endif // CLIENTPACKETS_H

View File

@ -1239,7 +1239,7 @@ void HandlePacket(Packet* packet) {
case eWorldMessageType::TMP_GUILD_CREATE: { case eWorldMessageType::TMP_GUILD_CREATE: {
Game::logger->Log("WorldServer", "create a guild"); Game::logger->Log("WorldServer", "create a guild");
ClientPackets::HandleGuildCreation(packet->systemAddress, packet); ClientPackets::HandleGuildCreation(packet);
} }
case eWorldMessageType::UI_HELP_TOP_5: { case eWorldMessageType::UI_HELP_TOP_5: {
ClientPackets::SendTop5HelpIssues(packet); ClientPackets::SendTop5HelpIssues(packet);

View File

@ -4,13 +4,13 @@ CREATE TABLE IF NOT EXISTS guilds (
owner_id BIGINT NOT NULL REFERENCES charinfo(id) ON DELETE CASCADE, owner_id BIGINT NOT NULL REFERENCES charinfo(id) ON DELETE CASCADE,
motd TEXT, motd TEXT,
reputation INT NOT NULL DEFAULT 0, reputation INT NOT NULL DEFAULT 0,
created BIGINT UNSIGNED NOT NULL DEFAULT 0 created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP()
); );
CREATE TABLE IF NOT EXISTS guild_members ( CREATE TABLE IF NOT EXISTS guild_members (
guild_id BIGINT NOT NULL REFERENCES guilds(id) ON DELETE CASCADE, guild_id BIGINT NOT NULL REFERENCES guilds(id) ON DELETE CASCADE,
character_id BIGINT NOT NULL REFERENCES charinfo(id) ON DELETE CASCADE, character_id BIGINT NOT NULL REFERENCES charinfo(id) ON DELETE CASCADE,
rank INT NOT NULL DEFAULT 4, rank INT NOT NULL DEFAULT 4,
joined BIGINT UNSIGNED NOT NULL DEFAULT 0 joined TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP(),
PRIMARY KEY (guild_id, character_id) PRIMARY KEY (guild_id, character_id)
); );