Merge remote-tracking branch 'refs/remotes/origin/main'

This commit is contained in:
wincent
2024-01-16 21:46:31 +01:00
597 changed files with 12170 additions and 9657 deletions

View File

@@ -17,26 +17,18 @@ const BrickList& BrickDatabase::GetBricks(const LxfmlPath& lxfmlPath) {
return cached->second;
}
AssetMemoryBuffer buffer = Game::assetManager->GetFileAsBuffer((lxfmlPath).c_str());
auto file = Game::assetManager->GetFile((lxfmlPath).c_str());
if (!buffer.m_Success) {
return emptyCache;
}
std::istream file(&buffer);
if (!file.good()) {
if (!file) {
return emptyCache;
}
std::stringstream data;
data << file.rdbuf();
if (data.str().empty()) {
buffer.close();
return emptyCache;
}
buffer.close();
auto* doc = new tinyxml2::XMLDocument();
if (doc->Parse(data.str().c_str(), data.str().size()) != 0) {
delete doc;

View File

@@ -3,7 +3,14 @@ set(DGAME_DUTILITIES_SOURCES "BrickDatabase.cpp"
"GUID.cpp"
"Loot.cpp"
"Mail.cpp"
"ObjectIDManager.cpp"
"Preconditions.cpp"
"SlashCommandHandler.cpp"
"ServerPreconditions.cpp"
"VanityUtilities.cpp" PARENT_SCOPE)
add_library(dUtilities STATIC ${DGAME_DUTILITIES_SOURCES})
target_precompile_headers(dUtilities REUSE_FROM dGameBase)
target_link_libraries(dUtilities
PUBLIC dDatabase dPhysics
INTERFACE dZoneManager)

View File

@@ -9,6 +9,8 @@
#include "User.h"
#include "UserManager.h"
#include "dConfig.h"
#include <optional>
#include "PlayerManager.h"
Entity* GetPossessedEntity(const LWOOBJID& objId) {
auto* entity = Game::entityManager->GetEntity(objId);
@@ -26,27 +28,29 @@ void ReportCheat(User* user, const SystemAddress& sysAddr, const char* messageIf
if (!user) {
LOG("WARNING: User is null, using defaults.");
}
std::unique_ptr<sql::PreparedStatement> stmt(Database::CreatePreppedStmt(
"INSERT INTO player_cheat_detections (account_id, name, violation_msg, violation_system_address) VALUES (?, ?, ?, ?)")
);
user ? stmt->setInt(1, user->GetAccountID()) : stmt->setNull(1, sql::DataType::INTEGER);
stmt->setString(2, user ? user->GetUsername().c_str() : "User is null.");
IPlayerCheatDetections::Info info;
if (user) info.userId = user->GetAccountID();
info.username = user ? user->GetUsername().c_str() : "User is null.";
// user string here because ToString is static and may change.
info.systemAddress = sysAddr.ToString();
constexpr int32_t bufSize = 4096;
char buffer[bufSize];
vsnprintf(buffer, bufSize, messageIfNotSender, args);
char extraMsg[bufSize];
vsnprintf(extraMsg, bufSize, messageIfNotSender, args);
info.extraMessage = extraMsg;
stmt->setString(3, buffer);
stmt->setString(4, Game::config->GetValue("log_ip_addresses_for_anti_cheat") == "1" ? sysAddr.ToString() : "IP logging disabled.");
stmt->execute();
LOG("Anti-cheat message: %s", buffer);
Database::Get()->InsertCheatDetection(info);
LOG("Anti-cheat message: %s", extraMsg);
}
void LogAndSaveFailedAntiCheatCheck(const LWOOBJID& id, const SystemAddress& sysAddr, const CheckType checkType, const char* messageIfNotSender, va_list args) {
User* toReport = nullptr;
switch (checkType) {
case CheckType::Entity: {
auto* player = Player::GetPlayer(sysAddr);
auto* player = PlayerManager::GetPlayer(sysAddr);
auto* entity = GetPossessedEntity(id);
// If player exists and entity exists in world, use both for logging info.

View File

@@ -242,7 +242,7 @@ void Loot::GiveActivityLoot(Entity* player, Entity* source, uint32_t activityID,
GiveLoot(player, selectedReward->LootMatrixIndex, eLootSourceType::ACTIVITY);
uint32_t coins = (int)(minCoins + GeneralUtils::GenerateRandomNumber<float>(0, 1) * (maxCoins - minCoins));
uint32_t coins = static_cast<uint32_t>(minCoins + GeneralUtils::GenerateRandomNumber<float>(0, 1) * (maxCoins - minCoins));
auto* character = player->GetCharacter();
@@ -280,7 +280,7 @@ void Loot::DropLoot(Entity* player, Entity* killedObject, std::unordered_map<LOT
}
}
uint32_t coins = (int)(minCoins + GeneralUtils::GenerateRandomNumber<float>(0, 1) * (maxCoins - minCoins));
uint32_t coins = static_cast<uint32_t>(minCoins + GeneralUtils::GenerateRandomNumber<float>(0, 1) * (maxCoins - minCoins));
GameMessages::SendDropClientLoot(player, source, LOT_NULL, coins, spawnPosition);
}

View File

@@ -12,7 +12,6 @@
#include "dServer.h"
#include "Entity.h"
#include "Character.h"
#include "PacketUtils.h"
#include "BitStreamUtils.h"
#include "Logger.h"
#include "EntityManager.h"
@@ -76,22 +75,19 @@ 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) {
auto* ins = Database::CreatePreppedStmt("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`) VALUES (?,?,?,?,?,?,?,?,?,?,?,0)");
IMail::MailInfo mailInsert;
mailInsert.senderUsername = senderName;
mailInsert.recipient = recipientName;
mailInsert.subject = subject;
mailInsert.body = body;
mailInsert.senderId = sender;
mailInsert.receiverId = recipient;
mailInsert.itemCount = attachmentCount;
mailInsert.itemID = LWOOBJID_EMPTY;
mailInsert.itemLOT = attachment;
mailInsert.itemSubkey = LWOOBJID_EMPTY;
ins->setUInt(1, sender);
ins->setString(2, senderName.c_str());
ins->setUInt(3, recipient);
ins->setString(4, recipientName.c_str());
ins->setUInt64(5, time(nullptr));
ins->setString(6, subject.c_str());
ins->setString(7, body.c_str());
ins->setUInt(8, 0);
ins->setInt(9, attachment);
ins->setInt(10, 0);
ins->setInt(11, attachmentCount);
ins->execute();
delete ins;
Database::Get()->InsertNewMail(mailInsert);
if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) return; // TODO: Echo to chat server
@@ -220,43 +216,30 @@ void Mail::HandleSendMail(RakNet::BitStream* packet, const SystemAddress& sysAdd
}
//Get the receiver's id:
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT id from charinfo WHERE name=? LIMIT 1;");
stmt->setString(1, recipient);
sql::ResultSet* res = stmt->executeQuery();
uint32_t receiverID = 0;
auto receiverID = Database::Get()->GetCharacterInfo(recipient);
if (res->rowsCount() > 0) {
while (res->next()) receiverID = res->getUInt(1);
} else {
if (!receiverID) {
Mail::SendSendResponse(sysAddr, Mail::MailSendResponse::RecipientNotFound);
delete stmt;
delete res;
return;
}
delete stmt;
delete res;
//Check if we have a valid receiver:
if (GeneralUtils::CaseInsensitiveStringCompare(recipient, character->GetName()) || receiverID == character->GetObjectID()) {
if (GeneralUtils::CaseInsensitiveStringCompare(recipient, character->GetName()) || receiverID->id == character->GetID()) {
Mail::SendSendResponse(sysAddr, Mail::MailSendResponse::CannotMailSelf);
return;
} else {
uint64_t currentTime = time(NULL);
sql::PreparedStatement* ins = Database::CreatePreppedStmt("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`) VALUES (?,?,?,?,?,?,?,?,?,?,?,0)");
ins->setUInt(1, character->GetObjectID());
ins->setString(2, character->GetName());
ins->setUInt(3, receiverID);
ins->setString(4, recipient);
ins->setUInt64(5, currentTime);
ins->setString(6, subject);
ins->setString(7, body);
ins->setUInt(8, itemID);
ins->setInt(9, itemLOT);
ins->setInt(10, 0);
ins->setInt(11, attachmentCount);
ins->execute();
delete ins;
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);
@@ -279,61 +262,48 @@ void Mail::HandleSendMail(RakNet::BitStream* packet, const SystemAddress& sysAdd
}
void Mail::HandleDataRequest(RakNet::BitStream* packet, const SystemAddress& sysAddr, Entity* player) {
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT * FROM mail WHERE receiver_id=? limit 20;");
stmt->setUInt(1, player->GetCharacter()->GetObjectID());
sql::ResultSet* res = stmt->executeQuery();
auto playerMail = Database::Get()->GetMailForPlayer(player->GetCharacter()->GetID(), 20);
RakNet::BitStream bitStream;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::MAIL);
bitStream.Write(int(MailMessageID::MailData));
bitStream.Write(int(0));
bitStream.Write(uint16_t(res->rowsCount()));
bitStream.Write(uint16_t(0));
bitStream.Write<uint16_t>(playerMail.size());
bitStream.Write<uint16_t>(0);
if (res->rowsCount() > 0) {
while (res->next()) {
bitStream.Write(res->getUInt64(1)); //MailID
for (const auto& mail : playerMail) {
bitStream.Write(mail.id); //MailID
/*std::u16string subject = GeneralUtils::UTF8ToUTF16(res->getString(7));
std::u16string body = GeneralUtils::UTF8ToUTF16(res->getString(8));
std::u16string sender = GeneralUtils::UTF8ToUTF16(res->getString(3));
WriteStringAsWString(&bitStream, mail.subject.c_str(), 50); //subject
WriteStringAsWString(&bitStream, mail.body.c_str(), 400); //body
WriteStringAsWString(&bitStream, mail.senderUsername.c_str(), 32); //sender
WriteToPacket(&bitStream, subject, 50);
WriteToPacket(&bitStream, body, 400);
WriteToPacket(&bitStream, sender, 32);*/
bitStream.Write(uint32_t(0));
bitStream.Write(uint64_t(0));
WriteStringAsWString(&bitStream, res->getString(7).c_str(), 50); //subject
WriteStringAsWString(&bitStream, res->getString(8).c_str(), 400); //body
WriteStringAsWString(&bitStream, res->getString(3).c_str(), 32); //sender
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));
bitStream.Write(uint32_t(0));
bitStream.Write(uint64_t(0));
bitStream.Write(mail.itemSubkey); //Attachment subKey
bitStream.Write<uint16_t>(mail.itemCount); //Attachment count
bitStream.Write(res->getUInt64(9)); //Attachment ID
LOT lot = res->getInt(10);
if (lot <= 0) bitStream.Write(LOT(-1));
else bitStream.Write(lot);
bitStream.Write(uint32_t(0));
bitStream.Write(uint32_t(0));
bitStream.Write(uint16_t(0));
bitStream.Write(res->getInt64(11)); //Attachment subKey
bitStream.Write(uint16_t(res->getInt(12))); //Attachment count
bitStream.Write<uint64_t>(mail.timeSent); //time sent (twice?)
bitStream.Write<uint64_t>(mail.timeSent);
bitStream.Write<uint8_t>(mail.wasRead); //was read
bitStream.Write(uint32_t(0));
bitStream.Write(uint16_t(0));
bitStream.Write(uint64_t(res->getUInt64(6))); //time sent (twice?)
bitStream.Write(uint64_t(res->getUInt64(6)));
bitStream.Write(uint8_t(res->getBoolean(13))); //was read
bitStream.Write(uint8_t(0));
bitStream.Write(uint16_t(0));
bitStream.Write(uint32_t(0));
}
bitStream.Write(uint8_t(0));
bitStream.Write(uint16_t(0));
bitStream.Write(uint32_t(0));
}
Game::server->Send(&bitStream, sysAddr, false);
PacketUtils::SavePacket("Max_Mail_Data.bin", (const char*)bitStream.GetData(), bitStream.GetNumberOfBytesUsed());
}
void Mail::HandleAttachmentCollect(RakNet::BitStream* packet, const SystemAddress& sysAddr, Entity* player) {
@@ -345,31 +315,24 @@ void Mail::HandleAttachmentCollect(RakNet::BitStream* packet, const SystemAddres
packet->Read(playerID);
if (mailID > 0 && playerID == player->GetObjectID()) {
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT attachment_lot, attachment_count FROM mail WHERE id=? LIMIT 1;");
stmt->setUInt64(1, mailID);
sql::ResultSet* res = stmt->executeQuery();
auto playerMail = Database::Get()->GetMail(mailID);
LOT attachmentLOT = 0;
uint32_t attachmentCount = 0;
while (res->next()) {
attachmentLOT = res->getInt(1);
attachmentCount = res->getInt(2);
if (playerMail) {
attachmentLOT = playerMail->itemLOT;
attachmentCount = playerMail->itemCount;
}
auto inv = static_cast<InventoryComponent*>(player->GetComponent(eReplicaComponentType::INVENTORY));
auto inv = player->GetComponent<InventoryComponent>();
if (!inv) return;
inv->AddItem(attachmentLOT, attachmentCount, eLootSourceType::MAIL);
Mail::SendAttachmentRemoveConfirm(sysAddr, mailID);
sql::PreparedStatement* up = Database::CreatePreppedStmt("UPDATE mail SET attachment_lot=0 WHERE id=?;");
up->setUInt64(1, mailID);
up->execute();
delete up;
delete res;
delete stmt;
Database::Get()->ClaimMailItem(mailID);
}
}
@@ -394,15 +357,9 @@ void Mail::HandleMailRead(RakNet::BitStream* packet, const SystemAddress& sysAdd
}
void Mail::HandleNotificationRequest(const SystemAddress& sysAddr, uint32_t objectID) {
auto returnVal = std::async(std::launch::async, [&]() {
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT id FROM mail WHERE receiver_id=? AND was_read=0");
stmt->setUInt(1, objectID);
sql::ResultSet* res = stmt->executeQuery();
auto unreadMailCount = Database::Get()->GetUnreadMailCount(objectID);
if (res->rowsCount() > 0) Mail::SendNotification(sysAddr, res->rowsCount());
delete res;
delete stmt;
});
if (unreadMailCount > 0) Mail::SendNotification(sysAddr, unreadMailCount);
}
void Mail::SendSendResponse(const SystemAddress& sysAddr, MailSendResponse response) {
@@ -449,10 +406,7 @@ void Mail::SendDeleteConfirm(const SystemAddress& sysAddr, uint64_t mailID, LWOO
bitStream.Write(mailID);
Game::server->Send(&bitStream, sysAddr, false);
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("DELETE FROM mail WHERE id=? LIMIT 1;");
stmt->setUInt64(1, mailID);
stmt->execute();
delete stmt;
Database::Get()->DeleteMail(mailID);
}
void Mail::SendReadConfirm(const SystemAddress& sysAddr, uint64_t mailID) {
@@ -463,8 +417,5 @@ void Mail::SendReadConfirm(const SystemAddress& sysAddr, uint64_t mailID) {
bitStream.Write(mailID);
Game::server->Send(&bitStream, sysAddr, false);
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("UPDATE mail SET was_read=1 WHERE id=?");
stmt->setUInt64(1, mailID);
stmt->execute();
delete stmt;
Database::Get()->MarkMailRead(mailID);
}

View File

@@ -0,0 +1,51 @@
#include "ObjectIDManager.h"
// Custom Classes
#include "MasterPackets.h"
#include "Database.h"
#include "Logger.h"
#include "Game.h"
//! The persistent ID request
struct PersistentIDRequest {
PersistentIDRequest(const uint64_t& requestID, const std::function<void(uint32_t)>& callback) : requestID(requestID), callback(callback) {}
uint64_t requestID;
std::function<void(uint32_t)> callback;
};
namespace {
std::vector<PersistentIDRequest> Requests; //!< All outstanding persistent ID requests
uint64_t CurrentRequestID = 0; //!< The current request ID
uint32_t CurrentObjectID = uint32_t(1152921508165007067); //!< The current object ID
std::uniform_int_distribution<int> Uni(10000000, INT32_MAX);
};
//! Requests a persistent ID
void ObjectIDManager::RequestPersistentID(const std::function<void(uint32_t)> callback) {
const auto& request = Requests.emplace_back(++CurrentRequestID, callback);
MasterPackets::SendPersistentIDRequest(Game::server, request.requestID);
}
//! Handles a persistent ID response
void ObjectIDManager::HandleRequestPersistentIDResponse(const uint64_t requestID, const uint32_t persistentID) {
auto it = std::find_if(Requests.begin(), Requests.end(), [requestID](const PersistentIDRequest& request) {
return request.requestID == requestID;
});
if (it == Requests.end()) return;
it->callback(persistentID);
Requests.erase(it);
}
//! Handles cases where we have to get a unique object ID synchronously
uint32_t ObjectIDManager::GenerateRandomObjectID() {
return Uni(Game::randomEngine);
}
//! Generates an object ID server-sided (used for regular entities like smashables)
uint32_t ObjectIDManager::GenerateObjectID() {
return ++CurrentObjectID;
}

View File

@@ -0,0 +1,40 @@
#pragma once
// C++
#include <functional>
#include <vector>
#include <stdint.h>
/*!
\file ObjectIDManager.h
\brief A manager for handling object ID generation
*/
//! The Object ID Manager
namespace ObjectIDManager {
//! Requests a persistent ID
/*!
\param callback The callback function
*/
void RequestPersistentID(const std::function<void(uint32_t)> callback);
//! Handles a persistent ID response
/*!
\param requestID The request ID
\param persistentID The persistent ID
*/
void HandleRequestPersistentIDResponse(const uint64_t requestID, const uint32_t persistentID);
//! Generates an object ID server-sided
/*!
\return A generated object ID
*/
uint32_t GenerateObjectID();
//! Generates a random object ID server-sided
/*!
\return A generated object ID
*/
uint32_t GenerateRandomObjectID();
};

View File

@@ -19,7 +19,7 @@ std::map<uint32_t, Precondition*> Preconditions::cache = {};
Precondition::Precondition(const uint32_t condition) {
auto query = CDClientDatabase::CreatePreppedStmt(
"SELECT type, targetLOT, targetCount FROM Preconditions WHERE id = ?;");
query.bind(1, (int)condition);
query.bind(1, static_cast<int>(condition));
auto result = query.execQuery();

View File

@@ -59,7 +59,7 @@
#include "dpShapeSphere.h"
#include "PossessableComponent.h"
#include "PossessorComponent.h"
#include "VehiclePhysicsComponent.h"
#include "HavokVehiclePhysicsComponent.h"
#include "BuffComponent.h"
#include "SkillComponent.h"
#include "VanityUtilities.h"
@@ -82,7 +82,9 @@
#include "eConnectionType.h"
#include "eChatInternalMessageType.h"
#include "eMasterMessageType.h"
#include "PlayerManager.h"
#include "CDRewardCodesTable.h"
#include "CDObjectsTable.h"
#include "CDZoneTableTable.h"
@@ -90,6 +92,7 @@
#include "ServerPreconditions.h"
#include "Prefab.h"
#include "Scene.h"
#include "ePlayerFlag.h"
void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entity* entity, const SystemAddress& sysAddr) {
auto commandCopy = command;
@@ -176,6 +179,21 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
return;
}
if (chatCommand == "toggleskipcinematics" && (Game::config->GetValue("allow_players_to_skip_cinematics") == "1" || entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER)) {
auto* character = entity->GetCharacter();
if (!character) return;
bool current = character->GetPlayerFlag(ePlayerFlag::DLU_SKIP_CINEMATICS);
character->SetPlayerFlag(ePlayerFlag::DLU_SKIP_CINEMATICS, !current);
if (!current) {
ChatPackets::SendSystemMessage(sysAddr, u"You have elected to skip cinematics. Note that not all cinematics can be skipped, but most will be skipped now.");
} else {
ChatPackets::SendSystemMessage(sysAddr, u"Cinematics will no longer be skipped.");
}
return;
}
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//HANDLE ALL NON GM SLASH COMMANDS RIGHT HERE!
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
@@ -202,10 +220,10 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
if (chatCommand == "who") {
ChatPackets::SendSystemMessage(
sysAddr,
u"Players in this instance: (" + GeneralUtils::to_u16string(Player::GetAllPlayers().size()) + u")"
u"Players in this instance: (" + GeneralUtils::to_u16string(PlayerManager::GetAllPlayers().size()) + u")"
);
for (auto* player : Player::GetAllPlayers()) {
for (auto* player : PlayerManager::GetAllPlayers()) {
const auto& name = player->GetCharacter()->GetName();
ChatPackets::SendSystemMessage(
@@ -276,11 +294,11 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
return;
}
if (chatCommand == "leave-zone") {
if (chatCommand == "leave-zone" || chatCommand == "leavezone") {
const auto currentZone = Game::zoneManager->GetZone()->GetZoneID().GetMapID();
LWOMAPID newZone = 0;
if (currentZone % 100 == 0) {
if (currentZone == 1001 || currentZone % 100 == 0) {
ChatPackets::SendSystemMessage(sysAddr, u"You are not in an instanced zone.");
return;
} else {
@@ -364,12 +382,20 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
if (entity->GetGMLevel() == eGameMasterLevel::CIVILIAN) return;
}
if (chatCommand == "resetmission" && args.size() >= 1 && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) {
uint32_t missionId;
if (!GeneralUtils::TryParse(args[0], missionId)) {
ChatPackets::SendSystemMessage(sysAddr, u"Invalid mission ID.");
return;
}
auto* missionComponent = entity->GetComponent<MissionComponent>();
if (!missionComponent) return;
missionComponent->ResetMission(missionId);
}
// Log command to database
auto stmt = Database::CreatePreppedStmt("INSERT INTO command_log (character_id, command) VALUES (?, ?);");
stmt->setInt(1, entity->GetCharacter()->GetID());
stmt->setString(2, GeneralUtils::UTF16ToWTF8(command).c_str());
stmt->execute();
delete stmt;
Database::Get()->InsertSlashCommandUsage(entity->GetObjectID(), chatCommand);
if (chatCommand == "setminifig" && args.size() == 2 && entity->GetGMLevel() >= eGameMasterLevel::FORUM_MODERATOR) { // could break characters so only allow if GM > 0
int32_t minifigItemId;
@@ -453,9 +479,8 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
if (chatCommand == "kill" && args.size() == 1 && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) {
ChatPackets::SendSystemMessage(sysAddr, u"Brutally murdering that player, if online on this server.");
auto* user = UserManager::Instance()->GetUser(args[0]);
if (user) {
auto* player = Game::entityManager->GetEntity(user->GetLoggedInChar());
auto* player = PlayerManager::GetPlayer(args[0]);
if (player) {
player->Smash(entity->GetObjectID());
ChatPackets::SendSystemMessage(sysAddr, u"It has been done, do you feel good about yourself now?");
return;
@@ -601,15 +626,13 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
if (args[0].find("/") != std::string::npos) return;
if (args[0].find("\\") != std::string::npos) return;
auto buf = Game::assetManager->GetFileAsBuffer(("macros/" + args[0] + ".scm").c_str());
auto infile = Game::assetManager->GetFile(("macros/" + args[0] + ".scm").c_str());
if (!buf.m_Success) {
if (!infile) {
ChatPackets::SendSystemMessage(sysAddr, u"Unknown macro! Is the filename right?");
return;
}
std::istream infile(&buf);
if (infile.good()) {
std::string line;
while (std::getline(infile, line)) {
@@ -619,8 +642,6 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
ChatPackets::SendSystemMessage(sysAddr, u"Unknown macro! Is the filename right?");
}
buf.close();
return;
}
@@ -689,33 +710,6 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
entity->GetCharacter()->SetPlayerFlag(flagId, false);
}
if (chatCommand == "resetmission" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) {
if (args.size() == 0) return;
uint32_t missionID;
if (!GeneralUtils::TryParse(args[0], missionID)) {
ChatPackets::SendSystemMessage(sysAddr, u"Invalid mission id.");
return;
}
auto* comp = static_cast<MissionComponent*>(entity->GetComponent(eReplicaComponentType::MISSION));
if (comp == nullptr) {
return;
}
auto* mission = comp->GetMission(missionID);
if (mission == nullptr) {
return;
}
mission->SetMissionState(eMissionState::ACTIVE);
return;
}
if (chatCommand == "removemission" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) {
if (args.size() == 0) return;
@@ -849,46 +843,36 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
if (chatCommand == "mailitem" && entity->GetGMLevel() >= eGameMasterLevel::MODERATOR && args.size() >= 2) {
const auto& playerName = args[0];
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT id from charinfo WHERE name=? LIMIT 1;");
stmt->setString(1, playerName);
sql::ResultSet* res = stmt->executeQuery();
auto playerInfo = Database::Get()->GetCharacterInfo(playerName);
uint32_t receiverID = 0;
if (res->rowsCount() > 0) {
while (res->next()) receiverID = res->getUInt(1);
}
delete stmt;
delete res;
if (receiverID == 0) {
if (!playerInfo) {
ChatPackets::SendSystemMessage(sysAddr, u"Failed to find that player");
return;
}
uint32_t lot;
receiverID = playerInfo->id;
LOT lot;
if (!GeneralUtils::TryParse(args[1], lot)) {
ChatPackets::SendSystemMessage(sysAddr, u"Invalid item lot.");
return;
}
uint64_t currentTime = time(NULL);
sql::PreparedStatement* ins = Database::CreatePreppedStmt("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`) VALUES (?,?,?,?,?,?,?,?,?,?,?,0)");
ins->setUInt(1, entity->GetObjectID());
ins->setString(2, "Darkflame Universe");
ins->setUInt(3, receiverID);
ins->setString(4, playerName);
ins->setUInt64(5, currentTime);
ins->setString(6, "Lost item");
ins->setString(7, "This is a replacement item for one you lost.");
ins->setUInt(8, 0);
ins->setInt(9, lot);
ins->setInt(10, 0);
ins->setInt(11, 1);
ins->execute();
delete ins;
IMail::MailInfo mailInsert;
mailInsert.senderId = entity->GetObjectID();
mailInsert.senderUsername = "Darkflame Universe";
mailInsert.receiverId = receiverID;
mailInsert.recipient = playerName;
mailInsert.subject = "Lost item";
mailInsert.body = "This is a replacement item for one you lost.";
mailInsert.itemID = LWOOBJID_EMPTY;
mailInsert.itemLOT = lot;
mailInsert.itemSubkey = LWOOBJID_EMPTY;
mailInsert.itemCount = 1;
Database::Get()->InsertNewMail(mailInsert);
ChatPackets::SendSystemMessage(sysAddr, u"Mail sent");
@@ -1116,9 +1100,9 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
auto* possassableEntity = Game::entityManager->GetEntity(possessorComponent->GetPossessable());
if (possassableEntity != nullptr) {
auto* vehiclePhysicsComponent = possassableEntity->GetComponent<VehiclePhysicsComponent>();
if (vehiclePhysicsComponent) {
vehiclePhysicsComponent->SetPosition(pos);
auto* havokVehiclePhysicsComponent = possassableEntity->GetComponent<HavokVehiclePhysicsComponent>();
if (havokVehiclePhysicsComponent) {
havokVehiclePhysicsComponent->SetPosition(pos);
Game::entityManager->SerializeEntity(possassableEntity);
} else GameMessages::SendTeleport(possassableEntity->GetObjectID(), pos, NiQuaternion(), sysAddr);
}
@@ -1186,31 +1170,22 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
if (chatCommand == "mute" && entity->GetGMLevel() >= eGameMasterLevel::JUNIOR_DEVELOPER) {
if (args.size() >= 1) {
auto* player = Player::GetPlayer(args[0]);
auto* player = PlayerManager::GetPlayer(args[0]);
uint32_t accountId = 0;
LWOOBJID characterId = 0;
if (player == nullptr) {
auto* accountQuery = Database::CreatePreppedStmt("SELECT account_id, id FROM charinfo WHERE name=? LIMIT 1;");
auto characterInfo = Database::Get()->GetCharacterInfo(args[0]);
accountQuery->setString(1, args[0]);
if (characterInfo) {
accountId = characterInfo->accountId;
characterId = characterInfo->id;
auto result = accountQuery->executeQuery();
if (result->rowsCount() > 0) {
while (result->next()) {
accountId = result->getUInt(1);
characterId = result->getUInt64(2);
GeneralUtils::SetBit(characterId, eObjectBits::CHARACTER);
GeneralUtils::SetBit(characterId, eObjectBits::PERSISTENT);
}
GeneralUtils::SetBit(characterId, eObjectBits::CHARACTER);
GeneralUtils::SetBit(characterId, eObjectBits::PERSISTENT);
}
delete accountQuery;
delete result;
if (accountId == 0) {
ChatPackets::SendSystemMessage(sysAddr, u"Count not find player of name: " + GeneralUtils::UTF8ToUTF16(args[0]));
@@ -1218,11 +1193,9 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
}
} else {
accountId = player->GetParentUser()->GetAccountID();
characterId = player->GetCharacter()->GetID();
characterId = player->GetObjectID();
}
auto* userUpdate = Database::CreatePreppedStmt("UPDATE accounts SET mute_expire = ? WHERE id = ?;");
time_t expire = 1; // Default to indefinate mute
if (args.size() >= 2) {
@@ -1247,12 +1220,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
expire += 60 * 60 * hours;
}
userUpdate->setUInt64(1, expire);
userUpdate->setInt(2, accountId);
userUpdate->executeUpdate();
delete userUpdate;
Database::Get()->UpdateAccountUnmuteTime(accountId, expire);
char buffer[32] = "brought up for review.\0";
@@ -1281,7 +1249,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
if (chatCommand == "kick" && entity->GetGMLevel() >= eGameMasterLevel::JUNIOR_MODERATOR) {
if (args.size() == 1) {
auto* player = Player::GetPlayer(args[0]);
auto* player = PlayerManager::GetPlayer(args[0]);
std::u16string username = GeneralUtils::UTF8ToUTF16(args[0]);
if (player == nullptr) {
@@ -1299,24 +1267,17 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
if (chatCommand == "ban" && entity->GetGMLevel() >= eGameMasterLevel::SENIOR_MODERATOR) {
if (args.size() == 1) {
auto* player = Player::GetPlayer(args[0]);
auto* player = PlayerManager::GetPlayer(args[0]);
uint32_t accountId = 0;
if (player == nullptr) {
auto* accountQuery = Database::CreatePreppedStmt("SELECT account_id FROM charinfo WHERE name=? LIMIT 1;");
auto characterInfo = Database::Get()->GetCharacterInfo(args[0]);
accountQuery->setString(1, args[0]);
auto result = accountQuery->executeQuery();
if (result->rowsCount() > 0) {
while (result->next()) accountId = result->getUInt(1);
if (characterInfo) {
accountId = characterInfo->accountId;
}
delete accountQuery;
delete result;
if (accountId == 0) {
ChatPackets::SendSystemMessage(sysAddr, u"Count not find player of name: " + GeneralUtils::UTF8ToUTF16(args[0]));
@@ -1326,13 +1287,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
accountId = player->GetParentUser()->GetAccountID();
}
auto* userUpdate = Database::CreatePreppedStmt("UPDATE accounts SET banned = true WHERE id = ?;");
userUpdate->setInt(1, accountId);
userUpdate->executeUpdate();
delete userUpdate;
Database::Get()->UpdateAccountBan(accountId, true);
if (player != nullptr) {
Game::server->Disconnect(player->GetSystemAddress(), eServerDisconnectIdentifiers::FREE_TRIAL_EXPIRED);
@@ -1387,9 +1342,9 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
auto dest = static_cast<DestroyableComponent*>(entity->GetComponent(eReplicaComponentType::DESTROYABLE));
if (dest) {
dest->SetHealth((int)dest->GetMaxHealth());
dest->SetArmor((int)dest->GetMaxArmor());
dest->SetImagination((int)dest->GetMaxImagination());
dest->SetHealth(static_cast<int32_t>(dest->GetMaxHealth()));
dest->SetArmor(static_cast<int32_t>(dest->GetMaxArmor()));
dest->SetImagination(static_cast<int32_t>(dest->GetMaxImagination()));
}
Game::entityManager->SerializeEntity(entity);
@@ -1513,7 +1468,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
int32_t type;
if (args.size() >= 2 && GeneralUtils::TryParse(args[1], type)) {
lootType = (eLootSourceType)type;
lootType = static_cast<eLootSourceType>(type);
}
GameMessages::SendModifyLEGOScore(entity, entity->GetSystemAddress(), uscore, lootType);
@@ -1525,7 +1480,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
if (args.size() > 1) {
requestedPlayerToSetLevelOf = args[1];
auto requestedPlayer = Player::GetPlayer(requestedPlayerToSetLevelOf);
auto requestedPlayer = PlayerManager::GetPlayer(requestedPlayerToSetLevelOf);
if (!requestedPlayer) {
ChatPackets::SendSystemMessage(sysAddr, u"No player found with username: (" + GeneralUtils::UTF8ToUTF16(requestedPlayerToSetLevelOf) + u").");
@@ -1553,7 +1508,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
if (!characterComponent) return;
auto levelComponent = entity->GetComponent<LevelProgressionComponent>();
auto query = CDClientDatabase::CreatePreppedStmt("SELECT requiredUScore from LevelProgressionLookup WHERE id = ?;");
query.bind(1, (int)requestedLevel);
query.bind(1, static_cast<int>(requestedLevel));
auto result = query.execQuery();
if (result.eof()) return;
@@ -1592,7 +1547,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
ChatPackets::SendSystemMessage(sysAddr, u"<" + (GeneralUtils::to_u16string(position.x)) + u", " + (GeneralUtils::to_u16string(position.y)) + u", " + (GeneralUtils::to_u16string(position.z)) + u">");
std::cout << position.x << ", " << position.y << ", " << position.z << std::endl;
LOG("Position: %f, %f, %f", position.x, position.y, position.z);
}
if (chatCommand == "rot" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) {
@@ -1600,14 +1555,14 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
ChatPackets::SendSystemMessage(sysAddr, u"<" + (GeneralUtils::to_u16string(rotation.w)) + u", " + (GeneralUtils::to_u16string(rotation.x)) + u", " + (GeneralUtils::to_u16string(rotation.y)) + u", " + (GeneralUtils::to_u16string(rotation.z)) + u">");
std::cout << rotation.w << ", " << rotation.x << ", " << rotation.y << ", " << rotation.z << std::endl;
LOG("Rotation: %f, %f, %f, %f", rotation.w, rotation.x, rotation.y, rotation.z);
}
if (chatCommand == "locrow" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) {
const auto position = entity->GetPosition();
const auto rotation = entity->GetRotation();
std::cout << "<location x=\"" << position.x << "\" y=\"" << position.y << "\" z=\"" << position.z << "\" rw=\"" << rotation.w << "\" rx=\"" << rotation.x << "\" ry=\"" << rotation.y << "\" rz=\"" << rotation.z << "\" />" << std::endl;
LOG("<location x=\"%f\" y=\"%f\" z=\"%f\" rw=\"%f\" rx=\"%f\" ry=\"%f\" rz=\"%f\" />", position.x, position.y, position.z, rotation.w, rotation.x, rotation.y, rotation.z);
}
if (chatCommand == "playlvlfx" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) {
@@ -1872,7 +1827,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
auto sphere = static_cast<dpShapeSphere*>(prox.second->GetShape());
auto pos = prox.second->GetPosition();
std::cout << prox.first << ", r: " << sphere->GetRadius() << ", pos: " << pos.x << "," << pos.y << "," << pos.z << std::endl;
LOG("Proximity: %s, r: %f, pos: %f, %f, %f", prox.first.c_str(), sphere->GetRadius(), pos.x, pos.y, pos.z);
}
}
}
@@ -1937,13 +1892,13 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
ChatPackets::SendSystemMessage(
sysAddr,
u"Peak RSS: " + GeneralUtils::to_u16string((float)((double)Metrics::GetPeakRSS() / 1.024e6)) +
u"Peak RSS: " + GeneralUtils::to_u16string(static_cast<float>(static_cast<double>(Metrics::GetPeakRSS()) / 1.024e6)) +
u"MB"
);
ChatPackets::SendSystemMessage(
sysAddr,
u"Current RSS: " + GeneralUtils::to_u16string((float)((double)Metrics::GetCurrentRSS() / 1.024e6)) +
u"Current RSS: " + GeneralUtils::to_u16string(static_cast<float>(static_cast<double>(Metrics::GetCurrentRSS()) / 1.024e6)) +
u"MB"
);
@@ -1988,7 +1943,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
totalRuns += 1;
bool doBreak = false;
for (const auto& kv : lootRoll) {
if ((uint32_t)kv.first == targetLot) {
if (static_cast<uint32_t>(kv.first) == targetLot) {
doBreak = true;
}
}
@@ -2003,7 +1958,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
+ u" times. It ran "
+ GeneralUtils::to_u16string(totalRuns)
+ u" times. Averaging out at "
+ GeneralUtils::to_u16string((float)totalRuns / loops);
+ GeneralUtils::to_u16string(static_cast<float>(totalRuns) / loops);
ChatPackets::SendSystemMessage(sysAddr, message);
}
@@ -2115,6 +2070,13 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
}
}
if (chatCommand == "setrewardcode" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() == 1) {
auto* cdrewardCodes = CDClientManager::Instance().GetTable<CDRewardCodesTable>();
auto id = cdrewardCodes->GetCodeID(args[0]);
if (id != -1) Database::Get()->InsertRewardCode(user->GetAccountID(), id);
}
if (chatCommand == "inspect" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 1) {
Entity* closest = nullptr;

View File

@@ -17,7 +17,7 @@
#include "EntityInfo.h"
#include "Spawner.h"
#include "dZoneManager.h"
#include "../dWorldServer/ObjectIDManager.h"
#include "ObjectIDManager.h"
#include "Level.h"
#include <fstream>
@@ -182,7 +182,7 @@ LWOOBJID VanityUtilities::SpawnSpawner(LOT lot, const NiPoint3& position, const
obj.lot = lot;
// guratantee we have no collisions
do {
obj.id = ObjectIDManager::Instance()->GenerateObjectID();
obj.id = ObjectIDManager::GenerateObjectID();
} while(Game::zoneManager->GetSpawner(obj.id));
obj.position = position;
obj.rotation = rotation;
@@ -294,21 +294,20 @@ void VanityUtilities::ParseXML(const std::string& file) {
auto* partyPhrases = npcs->FirstChildElement("partyphrases");
if (partyPhrases == nullptr) {
LOG("Failed to parse party phrases");
return;
}
for (auto* phrase = partyPhrases->FirstChildElement("phrase"); phrase != nullptr;
phrase = phrase->NextSiblingElement("phrase")) {
// Get the phrase
auto* text = phrase->GetText();
if (text == nullptr) {
LOG("Failed to parse party phrase");
continue;
LOG("No party phrases found");
} else {
for (auto* phrase = partyPhrases->FirstChildElement("phrase"); phrase != nullptr;
phrase = phrase->NextSiblingElement("phrase")) {
// Get the phrase
auto* text = phrase->GetText();
if (text == nullptr) {
LOG("Failed to parse party phrase");
continue;
}
m_PartyPhrases.push_back(text);
}
m_PartyPhrases.push_back(text);
}
for (auto* npc = npcs->FirstChildElement("npc"); npc != nullptr; npc = npc->NextSiblingElement("npc")) {
@@ -525,12 +524,12 @@ std::string VanityUtilities::ParseMarkdown(const std::string& file) {
#endif
// Replace "__TIMESTAMP__" with the __TIMESTAMP__
GeneralUtils::ReplaceInString(line, "__TIMESTAMP__", __TIMESTAMP__);
// Replace "__VERSION__" wit'h the PROJECT_VERSION
GeneralUtils::ReplaceInString(line, "__VERSION__", STRINGIFY(PROJECT_VERSION));
// Replace "__VERSION__" with the PROJECT_VERSION
GeneralUtils::ReplaceInString(line, "__VERSION__", Game::projectVersion);
// Replace "__SOURCE__" with SOURCE
GeneralUtils::ReplaceInString(line, "__SOURCE__", Game::config->GetValue("source"));
// Replace "__LICENSE__" with LICENSE
GeneralUtils::ReplaceInString(line, "__LICENSE__", STRINGIFY(LICENSE));
GeneralUtils::ReplaceInString(line, "__LICENSE__", "AGPL-3.0");
if (line.find("##") != std::string::npos) {
// Add "&lt;font size=&apos;18&apos; color=&apos;#000000&apos;&gt;" before the header