Compare commits

..

7 Commits

Author SHA1 Message Date
David Markowitz
a0913ff23d remove grandmas code 2025-01-14 02:18:46 -08:00
David Markowitz
b738504812 reduce traffic greatly 2025-01-14 02:09:54 -08:00
David Markowitz
c968dc9028 fix lego club teleport (#1731)
Tested that the lego club teleport and starbase 3001 teleports work now both before and after you visit nexus tower
2025-01-14 01:28:24 -06:00
David Markowitz
2209a4432f Update AgSpiderBossMessage.cpp (#1729) 2025-01-14 01:14:24 -06:00
David Markowitz
c855a6b9cf Remove added physics objects (#1727) 2025-01-12 14:03:35 -06:00
David Markowitz
8abc545bd1 fix: use generated bcrypt password for internal master connections (#1720)
* add password hashing for master server

* use define
2025-01-10 01:45:20 -08:00
David Markowitz
136133dde2 fix: friends (#1726)
* fix

* Update ChatPacketHandler.cpp
2025-01-08 22:44:55 -06:00
41 changed files with 538 additions and 753 deletions

View File

@@ -70,12 +70,15 @@ int main(int argc, char** argv) {
//Find out the master's IP:
std::string masterIP;
uint32_t masterPort = 1500;
std::string masterPassword;
auto masterInfo = Database::Get()->GetMasterInfo();
if (masterInfo) {
masterIP = masterInfo->ip;
masterPort = masterInfo->port;
masterPassword = masterInfo->password;
}
LOG("Master is at %s:%d", masterIP.c_str(), masterPort);
Game::randomEngine = std::mt19937(time(0));
@@ -89,7 +92,7 @@ int main(int argc, char** argv) {
const auto externalIPString = Game::config->GetValue("external_ip");
if (!externalIPString.empty()) ourIP = externalIPString;
Game::server = new dServer(ourIP, ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Auth, Game::config, &Game::lastSignal);
Game::server = new dServer(ourIP, ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Auth, Game::config, &Game::lastSignal, masterPassword);
//Run it until server gets a kill message from Master:
auto t = std::chrono::high_resolution_clock::now();

View File

@@ -103,7 +103,8 @@ void ChatPacketHandler::HandleFriendRequest(Packet* packet) {
return;
};
auto& requestee = Game::playerContainer.GetPlayerDataMutable(playerName);
// Intentional copy
PlayerData requestee = Game::playerContainer.GetPlayerData(playerName);
// Check if player is online first
if (isBestFriendRequest && !requestee) {
@@ -188,19 +189,24 @@ void ChatPacketHandler::HandleFriendRequest(Packet* packet) {
Database::Get()->SetBestFriendStatus(requestorPlayerID, requestee.playerID, bestFriendStatus);
// Sent the best friend update here if the value is 3
if (bestFriendStatus == 3U) {
requestee.countOfBestFriends += 1;
requestor.countOfBestFriends += 1;
if (requestee.sysAddr != UNASSIGNED_SYSTEM_ADDRESS) SendFriendResponse(requestee, requestor, eAddFriendResponseType::ACCEPTED, false, true);
if (requestor.sysAddr != UNASSIGNED_SYSTEM_ADDRESS) SendFriendResponse(requestor, requestee, eAddFriendResponseType::ACCEPTED, false, true);
for (auto& friendData : requestor.friends) {
if (friendData.friendID == requestee.playerID) {
friendData.isBestFriend = true;
}
}
for (auto& friendData : requestee.friends) {
if (friendData.friendID == requestor.playerID) {
friendData.isBestFriend = true;
requestor.countOfBestFriends += 1;
auto& toModify = Game::playerContainer.GetPlayerDataMutable(playerName);
if (toModify) {
for (auto& friendData : toModify.friends) {
if (friendData.friendID == requestor.playerID) {
friendData.isBestFriend = true;
}
}
toModify.countOfBestFriends += 1;
}
}
}

View File

@@ -92,10 +92,12 @@ int main(int argc, char** argv) {
//Find out the master's IP:
std::string masterIP;
uint32_t masterPort = 1000;
std::string masterPassword;
auto masterInfo = Database::Get()->GetMasterInfo();
if (masterInfo) {
masterIP = masterInfo->ip;
masterPort = masterInfo->port;
masterPassword = masterInfo->password;
}
//It's safe to pass 'localhost' here, as the IP is only used as the external IP.
std::string ourIP = "localhost";
@@ -104,7 +106,7 @@ int main(int argc, char** argv) {
const auto externalIPString = Game::config->GetValue("external_ip");
if (!externalIPString.empty()) ourIP = externalIPString;
Game::server = new dServer(ourIP, ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Chat, Game::config, &Game::lastSignal);
Game::server = new dServer(ourIP, ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Chat, Game::config, &Game::lastSignal, masterPassword);
const bool dontGenerateDCF = GeneralUtils::TryParse<bool>(Game::config->GetValue("dont_generate_dcf")).value_or(false);
Game::chatFilter = new dChatFilter(Game::assetManager->GetResPath().string() + "/chatplus_en_us", dontGenerateDCF);

View File

@@ -5,6 +5,7 @@
#include "Logger.h"
#include "Game.h"
#include <type_traits>
#include <unordered_map>
#include <vector>
@@ -257,10 +258,10 @@ public:
*
* @param key The key to remove from the associative portion
*/
void Remove(const std::string& key, const bool deleteValue = true) {
void Remove(const std::string& key) {
const AMFAssociative::const_iterator it = m_Associative.find(key);
if (it != m_Associative.cend()) {
if (deleteValue) m_Associative.erase(it);
m_Associative.erase(it);
}
}
@@ -343,6 +344,11 @@ public:
return index < m_Dense.size() ? m_Dense.at(index).get() : nullptr;
}
void Reset() {
m_Associative.clear();
m_Dense.clear();
}
private:
/**
* The associative portion. These values are key'd with strings to an AMFValue.

View File

@@ -7,8 +7,7 @@ enum class eConnectionType : uint16_t {
CHAT,
WORLD = 4,
CLIENT,
MASTER,
UNKNOWN
MASTER
};
#endif //!__ECONNECTIONTYPE__H__

View File

@@ -8,10 +8,27 @@
#include "dCommonVars.h"
#include "NiQuaternion.h"
#include "NiPoint3.h"
#include "MailInfo.h"
class IMail {
public:
struct MailInfo {
std::string senderUsername;
std::string recipient;
std::string subject;
std::string body;
uint64_t id{};
uint32_t senderId{};
uint32_t receiverId{};
uint64_t timeSent{};
bool wasRead{};
struct {
LWOOBJID itemID{};
int32_t itemCount{};
LOT itemLOT{};
LWOOBJID itemSubkey{};
};
};
// Insert a new mail into the database.
virtual void InsertNewMail(const MailInfo& mail) = 0;

View File

@@ -9,10 +9,11 @@ public:
struct MasterInfo {
std::string ip;
uint32_t port{};
std::string password{};
};
// Set the master server ip and port.
virtual void SetMasterIp(const std::string_view ip, const uint32_t port) = 0;
virtual void SetMasterInfo(const MasterInfo& info) = 0;
// Get the master server info.
virtual std::optional<MasterInfo> GetMasterInfo() = 0;

View File

@@ -79,14 +79,14 @@ public:
void UpdatePerformanceCost(const LWOZONEID& zoneId, const float performanceCost) override;
void InsertNewBugReport(const IBugReports::Info& info) override;
void InsertCheatDetection(const IPlayerCheatDetections::Info& info) override;
void InsertNewMail(const MailInfo& mail) override;
void InsertNewMail(const IMail::MailInfo& mail) override;
void InsertNewUgcModel(
std::istringstream& sd0Data,
const uint32_t blueprintId,
const uint32_t accountId,
const uint32_t characterId) override;
std::vector<MailInfo> GetMailForPlayer(const uint32_t characterId, const uint32_t numberOfMail) override;
std::optional<MailInfo> GetMail(const uint64_t mailId) override;
std::vector<IMail::MailInfo> GetMailForPlayer(const uint32_t characterId, const uint32_t numberOfMail) override;
std::optional<IMail::MailInfo> GetMail(const uint64_t mailId) override;
uint32_t GetUnreadMailCount(const uint32_t characterId) override;
void MarkMailRead(const uint64_t mailId) override;
void DeleteMail(const uint64_t mailId) override;
@@ -96,7 +96,7 @@ public:
void UpdateAccountBan(const uint32_t accountId, const bool banned) override;
void UpdateAccountPassword(const uint32_t accountId, const std::string_view bcryptpassword) override;
void InsertNewAccount(const std::string_view username, const std::string_view bcryptpassword) override;
void SetMasterIp(const std::string_view ip, const uint32_t port) override;
void SetMasterInfo(const IServers::MasterInfo& info) override;
std::optional<uint32_t> GetCurrentPersistentId() override;
void InsertDefaultPersistentId() override;
void UpdatePersistentId(const uint32_t id) override;

View File

@@ -1,7 +1,6 @@
#include "MySQLDatabase.h"
void MySQLDatabase::InsertNewMail(const MailInfo& mail) {
void MySQLDatabase::InsertNewMail(const IMail::MailInfo& mail) {
ExecuteInsert(
"INSERT INTO `mail` "
"(`sender_id`, `sender_name`, `receiver_id`, `receiver_name`, `time_sent`, `subject`, `body`, `attachment_id`, `attachment_lot`, `attachment_subkey`, `attachment_count`, `was_read`)"
@@ -19,17 +18,17 @@ void MySQLDatabase::InsertNewMail(const MailInfo& mail) {
mail.itemCount);
}
std::vector<MailInfo> MySQLDatabase::GetMailForPlayer(const uint32_t characterId, const uint32_t numberOfMail) {
std::vector<IMail::MailInfo> MySQLDatabase::GetMailForPlayer(const uint32_t characterId, const uint32_t numberOfMail) {
auto res = ExecuteSelect(
"SELECT id, subject, body, sender_name, attachment_id, attachment_lot, attachment_subkey, attachment_count, was_read, time_sent"
" FROM mail WHERE receiver_id=? limit ?;",
characterId, numberOfMail);
std::vector<MailInfo> toReturn;
std::vector<IMail::MailInfo> toReturn;
toReturn.reserve(res->rowsCount());
while (res->next()) {
MailInfo mail;
IMail::MailInfo mail;
mail.id = res->getUInt64("id");
mail.subject = res->getString("subject").c_str();
mail.body = res->getString("body").c_str();
@@ -47,14 +46,14 @@ std::vector<MailInfo> MySQLDatabase::GetMailForPlayer(const uint32_t characterId
return toReturn;
}
std::optional<MailInfo> MySQLDatabase::GetMail(const uint64_t mailId) {
std::optional<IMail::MailInfo> MySQLDatabase::GetMail(const uint64_t mailId) {
auto res = ExecuteSelect("SELECT attachment_lot, attachment_count FROM mail WHERE id=? LIMIT 1;", mailId);
if (!res->next()) {
return std::nullopt;
}
MailInfo toReturn;
IMail::MailInfo toReturn;
toReturn.itemLOT = res->getInt("attachment_lot");
toReturn.itemCount = res->getInt("attachment_count");

View File

@@ -1,14 +1,14 @@
#include "MySQLDatabase.h"
void MySQLDatabase::SetMasterIp(const std::string_view ip, const uint32_t port) {
void MySQLDatabase::SetMasterInfo(const MasterInfo& info) {
// We only want our 1 entry anyways, so we can just delete all and reinsert the one we want
// since it would be two queries anyways.
ExecuteDelete("TRUNCATE TABLE servers;");
ExecuteInsert("INSERT INTO `servers` (`name`, `ip`, `port`, `state`, `version`) VALUES ('master', ?, ?, 0, 171022)", ip, port);
ExecuteInsert("INSERT INTO `servers` (`name`, `ip`, `port`, `state`, `version`, `master_password`) VALUES ('master', ?, ?, 0, 171022, ?)", info.ip, info.port, info.password);
}
std::optional<IServers::MasterInfo> MySQLDatabase::GetMasterInfo() {
auto result = ExecuteSelect("SELECT ip, port FROM servers WHERE name='master' LIMIT 1;");
auto result = ExecuteSelect("SELECT ip, port, master_password FROM servers WHERE name='master' LIMIT 1;");
if (!result->next()) {
return std::nullopt;
@@ -18,6 +18,7 @@ std::optional<IServers::MasterInfo> MySQLDatabase::GetMasterInfo() {
toReturn.ip = result->getString("ip").c_str();
toReturn.port = result->getInt("port");
toReturn.password = result->getString("master_password").c_str();
return toReturn;
}

View File

@@ -77,14 +77,14 @@ public:
void UpdatePerformanceCost(const LWOZONEID& zoneId, const float performanceCost) override;
void InsertNewBugReport(const IBugReports::Info& info) override;
void InsertCheatDetection(const IPlayerCheatDetections::Info& info) override;
void InsertNewMail(const MailInfo& mail) override;
void InsertNewMail(const IMail::MailInfo& mail) override;
void InsertNewUgcModel(
std::istringstream& sd0Data,
const uint32_t blueprintId,
const uint32_t accountId,
const uint32_t characterId) override;
std::vector<MailInfo> GetMailForPlayer(const uint32_t characterId, const uint32_t numberOfMail) override;
std::optional<MailInfo> GetMail(const uint64_t mailId) override;
std::vector<IMail::MailInfo> GetMailForPlayer(const uint32_t characterId, const uint32_t numberOfMail) override;
std::optional<IMail::MailInfo> GetMail(const uint64_t mailId) override;
uint32_t GetUnreadMailCount(const uint32_t characterId) override;
void MarkMailRead(const uint64_t mailId) override;
void DeleteMail(const uint64_t mailId) override;
@@ -94,7 +94,7 @@ public:
void UpdateAccountBan(const uint32_t accountId, const bool banned) override;
void UpdateAccountPassword(const uint32_t accountId, const std::string_view bcryptpassword) override;
void InsertNewAccount(const std::string_view username, const std::string_view bcryptpassword) override;
void SetMasterIp(const std::string_view ip, const uint32_t port) override;
void SetMasterInfo(const IServers::MasterInfo& info) override;
std::optional<uint32_t> GetCurrentPersistentId() override;
void InsertDefaultPersistentId() override;
void UpdatePersistentId(const uint32_t id) override;

View File

@@ -1,6 +1,6 @@
#include "SQLiteDatabase.h"
void SQLiteDatabase::InsertNewMail(const MailInfo& mail) {
void SQLiteDatabase::InsertNewMail(const IMail::MailInfo& mail) {
ExecuteInsert(
"INSERT INTO `mail` "
"(`sender_id`, `sender_name`, `receiver_id`, `receiver_name`, `time_sent`, `subject`, `body`, `attachment_id`, `attachment_lot`, `attachment_subkey`, `attachment_count`, `was_read`)"
@@ -18,16 +18,16 @@ void SQLiteDatabase::InsertNewMail(const MailInfo& mail) {
mail.itemCount);
}
std::vector<MailInfo> SQLiteDatabase::GetMailForPlayer(const uint32_t characterId, const uint32_t numberOfMail) {
std::vector<IMail::MailInfo> SQLiteDatabase::GetMailForPlayer(const uint32_t characterId, const uint32_t numberOfMail) {
auto [_, res] = ExecuteSelect(
"SELECT id, subject, body, sender_name, attachment_id, attachment_lot, attachment_subkey, attachment_count, was_read, time_sent"
" FROM mail WHERE receiver_id=? limit ?;",
characterId, numberOfMail);
std::vector<MailInfo> toReturn;
std::vector<IMail::MailInfo> toReturn;
while (!res.eof()) {
MailInfo mail;
IMail::MailInfo mail;
mail.id = res.getInt64Field("id");
mail.subject = res.getStringField("subject");
mail.body = res.getStringField("body");
@@ -46,14 +46,14 @@ std::vector<MailInfo> SQLiteDatabase::GetMailForPlayer(const uint32_t characterI
return toReturn;
}
std::optional<MailInfo> SQLiteDatabase::GetMail(const uint64_t mailId) {
std::optional<IMail::MailInfo> SQLiteDatabase::GetMail(const uint64_t mailId) {
auto [_, res] = ExecuteSelect("SELECT attachment_lot, attachment_count FROM mail WHERE id=? LIMIT 1;", mailId);
if (res.eof()) {
return std::nullopt;
}
MailInfo toReturn;
IMail::MailInfo toReturn;
toReturn.itemLOT = res.getIntField("attachment_lot");
toReturn.itemCount = res.getIntField("attachment_count");

View File

@@ -1,14 +1,14 @@
#include "SQLiteDatabase.h"
void SQLiteDatabase::SetMasterIp(const std::string_view ip, const uint32_t port) {
void SQLiteDatabase::SetMasterInfo(const MasterInfo& info) {
// We only want our 1 entry anyways, so we can just delete all and reinsert the one we want
// since it would be two queries anyways.
ExecuteDelete("DELETE FROM servers;");
ExecuteInsert("INSERT INTO `servers` (`name`, `ip`, `port`, `state`, `version`) VALUES ('master', ?, ?, 0, 171022)", ip, port);
ExecuteInsert("INSERT INTO `servers` (`name`, `ip`, `port`, `state`, `version`, `master_password`) VALUES ('master', ?, ?, 0, 171022 ?)", info.ip, info.port, info.password);
}
std::optional<IServers::MasterInfo> SQLiteDatabase::GetMasterInfo() {
auto [_, result] = ExecuteSelect("SELECT ip, port FROM servers WHERE name='master' LIMIT 1;");
auto [_, result] = ExecuteSelect("SELECT ip, port, master_password FROM servers WHERE name='master' LIMIT 1;");
if (result.eof()) {
return std::nullopt;
@@ -18,6 +18,7 @@ std::optional<IServers::MasterInfo> SQLiteDatabase::GetMasterInfo() {
toReturn.ip = result.getStringField("ip");
toReturn.port = result.getIntField("port");
toReturn.password = result.getStringField("master_password");
return toReturn;
}

View File

@@ -184,7 +184,7 @@ void TestSQLDatabase::InsertCheatDetection(const IPlayerCheatDetections::Info& i
}
void TestSQLDatabase::InsertNewMail(const MailInfo& mail) {
void TestSQLDatabase::InsertNewMail(const IMail::MailInfo& mail) {
}
@@ -192,11 +192,11 @@ void TestSQLDatabase::InsertNewUgcModel(std::istringstream& sd0Data, const uint3
}
std::vector<MailInfo> TestSQLDatabase::GetMailForPlayer(const uint32_t characterId, const uint32_t numberOfMail) {
std::vector<IMail::MailInfo> TestSQLDatabase::GetMailForPlayer(const uint32_t characterId, const uint32_t numberOfMail) {
return {};
}
std::optional<MailInfo> TestSQLDatabase::GetMail(const uint64_t mailId) {
std::optional<IMail::MailInfo> TestSQLDatabase::GetMail(const uint64_t mailId) {
return {};
}
@@ -236,7 +236,7 @@ void TestSQLDatabase::InsertNewAccount(const std::string_view username, const st
}
void TestSQLDatabase::SetMasterIp(const std::string_view ip, const uint32_t port) {
void TestSQLDatabase::SetMasterInfo(const IServers::MasterInfo& info) {
}

View File

@@ -56,14 +56,14 @@ class TestSQLDatabase : public GameDatabase {
void UpdatePerformanceCost(const LWOZONEID& zoneId, const float performanceCost) override;
void InsertNewBugReport(const IBugReports::Info& info) override;
void InsertCheatDetection(const IPlayerCheatDetections::Info& info) override;
void InsertNewMail(const MailInfo& mail) override;
void InsertNewMail(const IMail::MailInfo& mail) override;
void InsertNewUgcModel(
std::istringstream& sd0Data,
const uint32_t blueprintId,
const uint32_t accountId,
const uint32_t characterId) override;
std::vector<MailInfo> GetMailForPlayer(const uint32_t characterId, const uint32_t numberOfMail) override;
std::optional<MailInfo> GetMail(const uint64_t mailId) override;
std::vector<IMail::MailInfo> GetMailForPlayer(const uint32_t characterId, const uint32_t numberOfMail) override;
std::optional<IMail::MailInfo> GetMail(const uint64_t mailId) override;
uint32_t GetUnreadMailCount(const uint32_t characterId) override;
void MarkMailRead(const uint64_t mailId) override;
void DeleteMail(const uint64_t mailId) override;
@@ -73,7 +73,7 @@ class TestSQLDatabase : public GameDatabase {
void UpdateAccountBan(const uint32_t accountId, const bool banned) override;
void UpdateAccountPassword(const uint32_t accountId, const std::string_view bcryptpassword) override;
void InsertNewAccount(const std::string_view username, const std::string_view bcryptpassword) override;
void SetMasterIp(const std::string_view ip, const uint32_t port) override;
void SetMasterInfo(const IServers::MasterInfo& info) override;
std::optional<uint32_t> GetCurrentPersistentId() override;
void InsertDefaultPersistentId() override;
void UpdatePersistentId(const uint32_t id) override;

View File

@@ -786,7 +786,7 @@ void CharacterComponent::AwardClaimCodes() {
subject << "%[RewardCodes_" << rewardCode << "_subjectText]";
std::ostringstream body;
body << "%[RewardCodes_" << rewardCode << "_bodyText]";
Mail::SendMail(m_Parent, subject.str(), body.str(), attachmentLOT, 1);
Mail::SendMail(LWOOBJID_EMPTY, "%[MAIL_SYSTEM_NOTIFICATION]", m_Parent, subject.str(), body.str(), attachmentLOT, 1);
}
}

View File

@@ -274,7 +274,7 @@ void InventoryComponent::AddItem(
switch (sourceType) {
case 0:
Mail::SendMail(m_Parent, "%[MAIL_ACTIVITY_OVERFLOW_HEADER]", "%[MAIL_ACTIVITY_OVERFLOW_BODY]", lot, size);
Mail::SendMail(LWOOBJID_EMPTY, "Darkflame Universe", m_Parent, "Lost Reward", "You received an item and didn&apos;t have room for it.", lot, size);
break;
case 1:

View File

@@ -99,8 +99,17 @@ void MissionComponent::AcceptMission(const uint32_t missionId, const bool skipCh
mission->Accept();
this->m_Missions.insert_or_assign(missionId, mission);
if (missionId == 1728) {
//Needs to send a mail
auto address = m_Parent->GetSystemAddress();
Mail::HandleNotificationRequest(address, m_Parent->GetObjectID());
}
}
void MissionComponent::CompleteMission(const uint32_t missionId, const bool skipChecks, const bool yieldRewards) {
// Get the mission first
auto* mission = this->GetMission(missionId);

View File

@@ -84,11 +84,12 @@ dpEntity* PhysicsComponent::CreatePhysicsEntity(eReplicaComponentType type) {
} else if (info->physicsAsset == "env\\env_won_fv_gas-blocking-volume.hkx") {
toReturn = new dpEntity(m_Parent->GetObjectID(), 390.496826f, 111.467964f, 600.821534f, true);
m_Position.y -= (111.467964f * m_Parent->GetDefaultScale()) / 2;
} else if (info->physicsAsset == "env\\GFTrack_DeathVolume1_CaveExit.hkx") {
// Leaving these out for now since they cause more issues than they solve in racing tracks without proper OBB checks.
} /* else if (info->physicsAsset == "env\\GFTrack_DeathVolume1_CaveExit.hkx") {
toReturn = new dpEntity(m_Parent->GetObjectID(), 112.416870f, 50.363434f, 87.679268f);
} else if (info->physicsAsset == "env\\GFTrack_DeathVolume2_RoadGaps.hkx") {
toReturn = new dpEntity(m_Parent->GetObjectID(), 48.386536f, 50.363434f, 259.361755f);
} else {
} */ else {
// LOG_DEBUG("This one is supposed to have %s", info->physicsAsset.c_str());
//add fallback cube:

View File

@@ -105,16 +105,6 @@ void QuickBuildComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsIni
void QuickBuildComponent::Update(float deltaTime) {
SetActivator(GetActivator());
// Serialize the quickbuild every so often, fixes the odd bug where the quickbuild is not buildable
/*if (m_SoftTimer > 0.0f) {
m_SoftTimer -= deltaTime;
}
else {
m_SoftTimer = 5.0f;
Game::entityManager->SerializeEntity(m_Parent);
}*/
switch (m_State) {
case eQuickBuildState::OPEN: {
SpawnActivator();
@@ -125,11 +115,10 @@ void QuickBuildComponent::Update(float deltaTime) {
if (isSmashGroup) {
ModifyIncompleteTimer(deltaTime);
Game::entityManager->SerializeEntity(m_Parent);
// For reset times < 0 this has to be handled manually
if (m_TimeBeforeSmash > 0) {
if (m_TimerIncomplete >= m_TimeBeforeSmash - 4.0f) {
if (m_TimerIncomplete >= m_TimeBeforeSmash - 4.0f && !m_ShowResetEffect) {
SetShowResetEffect(true);
Game::entityManager->SerializeEntity(m_Parent);
@@ -149,11 +138,10 @@ void QuickBuildComponent::Update(float deltaTime) {
}
case eQuickBuildState::COMPLETED: {
ModifyTimer(deltaTime);
Game::entityManager->SerializeEntity(m_Parent);
// For reset times < 0 this has to be handled manually
if (m_ResetTime > 0) {
if (m_Timer >= m_ResetTime - 4.0f) {
if (m_Timer >= m_ResetTime - 4.0f && !m_ShowResetEffect) {
SetShowResetEffect(true);
Game::entityManager->SerializeEntity(m_Parent);
@@ -210,11 +198,10 @@ void QuickBuildComponent::Update(float deltaTime) {
}
case eQuickBuildState::INCOMPLETE: {
ModifyIncompleteTimer(deltaTime);
Game::entityManager->SerializeEntity(m_Parent);
// For reset times < 0 this has to be handled manually
if (m_TimeBeforeSmash > 0) {
if (m_TimerIncomplete >= m_TimeBeforeSmash - 4.0f) {
if (m_TimerIncomplete >= m_TimeBeforeSmash - 4.0f && !m_ShowResetEffect) {
SetShowResetEffect(true);
Game::entityManager->SerializeEntity(m_Parent);

View File

@@ -26,278 +26,12 @@
#include "eMissionTaskType.h"
#include "eReplicaComponentType.h"
#include "eConnectionType.h"
#include "User.h"
#include "StringifiedEnum.h"
namespace {
const std::string DefaultSender = "%[MAIL_SYSTEM_NOTIFICATION]";
}
namespace Mail {
std::map<eMessageID, std::function<std::unique_ptr<MailLUBitStream>()>> g_Handlers = {
{eMessageID::SendRequest, []() {
return std::make_unique<SendRequest>();
}},
{eMessageID::DataRequest, []() {
return std::make_unique<DataRequest>();
}},
{eMessageID::AttachmentCollectRequest, []() {
return std::make_unique<AttachmentCollectRequest>();
}},
{eMessageID::DeleteRequest, []() {
return std::make_unique<DeleteRequest>();
}},
{eMessageID::ReadRequest, []() {
return std::make_unique<ReadRequest>();
}},
{eMessageID::NotificationRequest, []() {
return std::make_unique<NotificationRequest>();
}},
};
void MailLUBitStream::Serialize(RakNet::BitStream& bitStream) const {
bitStream.Write(messageID);
}
bool MailLUBitStream::Deserialize(RakNet::BitStream& bitstream) {
VALIDATE_READ(bitstream.Read(messageID));
return true;
}
bool SendRequest::Deserialize(RakNet::BitStream& bitStream) {
VALIDATE_READ(mailInfo.Deserialize(bitStream));
return true;
}
void SendRequest::Handle() {
SendResponse response;
auto* character = player->GetCharacter();
if (character && !(character->HasPermission(ePermissionMap::RestrictedMailAccess) || character->GetParentUser()->GetIsMuted())) {
mailInfo.recipient = std::regex_replace(mailInfo.recipient, std::regex("[^0-9a-zA-Z]+"), "");
auto receiverID = Database::Get()->GetCharacterInfo(mailInfo.recipient);
if (!receiverID) {
response.status = eSendResponse::RecipientNotFound;
} else if (GeneralUtils::CaseInsensitiveStringCompare(mailInfo.recipient, character->GetName()) || receiverID->id == character->GetID()) {
response.status = eSendResponse::CannotMailSelf;
} else {
uint32_t mailCost = Game::zoneManager->GetWorldConfig()->mailBaseFee;
uint32_t stackSize = 0;
auto inventoryComponent = player->GetComponent<InventoryComponent>();
Item* item = nullptr;
bool hasAttachment = mailInfo.itemID != 0 && mailInfo.itemCount > 0;
if (hasAttachment) {
item = inventoryComponent->FindItemById(mailInfo.itemID);
if (item) {
mailCost += (item->GetInfo().baseValue * Game::zoneManager->GetWorldConfig()->mailPercentAttachmentFee);
mailInfo.itemLOT = item->GetLot();
}
}
if (hasAttachment && !item) {
response.status = eSendResponse::AttachmentNotFound;
} else if (player->GetCharacter()->GetCoins() - mailCost < 0) {
response.status = eSendResponse::NotEnoughCoins;
} else {
bool removeSuccess = true;
// Remove coins and items from the sender
player->GetCharacter()->SetCoins(player->GetCharacter()->GetCoins() - mailCost, eLootSourceType::MAIL);
if (inventoryComponent && hasAttachment && item) {
removeSuccess = inventoryComponent->RemoveItem(mailInfo.itemLOT, mailInfo.itemCount, INVALID, true);
auto* missionComponent = player->GetComponent<MissionComponent>();
if (missionComponent && removeSuccess) missionComponent->Progress(eMissionTaskType::GATHER, mailInfo.itemLOT, LWOOBJID_EMPTY, "", -mailInfo.itemCount);
}
// we passed all the checks, now we can actully send the mail
if (removeSuccess) {
mailInfo.senderId = character->GetID();
mailInfo.senderUsername = character->GetName();
mailInfo.receiverId = receiverID->id;
mailInfo.itemSubkey = LWOOBJID_EMPTY;
//clear out the attachementID
mailInfo.itemID = 0;
Database::Get()->InsertNewMail(mailInfo);
response.status = eSendResponse::Success;
character->SaveXMLToDatabase();
} else {
response.status = eSendResponse::AttachmentNotFound;
}
}
}
} else {
response.status = eSendResponse::SenderAccountIsMuted;
}
response.Send(sysAddr);
}
void SendResponse::Serialize(RakNet::BitStream& bitStream) const {
MailLUBitStream::Serialize(bitStream);
bitStream.Write(status);
}
void NotificationResponse::Serialize(RakNet::BitStream& bitStream) const {
MailLUBitStream::Serialize(bitStream);
bitStream.Write(status);
bitStream.Write<uint64_t>(0); // unused
bitStream.Write<uint64_t>(0); // unused
bitStream.Write(auctionID);
bitStream.Write<uint64_t>(0); // unused
bitStream.Write(mailCount);
bitStream.Write<uint32_t>(0); // packing
}
void DataRequest::Handle() {
const auto* character = player->GetCharacter();
if (!character) return;
auto playerMail = Database::Get()->GetMailForPlayer(character->GetID(), 20);
DataResponse response;
response.playerMail = playerMail;
response.Send(sysAddr);
}
void DataResponse::Serialize(RakNet::BitStream& bitStream) const {
MailLUBitStream::Serialize(bitStream);
bitStream.Write(this->throttled);
bitStream.Write<uint16_t>(this->playerMail.size());
bitStream.Write<uint16_t>(0); // packing
for (const auto& mail : this->playerMail) {
mail.Serialize(bitStream);
}
}
bool AttachmentCollectRequest::Deserialize(RakNet::BitStream& bitStream) {
uint32_t unknown;
VALIDATE_READ(bitStream.Read(unknown));
VALIDATE_READ(bitStream.Read(mailID));
VALIDATE_READ(bitStream.Read(playerID));
return true;
}
void AttachmentCollectRequest::Handle() {
AttachmentCollectResponse response;
auto inv = player->GetComponent<InventoryComponent>();
if (mailID > 0 && playerID == player->GetObjectID() && inv) {
auto playerMail = Database::Get()->GetMail(mailID);
if (!playerMail) {
response.status = eAttachmentCollectResponse::MailNotFound;
} else if (!inv->HasSpaceForLoot({ {playerMail->itemLOT, playerMail->itemCount} })) {
response.status = eAttachmentCollectResponse::NoSpaceInInventory;
} else {
inv->AddItem(playerMail->itemLOT, playerMail->itemCount, eLootSourceType::MAIL);
Database::Get()->ClaimMailItem(mailID);
response.status = eAttachmentCollectResponse::Success;
}
}
response.Send(sysAddr);
}
void AttachmentCollectResponse::Serialize(RakNet::BitStream& bitStream) const {
MailLUBitStream::Serialize(bitStream);
bitStream.Write(status);
bitStream.Write(mailID);
}
bool DeleteRequest::Deserialize(RakNet::BitStream& bitStream) {
int32_t unknown;
VALIDATE_READ(bitStream.Read(unknown));
VALIDATE_READ(bitStream.Read(mailID));
VALIDATE_READ(bitStream.Read(playerID));
return true;
}
void DeleteRequest::Handle() {
DeleteResponse response;
response.mailID = mailID;
auto mailData = Database::Get()->GetMail(mailID);
if (mailData && !(mailData->itemLOT != 0 && mailData->itemCount > 0)) {
Database::Get()->DeleteMail(mailID);
response.status = eDeleteResponse::Success;
} else if (mailData && mailData->itemLOT != 0 && mailData->itemCount > 0) {
response.status = eDeleteResponse::HasAttachments;
} else {
response.status = eDeleteResponse::NotFound;
}
response.Send(sysAddr);
}
void DeleteResponse::Serialize(RakNet::BitStream& bitStream) const {
MailLUBitStream::Serialize(bitStream);
bitStream.Write(status);
bitStream.Write(mailID);
}
bool ReadRequest::Deserialize(RakNet::BitStream& bitStream) {
int32_t unknown;
VALIDATE_READ(bitStream.Read(unknown));
VALIDATE_READ(bitStream.Read(mailID));
return true;
}
void ReadRequest::Handle() {
ReadResponse response;
response.mailID = mailID;
if (Database::Get()->GetMail(mailID)) {
response.status = eReadResponse::Success;
Database::Get()->MarkMailRead(mailID);
}
response.Send(sysAddr);
}
void ReadResponse::Serialize(RakNet::BitStream& bitStream) const {
MailLUBitStream::Serialize(bitStream);
bitStream.Write(status);
bitStream.Write(mailID);
}
void NotificationRequest::Handle() {
NotificationResponse response;
auto character = player->GetCharacter();
if (character) {
auto unreadMailCount = Database::Get()->GetUnreadMailCount(character->GetID());
response.status = eNotificationResponse::NewMail;
response.mailCount = unreadMailCount;
}
response.Send(sysAddr);
}
}
// Non Stuct Functions
void Mail::HandleMail(RakNet::BitStream& inStream, const SystemAddress& sysAddr, Entity* player) {
MailLUBitStream data;
if (!data.Deserialize(inStream)) {
LOG_DEBUG("Error Reading Mail header");
return;
}
auto it = g_Handlers.find(data.messageID);
if (it != g_Handlers.end()) {
auto request = it->second();
request->sysAddr = sysAddr;
request->player = player;
if (!request->Deserialize(inStream)) {
LOG_DEBUG("Error Reading Mail Request: %s", StringifiedEnum::ToString(data.messageID).data());
return;
}
request->Handle();
} else {
LOG_DEBUG("Unhandled Mail Request with ID: %i", data.messageID);
}
}
void Mail::SendMail(const Entity* recipient, const std::string& subject, const std::string& body, const LOT attachment,
const uint16_t attachmentCount) {
SendMail(
LWOOBJID_EMPTY,
DefaultSender,
ServerName,
recipient->GetObjectID(),
recipient->GetCharacter()->GetName(),
subject,
@@ -312,7 +46,7 @@ void Mail::SendMail(const LWOOBJID recipient, const std::string& recipientName,
const std::string& body, const LOT attachment, const uint16_t attachmentCount, const SystemAddress& sysAddr) {
SendMail(
LWOOBJID_EMPTY,
DefaultSender,
ServerName,
recipient,
recipientName,
subject,
@@ -341,7 +75,7 @@ void Mail::SendMail(const LWOOBJID sender, const std::string& senderName, const
void Mail::SendMail(const LWOOBJID sender, const std::string& senderName, LWOOBJID recipient,
const std::string& recipientName, const std::string& subject, const std::string& body, const LOT attachment,
const uint16_t attachmentCount, const SystemAddress& sysAddr) {
MailInfo mailInsert;
IMail::MailInfo mailInsert;
mailInsert.senderUsername = senderName;
mailInsert.recipient = recipientName;
mailInsert.subject = subject;
@@ -356,7 +90,316 @@ void Mail::SendMail(const LWOOBJID sender, const std::string& senderName, LWOOBJ
Database::Get()->InsertNewMail(mailInsert);
if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) return; // TODO: Echo to chat server
NotificationResponse response;
response.status = eNotificationResponse::NewMail;
response.Send(sysAddr);
SendNotification(sysAddr, 1); //Show the "one new mail" message
}
void Mail::HandleMailStuff(RakNet::BitStream& packet, const SystemAddress& sysAddr, Entity* entity) {
int mailStuffID = 0;
packet.Read(mailStuffID);
auto returnVal = std::async(std::launch::async, [&packet, &sysAddr, entity, mailStuffID]() {
Mail::MailMessageID stuffID = MailMessageID(mailStuffID);
switch (stuffID) {
case MailMessageID::AttachmentCollect:
Mail::HandleAttachmentCollect(packet, sysAddr, entity);
break;
case MailMessageID::DataRequest:
Mail::HandleDataRequest(packet, sysAddr, entity);
break;
case MailMessageID::MailDelete:
Mail::HandleMailDelete(packet, sysAddr);
break;
case MailMessageID::MailRead:
Mail::HandleMailRead(packet, sysAddr);
break;
case MailMessageID::NotificationRequest:
Mail::HandleNotificationRequest(sysAddr, entity->GetObjectID());
break;
case MailMessageID::Send:
Mail::HandleSendMail(packet, sysAddr, entity);
break;
default:
LOG("Unhandled and possibly undefined MailStuffID: %i", int(stuffID));
}
});
}
void Mail::HandleSendMail(RakNet::BitStream& packet, const SystemAddress& sysAddr, Entity* entity) {
//std::string subject = GeneralUtils::WStringToString(ReadFromPacket(packet, 50));
//std::string body = GeneralUtils::WStringToString(ReadFromPacket(packet, 400));
//std::string recipient = GeneralUtils::WStringToString(ReadFromPacket(packet, 32));
// Check if the player has restricted mail access
auto* character = entity->GetCharacter();
if (!character) return;
if (character->HasPermission(ePermissionMap::RestrictedMailAccess)) {
// Send a message to the player
ChatPackets::SendSystemMessage(
sysAddr,
u"This character has restricted mail access."
);
Mail::SendSendResponse(sysAddr, Mail::MailSendResponse::AccountIsMuted);
return;
}
LUWString subjectRead(50);
packet.Read(subjectRead);
LUWString bodyRead(400);
packet.Read(bodyRead);
LUWString recipientRead(32);
packet.Read(recipientRead);
const std::string subject = subjectRead.GetAsString();
const std::string body = bodyRead.GetAsString();
//Cleanse recipient:
const std::string recipient = std::regex_replace(recipientRead.GetAsString(), std::regex("[^0-9a-zA-Z]+"), "");
uint64_t unknown64 = 0;
LWOOBJID attachmentID;
uint16_t attachmentCount;
packet.Read(unknown64);
packet.Read(attachmentID);
packet.Read(attachmentCount); //We don't care about the rest of the packet.
uint32_t itemID = static_cast<uint32_t>(attachmentID);
LOT itemLOT = 0;
//Inventory::InventoryType itemType;
int mailCost = Game::zoneManager->GetWorldConfig()->mailBaseFee;
int stackSize = 0;
auto inv = static_cast<InventoryComponent*>(entity->GetComponent(eReplicaComponentType::INVENTORY));
Item* item = nullptr;
if (itemID > 0 && attachmentCount > 0 && inv) {
item = inv->FindItemById(attachmentID);
if (item) {
mailCost += (item->GetInfo().baseValue * Game::zoneManager->GetWorldConfig()->mailPercentAttachmentFee);
stackSize = item->GetCount();
itemLOT = item->GetLot();
} else {
Mail::SendSendResponse(sysAddr, MailSendResponse::AttachmentNotFound);
return;
}
}
//Check if we can even send this mail (negative coins bug):
if (entity->GetCharacter()->GetCoins() - mailCost < 0) {
Mail::SendSendResponse(sysAddr, MailSendResponse::NotEnoughCoins);
return;
}
//Get the receiver's id:
auto receiverID = Database::Get()->GetCharacterInfo(recipient);
if (!receiverID) {
Mail::SendSendResponse(sysAddr, Mail::MailSendResponse::RecipientNotFound);
return;
}
//Check if we have a valid receiver:
if (GeneralUtils::CaseInsensitiveStringCompare(recipient, character->GetName()) || receiverID->id == character->GetID()) {
Mail::SendSendResponse(sysAddr, Mail::MailSendResponse::CannotMailSelf);
return;
} else {
IMail::MailInfo mailInsert;
mailInsert.senderUsername = character->GetName();
mailInsert.recipient = recipient;
mailInsert.subject = subject;
mailInsert.body = body;
mailInsert.senderId = character->GetID();
mailInsert.receiverId = receiverID->id;
mailInsert.itemCount = attachmentCount;
mailInsert.itemID = itemID;
mailInsert.itemLOT = itemLOT;
mailInsert.itemSubkey = LWOOBJID_EMPTY;
Database::Get()->InsertNewMail(mailInsert);
}
Mail::SendSendResponse(sysAddr, Mail::MailSendResponse::Success);
entity->GetCharacter()->SetCoins(entity->GetCharacter()->GetCoins() - mailCost, eLootSourceType::MAIL);
LOG("Seeing if we need to remove item with ID/count/LOT: %i %i %i", itemID, attachmentCount, itemLOT);
if (inv && itemLOT != 0 && attachmentCount > 0 && item) {
LOG("Trying to remove item with ID/count/LOT: %i %i %i", itemID, attachmentCount, itemLOT);
inv->RemoveItem(itemLOT, attachmentCount, INVALID, true);
auto* missionCompoent = entity->GetComponent<MissionComponent>();
if (missionCompoent != nullptr) {
missionCompoent->Progress(eMissionTaskType::GATHER, itemLOT, LWOOBJID_EMPTY, "", -attachmentCount);
}
}
character->SaveXMLToDatabase();
}
void Mail::HandleDataRequest(RakNet::BitStream& packet, const SystemAddress& sysAddr, Entity* player) {
auto playerMail = Database::Get()->GetMailForPlayer(player->GetCharacter()->GetID(), 20);
RakNet::BitStream bitStream;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::MAIL);
bitStream.Write(int(MailMessageID::MailData));
bitStream.Write(int(0)); // throttled
bitStream.Write<uint16_t>(playerMail.size()); // size
bitStream.Write<uint16_t>(0);
for (const auto& mail : playerMail) {
bitStream.Write(mail.id); //MailID
const LUWString subject(mail.subject, 50);
bitStream.Write(subject); //subject
const LUWString body(mail.body, 400);
bitStream.Write(body); //body
const LUWString sender(mail.senderUsername, 32);
bitStream.Write(sender); //sender
bitStream.Write(uint32_t(0)); // packing
bitStream.Write(uint64_t(0)); // attachedCurrency
bitStream.Write(mail.itemID); //Attachment ID
LOT lot = mail.itemLOT;
if (lot <= 0) bitStream.Write(LOT(-1));
else bitStream.Write(lot);
bitStream.Write(uint32_t(0)); // packing
bitStream.Write(mail.itemSubkey); // Attachment subKey
bitStream.Write<uint16_t>(mail.itemCount); // Attachment count
bitStream.Write(uint8_t(0)); // subject type (used for auction)
bitStream.Write(uint8_t(0)); // packing
bitStream.Write(uint32_t(0)); // packing
bitStream.Write<uint64_t>(mail.timeSent); // expiration date
bitStream.Write<uint64_t>(mail.timeSent);// send date
bitStream.Write<uint8_t>(mail.wasRead); //was read
bitStream.Write(uint8_t(0)); // isLocalized
bitStream.Write(uint16_t(0)); // packing
bitStream.Write(uint32_t(0)); // packing
}
Game::server->Send(bitStream, sysAddr, false);
}
void Mail::HandleAttachmentCollect(RakNet::BitStream& packet, const SystemAddress& sysAddr, Entity* player) {
int unknown;
uint64_t mailID;
LWOOBJID playerID;
packet.Read(unknown);
packet.Read(mailID);
packet.Read(playerID);
if (mailID > 0 && playerID == player->GetObjectID()) {
auto playerMail = Database::Get()->GetMail(mailID);
LOT attachmentLOT = 0;
uint32_t attachmentCount = 0;
if (playerMail) {
attachmentLOT = playerMail->itemLOT;
attachmentCount = playerMail->itemCount;
}
auto inv = player->GetComponent<InventoryComponent>();
if (!inv) return;
inv->AddItem(attachmentLOT, attachmentCount, eLootSourceType::MAIL);
Mail::SendAttachmentRemoveConfirm(sysAddr, mailID);
Database::Get()->ClaimMailItem(mailID);
}
}
void Mail::HandleMailDelete(RakNet::BitStream& packet, const SystemAddress& sysAddr) {
int unknown;
uint64_t mailID;
LWOOBJID playerID;
packet.Read(unknown);
packet.Read(mailID);
packet.Read(playerID);
if (mailID > 0) Mail::SendDeleteConfirm(sysAddr, mailID, playerID);
}
void Mail::HandleMailRead(RakNet::BitStream& packet, const SystemAddress& sysAddr) {
int unknown;
uint64_t mailID;
packet.Read(unknown);
packet.Read(mailID);
if (mailID > 0) Mail::SendReadConfirm(sysAddr, mailID);
}
void Mail::HandleNotificationRequest(const SystemAddress& sysAddr, uint32_t objectID) {
auto unreadMailCount = Database::Get()->GetUnreadMailCount(objectID);
if (unreadMailCount > 0) Mail::SendNotification(sysAddr, unreadMailCount);
}
void Mail::SendSendResponse(const SystemAddress& sysAddr, MailSendResponse response) {
RakNet::BitStream bitStream;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::MAIL);
bitStream.Write(int(MailMessageID::SendResponse));
bitStream.Write(int(response));
Game::server->Send(bitStream, sysAddr, false);
}
void Mail::SendNotification(const SystemAddress& sysAddr, int mailCount) {
RakNet::BitStream bitStream;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::MAIL);
uint64_t messageType = 2;
uint64_t s1 = 0;
uint64_t s2 = 0;
uint64_t s3 = 0;
uint64_t s4 = 0;
bitStream.Write(messageType);
bitStream.Write(s1);
bitStream.Write(s2);
bitStream.Write(s3);
bitStream.Write(s4);
bitStream.Write(mailCount);
bitStream.Write(int(0)); //Unknown
Game::server->Send(bitStream, sysAddr, false);
}
void Mail::SendAttachmentRemoveConfirm(const SystemAddress& sysAddr, uint64_t mailID) {
RakNet::BitStream bitStream;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::MAIL);
bitStream.Write(int(MailMessageID::AttachmentCollectConfirm));
bitStream.Write(int(0)); //unknown
bitStream.Write(mailID);
Game::server->Send(bitStream, sysAddr, false);
}
void Mail::SendDeleteConfirm(const SystemAddress& sysAddr, uint64_t mailID, LWOOBJID playerID) {
RakNet::BitStream bitStream;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::MAIL);
bitStream.Write(int(MailMessageID::MailDeleteConfirm));
bitStream.Write(int(0)); //unknown
bitStream.Write(mailID);
Game::server->Send(bitStream, sysAddr, false);
Database::Get()->DeleteMail(mailID);
}
void Mail::SendReadConfirm(const SystemAddress& sysAddr, uint64_t mailID) {
RakNet::BitStream bitStream;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::MAIL);
bitStream.Write(int(MailMessageID::MailReadConfirm));
bitStream.Write(int(0)); //unknown
bitStream.Write(mailID);
Game::server->Send(bitStream, sysAddr, false);
Database::Get()->MarkMailRead(mailID);
}

View File

@@ -1,210 +1,43 @@
#ifndef __MAIL_H__
#define __MAIL_H__
#include <cstdint>
#pragma once
#include "BitStream.h"
#include "RakNetTypes.h"
#include "dCommonVars.h"
#include "BitStreamUtils.h"
#include "MailInfo.h"
class Entity;
namespace Mail {
enum class eMessageID : uint32_t {
SendRequest = 0,
SendResponse,
NotificationResponse,
DataRequest,
DataResponse,
AttachmentCollectRequest,
AttachmentCollectResponse,
DeleteRequest,
DeleteResponse,
ReadRequest,
ReadResponse,
NotificationRequest,
AuctionCreate,
AuctionCreationResponse,
AuctionCancel,
AuctionCancelResponse,
AuctionList,
AuctionListResponse,
AuctionBid,
AuctionBidResponse,
UnknownError
enum class MailMessageID {
Send = 0x00,
SendResponse = 0x01,
DataRequest = 0x03,
MailData = 0x04,
AttachmentCollect = 0x05,
AttachmentCollectConfirm = 0x06,
MailDelete = 0x07,
MailDeleteConfirm = 0x08,
MailRead = 0x09,
MailReadConfirm = 0x0a,
NotificationRequest = 0x0b
};
enum class eSendResponse : uint32_t {
enum class MailSendResponse {
Success = 0,
NotEnoughCoins,
AttachmentNotFound,
ItemCannotBeMailed,
CannotMailSelf,
RecipientNotFound,
RecipientDifferentFaction,
UnHandled7,
DifferentFaction,
Unknown,
ModerationFailure,
SenderAccountIsMuted,
UnHandled10,
AccountIsMuted,
UnknownFailure,
RecipientIsIgnored,
UnHandled12,
RecipientIsFTP,
UnknownError
UnknownFailure3,
RecipientIsFTP
};
enum class eDeleteResponse : uint32_t {
Success = 0,
HasAttachments,
NotFound,
Throttled,
UnknownError
};
enum class eAttachmentCollectResponse : uint32_t {
Success = 0,
AttachmentNotFound,
NoSpaceInInventory,
MailNotFound,
Throttled,
UnknownError
};
enum class eNotificationResponse : uint32_t {
NewMail = 0,
UnHandled,
AuctionWon,
AuctionSold,
AuctionOutbided,
AuctionExpired,
AuctionCancelled,
AuctionUpdated,
UnknownError
};
enum class eReadResponse : uint32_t {
Success = 0,
UnknownError
};
enum class eAuctionCreateResponse : uint32_t {
Success = 0,
NotEnoughMoney,
ItemNotFound,
ItemNotSellable,
UnknownError
};
enum class eAuctionCancelResponse : uint32_t {
NotFound = 0,
NotYours,
HasBid,
NoLongerExists,
UnknownError
};
struct MailLUBitStream : public LUBitStream {
eMessageID messageID = eMessageID::UnknownError;
SystemAddress sysAddr = UNASSIGNED_SYSTEM_ADDRESS;
Entity* player = nullptr;
MailLUBitStream() = default;
MailLUBitStream(eMessageID _messageID) : LUBitStream(eConnectionType::CLIENT, MessageType::Client::MAIL), messageID{_messageID} {};
virtual void Serialize(RakNet::BitStream& bitStream) const override;
virtual bool Deserialize(RakNet::BitStream& bitStream) override;
virtual void Handle() override {};
};
struct SendRequest : public MailLUBitStream {
MailInfo mailInfo;
bool Deserialize(RakNet::BitStream& bitStream) override;
void Handle() override;
};
struct SendResponse :public MailLUBitStream {
eSendResponse status = eSendResponse::UnknownError;
void Serialize(RakNet::BitStream& bitStream) const override;
};
struct NotificationResponse : public MailLUBitStream {
eNotificationResponse status = eNotificationResponse::UnknownError;
LWOOBJID auctionID = LWOOBJID_EMPTY;
uint32_t mailCount = 1;
NotificationResponse() : MailLUBitStream(eMessageID::NotificationResponse) {};
void Serialize(RakNet::BitStream& bitStream) const override;
};
struct DataRequest : public MailLUBitStream {
bool Deserialize(RakNet::BitStream& bitStream) override { return true; };
void Handle() override;
};
struct DataResponse : public MailLUBitStream {
uint32_t throttled = 0;
std::vector<MailInfo> playerMail;
DataResponse() : MailLUBitStream(eMessageID::DataResponse) {};
void Serialize(RakNet::BitStream& bitStream) const override;
};
struct AttachmentCollectRequest : public MailLUBitStream {
uint64_t mailID = 0;
LWOOBJID playerID = LWOOBJID_EMPTY;
AttachmentCollectRequest() : MailLUBitStream(eMessageID::AttachmentCollectRequest) {};
bool Deserialize(RakNet::BitStream& bitStream) override;
void Handle() override;
};
struct AttachmentCollectResponse : public MailLUBitStream {
eAttachmentCollectResponse status = eAttachmentCollectResponse::UnknownError;
uint64_t mailID = 0;
AttachmentCollectResponse() : MailLUBitStream(eMessageID::AttachmentCollectResponse) {};
void Serialize(RakNet::BitStream& bitStream) const override;
};
struct DeleteRequest : public MailLUBitStream {
uint64_t mailID = 0;
LWOOBJID playerID = LWOOBJID_EMPTY;
DeleteRequest() : MailLUBitStream(eMessageID::DeleteRequest) {};
bool Deserialize(RakNet::BitStream& bitStream) override;
void Handle() override;
};
struct DeleteResponse : public MailLUBitStream {
eDeleteResponse status = eDeleteResponse::UnknownError;
uint64_t mailID = 0;
DeleteResponse() : MailLUBitStream(eMessageID::DeleteResponse) {};
void Serialize(RakNet::BitStream& bitStream) const override;
};
struct ReadRequest : public MailLUBitStream {
uint64_t mailID = 0;
ReadRequest() : MailLUBitStream(eMessageID::ReadRequest) {};
bool Deserialize(RakNet::BitStream& bitStream) override;
void Handle() override;
};
struct ReadResponse : public MailLUBitStream {
uint64_t mailID = 0;
eReadResponse status = eReadResponse::UnknownError;
ReadResponse() : MailLUBitStream(eMessageID::ReadResponse) {};
void Serialize(RakNet::BitStream& bitStream) const override;
};
struct NotificationRequest : public MailLUBitStream {
NotificationRequest() : MailLUBitStream(eMessageID::NotificationRequest) {};
bool Deserialize(RakNet::BitStream& bitStream) override { return true; };
void Handle() override;
};
void HandleMail(RakNet::BitStream& inStream, const SystemAddress& sysAddr, Entity* player);
const std::string ServerName = "Darkflame Universe";
void SendMail(
const Entity* recipient,
@@ -245,6 +78,18 @@ namespace Mail {
uint16_t attachmentCount,
const SystemAddress& sysAddr
);
void HandleMailStuff(RakNet::BitStream& packet, const SystemAddress& sysAddr, Entity* entity);
void HandleSendMail(RakNet::BitStream& packet, const SystemAddress& sysAddr, Entity* entity);
void HandleDataRequest(RakNet::BitStream& packet, const SystemAddress& sysAddr, Entity* player);
void HandleAttachmentCollect(RakNet::BitStream& packet, const SystemAddress& sysAddr, Entity* player);
void HandleMailDelete(RakNet::BitStream& packet, const SystemAddress& sysAddr);
void HandleMailRead(RakNet::BitStream& packet, const SystemAddress& sysAddr);
void HandleNotificationRequest(const SystemAddress& sysAddr, uint32_t objectID);
void SendSendResponse(const SystemAddress& sysAddr, MailSendResponse response);
void SendNotification(const SystemAddress& sysAddr, int mailCount);
void SendAttachmentRemoveConfirm(const SystemAddress& sysAddr, uint64_t mailID);
void SendDeleteConfirm(const SystemAddress& sysAddr, uint64_t mailID, LWOOBJID playerID);
void SendReadConfirm(const SystemAddress& sysAddr, uint64_t mailID);
};
#endif // !__MAIL_H__

View File

@@ -996,7 +996,7 @@ void SlashCommandHandler::Startup() {
Command RequestMailCountCommand{
.help = "Gets the players mail count",
.info = "Sends notification with number of unread messages in the player's mailbox",
.aliases = { "requestmailcount", "checkmail" },
.aliases = { "requestmailcount" },
.handle = GMZeroCommands::RequestMailCount,
.requiredLevel = eGameMasterLevel::CIVILIAN
};

View File

@@ -102,7 +102,7 @@ namespace GMGreaterThanZeroCommands {
return;
}
MailInfo mailInsert;
IMail::MailInfo mailInsert;
mailInsert.senderId = entity->GetObjectID();
mailInsert.senderUsername = "Darkflame Universe";
mailInsert.receiverId = receiverID;

View File

@@ -12,7 +12,6 @@
#include "VanityUtilities.h"
#include "WorldPackets.h"
#include "ZoneInstanceManager.h"
#include "Database.h"
// Components
#include "BuffComponent.h"
@@ -217,10 +216,7 @@ namespace GMZeroCommands {
}
void RequestMailCount(Entity* entity, const SystemAddress& sysAddr, const std::string args) {
Mail::NotificationResponse response;
response.status = Mail::eNotificationResponse::NewMail;
response.mailCount = Database::Get()->GetUnreadMailCount(entity->GetCharacter()->GetID());
response.Send(sysAddr);
Mail::HandleNotificationRequest(entity->GetSystemAddress(), entity->GetObjectID());
}
void InstanceInfo(Entity* entity, const SystemAddress& sysAddr, const std::string args) {

View File

@@ -62,6 +62,14 @@ std::map<uint32_t, std::string> activeSessions;
SystemAddress authServerMasterPeerSysAddr;
SystemAddress chatServerMasterPeerSysAddr;
int GenerateBCryptPassword(const std::string& password, const int workFactor, char salt[BCRYPT_HASHSIZE], char hash[BCRYPT_HASHSIZE]) {
int32_t bcryptState = ::bcrypt_gensalt(workFactor, salt);
assert(bcryptState == 0);
bcryptState = ::bcrypt_hashpw(password.c_str(), salt, hash);
assert(bcryptState == 0);
return 0;
}
int main(int argc, char** argv) {
constexpr uint32_t masterFramerate = mediumFramerate;
constexpr uint32_t masterFrameDelta = mediumFrameDelta;
@@ -94,7 +102,7 @@ int main(int argc, char** argv) {
std::string(folder) +
") folder from your download to the binary directory or re-run cmake.";
LOG("%s", msg.c_str());
// toss an error box up for windows users running the download
// toss an error box up for windows users running the download
#ifdef DARKFLAME_PLATFORM_WIN32
MessageBoxA(nullptr, msg.c_str(), "Missing Folder", MB_OK | MB_ICONERROR);
#endif
@@ -238,10 +246,7 @@ int main(int argc, char** argv) {
// Regenerate hash based on new password
char salt[BCRYPT_HASHSIZE];
char hash[BCRYPT_HASHSIZE];
int32_t bcryptState = ::bcrypt_gensalt(12, salt);
assert(bcryptState == 0);
bcryptState = ::bcrypt_hashpw(password.c_str(), salt, hash);
assert(bcryptState == 0);
assert(GenerateBCryptPassword(password, 12, salt, hash) == 0);
Database::Get()->UpdateAccountPassword(accountId->id, std::string(hash, BCRYPT_HASHSIZE));
@@ -279,10 +284,7 @@ int main(int argc, char** argv) {
//Generate new hash for bcrypt
char salt[BCRYPT_HASHSIZE];
char hash[BCRYPT_HASHSIZE];
int32_t bcryptState = ::bcrypt_gensalt(12, salt);
assert(bcryptState == 0);
bcryptState = ::bcrypt_hashpw(password.c_str(), salt, hash);
assert(bcryptState == 0);
assert(GenerateBCryptPassword(password, 12, salt, hash) == 0);
//Create account
try {
@@ -318,15 +320,24 @@ int main(int argc, char** argv) {
const auto externalIPString = Game::config->GetValue("external_ip");
if (!externalIPString.empty()) ourIP = externalIPString;
Game::server = new dServer(ourIP, ourPort, 0, maxClients, true, false, Game::logger, "", 0, ServerType::Master, Game::config, &Game::lastSignal);
char salt[BCRYPT_HASHSIZE];
char hash[BCRYPT_HASHSIZE];
const auto& cfgPassword = Game::config->GetValue("master_password");
GenerateBCryptPassword(!cfgPassword.empty() ? cfgPassword : "3.25DARKFLAME1", 13, salt, hash);
Game::server = new dServer(ourIP, ourPort, 0, maxClients, true, false, Game::logger, "", 0, ServerType::Master, Game::config, &Game::lastSignal, hash);
std::string master_server_ip = "localhost";
const auto masterServerIPString = Game::config->GetValue("master_ip");
if (!masterServerIPString.empty()) master_server_ip = masterServerIPString;
if (master_server_ip == "") master_server_ip = Game::server->GetIP();
IServers::MasterInfo info;
info.ip = master_server_ip;
info.port = Game::server->GetPort();
info.password = hash;
Database::Get()->SetMasterIp(master_server_ip, Game::server->GetPort());
Database::Get()->SetMasterInfo(info);
//Create additional objects here:
PersistentIDManager::Initialize();

View File

@@ -1,30 +0,0 @@
#include "BitStreamUtils.h"
#include "dServer.h"
#include "BitStream.h"
#include "PacketUtils.h"
void LUBitStream::WriteHeader(RakNet::BitStream& bitStream) const {
bitStream.Write<MessageID>(ID_USER_PACKET_ENUM);
bitStream.Write(this->connectionType);
bitStream.Write(this->internalPacketID);
bitStream.Write<uint8_t>(0); // padding
}
bool LUBitStream::ReadHeader(RakNet::BitStream& bitStream) {
MessageID messageID;
bitStream.Read(messageID);
if (messageID != ID_USER_PACKET_ENUM) return false;
VALIDATE_READ(bitStream.Read(this->connectionType));
VALIDATE_READ(bitStream.Read(this->internalPacketID));
uint8_t padding;
VALIDATE_READ(bitStream.Read<uint8_t>(padding));
return true;
}
void LUBitStream::Send(const SystemAddress& sysAddr) const {
RakNet::BitStream bitStream;
this->WriteHeader(bitStream);
this->Serialize(bitStream);
Game::server->Send(bitStream, sysAddr, sysAddr == UNASSIGNED_SYSTEM_ADDRESS);
}

View File

@@ -2,13 +2,12 @@
#define __BITSTREAMUTILS__H__
#include "GeneralUtils.h"
#include "BitStream.h"
#include "MessageIdentifiers.h"
#include "eConnectionType.h"
#include "BitStream.h"
#include <string>
#include <algorithm>
#define VALIDATE_READ(x) do { if (!x) return false; } while (0)
enum class eConnectionType : uint16_t;
struct LUString {
std::string string;
@@ -46,28 +45,6 @@ struct LUWString {
};
};
struct LUBitStream {
eConnectionType connectionType = eConnectionType::UNKNOWN;
uint32_t internalPacketID = 0xFFFFFFFF;
LUBitStream() = default;
template <typename T>
LUBitStream(eConnectionType connectionType, T internalPacketID) {
this->connectionType = connectionType;
this->internalPacketID = static_cast<uint32_t>(internalPacketID);
}
void WriteHeader(RakNet::BitStream& bitStream) const;
bool ReadHeader(RakNet::BitStream& bitStream);
void Send(const SystemAddress& sysAddr) const;
virtual void Serialize(RakNet::BitStream& bitStream) const {}
virtual bool Deserialize(RakNet::BitStream& bitStream) { return true; }
virtual void Handle() {};
};
namespace BitStreamUtils {
template<typename T>
void WriteHeader(RakNet::BitStream& bitStream, eConnectionType connectionType, T internalPacketID) {
@@ -76,6 +53,7 @@ namespace BitStreamUtils {
bitStream.Write(static_cast<uint32_t>(internalPacketID));
bitStream.Write<uint8_t>(0);
}
}
namespace RakNet {

View File

@@ -1,9 +1,7 @@
set(DNET_SOURCES "AuthPackets.cpp"
"BitStreamUtils.cpp"
"ChatPackets.cpp"
"ClientPackets.cpp"
"dServer.cpp"
"MailInfo.cpp"
"MasterPackets.cpp"
"PacketUtils.cpp"
"WorldPackets.cpp"

View File

@@ -1,63 +0,0 @@
#include "MailInfo.h"
#include "BitStream.h"
#include "DluAssert.h"
void MailInfo::Serialize(RakNet::BitStream& bitStream) const {
bitStream.Write(id);
const LUWString subject(this->subject, 50);
bitStream.Write(subject);
const LUWString body(this->body, 400);
bitStream.Write(body);
const LUWString sender(this->senderUsername, 32);
bitStream.Write(sender);
bitStream.Write<uint32_t>(0); // packing
bitStream.Write<uint64_t>(0); // attachedCurrency
bitStream.Write(itemID);
LOT lot = itemLOT;
if (lot <= 0) bitStream.Write<LOT>(LOT_NULL);
else bitStream.Write(lot);
bitStream.Write<uint32_t>(0); // packing
bitStream.Write(itemSubkey);
bitStream.Write(itemCount);
bitStream.Write<uint8_t>(0); // subject type (used for auction)
bitStream.Write<uint8_t>(0); // packing
bitStream.Write<uint32_t>(0); // packing
bitStream.Write<uint64_t>(timeSent); // expiration date
bitStream.Write<uint64_t>(timeSent);// send date
bitStream.Write<uint8_t>(wasRead); // was read
bitStream.Write<uint8_t>(0); // isLocalized
bitStream.Write<uint16_t>(1033); // language code
bitStream.Write<uint32_t>(0); // packing
}
bool MailInfo::Deserialize(RakNet::BitStream& bitStream) {
LUWString subject(50);
VALIDATE_READ(bitStream.Read(subject));
this->subject = subject.GetAsString();
LUWString body(400);
VALIDATE_READ(bitStream.Read(body));
this->body = body.GetAsString();
LUWString recipientName(32);
VALIDATE_READ(bitStream.Read(recipientName));
this->recipient = recipientName.GetAsString();
uint64_t unknown;
VALIDATE_READ(bitStream.Read(unknown));
VALIDATE_READ(bitStream.Read(itemID));
VALIDATE_READ(bitStream.Read(itemCount));
VALIDATE_READ(bitStream.Read(languageCode));
bitStream.IgnoreBytes(4); // padding
DluAssert(bitStream.GetNumberOfUnreadBits() == 0);
return true;
}

View File

@@ -1,34 +0,0 @@
#ifndef __MAILINFO_H__
#define __MAILINFO_H__
#include <string>
#include <cstdint>
#include "dCommonVars.h"
namespace RakNet {
class BitStream;
}
struct MailInfo {
std::string senderUsername;
std::string recipient;
std::string subject;
std::string body;
uint64_t id{};
uint32_t senderId{};
uint32_t receiverId{};
uint64_t timeSent{};
bool wasRead{};
uint16_t languageCode{};
struct {
LWOOBJID itemID{};
int16_t itemCount{};
LOT itemLOT{};
LWOOBJID itemSubkey{};
};
void Serialize(RakNet::BitStream& bitStream) const;
bool Deserialize(RakNet::BitStream& bitStream);
};
#endif // __MAILINFO_H__

View File

@@ -3,4 +3,3 @@
#include "RakPeer.h"
#define NET_PASSWORD_EXTERNAL "3.25 ND1"
#define NET_PASSWORD_INTERNAL "3.25 DARKFLAME1"

View File

@@ -40,7 +40,21 @@ public:
}
} ReceiveDownloadCompleteCB;
dServer::dServer(const std::string& ip, int port, int instanceID, int maxConnections, bool isInternal, bool useEncryption, Logger* logger, const std::string masterIP, int masterPort, ServerType serverType, dConfig* config, Game::signal_t* lastSignal, unsigned int zoneID) {
dServer::dServer(
const std::string& ip,
int port,
int instanceID,
int maxConnections,
bool isInternal,
bool useEncryption,
Logger* logger,
const std::string masterIP,
int masterPort,
ServerType serverType,
dConfig* config,
Game::signal_t* lastSignal,
const std::string& masterPassword,
unsigned int zoneID) {
mIP = ip;
mPort = port;
mZoneID = zoneID;
@@ -56,6 +70,7 @@ dServer::dServer(const std::string& ip, int port, int instanceID, int maxConnect
mReplicaManager = nullptr;
mServerType = serverType;
mConfig = config;
mMasterPassword = masterPassword;
mShouldShutdown = lastSignal;
//Attempt to start our server here:
mIsOkay = Startup();
@@ -203,11 +218,11 @@ bool dServer::Startup() {
if (!mPeer->Startup(mMaxConnections, 10, &mSocketDescriptor, 1)) return false;
if (mIsInternal) {
mPeer->SetIncomingPassword("3.25 DARKFLAME1", 15);
mPeer->SetIncomingPassword(mMasterPassword.c_str(), mMasterPassword.size());
} else {
UpdateBandwidthLimit();
UpdateMaximumMtuSize();
mPeer->SetIncomingPassword("3.25 ND1", 8);
mPeer->SetIncomingPassword(NET_PASSWORD_EXTERNAL, strnlen(NET_PASSWORD_EXTERNAL, sizeof(NET_PASSWORD_EXTERNAL)));
}
mPeer->SetMaximumIncomingConnections(mMaxConnections);
@@ -257,7 +272,7 @@ void dServer::SetupForMasterConnection() {
bool dServer::ConnectToMaster() {
//LOG("Connection to Master %s:%d", mMasterIP.c_str(), mMasterPort);
return mMasterPeer->Connect(mMasterIP.c_str(), mMasterPort, "3.25 DARKFLAME1", 15);
return mMasterPeer->Connect(mMasterIP.c_str(), mMasterPort, mMasterPassword.c_str(), mMasterPassword.size());
}
void dServer::UpdateReplica() {

View File

@@ -46,6 +46,7 @@ public:
ServerType serverType,
dConfig* config,
Game::signal_t* shouldShutdown,
const std::string& masterPassword,
unsigned int zoneID = 0);
~dServer();
@@ -121,4 +122,5 @@ protected:
std::string mMasterIP;
int mMasterPort;
std::chrono::steady_clock::time_point mStartTime = std::chrono::steady_clock::now();
std::string mMasterPassword;
};

View File

@@ -10,49 +10,38 @@ void NsLegoClubDoor::OnStartup(Entity* self) {
self->SetVar(u"teleportString", m_TeleportString);
self->SetVar(u"spawnPoint", m_SpawnPoint);
args = {};
teleportArgs.Reset();
args.Insert("callbackClient", std::to_string(self->GetObjectID()));
args.Insert("strIdentifier", "choiceDoor");
args.Insert("title", "%[UI_CHOICE_DESTINATION]");
teleportArgs.Insert("callbackClient", std::to_string(self->GetObjectID()));
teleportArgs.Insert("strIdentifier", "choiceDoor");
teleportArgs.Insert("title", "%[UI_CHOICE_DESTINATION]");
AMFArrayValue* choiceOptions = args.InsertArray("options");
auto& choiceOptions = *teleportArgs.InsertArray("options");
{
AMFArrayValue* nsArgs = choiceOptions->PushArray();
auto& nsArgs = *choiceOptions.PushArray();
nsArgs->Insert("image", "textures/ui/zone_thumnails/Nimbus_Station.dds");
nsArgs->Insert("caption", "%[UI_CHOICE_NS]");
nsArgs->Insert("identifier", "zoneID_1200");
nsArgs->Insert("tooltipText", "%[UI_CHOICE_NS_HOVER]");
nsArgs.Insert("image", "textures/ui/zone_thumnails/Nimbus_Station.dds");
nsArgs.Insert("caption", "%[UI_CHOICE_NS]");
nsArgs.Insert("identifier", "zoneID_1200");
nsArgs.Insert("tooltipText", "%[UI_CHOICE_NS_HOVER]");
}
{
AMFArrayValue* ntArgs = choiceOptions->PushArray();
auto& ntArgs = *choiceOptions.PushArray();
ntArgs->Insert("image", "textures/ui/zone_thumnails/Nexus_Tower.dds");
ntArgs->Insert("caption", "%[UI_CHOICE_NT]");
ntArgs->Insert("identifier", "zoneID_1900");
ntArgs->Insert("tooltipText", "%[UI_CHOICE_NT_HOVER]");
ntArgs.Insert("image", "textures/ui/zone_thumnails/Nexus_Tower.dds");
ntArgs.Insert("caption", "%[UI_CHOICE_NT]");
ntArgs.Insert("identifier", "zoneID_1900");
ntArgs.Insert("tooltipText", "%[UI_CHOICE_NT_HOVER]");
}
options = choiceOptions;
}
void NsLegoClubDoor::OnUse(Entity* self, Entity* user) {
auto* player = user;
if (CheckChoice(self, player)) {
AMFArrayValue multiArgs;
multiArgs.Insert("callbackClient", std::to_string(self->GetObjectID()));
multiArgs.Insert("strIdentifier", "choiceDoor");
multiArgs.Insert("title", "%[UI_CHOICE_DESTINATION]");
multiArgs.Insert("options", static_cast<AMFBaseValue*>(options));
GameMessages::SendUIMessageServerToSingleClient(player, player->GetSystemAddress(), "QueueChoiceBox", multiArgs);
multiArgs.Remove("options", false); // We do not want the local amf to delete the options!
GameMessages::SendUIMessageServerToSingleClient(player, player->GetSystemAddress(), "QueueChoiceBox", teleportArgs);
} else if (self->GetVar<int32_t>(u"currentZone") != m_ChoiceZoneID) {
AMFArrayValue multiArgs;
multiArgs.Insert("state", "Lobby");

View File

@@ -19,6 +19,5 @@ private:
std::string m_SpawnPoint = "NS_LEGO_Club";
std::u16string m_TeleportAnim = u"lup-teleport";
std::u16string m_TeleportString = u"ROCKET_TOOLTIP_USE_THE_GATEWAY_TO_TRAVEL_TO_LUP_WORLD";
AMFArrayValue args = {};
AMFArrayValue* options = {};
AMFArrayValue teleportArgs{};
};

View File

@@ -36,14 +36,14 @@ void AgSpiderBossMessage::OnCollisionPhantom(Entity* self, Entity* target) {
auto box = GetBox(self);
// knockback the target
auto forward = target->GetRotation().GetForwardVector();
auto forward = self->GetRotation().GetForwardVector();
box.boxTarget = target->GetObjectID();
GameMessages::SendPlayFXEffect(target->GetObjectID(), 1378, u"create", "pushBack");
RenderComponent::PlayAnimation(target, "knockback-recovery");
forward.y += 15;
forward.x *= 100;
forward.z *= 100;
GameMessages::SendKnockback(target->GetObjectID(), self->GetObjectID(), self->GetObjectID(), 0, forward);
GameMessages::SendKnockback(target->GetObjectID(), LWOOBJID_EMPTY, LWOOBJID_EMPTY, 0, forward);
if (box.isTouch || box.isDisplayed) return;
box.boxSelf = self->GetObjectID();

View File

@@ -202,11 +202,13 @@ int main(int argc, char** argv) {
//Find out the master's IP:
std::string masterIP = "localhost";
uint32_t masterPort = 1000;
std::string masterPassword;
auto masterInfo = Database::Get()->GetMasterInfo();
if (masterInfo) {
masterIP = masterInfo->ip;
masterPort = masterInfo->port;
masterPassword = masterInfo->password;
}
UserManager::Instance()->Initialize();
@@ -214,7 +216,7 @@ int main(int argc, char** argv) {
const bool dontGenerateDCF = GeneralUtils::TryParse<bool>(Game::config->GetValue("dont_generate_dcf")).value_or(false);
Game::chatFilter = new dChatFilter(Game::assetManager->GetResPath().string() + "/chatplus_en_us", dontGenerateDCF);
Game::server = new dServer(masterIP, ourPort, instanceID, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::World, Game::config, &Game::lastSignal, zoneID);
Game::server = new dServer(masterIP, ourPort, instanceID, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::World, Game::config, &Game::lastSignal, masterPassword, zoneID);
//Connect to the chat server:
uint32_t chatPort = 1501;
@@ -223,7 +225,7 @@ int main(int argc, char** argv) {
auto chatSock = SocketDescriptor(static_cast<uint16_t>(ourPort + 2), 0);
Game::chatServer = RakNetworkFactory::GetRakPeerInterface();
Game::chatServer->Startup(1, 30, &chatSock, 1);
Game::chatServer->Connect(masterIP.c_str(), chatPort, "3.25 ND1", 8);
Game::chatServer->Connect(masterIP.c_str(), chatPort, NET_PASSWORD_EXTERNAL, strnlen(NET_PASSWORD_EXTERNAL, sizeof(NET_PASSWORD_EXTERNAL)));
//Set up other things:
Game::randomEngine = std::mt19937(time(0));
@@ -371,7 +373,7 @@ int main(int argc, char** argv) {
if (framesSinceChatDisconnect >= chatReconnectionTime) {
framesSinceChatDisconnect = 0;
Game::chatServer->Connect(masterIP.c_str(), chatPort, "3.25 ND1", 8);
Game::chatServer->Connect(masterIP.c_str(), chatPort, NET_PASSWORD_EXTERNAL, strnlen(NET_PASSWORD_EXTERNAL, sizeof(NET_PASSWORD_EXTERNAL)));
}
} else framesSinceChatDisconnect = 0;
@@ -831,20 +833,15 @@ void HandlePacket(Packet* packet) {
}
if (packet->data[0] != ID_USER_PACKET_ENUM || packet->length < 4) return;
CINSTREAM;
LUBitStream luBitStream;
luBitStream.ReadHeader(inStream);
if (luBitStream.connectionType == eConnectionType::SERVER) {
if (static_cast<MessageType::Server>(luBitStream.internalPacketID) == MessageType::Server::VERSION_CONFIRM) {
if (static_cast<eConnectionType>(packet->data[1]) == eConnectionType::SERVER) {
if (static_cast<MessageType::Server>(packet->data[3]) == MessageType::Server::VERSION_CONFIRM) {
AuthPackets::HandleHandshake(Game::server, packet);
}
}
if (luBitStream.connectionType != eConnectionType::WORLD) return;
if (static_cast<eConnectionType>(packet->data[1]) != eConnectionType::WORLD) return;
switch (static_cast<MessageType::World>(luBitStream.internalPacketID)) {
switch (static_cast<MessageType::World>(packet->data[3])) {
case MessageType::World::VALIDATION: {
CINSTREAM_SKIP_HEADER;
LUWString username;
@@ -1190,7 +1187,11 @@ void HandlePacket(Packet* packet) {
}
case MessageType::World::MAIL: {
Mail::HandleMail(inStream, packet->systemAddress, UserManager::Instance()->GetUser(packet->systemAddress)->GetLastUsedChar()->GetEntity());
RakNet::BitStream bitStream(packet->data, packet->length, false);
// FIXME: Change this to the macro to skip the header...
LWOOBJID space;
bitStream.Read(space);
Mail::HandleMailStuff(bitStream, packet->systemAddress, UserManager::Instance()->GetUser(packet->systemAddress)->GetLastUsedChar()->GetEntity());
break;
}

View File

@@ -0,0 +1 @@
ALTER TABLE servers ADD COLUMN master_password TEXT NOT NULL DEFAULT ('3.25 DARKFLAME1');

View File

@@ -0,0 +1 @@
ALTER TABLE servers ADD COLUMN master_password TEXT NOT NULL DEFAULT ('3.25 DARKFLAME1');

View File

@@ -9,3 +9,5 @@ world_port_start=3000
# 0 or 1, should autostart auth, chat, and char servers
prestart_servers=1
master_password=3.25DARKFLAME1