From c4cea74d30829d45f7424508c36b5f05b237be23 Mon Sep 17 00:00:00 2001 From: Leonid Pospelov Date: Sat, 11 Nov 2023 03:14:49 +0600 Subject: [PATCH] feat(skymp5-server): add onCraft gamemode event (#1733) --- .../cpp/server_guest_lib/ActionListener.cpp | 22 ++++++++++++---- .../cpp/server_guest_lib/MpActor.cpp | 26 +++++++++++++++++-- skymp5-server/cpp/server_guest_lib/MpActor.h | 3 +++ 3 files changed, 44 insertions(+), 7 deletions(-) diff --git a/skymp5-server/cpp/server_guest_lib/ActionListener.cpp b/skymp5-server/cpp/server_guest_lib/ActionListener.cpp index 1ded5f774c..c0be3b84fa 100644 --- a/skymp5-server/cpp/server_guest_lib/ActionListener.cpp +++ b/skymp5-server/cpp/server_guest_lib/ActionListener.cpp @@ -363,17 +363,22 @@ void ActionListener::OnConsoleCommand( ConsoleCommands::Execute(*me, consoleCommandName, args); } -void UseCraftRecipe(MpActor* me, espm::COBJ::Data recipeData, +void UseCraftRecipe(MpActor* me, const espm::COBJ* recipeUsed, + espm::CompressedFieldsCache& cache, const espm::CombineBrowser& br, int espmIdx) { + auto recipeData = recipeUsed->GetData(cache); auto mapping = br.GetCombMapping(espmIdx); + std::vector entries; for (auto& entry : recipeData.inputObjects) { auto formId = espm::utils::GetMappedId(entry.formId, *mapping); entries.push_back({ formId, entry.count }); } + auto outputFormId = espm::utils::GetMappedId(recipeData.outputObjectFormId, *mapping); + if (spdlog::should_log(spdlog::level::debug)) { std::string s = fmt::format("User formId={:#x} crafted", me->GetFormId()); for (const auto& entry : entries) { @@ -382,8 +387,16 @@ void UseCraftRecipe(MpActor* me, espm::COBJ::Data recipeData, s += fmt::format(" +{:#x} x{}", outputFormId, recipeData.outputCount); spdlog::debug("{}", s); } - me->RemoveItems(entries); - me->AddItem(outputFormId, recipeData.outputCount); + + auto recipeId = espm::utils::GetMappedId(recipeUsed->GetId(), *mapping); + + if (me->MpApiCraft(outputFormId, recipeData.outputCount, recipeId)) { + spdlog::trace("onCraft - not blocked by gamemode"); + me->RemoveItems(entries); + me->AddItem(outputFormId, recipeData.outputCount); + } else { + spdlog::trace("onCraft - blocked by gamemode"); + } } void ActionListener::OnCraftItem(const RawMessageData& rawMsgData, @@ -422,8 +435,7 @@ void ActionListener::OnCraftItem(const RawMessageData& rawMsgData, throw std::runtime_error("Unable to craft without Actor attached"); } - auto recipeData = recipeUsed->GetData(cache); - UseCraftRecipe(me, recipeData, br, espmIdx); + UseCraftRecipe(me, recipeUsed, cache, br, espmIdx); } void ActionListener::OnHostAttempt(const RawMessageData& rawMsgData, diff --git a/skymp5-server/cpp/server_guest_lib/MpActor.cpp b/skymp5-server/cpp/server_guest_lib/MpActor.cpp index e25ab602a5..63e7d1a8da 100644 --- a/skymp5-server/cpp/server_guest_lib/MpActor.cpp +++ b/skymp5-server/cpp/server_guest_lib/MpActor.cpp @@ -602,8 +602,7 @@ void MpActor::MpApiDeath(MpActor* killer) simdjson::dom::parser parser; bool isRespawnBlocked = false; - std::string s = - "[" + std::to_string(killer ? killer->GetFormId() : 0) + " ]"; + std::string s = "[" + std::to_string(killer ? killer->GetFormId() : 0) + "]"; auto args = parser.parse(s).value(); if (auto wst = GetParent()) { @@ -614,11 +613,34 @@ void MpActor::MpApiDeath(MpActor* killer) }; } } + if (!isRespawnBlocked) { RespawnWithDelay(); } } +bool MpActor::MpApiCraft(uint32_t craftedItemBaseId, uint32_t count, + uint32_t recipeId) +{ + simdjson::dom::parser parser; + bool isCraftBlocked = false; + + std::string s = "[" + std::to_string(craftedItemBaseId) + "," + + std::to_string(count) + "," + std::to_string(recipeId) + "]"; + auto args = parser.parse(s).value(); + + if (auto wst = GetParent()) { + const auto id = GetFormId(); + for (auto& listener : wst->listeners) { + if (listener->OnMpApiEvent("onCraft", args, id) == false) { + isCraftBlocked = true; + }; + } + } + + return !isCraftBlocked; +} + void MpActor::EatItem(uint32_t baseId, espm::Type t) { auto espmProvider = GetParent(); diff --git a/skymp5-server/cpp/server_guest_lib/MpActor.h b/skymp5-server/cpp/server_guest_lib/MpActor.h index c3ec7d06cf..b327f85de2 100644 --- a/skymp5-server/cpp/server_guest_lib/MpActor.h +++ b/skymp5-server/cpp/server_guest_lib/MpActor.h @@ -130,6 +130,9 @@ class MpActor : public MpObjectReference void EquipBestWeapon(); + bool MpApiCraft(uint32_t craftedItemBaseId, uint32_t count, + uint32_t recipeId); + private: struct Impl; std::shared_ptr pImpl;