Skip to content

Commit

Permalink
fix: attached widgets flickering
Browse files Browse the repository at this point in the history
Co-authored-by: Renato Machado <mehahx@gmail.com>
  • Loading branch information
conde2 and mehah authored Jan 3, 2024
1 parent fa0cf54 commit e4350ce
Show file tree
Hide file tree
Showing 19 changed files with 153 additions and 118 deletions.
115 changes: 41 additions & 74 deletions src/client/attachableobject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,19 @@

#include "client.h"
#include "game.h"
#include "mapview.h"
#include "map.h"
#include "tile.h"
#include "uimap.h"
#include "mapview.h"

extern ParticleManager g_particles;

AttachableObject::~AttachableObject()
{
clearAttachedEffects();
clearAttachedParticlesEffect();
clearAttachedWidgets();
}

void AttachableObject::attachEffect(const AttachedEffectPtr& obj)
{
if (!obj)
Expand Down Expand Up @@ -95,25 +101,25 @@ void AttachableObject::clearAttachedEffects()
void AttachableObject::clearTemporaryAttachedEffects()
{
m_attachedEffects.erase(std::remove_if(m_attachedEffects.begin(), m_attachedEffects.end(),
[&](const AttachedEffectPtr& obj) {
if (!obj->isPermanent()) {
onDetachEffect(obj);
return true;
}
return false;
}), m_attachedEffects.end());
[&](const AttachedEffectPtr& obj) {
if (!obj->isPermanent()) {
onDetachEffect(obj);
return true;
}
return false;
}), m_attachedEffects.end());
}

void AttachableObject::clearPermanentAttachedEffects()
{
m_attachedEffects.erase(std::remove_if(m_attachedEffects.begin(), m_attachedEffects.end(),
[&](const AttachedEffectPtr& obj) {
if (obj->isPermanent()) {
onDetachEffect(obj);
return true;
}
return false;
}), m_attachedEffects.end());
[&](const AttachedEffectPtr& obj) {
if (obj->isPermanent()) {
onDetachEffect(obj);
return true;
}
return false;
}), m_attachedEffects.end());
}

AttachedEffectPtr AttachableObject::getAttachedEffectById(uint16_t id)
Expand Down Expand Up @@ -201,24 +207,28 @@ void AttachableObject::updateAndAttachParticlesEffects(std::vector<std::string>&
attachParticleEffect(name);
}

void AttachableObject::attachWidget(const UIWidgetPtr& widget)
{
if (!widget)
return;
bool AttachableObject::isWidgetAttached(const UIWidgetPtr& widget) {
return std::find_if(m_attachedWidgets.begin(), m_attachedWidgets.end(),
[widget](const UIWidgetPtr& obj) { return obj == widget; }) != m_attachedWidgets.end();
}

const auto& mapWidget = g_client.getMapWidget();
if (!mapWidget)
void AttachableObject::attachWidget(const UIWidgetPtr& widget) {
if (!widget || isWidgetAttached(widget))
return;

if (widget->isAttached()) {
g_logger.error(stdext::format("Failed to attach widget %s, this widget is already attached to other object.", widget->getId()));
if (g_map.isWidgetAttached(widget)) {
g_logger.error(stdext::format("Failed to attach widget %s, this widget is already attached to map.", widget->getId()));
return;
}

widget->setDraggable(false);
widget->setAttached(true);
widget->setParent(g_client.getMapWidget());
m_attachedWidgets.emplace_back(widget);
g_map.addAttachedWidgetToObject(widget, std::static_pointer_cast<AttachableObject>(shared_from_this()));
widget->callLuaField("onAttached", asLuaObject());
widget->addOnDestroyCallback("attached-widget-destroy", [this, widget]() {
detachWidget(widget);
});
}

bool AttachableObject::detachWidgetById(const std::string& id)
Expand All @@ -231,9 +241,8 @@ bool AttachableObject::detachWidgetById(const std::string& id)

const auto widget = (*it);
m_attachedWidgets.erase(it);

widget->setAttached(false);
widget->setVisible(false);
g_map.removeAttachedWidgetFromObject(widget);
widget->removeOnDestroyCallback("attached-widget-destroy");
widget->callLuaField("onDetached", asLuaObject());
return true;
}
Expand All @@ -245,9 +254,8 @@ bool AttachableObject::detachWidget(const UIWidgetPtr& widget)
return false;

m_attachedWidgets.erase(it);

widget->setAttached(false);
widget->setVisible(false);
g_map.removeAttachedWidgetFromObject(widget);
widget->removeOnDestroyCallback("attached-widget-destroy");
widget->callLuaField("onDetached", asLuaObject());
return true;
}
Expand All @@ -259,8 +267,8 @@ void AttachableObject::clearAttachedWidgets()
m_attachedWidgets.clear();

