From ee322f743381ec8b4c55df53ec116ef2ec4cb4d8 Mon Sep 17 00:00:00 2001 From: Joao Pasqualini Costa Date: Tue, 14 Nov 2023 11:58:24 -0300 Subject: [PATCH] Now it is possible to attache effects to tiles and set where it will be drawn --- modules/gamelib/gamelib.otmod | 1 + modules/gamelib/thing.lua | 4 ++ modules/gamelib/tile.lua | 39 ++++++++++++ src/CMakeLists.txt | 1 + src/client/attachableobject.cpp | 102 ++++++++++++++++++++++++++++++ src/client/attachableobject.h | 52 +++++++++++++++ src/client/attachedeffect.h | 14 ++++ src/client/luafunctions.cpp | 18 ++++-- src/client/thing.cpp | 109 +++++++------------------------- src/client/thing.h | 24 +++---- src/client/tile.cpp | 8 ++- src/client/tile.h | 5 +- vc17/otclient.vcxproj | 2 + vc17/otclient.vcxproj.filters | 6 ++ 14 files changed, 275 insertions(+), 110 deletions(-) create mode 100644 modules/gamelib/tile.lua create mode 100644 src/client/attachableobject.cpp create mode 100644 src/client/attachableobject.h diff --git a/modules/gamelib/gamelib.otmod b/modules/gamelib/gamelib.otmod index 4e066fb4b0..846c3287fa 100644 --- a/modules/gamelib/gamelib.otmod +++ b/modules/gamelib/gamelib.otmod @@ -19,6 +19,7 @@ Module dofile 'textmessages' dofile 'thing' dofile 'spells' + dofile 'tile' dofile 'eventcontroller' dofile 'controller' diff --git a/modules/gamelib/thing.lua b/modules/gamelib/thing.lua index 08cf79edb2..e26e5d3ef2 100644 --- a/modules/gamelib/thing.lua +++ b/modules/gamelib/thing.lua @@ -48,3 +48,7 @@ SpriteMaskRed = 1 SpriteMaskGreen = 2 SpriteMaskBlue = 3 SpriteMaskYellow = 4 + +function Thing:isTile() + return false +end diff --git a/modules/gamelib/tile.lua b/modules/gamelib/tile.lua new file mode 100644 index 0000000000..7b6b26f926 --- /dev/null +++ b/modules/gamelib/tile.lua @@ -0,0 +1,39 @@ +function Tile:isTile() + return true +end + +function Tile:isCreature() + return false +end + +function Tile:isLocalPlayer() + return false +end + +function Tile:isNpc() + return false +end + +function Tile:isMonster() + return false +end + +function Tile:isPlayer() + return false +end + +function Tile:isEffect() + return false +end + +function Tile:isMissile() + return false +end + +function Tile:isItem() + return false +end + +function Tile:isContainer() + return false +end diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 254210a352..dc8e6a408b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -234,6 +234,7 @@ endif() set(SOURCE_FILES client/animatedtext.cpp client/animator.cpp + client/attachableobject.cpp client/attachedeffect.cpp client/attachedeffectmanager.cpp client/client.cpp diff --git a/src/client/attachableobject.cpp b/src/client/attachableobject.cpp new file mode 100644 index 0000000000..9fb4347c93 --- /dev/null +++ b/src/client/attachableobject.cpp @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2010-2022 OTClient + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "attachableobject.h" +#include "tile.h" + +#include +#include + +void AttachableObject::attachEffect(const AttachedEffectPtr& obj) { + if (!obj) + return; + + onStartAttachEffect(obj); + + if (obj->isHidedOwner()) + ++m_ownerHidden; + + if (obj->getDuration() > 0) { + g_dispatcher.scheduleEvent([self = std::static_pointer_cast(shared_from_this()), effectId = obj->getId()]() { + self->detachEffectById(effectId); + }, obj->getDuration()); + } + + m_attachedEffects.emplace_back(obj); + g_dispatcher.addEvent([effect = obj, self = std::static_pointer_cast(shared_from_this())] { + self->onDispatcherAttachEffect(effect); + effect->callLuaField("onAttach", self->attachedObjectToLuaObject()); + }); +} + +bool AttachableObject::detachEffectById(uint16_t id) { + const auto it = std::find_if(m_attachedEffects.begin(), m_attachedEffects.end(), + [id](const AttachedEffectPtr& obj) { return obj->getId() == id; }); + + if (it == m_attachedEffects.end()) + return false; + + onDetachEffect(*it); + m_attachedEffects.erase(it); + + return true; +} + +void AttachableObject::onDetachEffect(const AttachedEffectPtr& effect) { + if (effect->isHidedOwner()) + --m_ownerHidden; + + onStartDetachEffect(effect); + + effect->callLuaField("onDetach", attachedObjectToLuaObject()); +} + +void AttachableObject::clearAttachedEffects() { + for (const auto& e : m_attachedEffects) + onDetachEffect(e); + m_attachedEffects.clear(); +} + +AttachedEffectPtr AttachableObject::getAttachedEffectById(uint16_t id) { + const auto it = std::find_if(m_attachedEffects.begin(), m_attachedEffects.end(), + [id](const AttachedEffectPtr& obj) { return obj->getId() == id; }); + + if (it == m_attachedEffects.end()) + return nullptr; + + return *it; +} + +void AttachableObject::drawAttachedEffect(const Point& dest, LightView* lightView, bool isOnTop, AttachedEffectDrawPlace drawPlace) +{ + for (const auto& effect : m_attachedEffects) { + if (effect->getDrawPlace() != drawPlace) + continue; + + effect->draw(dest, isOnTop, lightView); + if (effect->getLoop() == 0) { + g_dispatcher.addEvent([self = std::static_pointer_cast(shared_from_this()), effectId = effect->getId()]() { + self->detachEffectById(effectId); + }); + } + } +} diff --git a/src/client/attachableobject.h b/src/client/attachableobject.h new file mode 100644 index 0000000000..a19ebf942e --- /dev/null +++ b/src/client/attachableobject.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2010-2022 OTClient + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#pragma once +#include "attachedeffect.h" + + // @bindclass +#pragma pack(push,1) // disable memory alignment +class AttachableObject : public LuaObject +{ +public: + void attachEffect(const AttachedEffectPtr& obj); + void clearAttachedEffects(); + bool detachEffectById(uint16_t id); + AttachedEffectPtr getAttachedEffectById(uint16_t id); + + virtual LuaObjectPtr attachedObjectToLuaObject() = 0; + virtual void onStartAttachEffect(const AttachedEffectPtr& effect) { }; + virtual void onDispatcherAttachEffect(const AttachedEffectPtr& effect) { }; + virtual void onStartDetachEffect(const AttachedEffectPtr& effect) { }; + + bool isOwnerHidden() { return m_ownerHidden > 0; } + + const std::vector& getAttachedEffects() { return m_attachedEffects; }; + +protected: + void drawAttachedEffect(const Point& dest, LightView* lightView, bool isOnTop, AttachedEffectDrawPlace drawPlace = AttachedEffectDrawPlace::DEFAULT); + void onDetachEffect(const AttachedEffectPtr& effect); + + std::vector m_attachedEffects; + uint8_t m_ownerHidden{ 0 }; +}; +#pragma pack(pop) diff --git a/src/client/attachedeffect.h b/src/client/attachedeffect.h index 2f8dd891c9..f0d12cf1dd 100644 --- a/src/client/attachedeffect.h +++ b/src/client/attachedeffect.h @@ -25,6 +25,16 @@ #include "thingtype.h" #include "outfit.h" +enum class AttachedEffectDrawPlace : uint8_t +{ + DEFAULT, + BEFORE_GROUND, + BEFORE_ITEM, + BEFORE_CREATURE, + BEFORE_EFFECTS, + LAST, +}; + class AttachedEffect : public LuaObject { public: @@ -72,6 +82,9 @@ class AttachedEffect : public LuaObject void attachEffect(const AttachedEffectPtr& e) { m_effects.emplace_back(e); } + AttachedEffectDrawPlace getDrawPlace() { return m_drawPlace; } + void setDrawPlace(AttachedEffectDrawPlace drawPlace) { m_drawPlace = drawPlace; } + private: int getCurrentAnimationPhase(); @@ -86,6 +99,7 @@ class AttachedEffect : public LuaObject uint8_t m_speed{ 100 }; uint8_t m_opacity{ 100 }; uint8_t m_lastAnimation{ 0 }; + AttachedEffectDrawPlace m_drawPlace{ AttachedEffectDrawPlace::DEFAULT }; uint16_t m_id{ 0 }; uint16_t m_duration{ 0 }; diff --git a/src/client/luafunctions.cpp b/src/client/luafunctions.cpp index e023a41784..d44259d246 100644 --- a/src/client/luafunctions.cpp +++ b/src/client/luafunctions.cpp @@ -52,6 +52,7 @@ #include "uiminimap.h" #include "uiprogressrect.h" #include "uisprite.h" +#include "attachableobject.h" #ifdef FRAMEWORK_EDITOR #include "houses.h" @@ -391,7 +392,14 @@ void Client::registerLuaFunctions() g_lua.bindClassMemberFunction("getSize", &Container::getSize); g_lua.bindClassMemberFunction("getFirstIndex", &Container::getFirstIndex); - g_lua.registerClass(); + g_lua.registerClass(); + g_lua.bindClassMemberFunction("getAttachedEffects", &AttachableObject::getAttachedEffects); + g_lua.bindClassMemberFunction("attachEffect", &AttachableObject::attachEffect); + g_lua.bindClassMemberFunction("detachEffectById", &AttachableObject::detachEffectById); + g_lua.bindClassMemberFunction("getAttachedEffectById", &AttachableObject::getAttachedEffectById); + g_lua.bindClassMemberFunction("clearAttachedEffects", &AttachableObject::clearAttachedEffects); + + g_lua.registerClass(); g_lua.bindClassMemberFunction("setId", &Thing::setId); g_lua.bindClassMemberFunction("setShader", &Thing::setShader); g_lua.bindClassMemberFunction("setPosition", &Thing::setPosition); @@ -434,11 +442,6 @@ void Client::registerLuaFunctions() g_lua.bindClassMemberFunction("isTopEffect", &Thing::isTopEffect); g_lua.bindClassMemberFunction("isLyingCorpse", &Thing::isLyingCorpse); g_lua.bindClassMemberFunction("getDefaultAction", &Thing::getDefaultAction); - g_lua.bindClassMemberFunction("getAttachedEffects", &Thing::getAttachedEffects); - g_lua.bindClassMemberFunction("attachEffect", &Thing::attachEffect); - g_lua.bindClassMemberFunction("detachEffectById", &Thing::detachEffectById); - g_lua.bindClassMemberFunction("getAttachedEffectById", &Thing::getAttachedEffectById); - g_lua.bindClassMemberFunction("clearAttachedEffects", &Thing::clearAttachedEffects); g_lua.bindClassMemberFunction("getClassification", &Thing::getClassification); #ifdef FRAMEWORK_EDITOR @@ -690,6 +693,7 @@ void Client::registerLuaFunctions() g_lua.bindClassMemberFunction("canDrawOnUI", &AttachedEffect::canDrawOnUI); g_lua.bindClassMemberFunction("setCanDrawOnUI", &AttachedEffect::setCanDrawOnUI); g_lua.bindClassMemberFunction("attachEffect", &AttachedEffect::attachEffect); + g_lua.bindClassMemberFunction("setDrawPlace", &AttachedEffect::setDrawPlace); g_lua.registerClass(); g_lua.bindClassStaticFunction("create", [] { return std::make_shared(); }); @@ -756,7 +760,7 @@ void Client::registerLuaFunctions() g_lua.bindClassMemberFunction("setResourceBalance", &LocalPlayer::setResourceBalance); g_lua.bindClassMemberFunction("getTotalMoney", &LocalPlayer::getTotalMoney); - g_lua.registerClass(); + g_lua.registerClass(); g_lua.bindClassMemberFunction("clean", &Tile::clean); g_lua.bindClassMemberFunction("addThing", &Tile::addThing); g_lua.bindClassMemberFunction("getThing", &Tile::getThing); diff --git a/src/client/thing.cpp b/src/client/thing.cpp index 8ba9c590c0..1621195ad1 100644 --- a/src/client/thing.cpp +++ b/src/client/thing.cpp @@ -97,71 +97,40 @@ void Thing::setShader(const std::string_view name) { m_shader = g_shaders.getShader(name.data()); } -void Thing::attachEffect(const AttachedEffectPtr& obj) { - if (!obj) - return; - +void Thing::onStartAttachEffect(const AttachedEffectPtr& effect) { if (isCreature()) { - if (obj->m_thingType && (obj->m_thingType->isCreature() || obj->m_thingType->isMissile())) - obj->m_direction = static_self_cast()->getDirection(); - } - - if (obj->isHidedOwner()) - ++m_hidden; - - if (obj->getDuration() > 0) { - g_dispatcher.scheduleEvent([self = static_self_cast(), effectId = obj->getId()]() { - self->detachEffectById(effectId); - }, obj->getDuration()); - } - - if (obj->isDisabledWalkAnimation() && isCreature()) { - const auto& creature = static_self_cast(); - creature->setDisableWalkAnimation(true); - } - - m_attachedEffects.emplace_back(obj); - g_dispatcher.addEvent([effect = obj, self = static_self_cast()] { - if (effect->isTransform() && self->isCreature() && effect->m_thingType) { - const auto& creature = self->static_self_cast(); - const auto& outfit = creature->getOutfit(); - if (outfit.isTemp()) - return; - - effect->m_outfitOwner = outfit; - - Outfit newOutfit = outfit; - newOutfit.setTemp(true); - newOutfit.setCategory(effect->m_thingType->getCategory()); - if (newOutfit.isCreature()) - newOutfit.setId(effect->m_thingType->getId()); - else - newOutfit.setAuxId(effect->m_thingType->getId()); - - creature->setOutfit(newOutfit); + if (effect->isDisabledWalkAnimation()) { + const auto& creature = static_self_cast(); + creature->setDisableWalkAnimation(true); } - effect->callLuaField("onAttach", self->asLuaObject()); - }); + if (effect->m_thingType && (effect->m_thingType->isCreature() || effect->m_thingType->isMissile())) + effect->m_direction = static_self_cast()->getDirection(); + } } -bool Thing::detachEffectById(uint16_t id) { - const auto it = std::find_if(m_attachedEffects.begin(), m_attachedEffects.end(), - [id](const AttachedEffectPtr& obj) { return obj->getId() == id; }); +void Thing::onDispatcherAttachEffect(const AttachedEffectPtr& effect) { + if (effect->isTransform() && isCreature() && effect->m_thingType) { + const auto& creature = static_self_cast(); + const auto& outfit = creature->getOutfit(); + if (outfit.isTemp()) + return; - if (it == m_attachedEffects.end()) - return false; + effect->m_outfitOwner = outfit; - onDetachEffect(*it); - m_attachedEffects.erase(it); + Outfit newOutfit = outfit; + newOutfit.setTemp(true); + newOutfit.setCategory(effect->m_thingType->getCategory()); + if (newOutfit.isCreature()) + newOutfit.setId(effect->m_thingType->getId()); + else + newOutfit.setAuxId(effect->m_thingType->getId()); - return true; + creature->setOutfit(newOutfit); + } } -void Thing::onDetachEffect(const AttachedEffectPtr& effect) { - if (effect->isHidedOwner()) - --m_hidden; - +void Thing::onStartDetachEffect(const AttachedEffectPtr& effect) { if (isCreature()) { const auto& creature = static_self_cast(); @@ -172,34 +141,4 @@ void Thing::onDetachEffect(const AttachedEffectPtr& effect) { creature->setOutfit(effect->m_outfitOwner); } } - - effect->callLuaField("onDetach", asLuaObject()); -} - -void Thing::clearAttachedEffects() { - for (const auto& e : m_attachedEffects) - onDetachEffect(e); - m_attachedEffects.clear(); -} - -AttachedEffectPtr Thing::getAttachedEffectById(uint16_t id) { - const auto it = std::find_if(m_attachedEffects.begin(), m_attachedEffects.end(), - [id](const AttachedEffectPtr& obj) { return obj->getId() == id; }); - - if (it == m_attachedEffects.end()) - return nullptr; - - return *it; -} - -void Thing::drawAttachedEffect(const Point& dest, LightView* lightView, bool isOnTop) -{ - for (const auto& effect : m_attachedEffects) { - effect->draw(dest, isOnTop, lightView); - if (effect->getLoop() == 0) { - g_dispatcher.addEvent([self = static_self_cast(), effectId = effect->getId()]() { - self->detachEffectById(effectId); - }); - } - } } \ No newline at end of file diff --git a/src/client/thing.h b/src/client/thing.h index fdb09aa6e7..e8a29c1fb6 100644 --- a/src/client/thing.h +++ b/src/client/thing.h @@ -30,14 +30,17 @@ #include "spritemanager.h" #include "thingtype.h" #include "thingtypemanager.h" +#include "attachableobject.h" // @bindclass #pragma pack(push,1) // disable memory alignment -class Thing : public LuaObject +class Thing : public AttachableObject { public: virtual void draw(const Point& /*dest*/, bool drawThings = true, LightView* /*lightView*/ = nullptr) {} + LuaObjectPtr attachedObjectToLuaObject() override { return asLuaObject(); } + virtual void setId(uint32_t /*id*/) {} virtual void setPosition(const Position& position, uint8_t stackPos = 0, bool hasElevation = false); @@ -182,19 +185,12 @@ class Thing : public LuaObject bool isMarked() { return m_markedColor != Color::white; } void setMarkColor(const Color& color) { if (m_markedColor != color) m_markedColor = color; } - bool isHided() { return m_hidden > 0; } - - void attachEffect(const AttachedEffectPtr& obj); - void clearAttachedEffects(); - bool detachEffectById(uint16_t id); - AttachedEffectPtr getAttachedEffectById(uint16_t id); - - const std::vector& getAttachedEffects() { return m_attachedEffects; }; + bool isHided() { return isOwnerHidden(); } + void onStartAttachEffect(const AttachedEffectPtr& effect) override; + void onDispatcherAttachEffect(const AttachedEffectPtr& effect) override; + void onStartDetachEffect(const AttachedEffectPtr& effect) override; protected: - void drawAttachedEffect(const Point& dest, LightView* lightView, bool isOnTop); - - void onDetachEffect(const AttachedEffectPtr& effect); void setAttachedEffectDirection(Otc::Direction dir) const { for (const auto& effect : m_attachedEffects) { @@ -203,8 +199,6 @@ class Thing : public LuaObject } } - uint8_t m_hidden{ 0 }; - uint8_t m_numPatternX{ 0 }; uint8_t m_numPatternY{ 0 }; uint8_t m_numPatternZ{ 0 }; @@ -221,8 +215,6 @@ class Thing : public LuaObject PainterShaderProgramPtr m_shader; std::function m_shaderAction{ nullptr }; - std::vector m_attachedEffects; - private: bool m_canDraw{ true }; }; diff --git a/src/client/tile.cpp b/src/client/tile.cpp index 1776848ce1..8bc7bd0c06 100644 --- a/src/client/tile.cpp +++ b/src/client/tile.cpp @@ -48,6 +48,7 @@ void Tile::draw(const Point& dest, const MapPosInfo& mapRect, int flags, bool is m_drawElevation = 0; m_lastDrawDest = dest; + drawAttachedEffect(dest, lightView, false, AttachedEffectDrawPlace::BEFORE_GROUND); for (const auto& thing : m_things) { if (!thing->isGround() && !thing->isGroundBorder() && !thing->isOnBottom()) break; @@ -55,6 +56,7 @@ void Tile::draw(const Point& dest, const MapPosInfo& mapRect, int flags, bool is drawThing(thing, dest, flags, lightView); } + drawAttachedEffect(dest, lightView, false, AttachedEffectDrawPlace::BEFORE_ITEM); if (hasCommonItem()) { for (auto it = m_things.rbegin(); it != m_things.rend(); ++it) { const auto& item = *it; @@ -63,14 +65,18 @@ void Tile::draw(const Point& dest, const MapPosInfo& mapRect, int flags, bool is } } + drawAttachedEffect(dest, lightView, false, AttachedEffectDrawPlace::BEFORE_CREATURE); // after we render 2x2 lying corpses, we must redraw previous creatures/ontop above them for (const auto& tile : m_tilesRedraw) { tile->drawCreature(tile->m_lastDrawDest, mapRect, flags, isCovered, true, lightView); tile->drawTop(tile->m_lastDrawDest, flags, true, lightView); } - drawCreature(dest, mapRect, flags, isCovered, false, lightView); + + drawAttachedEffect(dest, lightView, false, AttachedEffectDrawPlace::BEFORE_EFFECTS); drawTop(dest, flags, false, lightView); + + drawAttachedEffect(dest, lightView, false, AttachedEffectDrawPlace::DEFAULT); updateWidget(dest, mapRect); } diff --git a/src/client/tile.h b/src/client/tile.h index 73486987b4..343693ad93 100644 --- a/src/client/tile.h +++ b/src/client/tile.h @@ -27,6 +27,7 @@ #include "effect.h" #include "item.h" #include "mapview.h" +#include "attachableobject.h" #ifdef FRAMEWORK_EDITOR enum tileflags_t : uint32_t @@ -88,11 +89,13 @@ enum TileThingType : uint32_t CORRECT_CORPSE = 1 << 25 }; -class Tile : public LuaObject +class Tile : public AttachableObject { public: Tile(const Position& position); + LuaObjectPtr attachedObjectToLuaObject() override { return asLuaObject(); } + void onAddInMapView(); void draw(const Point& dest, const MapPosInfo& mapRect, int flags, bool isCovered, LightView* lightView = nullptr); diff --git a/vc17/otclient.vcxproj b/vc17/otclient.vcxproj index 4e5a726a99..5a72bb26cc 100644 --- a/vc17/otclient.vcxproj +++ b/vc17/otclient.vcxproj @@ -206,6 +206,7 @@ cmd /c "start ../vcpkg_installed\$(VcpkgTriplet)\$(VcpkgTriplet)\tools\protobuf\ + @@ -356,6 +357,7 @@ cmd /c "start ../vcpkg_installed\$(VcpkgTriplet)\$(VcpkgTriplet)\tools\protobuf\ + diff --git a/vc17/otclient.vcxproj.filters b/vc17/otclient.vcxproj.filters index b4547e0517..04f550a23b 100644 --- a/vc17/otclient.vcxproj.filters +++ b/vc17/otclient.vcxproj.filters @@ -534,6 +534,9 @@ Source Files\protobuf + + Source Files\client + Source Files\client @@ -1046,6 +1049,9 @@ Header Files\protobuf + + Header Files\client + Header Files\client