Compare commits

...

17 Commits

Author SHA1 Message Date
6a921f4ee6 Merge branch 'main' into guild_temp 2023-11-27 17:39:39 -06:00
443f9e37e8 more notes 2023-11-27 17:35:52 -06:00
David Markowitz
0f260ba682 Update ChatPacketHandler.cpp 2023-11-26 21:04:14 -08:00
David Markowitz
0d668aefcf Merge branch 'guild_temp' of https://github.com/DarkflameUniverse/DarkflameServer into guild_temp 2023-11-26 20:56:44 -08:00
David Markowitz
7c0fc72294 working guild data 2023-11-26 20:56:31 -08:00
ce3021310c WIP 2023-11-26 21:28:21 -06:00
4722c1fdea fully define guidl ranks
more testing with the guild list
2023-11-23 06:48:55 -06:00
a4bf11502f WIP
no crashes
2023-11-21 14:16:56 -06:00
e5f62e870b Merge branch 'main' into guild_temp 2023-11-19 21:15:06 -06:00
124e10e923 more work 2023-11-16 13:26:35 -06:00
449202e39f more worky 2023-11-16 07:12:18 -06:00
09bd4e9089 make it compile 2023-11-16 00:32:50 -06:00
2a34cff008 Merge branch 'main' into guild_temp 2023-11-15 21:14:20 -06:00
9ac11f281d better WIP 2022-12-20 18:19:21 -06:00
c4ae05ecee fix guild creation 2022-12-20 08:54:52 -06:00
30fbdd3956 WIP 2022-12-20 08:14:58 -06:00
Neal Spellman
192948a87f Initial NPC script and gating
- TEMP: Adds guilds gating.
- FV Guild Master script added which will toggle the guild UI.
2022-12-19 17:56:49 -05:00
26 changed files with 524 additions and 47 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"
void ChatPacketHandler::HandleFriendlistRequest(Packet* packet) { void ChatPacketHandler::HandleFriendlistRequest(Packet* packet) {
//Get from the packet which player we want to do something with: //Get from the packet which player we want to do something with:
@@ -363,39 +364,37 @@ void ChatPacketHandler::HandleChatMessage(Packet* packet) {
LOG("Got a message from (%s) [%d]: %s", senderName.c_str(), channel, message.c_str()); LOG("Got a message from (%s) [%d]: %s", senderName.c_str(), channel, message.c_str());
if (channel != 8) return; if (channel == 8) {
auto* team = Game::playerContainer.GetTeam(playerID); auto* team = playerContainer.GetTeam(playerID);
if (!team) return;
if (team == nullptr) return; for (const auto memberId : team->memberIDs) {
auto* otherMember = playerContainer.GetPlayerData(memberId);
if (!otherMember) return;
const auto otherName = std::string(otherMember->playerName.c_str());
for (const auto memberId : team->memberIDs) { CBITSTREAM;
auto* otherMember = Game::playerContainer.GetPlayerData(memberId); BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
bitStream.Write(otherMember->playerID);
if (otherMember == nullptr) return; BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::PRIVATE_CHAT_MESSAGE);
bitStream.Write(otherMember->playerID);
bitStream.Write<uint8_t>(8);
bitStream.Write<unsigned int>(69);
bitStream.Write(LUWString(senderName));
bitStream.Write(sender->playerID);
bitStream.Write<uint16_t>(0);
bitStream.Write<uint8_t>(0); //not mythran nametag
bitStream.Write(LUWString(otherName));
bitStream.Write<uint8_t>(0); //not mythran for receiver
bitStream.Write<uint8_t>(0); //teams?
bitStream.Write(LUWString(message, 512));
const auto otherName = std::string(otherMember->playerName.c_str()); SystemAddress sysAddr = otherMember->sysAddr;
SEND_PACKET;
CBITSTREAM; }
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER); } else LOG("Private chat channel is %i", channel);
bitStream.Write(otherMember->playerID);
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::PRIVATE_CHAT_MESSAGE);
bitStream.Write(otherMember->playerID);
bitStream.Write<uint8_t>(8);
bitStream.Write<unsigned int>(69);
bitStream.Write(LUWString(senderName));
bitStream.Write(sender->playerID);
bitStream.Write<uint16_t>(0);
bitStream.Write<uint8_t>(0); //not mythran nametag
bitStream.Write(LUWString(otherName));
bitStream.Write<uint8_t>(0); //not mythran for receiver
bitStream.Write<uint8_t>(0); //teams?
bitStream.Write(LUWString(message, 512));
SystemAddress sysAddr = otherMember->sysAddr;
SEND_PACKET;
}
} }
void ChatPacketHandler::HandlePrivateChatMessage(Packet* packet) { void ChatPacketHandler::HandlePrivateChatMessage(Packet* packet) {
@@ -672,6 +671,80 @@ void ChatPacketHandler::HandleTeamStatusRequest(Packet* packet) {
} }
} }
void ChatPacketHandler::HandleGuildLeave(Packet* packet) {
CINSTREAM_SKIP_HEADER;
LWOOBJID playerID = LWOOBJID_EMPTY;
inStream.Read(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) {
CINSTREAM_SKIP_HEADER;
LWOOBJID playerID = LWOOBJID_EMPTY;
inStream.Read(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.Write<uint8_t>(0); // has Guild data/in a guild
bitStream.Write(LUWString(guild->name, 31)); // guild name
bitStream.Write(LUWString("test1", 11)); // unknown
bitStream.Write(LUWString("test2", 11)); // unknown
bitStream.Write<uint32_t>(69); // unknown
bitStream.Write<uint32_t>(0); // unknown
bitStream.Write<uint32_t>(1); // unknown
bitStream.Write<uint16_t>(0); // unknown
bitStream.Write<uint16_t>(members.size()); // Size
//Member data
for (const auto &member : members) {
bitStream.Write<uint8_t>(member.rank); // rank
bitStream.Write<uint8_t>(1); // online status
bitStream.Write<uint16_t>(1100); // zone
bitStream.Write<uint16_t>(1200); // instance
bitStream.Write<uint16_t>(1300); // clone
bitStream.Write<uint16_t>(1200); // unknown
bitStream.Write<LWOOBJID>(player->playerID); // playerId
bitStream.Write(LUWString(player->playerName, 24)); // playername Wchar[24]
bitStream.Write<uint16_t>(0); // null terminator for playername
bitStream.Write<LWOOBJID>(0); // unknown
bitStream.Write<LWOOBJID>(0); // unknown
}
SystemAddress sysAddr = packet->systemAddress;
SEND_PACKET;
LOG("Send GUILD DATA");
PacketUtils::SavePacket("GuildData.bin", (char*)bitStream.GetData(), bitStream.GetNumberOfBytesUsed());
}
void ChatPacketHandler::SendTeamInvite(PlayerData* receiver, PlayerData* sender) { void ChatPacketHandler::SendTeamInvite(PlayerData* receiver, PlayerData* sender) {
CBITSTREAM; CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER); BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);

View File

@@ -23,6 +23,10 @@ namespace ChatPacketHandler {
void HandleTeamLootOption(Packet* packet); void HandleTeamLootOption(Packet* packet);
void HandleTeamStatusRequest(Packet* packet); void HandleTeamStatusRequest(Packet* packet);
void HandleGuildLeave(Packet* packet);
void HandleGuildGetAll(Packet* packet);
void SendTeamInvite(PlayerData* receiver, PlayerData* sender); void SendTeamInvite(PlayerData* receiver, PlayerData* sender);
void SendTeamInviteConfirm(PlayerData* receiver, bool bLeaderIsFreeTrial, LWOOBJID i64LeaderID, LWOZONEID i64LeaderZoneID, uint8_t ucLootFlag, uint8_t ucNumOfOtherPlayers, uint8_t ucResponseCode, std::u16string wsLeaderName); void SendTeamInviteConfirm(PlayerData* receiver, bool bLeaderIsFreeTrial, LWOOBJID i64LeaderID, LWOZONEID i64LeaderZoneID, uint8_t ucLootFlag, uint8_t ucNumOfOtherPlayers, uint8_t ucResponseCode, std::u16string wsLeaderName);
void SendTeamStatus(PlayerData* receiver, LWOOBJID i64LeaderID, LWOZONEID i64LeaderZoneID, uint8_t ucLootFlag, uint8_t ucNumOfOtherPlayers, std::u16string wsLeaderName); void SendTeamStatus(PlayerData* receiver, LWOOBJID i64LeaderID, LWOZONEID i64LeaderZoneID, uint8_t ucLootFlag, uint8_t ucNumOfOtherPlayers, std::u16string wsLeaderName);

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 "ChatIgnoreList.h" #include "ChatIgnoreList.h"
#include "Game.h" #include "Game.h"
@@ -298,6 +299,41 @@ void HandlePacket(Packet* packet) {
ChatPacketHandler::HandleTeamLootOption(packet); ChatPacketHandler::HandleTeamLootOption(packet);
break; break;
// Guild messages
case eChatMessageType::GUILD_CREATE:
PacketUtils::SavePacket("GUILD_CREATE", (const char*) packet->data, packet->length);
LOG("GUILD_CREATE");
break;
case eChatMessageType::GUILD_INVITE:
PacketUtils::SavePacket("GUILD_INVITE", (const char*) packet->data, packet->length);
break;
case eChatMessageType::GUILD_INVITE_RESPONSE:
PacketUtils::SavePacket("GUILD_INVITE_RESPONSE", (const char*) packet->data, packet->length);
LOG("GUILD_INVITE_RESPONSE");
break;
case eChatMessageType::GUILD_LEAVE:
ChatPacketHandler::HandleGuildLeave(packet);
break;
case eChatMessageType::GUILD_KICK:
PacketUtils::SavePacket("GUILD_KICK", (const char*) packet->data, packet->length);
LOG("GUILD_KICK");
break;
case eChatMessageType::GUILD_GET_STATUS:
PacketUtils::SavePacket("GUILD_GET_STATUS", (const char*) packet->data, packet->length);
LOG("GUILD_GET_STATUS");
break;
case eChatMessageType::GUILD_GET_ALL:
PacketUtils::SavePacket("GUILD_GET_ALL", (const char*) packet->data, packet->length);
LOG("GUILD_GET_ALL");
ChatPacketHandler::HandleGuildGetAll(packet);
break;
default: default:
LOG("Unknown CHAT id: %i", int(packet->data[3])); LOG("Unknown CHAT id: %i", int(packet->data[3]));
} }

View File

@@ -0,0 +1,13 @@
#pragma once
#ifndef __EGUILDCREATIONRESPONSE__H__
#define __EGUILDCREATIONRESPONSE__H__
enum eGuildCreationResponse {
CREATED = 0,
REJECTED_BAD_NAME,
REJECTED_EXISTS,
UNKNOWN_ERROR
};
#endif //!__EGUILDCREATIONRESPONSE__H__

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

@@ -0,0 +1,14 @@
#pragma once
#ifndef __EGUILDRANK__H__
#define __EGUILDRANK__H__
enum eGuildRank {
LEADER = 1,
OFFICER,
VETERAN,
RECRUIT
};
#endif //!__EGUILDRANK__H__

View File

@@ -21,6 +21,8 @@
#include "ICharInfo.h" #include "ICharInfo.h"
#include "IAccounts.h" #include "IAccounts.h"
#include "IActivityLog.h" #include "IActivityLog.h"
#include "IGuilds.h"
#include "IGuildMembers.h"
#include "IIgnoreList.h" #include "IIgnoreList.h"
#include "IAccountsRewardCodes.h" #include "IAccountsRewardCodes.h"
@@ -28,7 +30,7 @@ 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
@@ -40,7 +42,9 @@ 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 IAccountsRewardCodes, public IIgnoreList { public IAccounts, public IActivityLog, public IAccountsRewardCodes, public IIgnoreList,
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

@@ -108,6 +108,17 @@ public:
std::vector<IIgnoreList::Info> GetIgnoreList(const uint32_t playerId) override; std::vector<IIgnoreList::Info> GetIgnoreList(const uint32_t playerId) override;
void InsertRewardCode(const uint32_t account_id, const uint32_t reward_code) override; void InsertRewardCode(const uint32_t account_id, const uint32_t reward_code) override;
std::vector<uint32_t> GetRewardCodesByAccountID(const uint32_t account_id) override; std::vector<uint32_t> GetRewardCodesByAccountID(const uint32_t account_id) 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

@@ -7,6 +7,8 @@ set(DDATABASES_DATABASES_MYSQL_TABLES_SOURCES
"CharXml.cpp" "CharXml.cpp"
"CommandLog.cpp" "CommandLog.cpp"
"Friends.cpp" "Friends.cpp"
"Guilds.cpp"
"GuildMembers.cpp"
"IgnoreList.cpp" "IgnoreList.cpp"
"Leaderboard.cpp" "Leaderboard.cpp"
"Mail.cpp" "Mail.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

@@ -21,6 +21,8 @@
#include "CDRewardCodesTable.h" #include "CDRewardCodesTable.h"
#include "Mail.h" #include "Mail.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;
@@ -44,6 +46,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;
} }
bool CharacterComponent::LandingAnimDisabled(int zoneID) { bool CharacterComponent::LandingAnimDisabled(int zoneID) {
@@ -154,15 +157,15 @@ void CharacterComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInit
outBitStream->Write(m_DirtyCurrentActivity); outBitStream->Write(m_DirtyCurrentActivity);
if (m_DirtyCurrentActivity) outBitStream->Write(m_CurrentActivity); if (m_DirtyCurrentActivity) outBitStream->Write(m_CurrentActivity);
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;
} }
} }
@@ -172,7 +175,6 @@ bool CharacterComponent::GetPvpEnabled() const {
void CharacterComponent::SetPvpEnabled(const bool value) { void CharacterComponent::SetPvpEnabled(const bool value) {
m_DirtyGMInfo = true; m_DirtyGMInfo = true;
m_PvpEnabled = value; m_PvpEnabled = value;
} }
@@ -183,6 +185,18 @@ void CharacterComponent::SetGMLevel(eGameMasterLevel gmlevel) {
m_GMLevel = gmlevel; m_GMLevel = gmlevel;
} }
void CharacterComponent::SetGuild(uint32_t guild_id, std::u16string guildName) {
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_DirtySocialInfo = true;
}
void CharacterComponent::LoadFromXml(tinyxml2::XMLDocument* doc) { void CharacterComponent::LoadFromXml(tinyxml2::XMLDocument* doc) {
tinyxml2::XMLElement* character = doc->FirstChildElement("obj")->FirstChildElement("char"); tinyxml2::XMLElement* character = doc->FirstChildElement("obj")->FirstChildElement("char");
@@ -264,17 +278,19 @@ void CharacterComponent::LoadFromXml(tinyxml2::XMLDocument* doc) {
m_EditorEnabled = false; //We're not currently in HF if we're loading in m_EditorEnabled = false; //We're not currently in HF if we're loading in
} }
//Annoying guild bs: // 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) { auto guild = Database::Get()->GetGuild(gid);
std::string guildname(gn); if (guild && Database::Get()->CheckIsInGuild(guild->id, m_Parent->GetCharacter()->GetID())) {
m_GuildName = GeneralUtils::UTF8ToUTF16(guildname); m_GuildName = GeneralUtils::UTF8ToUTF16(guild->name);
m_GuildID = gid; m_GuildID = gid;
m_DirtySocialInfo = true; m_DirtySocialInfo = true;
} else {
SetGuild(0, u"");
} }
} }
@@ -371,6 +387,11 @@ void CharacterComponent::UpdateXml(tinyxml2::XMLDocument* doc) {
// End custom attributes // End custom attributes
// //
if (m_GuildID != 0 || !m_GuildName.empty()) {
character->SetAttribute("gn", GeneralUtils::UTF16ToWTF8(m_GuildName).c_str());
character->SetAttribute("gid", m_GuildID);
}
auto newUpdateTimestamp = std::time(nullptr); auto newUpdateTimestamp = std::time(nullptr);
LOG("Time since last save: %d", newUpdateTimestamp - m_LastUpdateTimestamp); LOG("Time since last save: %d", newUpdateTimestamp - m_LastUpdateTimestamp);

View File

@@ -183,6 +183,26 @@ public:
*/ */
void SetGMLevel(eGameMasterLevel gmlevel); void SetGMLevel(eGameMasterLevel gmlevel);
/**
* @brief Get the Guild ID that the character is in
* @return const LWOOBJID& The guild
*/
const LWOOBJID& GetGuildID() const { return m_GuildID; }
/**
* @brief Get the character's Guild's Name
* @return const std::u16string& the guild name
*/
const std::u16string& GetGuildName() const { return m_GuildName; }
/**
* @brief Set the character's Guild
*
* @param guild_id
* @param 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
* @param statisticsString the string to parse * @param statisticsString the string to parse

View File

@@ -17,6 +17,7 @@
* Component that handles rigid bodies that can be interacted with, mostly client-side rendered. An example is the * Component that handles rigid bodies that can be interacted with, mostly client-side rendered. An example is the
* bananas that fall from trees in GF. * bananas that fall from trees in GF.
*/ */
class RigidbodyPhantomPhysicsComponent : public PhysicsComponent { class RigidbodyPhantomPhysicsComponent : public PhysicsComponent {
public: public:
inline static const eReplicaComponentType ComponentType = eReplicaComponentType::RIGID_BODY_PHANTOM_PHYSICS; inline static const eReplicaComponentType ComponentType = eReplicaComponentType::RIGID_BODY_PHANTOM_PHYSICS;

View File

@@ -4581,6 +4581,17 @@ void GameMessages::SendShowActivityCountdown(LWOOBJID objectId, bool bPlayAdditi
SEND_PACKET; SEND_PACKET;
} }
void GameMessages::SendDisplayGuildCreateBox(const LWOOBJID& objectID, bool bShow, const SystemAddress& sysAddr) {
CBITSTREAM;
CMSGHEADER;
bitStream.Write(eGameMessageType::DISPLAY_GUILD_CREATE_BOX);
bitStream.Write(objectID);
bitStream.Write((unsigned char)bShow);
SEND_PACKET;
}
//----------------------------------------------------------------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------------------------------------------------------------
//------------------------------------------------------------------- Handlers ------------------------------------------------------------------ //------------------------------------------------------------------- Handlers ------------------------------------------------------------------
@@ -4838,7 +4849,7 @@ void GameMessages::HandleParseChatMessage(RakNet::BitStream* inStream, Entity* e
inStream->Read(character); inStream->Read(character);
wsString.push_back(character); wsString.push_back(character);
} }
LOG("state: %i, str: %s", iClientState, GeneralUtils::UTF16ToWTF8(wsString).c_str());
if (wsString[0] == L'/') { if (wsString[0] == L'/') {
SlashCommandHandler::HandleChatCommand(wsString, entity, sysAddr); SlashCommandHandler::HandleChatCommand(wsString, entity, sysAddr);
} }

View File

@@ -4,6 +4,13 @@
#include "dCommonVars.h" #include "dCommonVars.h"
#include <map> #include <map>
#include <string> #include <string>
#include "NiQuaternion.h"
#include "PropertySelectQueryProperty.h"
#include "TradingManager.h"
#include "LeaderboardManager.h"
#include "MovingPlatformComponent.h"
#include "eAninmationFlags.h"
#include "eGuildCreationResponse.h"
#include <vector> #include <vector>
#include "eMovementPlatformState.h" #include "eMovementPlatformState.h"
#include "NiPoint3.h" #include "NiPoint3.h"
@@ -586,6 +593,9 @@ namespace GameMessages {
void SendShowActivityCountdown(LWOOBJID objectId, bool bPlayAdditionalSound, bool bPlayCountdownSound, std::u16string sndName, int32_t stateToPlaySoundOn, const SystemAddress& sysAddr); void SendShowActivityCountdown(LWOOBJID objectId, bool bPlayAdditionalSound, bool bPlayCountdownSound, std::u16string sndName, int32_t stateToPlaySoundOn, const SystemAddress& sysAddr);
//Guild messages:
void SendDisplayGuildCreateBox(const LWOOBJID& objectID, bool bShow, const SystemAddress& sysAddr);
//Handlers: //Handlers:
void HandleToggleGhostReferenceOverride(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); void HandleToggleGhostReferenceOverride(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr);

View File

@@ -31,10 +31,13 @@
#include "dConfig.h" #include "dConfig.h"
#include "CharacterComponent.h" #include "CharacterComponent.h"
#include "Database.h" #include "Database.h"
#include "PacketUtils.h"
#include "eGuildRank.h"
#include "eGameMasterLevel.h" #include "eGameMasterLevel.h"
#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);
@@ -389,6 +392,74 @@ void ClientPackets::HandleChatModerationRequest(const SystemAddress& sysAddr, Pa
WorldPackets::SendChatModerationResponse(sysAddr, bAllClean, requestID, receiver, segments); WorldPackets::SendChatModerationResponse(sysAddr, bAllClean, requestID, receiver, segments);
} }
void ClientPackets::HandleGuildCreation(Packet* packet) {
CINSTREAM_SKIP_HEADER;
LUWString guildName(31);
inStream.Read(guildName);
auto user = UserManager::Instance()->GetUser(packet->systemAddress);
if (!user) return;
auto character = user->GetLastUsedChar();
if (!character) return;
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:
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);
return;
}
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);
return;
}
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) {
ChatPackets::SendSystemMessage(packet->systemAddress, u"You are already in a guild! Leave your current guild first.");
return;
}
LOG("Creating Guild");
auto newGuild = Database::Get()->CreateGuild(guildName.GetAsString(), character->GetID(), characterComp->GetUScore());
if (!newGuild){
LOG("Unknown error ocurred while creating a guild! Got %i", newGuild->id);
SendGuildCreateResponse(packet->systemAddress, eGuildCreationResponse::UNKNOWN_ERROR, LWOOBJID_EMPTY, guildName.string);
return;
}
Database::Get()->InsertGuildMember(newGuild->id, character->GetID(), eGuildRank::LEADER);
characterComp->SetGuild(newGuild->id, guildName.string);
SendGuildCreateResponse(packet->systemAddress, eGuildCreationResponse::CREATED, newGuild->id, guildName.string);
AMFArrayValue data;
data.Insert("bDisplay", true);
GameMessages::SendUIMessageServerToSingleClient(entity, packet->systemAddress, "EnableGuild", data);
}
void ClientPackets::SendGuildCreateResponse(const SystemAddress& sysAddr, eGuildCreationResponse guildResponse, LWOOBJID guild_id, std::u16string& guildName) {
CBITSTREAM;
GeneralUtils::SetBit(guild_id, eObjectBits::CHARACTER);
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::GUILD_CREATE_RESPONSE);
bitStream.Write<uint8_t>(guildResponse);
bitStream.Write(guild_id);
bitStream.Write(LUWString(guildName));
SEND_PACKET;
}
void ClientPackets::SendTop5HelpIssues(Packet* packet) { void ClientPackets::SendTop5HelpIssues(Packet* packet) {
auto* user = UserManager::Instance()->GetUser(packet->systemAddress); auto* user = UserManager::Instance()->GetUser(packet->systemAddress);
if (!user) return; if (!user) return;

View File

@@ -7,12 +7,18 @@
#define CLIENTPACKETS_H #define CLIENTPACKETS_H
#include "RakNetTypes.h" #include "RakNetTypes.h"
#include "eGuildCreationResponse.h"
#include "dCommonVars.h"
namespace ClientPackets { namespace ClientPackets {
void HandleChatMessage(const SystemAddress& sysAddr, Packet* packet); void HandleChatMessage(const SystemAddress& sysAddr, Packet* packet);
void HandleClientPositionUpdate(const SystemAddress& sysAddr, Packet* packet); void HandleClientPositionUpdate(const SystemAddress& sysAddr, Packet* packet);
void HandleChatModerationRequest(const SystemAddress& sysAddr, Packet* packet); void HandleChatModerationRequest(const SystemAddress& sysAddr, Packet* packet);
void SendTop5HelpIssues(Packet* packet); void SendTop5HelpIssues(Packet* packet);
// Guild stuff
void HandleGuildCreation(Packet* packet);
void SendGuildCreateResponse(const SystemAddress& sysAddr, eGuildCreationResponse guildResponse, LWOOBJID guild_id, std::u16string& guildName);
}; };
#endif // CLIENTPACKETS_H #endif // CLIENTPACKETS_H

View File

@@ -139,6 +139,7 @@
#include "TreasureChestDragonServer.h" #include "TreasureChestDragonServer.h"
#include "InstanceExitTransferPlayerToLastNonInstance.h" #include "InstanceExitTransferPlayerToLastNonInstance.h"
#include "FvFreeGfNinjas.h" #include "FvFreeGfNinjas.h"
#include "FvGuildCreate.h"
#include "FvPandaServer.h" #include "FvPandaServer.h"
#include "FvPandaSpawnerServer.h" #include "FvPandaSpawnerServer.h"
#include "ZoneFvProperty.h" #include "ZoneFvProperty.h"
@@ -583,6 +584,8 @@ CppScripts::Script* CppScripts::GetScript(Entity* parent, const std::string& scr
script = new InstanceExitTransferPlayerToLastNonInstance(); script = new InstanceExitTransferPlayerToLastNonInstance();
else if (scriptName == "scripts\\ai\\FV\\L_NPC_FREE_GF_NINJAS.lua") else if (scriptName == "scripts\\ai\\FV\\L_NPC_FREE_GF_NINJAS.lua")
script = new FvFreeGfNinjas(); script = new FvFreeGfNinjas();
else if (scriptName == "scripts\\ai\\FV\\L_GUILD_CREATE.lua")
script = new FvGuildCreate();
else if (scriptName == "scripts\\ai\\FV\\L_FV_PANDA_SPAWNER_SERVER.lua") else if (scriptName == "scripts\\ai\\FV\\L_FV_PANDA_SPAWNER_SERVER.lua")
script = new FvPandaSpawnerServer(); script = new FvPandaSpawnerServer();
else if (scriptName == "scripts\\ai\\FV\\L_FV_PANDA_SERVER.lua") else if (scriptName == "scripts\\ai\\FV\\L_FV_PANDA_SERVER.lua")

View File

@@ -4,6 +4,7 @@ set(DSCRIPTS_SOURCES_AI_FV
"FvFlyingCreviceDragon.cpp" "FvFlyingCreviceDragon.cpp"
"FvDragonSmashingGolemQb.cpp" "FvDragonSmashingGolemQb.cpp"
"FvFreeGfNinjas.cpp" "FvFreeGfNinjas.cpp"
"FvGuildCreate.cpp"
"FvPandaSpawnerServer.cpp" "FvPandaSpawnerServer.cpp"
"FvPandaServer.cpp" "FvPandaServer.cpp"
"FvBrickPuzzleServer.cpp" "FvBrickPuzzleServer.cpp"

View File

@@ -0,0 +1,12 @@
#include "FvGuildCreate.h"
#include "GameMessages.h"
#include "Amf3.h"
// Server script for Guild Master NPC in FV area.
// This NPC will react to a user interaction and display
// the guild creation screen.
void FvGuildCreate::OnUse(Entity* self, Entity* user) {
AMFArrayValue args;
GameMessages::SendUIMessageServerToSingleClient(user, user->GetSystemAddress(), "ToggleGuildCreate", args);
}

View File

@@ -0,0 +1,7 @@
#pragma once
#include "CppScripts.h"
class FvGuildCreate : public CppScripts::Script {
public:
void OnUse(Entity* self, Entity* user) override;
};

View File

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

View File

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