for (const auto& widget : oldList) {
widget->setAttached(false);
widget->setVisible(false);
g_map.removeAttachedWidgetFromObject(widget);
widget->removeOnDestroyCallback("attached-widget-destroy");
widget->callLuaField("onDetached", asLuaObject());
}
}
Expand All @@ -274,45 +282,4 @@ UIWidgetPtr AttachableObject::getAttachedWidgetById(const std::string& id)
return nullptr;

return *it;
}

void AttachableObject::drawAttachedWidgets(const Point& dest, const MapPosInfo& mapRect)
{
if (m_attachedWidgets.empty())
return;

g_drawPool.select(DrawPoolType::FOREGROUND_MAP_WIDGETS);
{
std::vector<UIWidgetPtr> toRemove;
for (const auto& widget : m_attachedWidgets) {
if (widget->isDestroyed()) {
toRemove.emplace_back(widget);
continue;
}

if (!widget->isVisible())
continue;

Point p = dest - mapRect.drawOffset;
p.x *= mapRect.horizontalStretchFactor;
p.y *= mapRect.verticalStretchFactor;
p += mapRect.rect.topLeft();

p.x += widget->getMarginLeft();
p.x -= widget->getMarginRight();
p.y += widget->getMarginTop();
p.y -= widget->getMarginBottom();

const auto& widgetRect = widget->getRect();
const auto& rect = Rect(p, widgetRect.width(), widgetRect.height());

widget->setRect(rect);
widget->draw(mapRect.rect, DrawPoolType::FOREGROUND);
}

for (const auto& widget : toRemove)
detachWidget(widget);
}
// Go back to use map pool
g_drawPool.select(DrawPoolType::MAP);
}
13 changes: 7 additions & 6 deletions src/client/attachableobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,22 +24,23 @@
#include "attachedeffect.h"
#include <framework/luaengine/luaobject.h>

struct MapPosInfo;

class AttachableObject : public LuaObject
{
public:
AttachableObject() = default;
virtual ~AttachableObject() = default;

virtual ~AttachableObject();

virtual LuaObjectPtr attachedObjectToLuaObject() = 0;
virtual bool isTile() { return false; }
virtual bool isThing() { return false; }

void attachEffect(const AttachedEffectPtr& obj);
void clearAttachedEffects();
void clearTemporaryAttachedEffects();
void clearPermanentAttachedEffects();
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) { };
Expand All @@ -55,6 +56,7 @@ class AttachableObject : public LuaObject

const std::vector<UIWidgetPtr>& getAttachedWidgets() { return m_attachedWidgets; };
bool hasAttachedWidgets() { return !m_attachedWidgets.empty(); };
bool isWidgetAttached(const UIWidgetPtr& widget);
void attachWidget(const UIWidgetPtr& widget);
void clearAttachedWidgets();
bool detachWidgetById(const std::string& id);
Expand All @@ -65,7 +67,6 @@ class AttachableObject : public LuaObject
void drawAttachedEffect(const Point& dest, LightView* lightView, bool isOnTop);
void onDetachEffect(const AttachedEffectPtr& effect);
void drawAttachedParticlesEffect(const Point& dest);
void drawAttachedWidgets(const Point& dest, const MapPosInfo& mapRect);

std::vector<AttachedEffectPtr> m_attachedEffects;
std::vector<ParticleEffectPtr> m_attachedParticles;
Expand Down
1 change: 0 additions & 1 deletion src/client/creature.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,6 @@ void Creature::internalDraw(Point dest, LightView* lightView, const Color& color
if (replaceColorShader)
g_drawPool.resetShaderProgram();
else {
m_lastDrawDest = dest;
drawAttachedEffect(dest, lightView, true); // On Top
drawAttachedParticlesEffect(dest);
}
Expand Down
2 changes: 2 additions & 0 deletions src/client/declarations.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ class ThingType;
class ItemType;
class TileBlock;
class AttachedEffect;
class AttachableObject;

#ifdef FRAMEWORK_EDITOR
class House;
Expand All @@ -75,6 +76,7 @@ using StaticTextPtr = std::shared_ptr<StaticText>;
using ThingTypePtr = std::shared_ptr<ThingType>;
using ItemTypePtr = std::shared_ptr<ItemType>;
using AttachedEffectPtr = std::shared_ptr<AttachedEffect>;
using AttachableObjectPtr = std::shared_ptr<AttachableObject>;

#ifdef FRAMEWORK_EDITOR
using HousePtr = std::shared_ptr<House>;
Expand Down
2 changes: 0 additions & 2 deletions src/client/item.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,6 @@ void Item::draw(const Point& dest, bool drawThings, LightView* lightView)
internalDraw(animationPhase, dest, getMarkedColor(), drawThings, true);
else if (isHighlighted())
internalDraw(animationPhase, dest, getHighlightColor(), drawThings, true);

m_lastDrawDest = dest;
}

