DarkflameServer/dGame/dComponents/PropertyManagementComponent.cpp

861 lines
26 KiB
C++
Raw Normal View History

2022-08-06 03:01:59 +00:00
#include "PropertyManagementComponent.h"
#include <sstream>
#include "MissionComponent.h"
#include "EntityManager.h"
#include "PropertyDataMessage.h"
#include "UserManager.h"
#include "GameMessages.h"
#include "Character.h"
#include "CDClientDatabase.h"
#include "dZoneManager.h"
#include "Game.h"
#include "Item.h"
#include "Database.h"
#include "../dWorldServer/ObjectIDManager.h"
#include "Player.h"
#include "RocketLaunchpadControlComponent.h"
#include "PropertyEntranceComponent.h"
#include <vector>
#include "CppScripts.h"
PropertyManagementComponent* PropertyManagementComponent::instance = nullptr;
2022-07-28 13:39:57 +00:00
PropertyManagementComponent::PropertyManagementComponent(Entity* parent) : Component(parent) {
this->owner = LWOOBJID_EMPTY;
this->templateId = 0;
this->propertyId = LWOOBJID_EMPTY;
this->models = {};
this->propertyName = "";
this->propertyDescription = "";
this->privacyOption = PropertyPrivacyOption::Private;
this->originalPrivacyOption = PropertyPrivacyOption::Private;
instance = this;
const auto& worldId = dZoneManager::Instance()->GetZone()->GetZoneID();
const auto zoneId = worldId.GetMapID();
const auto cloneId = worldId.GetCloneID();
auto query = CDClientDatabase::CreatePreppedStmt(
"SELECT id FROM PropertyTemplate WHERE mapID = ?;");
2022-07-28 13:39:57 +00:00
query.bind(1, (int)zoneId);
auto result = query.execQuery();
2022-07-28 13:39:57 +00:00
if (result.eof() || result.fieldIsNull(0)) {
return;
}
templateId = result.getIntField(0);
result.finalize();
auto* propertyLookup = Database::CreatePreppedStmt("SELECT * FROM properties WHERE template_id = ? AND clone_id = ?;");
propertyLookup->setInt(1, templateId);
propertyLookup->setInt64(2, cloneId);
auto* propertyEntry = propertyLookup->executeQuery();
2022-07-28 13:39:57 +00:00
if (propertyEntry->next()) {
this->propertyId = propertyEntry->getUInt64(1);
this->owner = propertyEntry->getUInt64(2);
this->owner = GeneralUtils::SetBit(this->owner, OBJECT_BIT_CHARACTER);
this->owner = GeneralUtils::SetBit(this->owner, OBJECT_BIT_PERSISTENT);
this->clone_Id = propertyEntry->getInt(2);
this->propertyName = propertyEntry->getString(5).c_str();
this->propertyDescription = propertyEntry->getString(6).c_str();
this->privacyOption = static_cast<PropertyPrivacyOption>(propertyEntry->getUInt(9));
this->moderatorRequested = propertyEntry->getInt(10) == 0 && rejectionReason == "" && privacyOption == PropertyPrivacyOption::Public;
this->LastUpdatedTime = propertyEntry->getUInt64(11);
2022-03-28 10:58:40 +00:00
this->claimedTime = propertyEntry->getUInt64(12);
Add Aarch64 support (#231) * added mariadb-connector-cpp submodule * raknet aarch64 support * fix compile errors * mariadb connector swap (in progress) * update CMakeLists, add preprocessor definition to switch between mysql and mariadb connectors * update types with missing aarch64 check * corrected adding extra flag to properly compile mariadbconn in CMakeLists * updated readme with arm builds section * fix build failure if test folder does not exist * Remove mysql connector from all builds, add mariadbconnector to windows build * readd Linux check for backtrace lib to CMakeLists.txt * Separate system specific mariadbconncpp extra compile flags * Copy dlls to exes directory once built * fetch prebuilt binaries on windows so that ClangCL can be used * Delay load dll so that plugin directory is set correctly * Fixed typo in glibcxx compile flag * whitespacing, spaces -> tabs * Updated README.md, included instructions to update * Updated README.md added libssl-dev requirement and removed mysql connector references from macOS builds section * apple compile fixes for zlib and shared library name * add windows arm64 checks to raknet * remove extra . in shared library location * Setup plugins directory for the connector to search in, pass openssl_root_dir on for apple * Fix copy paths for single config generators and non windows * change plugin folder location, another single config generator fix * GENERATOR_IS_MULTI_CONFIG is a property not a variable * Fixed a few errors after merge * Fix plugin directory path, force windows to look at the right folder * fixed directory name for make_directory command * Update README.md Updated MacOS, Windows build instructions. * set INSTALL_PLUGINDIR so that the right directory is used * Support for relative rpath for docker build * added mariadb-connector-cpp submodule * raknet aarch64 support * fix compile errors * mariadb connector swap (in progress) * update CMakeLists, add preprocessor definition to switch between mysql and mariadb connectors * update types with missing aarch64 check * corrected adding extra flag to properly compile mariadbconn in CMakeLists * updated readme with arm builds section * fix build failure if test folder does not exist * Remove mysql connector from all builds, add mariadbconnector to windows build * readd Linux check for backtrace lib to CMakeLists.txt * Separate system specific mariadbconncpp extra compile flags * Copy dlls to exes directory once built * fetch prebuilt binaries on windows so that ClangCL can be used * Delay load dll so that plugin directory is set correctly * Fixed typo in glibcxx compile flag * whitespacing, spaces -> tabs * Updated README.md, included instructions to update * Updated README.md added libssl-dev requirement and removed mysql connector references from macOS builds section * apple compile fixes for zlib and shared library name * add windows arm64 checks to raknet * Setup plugins directory for the connector to search in, pass openssl_root_dir on for apple * Fix copy paths for single config generators and non windows * change plugin folder location, another single config generator fix * GENERATOR_IS_MULTI_CONFIG is a property not a variable * Fixed a few errors after merge * Fix plugin directory path, force windows to look at the right folder * fixed directory name for make_directory command * Update README.md Updated MacOS, Windows build instructions. * set INSTALL_PLUGINDIR so that the right directory is used * Support for relative rpath for docker build * Rebase on main * Remove extra git submodule * Update CMakeLists.txt * Remove CMakeLists.txt file from mariadb Remove the CMakeLists.txt file from the mariaDBConnector so we dont build the tests. Also add a config option to the CMakeVariables.txt so you can build the connector with multiple jobs * Compile on windows Specify the mariadbcpp.dll file location with a defined absolute path so windows knows it actually exists. * default to 1 job Default mariadb jobs running in parallel to 1 instead of 4 * Move mariadbcpp.dll file to the expected directory on windows * Changed plugin Updated the plugin location from the project binary directory to the expected location, the mariadb binary directory. * Addressed windows dll issues by moving files to the expected directory instead of a directory that wouldnt get created * Update README Co-authored-by: Aaron Kimbrell <aronwk.aaron@gmail.com> Co-authored-by: EmosewaMC <39972741+EmosewaMC@users.noreply.github.com>
2022-07-04 04:33:05 +00:00
this->rejectionReason = std::string(propertyEntry->getString(13).c_str());
this->reputation = propertyEntry->getUInt(14);
Load();
}
delete propertyLookup;
}
2022-07-28 13:39:57 +00:00
LWOOBJID PropertyManagementComponent::GetOwnerId() const {
return owner;
}
2022-07-28 13:39:57 +00:00
Entity* PropertyManagementComponent::GetOwner() const {
return EntityManager::Instance()->GetEntity(owner);
}
2022-07-28 13:39:57 +00:00
void PropertyManagementComponent::SetOwner(Entity* value) {
owner = value->GetObjectID();
}
2022-07-28 13:39:57 +00:00
std::vector<NiPoint3> PropertyManagementComponent::GetPaths() const {
const auto zoneId = dZoneManager::Instance()->GetZone()->GetWorldID();
auto query = CDClientDatabase::CreatePreppedStmt(
"SELECT path FROM PropertyTemplate WHERE mapID = ?;");
2022-07-28 13:39:57 +00:00
query.bind(1, (int)zoneId);
auto result = query.execQuery();
2022-07-28 13:39:57 +00:00
std::vector<NiPoint3> paths{};
2022-07-28 13:39:57 +00:00
if (result.eof()) {
return paths;
}
std::vector<float> points;
std::istringstream stream(result.getStringField(0));
std::string token;
2022-07-28 13:39:57 +00:00
while (std::getline(stream, token, ' ')) {
try {
auto value = std::stof(token);
points.push_back(value);
2022-07-28 13:39:57 +00:00
} catch (std::invalid_argument& exception) {
Game::logger->Log("PropertyManagementComponent", "Failed to parse value (%s): (%s)!", token.c_str(), exception.what());
}
}
2022-07-28 13:39:57 +00:00
for (auto i = 0u; i < points.size(); i += 3) {
paths.emplace_back(points[i], points[i + 1], points[i + 2]);
}
return paths;
}
2022-07-28 13:39:57 +00:00
PropertyPrivacyOption PropertyManagementComponent::GetPrivacyOption() const {
return privacyOption;
}
2022-07-28 13:39:57 +00:00
void PropertyManagementComponent::SetPrivacyOption(PropertyPrivacyOption value) {
if (owner == LWOOBJID_EMPTY) return;
if (value == static_cast<PropertyPrivacyOption>(3)) // Client sends 3 for private for some reason, but expects 0 in return?
{
value = PropertyPrivacyOption::Private;
}
if (value == PropertyPrivacyOption::Public && privacyOption != PropertyPrivacyOption::Public) {
rejectionReason = "";
moderatorRequested = true;
}
privacyOption = value;
auto* propertyUpdate = Database::CreatePreppedStmt("UPDATE properties SET privacy_option = ?, rejection_reason = ?, mod_approved = ? WHERE id = ?;");
propertyUpdate->setInt(1, static_cast<int32_t>(value));
propertyUpdate->setString(2, "");
propertyUpdate->setInt(3, 0);
propertyUpdate->setInt64(4, propertyId);
propertyUpdate->executeUpdate();
}
2022-07-28 13:39:57 +00:00
void PropertyManagementComponent::UpdatePropertyDetails(std::string name, std::string description) {
if (owner == LWOOBJID_EMPTY) return;
propertyName = name;
propertyDescription = description;
auto* propertyUpdate = Database::CreatePreppedStmt("UPDATE properties SET name = ?, description = ? WHERE id = ?;");
propertyUpdate->setString(1, name.c_str());
propertyUpdate->setString(2, description.c_str());
propertyUpdate->setInt64(3, propertyId);
propertyUpdate->executeUpdate();
OnQueryPropertyData(GetOwner(), UNASSIGNED_SYSTEM_ADDRESS);
}
2022-07-28 13:39:57 +00:00
bool PropertyManagementComponent::Claim(const LWOOBJID playerId) {
if (owner != LWOOBJID_EMPTY) {
2022-03-31 04:58:59 +00:00
return false;
}
auto* entity = EntityManager::Instance()->GetEntity(playerId);
auto* user = entity->GetParentUser();
2022-03-30 07:33:31 +00:00
auto character = entity->GetCharacter();
2022-03-31 04:58:59 +00:00
if (!character) return false;
auto* zone = dZoneManager::Instance()->GetZone();
const auto& worldId = zone->GetZoneID();
2022-03-31 04:58:59 +00:00
const auto propertyZoneId = worldId.GetMapID();
const auto propertyCloneId = worldId.GetCloneID();
2022-03-31 04:58:59 +00:00
const auto playerCloneId = character->GetPropertyCloneID();
2022-03-31 04:58:59 +00:00
// If we are not on our clone do not allow us to claim the property
if (propertyCloneId != playerCloneId) return false;
SetOwnerId(playerId);
propertyId = ObjectIDManager::GenerateRandomObjectID();
2022-03-31 04:58:59 +00:00
auto* insertion = Database::CreatePreppedStmt(
"INSERT INTO properties"
2022-03-30 07:20:15 +00:00
"(id, owner_id, template_id, clone_id, name, description, rent_amount, rent_due, privacy_option, last_updated, time_claimed, rejection_reason, reputation, zone_id, performance_cost)"
"VALUES (?, ?, ?, ?, ?, '', 0, 0, 0, UNIX_TIMESTAMP(), UNIX_TIMESTAMP(), '', 0, ?, 0.0)"
);
insertion->setUInt64(1, propertyId);
2022-07-28 13:39:57 +00:00
insertion->setUInt64(2, (uint32_t)playerId);
insertion->setUInt(3, templateId);
2022-03-31 04:58:59 +00:00
insertion->setUInt64(4, playerCloneId);
insertion->setString(5, zone->GetZoneName().c_str());
2022-03-31 04:58:59 +00:00
insertion->setInt(6, propertyZoneId);
// Try and execute the query, print an error if it fails.
2022-07-28 13:39:57 +00:00
try {
insertion->execute();
2022-07-28 13:39:57 +00:00
} catch (sql::SQLException& exception) {
Game::logger->Log("PropertyManagementComponent", "Failed to execute query: (%s)!", exception.what());
throw exception;
2022-03-31 04:58:59 +00:00
return false;
}
auto* zoneControlObject = dZoneManager::Instance()->GetZoneControlObject();
2022-07-28 13:39:57 +00:00
for (CppScripts::Script* script : CppScripts::GetEntityScripts(zoneControlObject)) {
script->OnZonePropertyRented(zoneControlObject, entity);
}
2022-03-31 04:58:59 +00:00
return true;
}
2022-07-28 13:39:57 +00:00
void PropertyManagementComponent::OnStartBuilding() {
auto* ownerEntity = GetOwner();
if (ownerEntity == nullptr) return;
const auto players = Player::GetAllPlayers();
LWOMAPID zoneId = 1100;
const auto entrance = EntityManager::Instance()->GetEntitiesByComponent(COMPONENT_TYPE_PROPERTY_ENTRANCE);
originalPrivacyOption = privacyOption;
SetPrivacyOption(PropertyPrivacyOption::Private); // Cant visit player which is building
2022-07-28 13:39:57 +00:00
if (!entrance.empty()) {
auto* rocketPad = entrance[0]->GetComponent<RocketLaunchpadControlComponent>();
2022-07-28 13:39:57 +00:00
if (rocketPad != nullptr) {
zoneId = rocketPad->GetDefaultZone();
}
}
2022-07-28 13:39:57 +00:00
for (auto* player : players) {
if (player == ownerEntity) continue;
player->SendToZone(zoneId);
}
auto inventoryComponent = ownerEntity->GetComponent<InventoryComponent>();
// Push equipped items
if (inventoryComponent) inventoryComponent->PushEquippedItems();
}
2022-07-28 13:39:57 +00:00
void PropertyManagementComponent::OnFinishBuilding() {
auto* ownerEntity = GetOwner();
if (ownerEntity == nullptr) return;
SetPrivacyOption(originalPrivacyOption);
UpdateApprovedStatus(false);
Save();
}
2022-07-28 13:39:57 +00:00
void PropertyManagementComponent::UpdateModelPosition(const LWOOBJID id, const NiPoint3 position, NiQuaternion rotation) {
Game::logger->Log("PropertyManagementComponent", "Placing model <%f, %f, %f>", position.x, position.y, position.z);
auto* entity = GetOwner();
2022-07-28 13:39:57 +00:00
if (entity == nullptr) {
return;
}
auto* inventoryComponent = entity->GetComponent<InventoryComponent>();
2022-07-28 13:39:57 +00:00
if (inventoryComponent == nullptr) {
return;
}
auto* item = inventoryComponent->FindItemById(id);
2022-07-28 13:39:57 +00:00
if (item == nullptr) {
Game::logger->Log("PropertyManagementComponent", "Failed to find item with id %d", id);
return;
}
NiQuaternion originalRotation = rotation;
const auto modelLOT = item->GetLot();
2022-07-28 13:39:57 +00:00
if (rotation != NiQuaternion::IDENTITY) {
rotation = { rotation.w, rotation.z, rotation.y, rotation.x };
}
if (item->GetLot() == 6662) {
LWOOBJID spawnerID = item->GetSubKey();
EntityInfo info;
info.lot = 14;
info.pos = {};
info.rot = {};
info.spawner = nullptr;
info.spawnerID = spawnerID;
info.spawnerNodeID = 0;
for (auto* setting : item->GetConfig()) {
info.settings.push_back(setting->Copy());
}
Entity* newEntity = EntityManager::Instance()->CreateEntity(info);
if (newEntity != nullptr) {
EntityManager::Instance()->ConstructEntity(newEntity);
// Make sure the propMgmt doesn't delete our model after the server dies
// Trying to do this after the entity is constructed. Shouldn't really change anything but
// There was an issue with builds not appearing since it was placed above ConstructEntity.
PropertyManagementComponent::Instance()->AddModel(newEntity->GetObjectID(), spawnerID);
}
item->SetCount(item->GetCount() - 1);
return;
}
item->SetCount(item->GetCount() - 1);
auto* node = new SpawnerNode();
node->position = position;
node->rotation = rotation;
2022-07-28 13:39:57 +00:00
ObjectIDManager::Instance()->RequestPersistentID([this, node, modelLOT, entity, position, rotation, originalRotation](uint32_t persistentId) {
SpawnerInfo info{};
2022-07-28 13:39:57 +00:00
info.templateID = modelLOT;
info.nodes = { node };
info.templateScale = 1.0f;
info.activeOnLoad = true;
info.amountMaintained = 1;
info.respawnTime = 10;
2022-07-28 13:39:57 +00:00
info.emulated = true;
info.emulator = EntityManager::Instance()->GetZoneControlEntity()->GetObjectID();
2022-07-28 13:39:57 +00:00
LWOOBJID id = static_cast<LWOOBJID>(persistentId) | 1ull << OBJECT_BIT_CLIENT;
2022-07-28 13:39:57 +00:00
info.spawnerID = id;
2022-07-28 13:39:57 +00:00
const auto spawnerId = dZoneManager::Instance()->MakeSpawner(info);
2022-07-28 13:39:57 +00:00
auto* spawner = dZoneManager::Instance()->GetSpawner(spawnerId);
2022-07-28 13:39:57 +00:00
auto ldfModelBehavior = new LDFData<LWOOBJID>(u"modelBehaviors", 0);
auto userModelID = new LDFData<LWOOBJID>(u"userModelID", id);
auto modelType = new LDFData<int>(u"modelType", 2);
auto propertyObjectID = new LDFData<bool>(u"propertyObjectID", true);
auto componentWhitelist = new LDFData<int>(u"componentWhitelist", 1);
info.nodes[0]->config.push_back(componentWhitelist);
info.nodes[0]->config.push_back(ldfModelBehavior);
info.nodes[0]->config.push_back(modelType);
info.nodes[0]->config.push_back(propertyObjectID);
info.nodes[0]->config.push_back(userModelID);
2022-07-28 13:39:57 +00:00
auto* model = spawner->Spawn();
2022-07-28 13:39:57 +00:00
models.insert_or_assign(model->GetObjectID(), spawnerId);
2022-07-28 13:39:57 +00:00
GameMessages::SendPlaceModelResponse(entity->GetObjectID(), entity->GetSystemAddress(), position, m_Parent->GetObjectID(), 14, originalRotation);
2022-07-28 13:39:57 +00:00
GameMessages::SendUGCEquipPreCreateBasedOnEditMode(entity->GetObjectID(), entity->GetSystemAddress(), 0, spawnerId);
2022-07-28 13:39:57 +00:00
GameMessages::SendGetModelsOnProperty(entity->GetObjectID(), GetModels(), UNASSIGNED_SYSTEM_ADDRESS);
2022-07-28 13:39:57 +00:00
EntityManager::Instance()->GetZoneControlEntity()->OnZonePropertyModelPlaced(entity);
});
2022-07-28 13:39:57 +00:00
// Progress place model missions
auto missionComponent = entity->GetComponent<MissionComponent>();
if (missionComponent != nullptr) missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_PLACE_MODEL, 0);
}
2022-07-28 13:39:57 +00:00
void PropertyManagementComponent::DeleteModel(const LWOOBJID id, const int deleteReason) {
Game::logger->Log("PropertyManagementComponent", "Delete model: (%llu) (%i)", id, deleteReason);
auto* entity = GetOwner();
2022-07-28 13:39:57 +00:00
if (entity == nullptr) {
return;
}
auto* inventoryComponent = entity->GetComponent<InventoryComponent>();
2022-07-28 13:39:57 +00:00
if (inventoryComponent == nullptr) {
return;
}
const auto index = models.find(id);
2022-07-28 13:39:57 +00:00
if (index == models.end()) {
Game::logger->Log("PropertyManagementComponent", "Failed to find model");
return;
}
const auto spawnerId = index->second;
auto* spawner = dZoneManager::Instance()->GetSpawner(spawnerId);
models.erase(id);
2022-07-28 13:39:57 +00:00
if (spawner == nullptr) {
Game::logger->Log("PropertyManagementComponent", "Failed to find spawner");
}
auto* model = EntityManager::Instance()->GetEntity(id);
2022-07-28 13:39:57 +00:00
if (model == nullptr) {
Game::logger->Log("PropertyManagementComponent", "Failed to find model entity");
return;
}
EntityManager::Instance()->DestructEntity(model);
Game::logger->Log("PropertyManagementComponent", "Deleting model LOT %i", model->GetLOT());
2022-07-28 13:39:57 +00:00
if (model->GetLOT() == 14) {
//add it to the inv
std::vector<LDFBaseData*> settings;
//fill our settings with BBB gurbage
LDFBaseData* ldfBlueprintID = new LDFData<LWOOBJID>(u"blueprintid", model->GetVar<LWOOBJID>(u"blueprintid"));
LDFBaseData* userModelDesc = new LDFData<std::u16string>(u"userModelDesc", u"A cool model you made!");
LDFBaseData* userModelHasBhvr = new LDFData<bool>(u"userModelHasBhvr", false);
LDFBaseData* userModelID = new LDFData<LWOOBJID>(u"userModelID", model->GetVar<LWOOBJID>(u"userModelID"));
LDFBaseData* userModelMod = new LDFData<bool>(u"userModelMod", false);
LDFBaseData* userModelName = new LDFData<std::u16string>(u"userModelName", u"My Cool Model");
LDFBaseData* propertyObjectID = new LDFData<bool>(u"userModelOpt", true);
LDFBaseData* modelType = new LDFData<int>(u"userModelPhysicsType", 2);
settings.push_back(ldfBlueprintID);
settings.push_back(userModelDesc);
settings.push_back(userModelHasBhvr);
settings.push_back(userModelID);
settings.push_back(userModelMod);
settings.push_back(userModelName);
settings.push_back(propertyObjectID);
settings.push_back(modelType);
inventoryComponent->AddItem(6662, 1, eLootSourceType::LOOT_SOURCE_DELETION, eInventoryType::HIDDEN, settings, LWOOBJID_EMPTY, false, false, spawnerId);
auto* item = inventoryComponent->FindItemBySubKey(spawnerId);
if (item == nullptr) {
return;
}
2022-07-28 13:39:57 +00:00
if (deleteReason == 0) {
//item->Equip();
}
2022-07-28 13:39:57 +00:00
if (deleteReason == 0 || deleteReason == 2) {
GameMessages::SendUGCEquipPostDeleteBasedOnEditMode(entity->GetObjectID(), entity->GetSystemAddress(), item->GetId(), item->GetCount());
}
GameMessages::SendGetModelsOnProperty(entity->GetObjectID(), GetModels(), UNASSIGNED_SYSTEM_ADDRESS);
GameMessages::SendPlaceModelResponse(entity->GetObjectID(), entity->GetSystemAddress(), NiPoint3::ZERO, LWOOBJID_EMPTY, 16, NiQuaternion::IDENTITY);
2022-07-28 13:39:57 +00:00
if (spawner != nullptr) {
dZoneManager::Instance()->RemoveSpawner(spawner->m_Info.spawnerID);
2022-07-28 13:39:57 +00:00
} else {
model->Smash(SILENT);
}
item->SetCount(0, true, false, false);
return;
}
inventoryComponent->AddItem(model->GetLOT(), 1, eLootSourceType::LOOT_SOURCE_DELETION, INVALID, {}, LWOOBJID_EMPTY, false);
auto* item = inventoryComponent->FindItemByLot(model->GetLOT());
if (item == nullptr) {
return;
}
2022-07-28 13:39:57 +00:00
switch (deleteReason) {
case 0: // Pickup
{
item->Equip();
GameMessages::SendUGCEquipPostDeleteBasedOnEditMode(entity->GetObjectID(), entity->GetSystemAddress(), item->GetId(), item->GetCount());
EntityManager::Instance()->GetZoneControlEntity()->OnZonePropertyModelPickedUp(entity);
break;
}
case 1: // Return to inv
{
EntityManager::Instance()->GetZoneControlEntity()->OnZonePropertyModelRemoved(entity);
break;
}
case 2: // Break apart
{
item->SetCount(item->GetCount() - 1);
Game::logger->Log("BODGE TIME", "YES IT GOES HERE");
break;
}
default:
{
Game::logger->Log("PropertyManagementComponent", "Invalid delete reason");
}
}
GameMessages::SendGetModelsOnProperty(entity->GetObjectID(), GetModels(), UNASSIGNED_SYSTEM_ADDRESS);
GameMessages::SendPlaceModelResponse(entity->GetObjectID(), entity->GetSystemAddress(), NiPoint3::ZERO, LWOOBJID_EMPTY, 16, NiQuaternion::IDENTITY);
2022-07-28 13:39:57 +00:00
if (spawner != nullptr) {
dZoneManager::Instance()->RemoveSpawner(spawner->m_Info.spawnerID);
2022-07-28 13:39:57 +00:00
} else {
model->Smash(SILENT);
}
}
2022-07-28 13:39:57 +00:00
void PropertyManagementComponent::UpdateApprovedStatus(const bool value) {
if (owner == LWOOBJID_EMPTY) return;
auto* update = Database::CreatePreppedStmt("UPDATE properties SET mod_approved = ? WHERE id = ?;");
update->setBoolean(1, value);
update->setInt64(2, propertyId);
update->executeUpdate();
delete update;
}
2022-07-28 13:39:57 +00:00
void PropertyManagementComponent::Load() {
if (propertyId == LWOOBJID_EMPTY) {
return;
}
auto* lookup = Database::CreatePreppedStmt("SELECT id, lot, x, y, z, rx, ry, rz, rw, ugc_id FROM properties_contents WHERE property_id = ?;");
lookup->setUInt64(1, propertyId);
auto* lookupResult = lookup->executeQuery();
2022-07-28 13:39:57 +00:00
while (lookupResult->next()) {
const LWOOBJID id = lookupResult->getUInt64(1);
const LOT lot = lookupResult->getInt(2);
const NiPoint3 position =
{
static_cast<float>(lookupResult->getDouble(3)),
static_cast<float>(lookupResult->getDouble(4)),
static_cast<float>(lookupResult->getDouble(5))
};
const NiQuaternion rotation =
{
static_cast<float>(lookupResult->getDouble(9)),
static_cast<float>(lookupResult->getDouble(6)),
static_cast<float>(lookupResult->getDouble(7)),
static_cast<float>(lookupResult->getDouble(8))
};
auto* node = new SpawnerNode();
node->position = position;
node->rotation = rotation;
SpawnerInfo info{};
info.templateID = lot;
info.nodes = { node };
info.templateScale = 1.0f;
info.activeOnLoad = true;
info.amountMaintained = 1;
info.respawnTime = 10;
//info.emulated = true;
//info.emulator = EntityManager::Instance()->GetZoneControlEntity()->GetObjectID();
info.spawnerID = id;
std::vector<LDFBaseData*> settings;
//BBB property models need to have extra stuff set for them:
if (lot == 14) {
LWOOBJID blueprintID = lookupResult->getUInt(10);
blueprintID = GeneralUtils::SetBit(blueprintID, OBJECT_BIT_CHARACTER);
blueprintID = GeneralUtils::SetBit(blueprintID, OBJECT_BIT_PERSISTENT);
LDFBaseData* ldfBlueprintID = new LDFData<LWOOBJID>(u"blueprintid", blueprintID);
LDFBaseData* componentWhitelist = new LDFData<int>(u"componentWhitelist", 1);
LDFBaseData* modelType = new LDFData<int>(u"modelType", 2);
LDFBaseData* propertyObjectID = new LDFData<bool>(u"propertyObjectID", true);
LDFBaseData* userModelID = new LDFData<LWOOBJID>(u"userModelID", id);
settings.push_back(ldfBlueprintID);
settings.push_back(componentWhitelist);
settings.push_back(modelType);
settings.push_back(propertyObjectID);
settings.push_back(userModelID);
} else {
auto modelType = new LDFData<int>(u"modelType", 2);
auto userModelID = new LDFData<LWOOBJID>(u"userModelID", id);
auto ldfModelBehavior = new LDFData<LWOOBJID>(u"modelBehaviors", 0);
auto propertyObjectID = new LDFData<bool>(u"propertyObjectID", true);
auto componentWhitelist = new LDFData<int>(u"componentWhitelist", 1);
settings.push_back(componentWhitelist);
settings.push_back(ldfModelBehavior);
settings.push_back(modelType);
settings.push_back(propertyObjectID);
settings.push_back(userModelID);
}
node->config = settings;
const auto spawnerId = dZoneManager::Instance()->MakeSpawner(info);
auto* spawner = dZoneManager::Instance()->GetSpawner(spawnerId);
auto* model = spawner->Spawn();
models.insert_or_assign(model->GetObjectID(), spawnerId);
}
delete lookup;
}
2022-07-28 13:39:57 +00:00
void PropertyManagementComponent::Save() {
if (propertyId == LWOOBJID_EMPTY) {
return;
}
auto* insertion = Database::CreatePreppedStmt("INSERT INTO properties_contents VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);");
auto* update = Database::CreatePreppedStmt("UPDATE properties_contents SET x = ?, y = ?, z = ?, rx = ?, ry = ?, rz = ?, rw = ? WHERE id = ?;");
auto* lookup = Database::CreatePreppedStmt("SELECT id FROM properties_contents WHERE property_id = ?;");
auto* remove = Database::CreatePreppedStmt("DELETE FROM properties_contents WHERE id = ?;");
lookup->setUInt64(1, propertyId);
sql::ResultSet* lookupResult = nullptr;
try {
lookupResult = lookup->executeQuery();
} catch (sql::SQLException& ex) {
Game::logger->Log("PropertyManagementComponent", "lookup error %s", ex.what());
}
std::vector<LWOOBJID> present;
2022-07-28 13:39:57 +00:00
while (lookupResult->next()) {
const auto dbId = lookupResult->getUInt64(1);
present.push_back(dbId);
}
delete lookupResult;
std::vector<LWOOBJID> modelIds;
2022-07-28 13:39:57 +00:00
for (const auto& pair : models) {
const auto id = pair.second;
modelIds.push_back(id);
auto* entity = EntityManager::Instance()->GetEntity(pair.first);
2022-07-28 13:39:57 +00:00
if (entity == nullptr) {
continue;
}
const auto position = entity->GetPosition();
const auto rotation = entity->GetRotation();
2022-07-28 13:39:57 +00:00
if (std::find(present.begin(), present.end(), id) == present.end()) {
insertion->setInt64(1, id);
insertion->setUInt64(2, propertyId);
insertion->setNull(3, 0);
insertion->setInt(4, entity->GetLOT());
insertion->setDouble(5, position.x);
insertion->setDouble(6, position.y);
insertion->setDouble(7, position.z);
insertion->setDouble(8, rotation.x);
insertion->setDouble(9, rotation.y);
insertion->setDouble(10, rotation.z);
insertion->setDouble(11, rotation.w);
insertion->setString(12, "Objects_" + std::to_string(entity->GetLOT()) + "_name"); // Model name. TODO make this customizable
insertion->setString(13, ""); // Model description. TODO implement this.
insertion->setDouble(14, 0); // behavior 1. TODO implement this.
insertion->setDouble(15, 0); // behavior 2. TODO implement this.
insertion->setDouble(16, 0); // behavior 3. TODO implement this.
insertion->setDouble(17, 0); // behavior 4. TODO implement this.
insertion->setDouble(18, 0); // behavior 5. TODO implement this.
try {
insertion->execute();
} catch (sql::SQLException& ex) {
Game::logger->Log("PropertyManagementComponent", "Error inserting into properties_contents. Error %s", ex.what());
}
2022-07-28 13:39:57 +00:00
} else {
update->setDouble(1, position.x);
update->setDouble(2, position.y);
update->setDouble(3, position.z);
update->setDouble(4, rotation.x);
update->setDouble(5, rotation.y);
update->setDouble(6, rotation.z);
update->setDouble(7, rotation.w);
update->setInt64(8, id);
try {
update->executeUpdate();
} catch (sql::SQLException& ex) {
Game::logger->Log("PropertyManagementComponent", "Error updating properties_contents. Error: %s", ex.what());
}
}
}
2022-07-28 13:39:57 +00:00
for (auto id : present) {
if (std::find(modelIds.begin(), modelIds.end(), id) != modelIds.end()) {
continue;
}
remove->setInt64(1, id);
try {
remove->execute();
} catch (sql::SQLException& ex) {
Game::logger->Log("PropertyManagementComponent", "Error removing from properties_contents. Error %s", ex.what());
}
}
auto* removeUGC = Database::CreatePreppedStmt("DELETE FROM ugc WHERE id NOT IN (SELECT ugc_id FROM properties_contents);");
removeUGC->execute();
delete removeUGC;
delete insertion;
delete update;
delete lookup;
delete remove;
}
2022-07-28 13:39:57 +00:00
void PropertyManagementComponent::AddModel(LWOOBJID modelId, LWOOBJID spawnerId) {
models[modelId] = spawnerId;
}
2022-07-28 13:39:57 +00:00
PropertyManagementComponent* PropertyManagementComponent::Instance() {
return instance;
}
2022-07-28 13:39:57 +00:00
void PropertyManagementComponent::OnQueryPropertyData(Entity* originator, const SystemAddress& sysAddr, LWOOBJID author) {
if (author == LWOOBJID_EMPTY) {
author = m_Parent->GetObjectID();
}
2022-07-28 13:39:57 +00:00
const auto& worldId = dZoneManager::Instance()->GetZone()->GetZoneID();
const auto zoneId = worldId.GetMapID();
2022-07-28 13:39:57 +00:00
Game::logger->Log("Properties", "Getting property info for %d", zoneId);
GameMessages::PropertyDataMessage message = GameMessages::PropertyDataMessage(zoneId);
const auto isClaimed = GetOwnerId() != LWOOBJID_EMPTY;
LWOOBJID ownerId = GetOwnerId();
std::string ownerName = "";
std::string name = "";
std::string description = "";
uint64_t claimed = 0;
char privacy = 0;
if (isClaimed) {
const auto cloneId = worldId.GetCloneID();
auto* nameLookup = Database::CreatePreppedStmt("SELECT name FROM charinfo WHERE prop_clone_id = ?;");
nameLookup->setUInt64(1, cloneId);
auto* nameResult = nameLookup->executeQuery();
if (nameResult->next()) {
ownerName = nameResult->getString(1).c_str();
}
delete nameResult;
delete nameLookup;
name = propertyName;
description = propertyDescription;
claimed = claimedTime;
privacy = static_cast<char>(this->privacyOption);
if (moderatorRequested) {
auto checkStatus = Database::CreatePreppedStmt("SELECT rejection_reason, mod_approved FROM properties WHERE id = ?;");
checkStatus->setInt64(1, propertyId);
auto result = checkStatus->executeQuery();
result->next();
Add Aarch64 support (#231) * added mariadb-connector-cpp submodule * raknet aarch64 support * fix compile errors * mariadb connector swap (in progress) * update CMakeLists, add preprocessor definition to switch between mysql and mariadb connectors * update types with missing aarch64 check * corrected adding extra flag to properly compile mariadbconn in CMakeLists * updated readme with arm builds section * fix build failure if test folder does not exist * Remove mysql connector from all builds, add mariadbconnector to windows build * readd Linux check for backtrace lib to CMakeLists.txt * Separate system specific mariadbconncpp extra compile flags * Copy dlls to exes directory once built * fetch prebuilt binaries on windows so that ClangCL can be used * Delay load dll so that plugin directory is set correctly * Fixed typo in glibcxx compile flag * whitespacing, spaces -> tabs * Updated README.md, included instructions to update * Updated README.md added libssl-dev requirement and removed mysql connector references from macOS builds section * apple compile fixes for zlib and shared library name * add windows arm64 checks to raknet * remove extra . in shared library location * Setup plugins directory for the connector to search in, pass openssl_root_dir on for apple * Fix copy paths for single config generators and non windows * change plugin folder location, another single config generator fix * GENERATOR_IS_MULTI_CONFIG is a property not a variable * Fixed a few errors after merge * Fix plugin directory path, force windows to look at the right folder * fixed directory name for make_directory command * Update README.md Updated MacOS, Windows build instructions. * set INSTALL_PLUGINDIR so that the right directory is used * Support for relative rpath for docker build * added mariadb-connector-cpp submodule * raknet aarch64 support * fix compile errors * mariadb connector swap (in progress) * update CMakeLists, add preprocessor definition to switch between mysql and mariadb connectors * update types with missing aarch64 check * corrected adding extra flag to properly compile mariadbconn in CMakeLists * updated readme with arm builds section * fix build failure if test folder does not exist * Remove mysql connector from all builds, add mariadbconnector to windows build * readd Linux check for backtrace lib to CMakeLists.txt * Separate system specific mariadbconncpp extra compile flags * Copy dlls to exes directory once built * fetch prebuilt binaries on windows so that ClangCL can be used * Delay load dll so that plugin directory is set correctly * Fixed typo in glibcxx compile flag * whitespacing, spaces -> tabs * Updated README.md, included instructions to update * Updated README.md added libssl-dev requirement and removed mysql connector references from macOS builds section * apple compile fixes for zlib and shared library name * add windows arm64 checks to raknet * Setup plugins directory for the connector to search in, pass openssl_root_dir on for apple * Fix copy paths for single config generators and non windows * change plugin folder location, another single config generator fix * GENERATOR_IS_MULTI_CONFIG is a property not a variable * Fixed a few errors after merge * Fix plugin directory path, force windows to look at the right folder * fixed directory name for make_directory command * Update README.md Updated MacOS, Windows build instructions. * set INSTALL_PLUGINDIR so that the right directory is used * Support for relative rpath for docker build * Rebase on main * Remove extra git submodule * Update CMakeLists.txt * Remove CMakeLists.txt file from mariadb Remove the CMakeLists.txt file from the mariaDBConnector so we dont build the tests. Also add a config option to the CMakeVariables.txt so you can build the connector with multiple jobs * Compile on windows Specify the mariadbcpp.dll file location with a defined absolute path so windows knows it actually exists. * default to 1 job Default mariadb jobs running in parallel to 1 instead of 4 * Move mariadbcpp.dll file to the expected directory on windows * Changed plugin Updated the plugin location from the project binary directory to the expected location, the mariadb binary directory. * Addressed windows dll issues by moving files to the expected directory instead of a directory that wouldnt get created * Update README Co-authored-by: Aaron Kimbrell <aronwk.aaron@gmail.com> Co-authored-by: EmosewaMC <39972741+EmosewaMC@users.noreply.github.com>
2022-07-04 04:33:05 +00:00
const auto reason = std::string(result->getString(1).c_str());
const auto modApproved = result->getInt(2);
if (reason != "") {
moderatorRequested = false;
rejectionReason = reason;
} else if (reason == "" && modApproved == 1) {
moderatorRequested = false;
rejectionReason = "";
} else {
moderatorRequested = true;
rejectionReason = "";
}
}
}
message.moderatorRequested = moderatorRequested;
message.reputation = reputation;
message.LastUpdatedTime = LastUpdatedTime;
message.OwnerId = ownerId;
message.OwnerName = ownerName;
message.Name = name;
message.Description = description;
message.ClaimedTime = claimed;
message.PrivacyOption = privacy;
message.cloneId = clone_Id;
message.rejectionReason = rejectionReason;
message.Paths = GetPaths();
SendDownloadPropertyData(author, message, UNASSIGNED_SYSTEM_ADDRESS);
// send rejection here?
}
2022-07-28 13:39:57 +00:00
void PropertyManagementComponent::OnUse(Entity* originator) {
OnQueryPropertyData(originator, UNASSIGNED_SYSTEM_ADDRESS);
GameMessages::SendOpenPropertyManagment(m_Parent->GetObjectID(), originator->GetSystemAddress());
}
2022-07-28 13:39:57 +00:00
void PropertyManagementComponent::SetOwnerId(const LWOOBJID value) {
owner = value;
}
2022-07-28 13:39:57 +00:00
const std::map<LWOOBJID, LWOOBJID>& PropertyManagementComponent::GetModels() const {
return models;
}