diff --git a/README.md b/README.md index 86e54a735e..97e5905f97 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,7 @@ - Client 12.85 ~ 12.92, 13.00 ~ 13.14 support (protobuf) - Market has been rewritten to work only [Canary](https://github.com/opentibiabr/canary) - Async Texture Loading +- Tile Widget ##### Community (Features) - Mobile Support [@tuliomagalhaes](https://github.com/tuliomagalhaes) & [@BenDol](https://github.com/BenDol) diff --git a/src/client/luafunctions.cpp b/src/client/luafunctions.cpp index c31f56be66..e023a41784 100644 --- a/src/client/luafunctions.cpp +++ b/src/client/luafunctions.cpp @@ -788,6 +788,11 @@ void Client::registerLuaFunctions() g_lua.bindClassMemberFunction("select", &Tile::select); g_lua.bindClassMemberFunction("unselect", &Tile::unselect); g_lua.bindClassMemberFunction("isSelected", &Tile::isSelected); + + g_lua.bindClassMemberFunction("setWidget", &Tile::setWidget); + g_lua.bindClassMemberFunction("getWidget", &Tile::getWidget); + g_lua.bindClassMemberFunction("removeWidget", &Tile::removeWidget); + #ifdef FRAMEWORK_EDITOR g_lua.bindClassMemberFunction("isHouseTile", &Tile::isHouseTile); g_lua.bindClassMemberFunction("overwriteMinimapColor", &Tile::overwriteMinimapColor); diff --git a/src/client/map.cpp b/src/client/map.cpp index 7352e43b0d..1984077efb 100644 --- a/src/client/map.cpp +++ b/src/client/map.cpp @@ -519,7 +519,10 @@ void Map::removeUnawareThings() continue; } + tile->clean(); + block.remove(pos); + notificateTileUpdate(pos, nullptr, Otc::OPERATION_CLEAN); } if (blockEmpty) diff --git a/src/client/tile.cpp b/src/client/tile.cpp index e9bc47e04d..e8e1c7bda7 100644 --- a/src/client/tile.cpp +++ b/src/client/tile.cpp @@ -24,11 +24,14 @@ #include #include #include +#include +#include #include "effect.h" #include "game.h" #include "item.h" #include "lightview.h" #include "map.h" +#include "uimap.h" #include "protocolgame.h" Tile::Tile(const Position& position) : m_position(position) {} @@ -68,6 +71,7 @@ void Tile::draw(const Point& dest, const MapPosInfo& mapRect, int flags, bool is drawCreature(dest, mapRect, flags, isCovered, false, lightView); drawTop(dest, flags, false, lightView); + updateWidget(dest, mapRect); } void Tile::drawCreature(const Point& dest, const MapPosInfo& mapRect, int flags, bool isCovered, bool forceDraw, LightView* lightView) @@ -110,8 +114,62 @@ void Tile::drawTop(const Point& dest, int flags, bool forceDraw, LightView* ligh } } +void Tile::updateWidget(const Point& dest, const MapPosInfo& mapRect) +{ + if (!m_widget) + return; + + Point p = dest - mapRect.drawOffset; + p.x *= mapRect.horizontalStretchFactor; + p.y *= mapRect.verticalStretchFactor; + p += mapRect.rect.topLeft(); + + p.x += m_widget->getMarginLeft(); + p.x -= m_widget->getMarginRight(); + p.y += m_widget->getMarginTop(); + p.y -= m_widget->getMarginBottom(); + + const auto& widgetRect = m_widget->getRect(); + const auto& rect = Rect(p - Point(widgetRect.width() / 2 - g_gameConfig.getSpriteSize(), widgetRect.height() / 2 - g_gameConfig.getSpriteSize()), widgetRect.width(), widgetRect.height()); + + m_widget->setRect(rect); +} + +void Tile::drawWidget(const Point& dest, const MapPosInfo& mapRect) +{ + if (!m_widget) + return; + + m_widget->draw(mapRect.rect, DrawPoolType::FOREGROUND); +} + +void Tile::setWidget(const UIWidgetPtr& widget) { + removeWidget(); + + m_widget = widget; + m_widget->setClipping(true); + g_dispatcher.scheduleEvent([tile = static_self_cast()] { + g_ui.getMapWidget()->addTileWidget(tile); + }, g_game.getServerBeat()); +} + +void Tile::removeWidget() +{ + if (!m_widget) + return; + + m_widget->destroy(); + m_widget = nullptr; + + g_dispatcher.scheduleEvent([tile = static_self_cast()] { + g_ui.getMapWidget()->removeTileWidget(tile); + }, g_game.getServerBeat()); +} + void Tile::clean() { + removeWidget(); + m_highlightThing = nullptr; while (!m_things.empty()) removeThing(m_things.front()); diff --git a/src/client/tile.h b/src/client/tile.h index a935b00877..73486987b4 100644 --- a/src/client/tile.h +++ b/src/client/tile.h @@ -115,6 +115,12 @@ class Tile : public LuaObject ThingPtr getTopMoveThing(); ThingPtr getTopMultiUseThing(); + bool hasWidget() const { return m_widget != nullptr; } + void drawWidget(const Point& dest, const MapPosInfo& mapRect); + void setWidget(const UIWidgetPtr& widget); + UIWidgetPtr getWidget() { return m_widget; } + void removeWidget(); + int getDrawElevation() { return m_drawElevation; } const Position& getPosition() { return m_position; } const std::vector& getWalkingCreatures() { return m_walkingCreatures; } @@ -208,6 +214,7 @@ class Tile : public LuaObject void setThingFlag(const ThingPtr& thing); + void updateWidget(const Point& dest, const MapPosInfo& mapRect); void recalculateThingFlag() { m_thingTypeFlag = 0; @@ -239,6 +246,7 @@ class Tile : public LuaObject std::vector m_tilesRedraw; ThingPtr m_highlightThing; + UIWidgetPtr m_widget; TileSelectType m_selectType{ TileSelectType::NONE }; diff --git a/src/client/uimap.cpp b/src/client/uimap.cpp index 45480a2bea..38b9642c76 100644 --- a/src/client/uimap.cpp +++ b/src/client/uimap.cpp @@ -57,6 +57,14 @@ void UIMap::drawSelf(DrawPoolType drawPane) g_drawPool.addAction([] {glDisable(GL_BLEND); }); g_drawPool.addFilledRect(m_mapRect, Color::alpha); g_drawPool.addAction([] {glEnable(GL_BLEND); }); + + if (m_mapView) { + for (const auto& tile : m_tiles) { + const auto& dest = m_mapView->transformPositionTo2D(tile->getPosition(), m_mapView->m_lastCameraPosition); + tile->drawWidget(dest, m_mapView->m_posInfo); + } + } + return; } @@ -200,4 +208,17 @@ void UIMap::updateMapSize() updateVisibleDimension(); } +void UIMap::addTileWidget(const TilePtr& tile) { + std::scoped_lock l(g_drawPool.get(DrawPoolType::FOREGROUND)->getMutex()); + m_tiles.emplace_back(tile); +} +void UIMap::removeTileWidget(const TilePtr& tile) { + std::scoped_lock l(g_drawPool.get(DrawPoolType::FOREGROUND)->getMutex()); + const auto it = std::find(m_tiles.begin(), m_tiles.end(), tile); + if (it == m_tiles.end()) + return; + + m_tiles.erase(it); +} + /* vim: set ts=4 sw=4 et: */ \ No newline at end of file diff --git a/src/client/uimap.h b/src/client/uimap.h index fdee885201..7cc6979029 100644 --- a/src/client/uimap.h +++ b/src/client/uimap.h @@ -94,6 +94,9 @@ class UIMap : public UIWidget void setAntiAliasingMode(const MapView::AntialiasingMode mode) { m_mapView->setAntiAliasingMode(mode); } void setFloorFading(const uint16_t v) { m_mapView->setFloorFading(v); } + void addTileWidget(const TilePtr& tile); + void removeTileWidget(const TilePtr& tile); + protected: void onStyleApply(const std::string_view styleName, const OTMLNodePtr& styleNode) override; void onGeometryChange(const Rect& oldRect, const Rect& newRect) override; @@ -103,8 +106,10 @@ class UIMap : public UIWidget void updateVisibleDimension(); void updateMapSize(); + std::vector m_tiles; MapViewPtr m_mapView; Rect m_mapRect; + float m_aspectRatio; bool m_keepAspectRatio; diff --git a/src/framework/core/graphicalapplication.cpp b/src/framework/core/graphicalapplication.cpp index 684be96979..ee473bcbae 100644 --- a/src/framework/core/graphicalapplication.cpp +++ b/src/framework/core/graphicalapplication.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -139,8 +140,6 @@ void GraphicalApplication::run() std::condition_variable foreCondition, txtCondition; - UIWidgetPtr mapWidget; - // clang c++20 dont support jthread std::thread t1([&]() { while (!m_stopping) { @@ -161,17 +160,17 @@ void GraphicalApplication::run() foreCondition.notify_one(); if (g_game.isOnline()) { - if (!mapWidget) - mapWidget = g_ui.getRootWidget()->recursiveGetChildById("gameMapPanel"); + if (!g_ui.m_mapWidget) + g_ui.m_mapWidget = g_ui.getRootWidget()->recursiveGetChildById("gameMapPanel")->static_self_cast(); if (txt->canRepaint()) txtCondition.notify_one(); { std::scoped_lock l(map->getMutex()); - mapWidget->drawSelf(DrawPoolType::MAP); + g_ui.m_mapWidget->drawSelf(DrawPoolType::MAP); } - } else mapWidget = nullptr; + } else g_ui.m_mapWidget = nullptr; stdext::millisleep(1); } @@ -194,8 +193,8 @@ void GraphicalApplication::run() g_textDispatcher.poll(); txt->setEnable(canDrawTexts()); - if (mapWidget && txt->isEnabled()) - mapWidget->drawSelf(DrawPoolType::TEXT); + if (g_ui.m_mapWidget && txt->isEnabled()) + g_ui.m_mapWidget->drawSelf(DrawPoolType::TEXT); return m_stopping; }); diff --git a/src/framework/ui/declarations.h b/src/framework/ui/declarations.h index ec7c1a3ae1..4aebd615af 100644 --- a/src/framework/ui/declarations.h +++ b/src/framework/ui/declarations.h @@ -38,7 +38,9 @@ class UIAnchor; class UIAnchorGroup; class UIAnchorLayout; class UIParticles; +class UIMap; +using UIMapPtr = std::shared_ptr; using UIWidgetPtr = std::shared_ptr; using UIParticlesPtr = std::shared_ptr; using UITextEditPtr = std::shared_ptr; diff --git a/src/framework/ui/uimanager.h b/src/framework/ui/uimanager.h index bb8d4c0a91..a5a2e25374 100644 --- a/src/framework/ui/uimanager.h +++ b/src/framework/ui/uimanager.h @@ -50,6 +50,7 @@ class UIManager std::string getStyleClass(const std::string_view styleName); OTMLNodePtr findMainWidgetNode(const OTMLDocumentPtr& doc); + UIMapPtr getMapWidget() const { return m_mapWidget; } UIWidgetPtr loadUI(const std::string& file, const UIWidgetPtr& parent); OTMLNodePtr loadDeviceUI(const std::string& file, Platform::OperatingSystem os); OTMLNodePtr loadDeviceUI(const std::string& file, Platform::DeviceType deviceType); @@ -79,9 +80,11 @@ class UIManager void onWidgetDestroy(const UIWidgetPtr& widget); friend class UIWidget; + friend class GraphicalApplication; private: UIWidgetPtr m_rootWidget; + UIMapPtr m_mapWidget; UIWidgetPtr m_mouseReceiver; UIWidgetPtr m_keyboardReceiver; UIWidgetPtr m_draggingWidget; diff --git a/src/framework/ui/uiwidget.h b/src/framework/ui/uiwidget.h index f70dea568b..680c1bbd1a 100644 --- a/src/framework/ui/uiwidget.h +++ b/src/framework/ui/uiwidget.h @@ -80,8 +80,8 @@ class UIWidget : public LuaObject UIWidget(); ~UIWidget() override; virtual void drawSelf(DrawPoolType drawPane); -protected: virtual void draw(const Rect& visibleRect, DrawPoolType drawPane); +protected: virtual void drawChildren(const Rect& visibleRect, DrawPoolType drawPane); friend class UIManager;