void Item::internalDraw(int animationPhase, const Point& dest, const Color& color, bool drawThings, bool replaceColorShader, LightView* lightView)
Expand Down
69 changes: 69 additions & 0 deletions src/client/map.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include <framework/core/asyncdispatcher.h>
#include <framework/core/graphicalapplication.h>
#include <framework/core/eventdispatcher.h>
#include <framework/ui/uiwidget.h>
#include <queue>

#ifdef FRAMEWORK_EDITOR
Expand Down Expand Up @@ -1130,6 +1131,74 @@ bool Map::isSightClear(const Position& fromPos, const Position& toPos)
return true;
}

bool Map::isWidgetAttached(const UIWidgetPtr& widget) const {
return m_attachedObjectWidgetMap.find(widget) != m_attachedObjectWidgetMap.end();
}

void Map::addAttachedWidgetToObject(const UIWidgetPtr& widget, const AttachableObjectPtr& object) {
if (isWidgetAttached(widget))
return;

m_attachedObjectWidgetMap.emplace(widget, object);
}

bool Map::removeAttachedWidgetFromObject(const UIWidgetPtr& widget) {
// remove elemnt form unordered map
const auto it = m_attachedObjectWidgetMap.find(widget);
if (it == m_attachedObjectWidgetMap.end())
return false;

m_attachedObjectWidgetMap.erase(it);
return true;
}

void Map::updateAttachedWidgets(const MapViewPtr& mapView)
{
for (const auto& [widget, object] : m_attachedObjectWidgetMap) {
if (widget->isDestroyed()) {
continue;
}

if (!widget->isVisible())
continue;

Position pos;
if (object->isTile()) {
const auto& tile = object->static_self_cast<Tile>();
pos = tile->getPosition();
} else if (object->isThing()) {
const auto& thing = object->static_self_cast<Thing>();
pos = thing->getPosition();
}

if (!pos.isValid())
continue;

Point p = mapView->transformPositionTo2D(pos) - mapView->m_posInfo.drawOffset;

if (object->isThing() && object->static_self_cast<Thing>()->isCreature()) {
const auto& creature = object->static_self_cast<Thing>()->static_self_cast<Creature>();
const auto& jumpOffset = creature->getJumpOffset() * g_drawPool.getScaleFactor();
const auto& creatureOffset = Point(16 - creature->getDisplacementX(), -creature->getDisplacementY() - 2) + creature->getWalkOffset();
p += creatureOffset * g_drawPool.getScaleFactor() - Point(std::round(jumpOffset.x), std::round(jumpOffset.y));
}

p.x *= mapView->m_posInfo.horizontalStretchFactor;
p.y *= mapView->m_posInfo.verticalStretchFactor;
p += mapView->m_posInfo.rect.topLeft();

p.x += widget->getMarginLeft();
p.x -= widget->getMarginRight();
p.y += widget->getMarginTop();
p.y -= widget->getMarginBottom();

const auto& widgetRect = widget->getRect();
const auto& newWidgetRect = Rect(p, widgetRect.width(), widgetRect.height());

widget->setRect(newWidgetRect);
}
}

#ifndef BOT_PROTECTION
std::map<std::string, std::tuple<int, int, int, std::string>> Map::findEveryPath(const Position& start, int maxDistance, const std::map<std::string, std::string>& params)
{
Expand Down
7 changes: 7 additions & 0 deletions src/client/map.h
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,11 @@ class Map
void addAnimatedText(const AnimatedTextPtr& txt, const Position& pos);
bool removeAnimatedText(const AnimatedTextPtr& txt);

bool isWidgetAttached(const UIWidgetPtr& widget) const;
void addAttachedWidgetToObject(const UIWidgetPtr& widget, const AttachableObjectPtr& object);
bool removeAttachedWidgetFromObject(const UIWidgetPtr& widget);
void updateAttachedWidgets(const MapViewPtr& mapView);

void colorizeThing(const ThingPtr& thing, const Color& color);
void removeThingColor(const ThingPtr& thing);

Expand Down Expand Up @@ -317,6 +322,8 @@ class Map

std::unordered_map<uint32_t, CreaturePtr> m_knownCreatures;

std::unordered_map<UIWidgetPtr, AttachableObjectPtr> m_attachedObjectWidgetMap;

#ifdef FRAMEWORK_EDITOR
std::unordered_map<Position, std::string, Position::Hasher> m_waypoints;
std::unordered_map<uint32_t, Color> m_zoneColors;
Expand Down
2 changes: 2 additions & 0 deletions src/client/mapview.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@ void MapView::preLoad() {
m_fadeFinish = true;
}
}

g_map.updateAttachedWidgets(static_self_cast<MapView>());
}

void MapView::draw(const Rect& rect)
Expand Down
3 changes: 0 additions & 3 deletions src/client/thing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,3 @@ void Thing::setShader(const std::string_view name) {
m_shader = g_shaders.getShader(name.data());
}

void Thing::drawWidgets(const MapPosInfo& mapRect) {
drawAttachedWidgets(m_lastDrawDest, mapRect);
}
Loading

0 comments on commit e4350ce

Please sign in to comment.