From a4cef0d390e2b373404e84ed729be45de836ae96 Mon Sep 17 00:00:00 2001 From: Eduardo Bart Date: Wed, 28 Mar 2012 16:09:45 -0300 Subject: [PATCH] fix possible mapview crash --- modules/core_lib/widgets/uiresizeborder.lua | 6 +- modules/game/widgets/uiminiwindow.lua | 3 + .../game/widgets/uiminiwindowcontainer.lua | 6 +- src/framework/core/eventdispatcher.cpp | 18 ++- src/otclient/core/mapview.cpp | 115 ++++++++++-------- src/otclient/core/mapview.h | 4 +- 6 files changed, 92 insertions(+), 60 deletions(-) diff --git a/modules/core_lib/widgets/uiresizeborder.lua b/modules/core_lib/widgets/uiresizeborder.lua index 7139fe51..8f6eaa73 100644 --- a/modules/core_lib/widgets/uiresizeborder.lua +++ b/modules/core_lib/widgets/uiresizeborder.lua @@ -10,6 +10,7 @@ end function UIResizeBorder:onHoverChange(hovered) if hovered then + if g_ui.getDraggingWidget() then return end if self:getWidth() > self:getHeight() then Mouse.setVerticalCursor() self.vertical = true @@ -17,13 +18,15 @@ function UIResizeBorder:onHoverChange(hovered) Mouse.setHorizontalCursor() self.vertical = false end + self.hovering = true if not self:isPressed() then Effects.fadeIn(self) end else - if not self:isPressed() then + if not self:isPressed() and self.hovering then Mouse.restoreCursor() Effects.fadeOut(self) + self.hovering = false end end end @@ -63,6 +66,7 @@ function UIResizeBorder:onMouseRelease(mousePos, mouseButton) if not self:isHovered() then Mouse.restoreCursor() Effects.fadeOut(self) + self.hovering = false end end diff --git a/modules/game/widgets/uiminiwindow.lua b/modules/game/widgets/uiminiwindow.lua index aa04b7e3..172a33fc 100644 --- a/modules/game/widgets/uiminiwindow.lua +++ b/modules/game/widgets/uiminiwindow.lua @@ -73,3 +73,6 @@ function UIMiniWindow:onMinimize() end end +function UIMiniWindow:getClassName() + return 'UIMiniWindow' +end diff --git a/modules/game/widgets/uiminiwindowcontainer.lua b/modules/game/widgets/uiminiwindowcontainer.lua index a463c5d1..4e82f24d 100644 --- a/modules/game/widgets/uiminiwindowcontainer.lua +++ b/modules/game/widgets/uiminiwindowcontainer.lua @@ -8,8 +8,10 @@ function UIMiniWindowContainer.create() end function UIMiniWindowContainer:onDrop(widget, mousePos) - widget:setParent(self) - return true + if widget:getClassName() == 'UIMiniWindow' then + widget:setParent(self) + return true + end end function UIMiniWindowContainer:getClassName() diff --git a/src/framework/core/eventdispatcher.cpp b/src/framework/core/eventdispatcher.cpp index 6a855161..dbd6fb8f 100644 --- a/src/framework/core/eventdispatcher.cpp +++ b/src/framework/core/eventdispatcher.cpp @@ -45,19 +45,29 @@ void EventDispatcher::poll() scheduledEvent->execute(); } - // execute events list up to 3 times, this is needed because some events can schedule new events that would + // execute events list up to 10 times, this is needed because some events can schedule new events that would // change the UIWidgets layout, in this case we must execute these new events before we continue rendering, // we can't loop until the event list is empty, because this could lead to infinite loops // if someone write a module with bad code - for(int i=0;i<3;++i) { - m_pollEventsSize = m_eventList.size(); - if(m_pollEventsSize == 0) + m_pollEventsSize = m_eventList.size(); + int count = 0; + while(m_pollEventsSize > 0) { + if(count > 50) { + static bool reported = false; + if(!reported) { + logError("ATTENTION the event list is not getting empty, this could be caused by some bad code"); + reported = true; + } break; + } + for(int i=0;iexecute(); } + m_pollEventsSize = m_eventList.size(); + count++; } } diff --git a/src/otclient/core/mapview.cpp b/src/otclient/core/mapview.cpp index a63e17de..cb9a3388 100644 --- a/src/otclient/core/mapview.cpp +++ b/src/otclient/core/mapview.cpp @@ -193,8 +193,10 @@ void MapView::updateVisibleTilesCache(int start) m_updateTilesCacheEvent = nullptr; } - m_cachedFirstVisibleFloor = getFirstVisibleFloor(); - m_cachedLastVisibleFloor = getLastVisibleFloor(); + m_cachedFirstVisibleFloor = calcFirstVisibleFloor(); + m_cachedLastVisibleFloor = calcLastVisibleFloor(); + assert(m_cachedFirstVisibleFloor >= 0 && m_cachedLastVisibleFloor >= 0 && + m_cachedFirstVisibleFloor <= Otc::MAX_Z && m_cachedLastVisibleFloor <= Otc::MAX_Z); if(m_cachedLastVisibleFloor < m_cachedFirstVisibleFloor) m_cachedLastVisibleFloor = m_cachedFirstVisibleFloor; @@ -461,70 +463,81 @@ void MapView::setVisibleDimension(const Size& visibleDimension) requestVisibleTilesCacheUpdate(); } -int MapView::getFirstVisibleFloor() +int MapView::calcFirstVisibleFloor() { + int z = 7; // return forced first visible floor - if(m_lockedFirstVisibleFloor != -1) - return m_lockedFirstVisibleFloor; - - Position cameraPosition = getCameraPosition(); - - // avoid rendering multifloors in far views - if(m_viewRange >= FAR_VIEW) - return cameraPosition.z; - - // if nothing is limiting the view, the first visible floor is 0 - int firstFloor = 0; - - // limits to underground floors while under sea level - if(cameraPosition.z > Otc::SEA_FLOOR) - firstFloor = std::max(cameraPosition.z - Otc::AWARE_UNDEGROUND_FLOOR_RANGE, (int)Otc::UNDERGROUND_FLOOR); - - // loop in 3x3 tiles around the camera - for(int ix = -1; ix <= 1 && firstFloor < cameraPosition.z; ++ix) { - for(int iy = -1; iy <= 1 && firstFloor < cameraPosition.z; ++iy) { - Position pos = cameraPosition.translated(ix, iy); - - // process tiles that we can look through, e.g. windows, doors - if((ix == 0 && iy == 0) || (/*(std::abs(ix) != std::abs(iy)) && */g_map.isLookPossible(pos))) { - Position upperPos = pos; - Position coveredPos = pos; - - while(coveredPos.coveredUp() && upperPos.up() && upperPos.z >= firstFloor) { - // check tiles physically above - TilePtr tile = g_map.getTile(upperPos); - if(tile && tile->limitsFloorsView()) { - firstFloor = upperPos.z + 1; - break; - } + if(m_lockedFirstVisibleFloor != -1) { + z = m_lockedFirstVisibleFloor; + } else { + Position cameraPosition = getCameraPosition(); - // check tiles geometrically above - tile = g_map.getTile(coveredPos); - if(tile && tile->limitsFloorsView()) { - firstFloor = coveredPos.z + 1; - break; + // avoid rendering multifloors in far views + if(m_viewRange >= FAR_VIEW) { + z = cameraPosition.z; + } else { + // if nothing is limiting the view, the first visible floor is 0 + int firstFloor = 0; + + // limits to underground floors while under sea level + if(cameraPosition.z > Otc::SEA_FLOOR) + firstFloor = std::max(cameraPosition.z - Otc::AWARE_UNDEGROUND_FLOOR_RANGE, (int)Otc::UNDERGROUND_FLOOR); + + // loop in 3x3 tiles around the camera + for(int ix = -1; ix <= 1 && firstFloor < cameraPosition.z; ++ix) { + for(int iy = -1; iy <= 1 && firstFloor < cameraPosition.z; ++iy) { + Position pos = cameraPosition.translated(ix, iy); + + // process tiles that we can look through, e.g. windows, doors + if((ix == 0 && iy == 0) || (/*(std::abs(ix) != std::abs(iy)) && */g_map.isLookPossible(pos))) { + Position upperPos = pos; + Position coveredPos = pos; + + while(coveredPos.coveredUp() && upperPos.up() && upperPos.z >= firstFloor) { + // check tiles physically above + TilePtr tile = g_map.getTile(upperPos); + if(tile && tile->limitsFloorsView()) { + firstFloor = upperPos.z + 1; + break; + } + + // check tiles geometrically above + tile = g_map.getTile(coveredPos); + if(tile && tile->limitsFloorsView()) { + firstFloor = coveredPos.z + 1; + break; + } + } } } } + + z = firstFloor; } } - return firstFloor; + z = std::min(std::max(z, 0), (int)Otc::MAX_Z); + return z; } -int MapView::getLastVisibleFloor() +int MapView::calcLastVisibleFloor() { - Position cameraPosition = getCameraPosition(); + int z = 7; + Position cameraPosition = getCameraPosition(); // avoid rendering multifloors in far views - if(m_viewRange >= FAR_VIEW) - return cameraPosition.z; + if(m_viewRange >= FAR_VIEW) { + z = cameraPosition.z; + } else { + // view only underground floors when below sea level + if(cameraPosition.z > Otc::SEA_FLOOR) + z = cameraPosition.z + Otc::AWARE_UNDEGROUND_FLOOR_RANGE; + else + z = Otc::SEA_FLOOR; + } - // view only underground floors when below sea level - if(cameraPosition.z > Otc::SEA_FLOOR) - return std::min(cameraPosition.z + Otc::AWARE_UNDEGROUND_FLOOR_RANGE, (int)Otc::MAX_Z); - else - return Otc::SEA_FLOOR; + z = std::min(std::max(z, 0), (int)Otc::MAX_Z); + return z; } Position MapView::getCameraPosition() diff --git a/src/otclient/core/mapview.h b/src/otclient/core/mapview.h index fb138ce8..6c5445fc 100644 --- a/src/otclient/core/mapview.h +++ b/src/otclient/core/mapview.h @@ -77,8 +77,8 @@ public: bool isFollowingCreature() { return !!m_followingCreature; } - int getFirstVisibleFloor(); - int getLastVisibleFloor(); + int calcFirstVisibleFloor(); + int calcLastVisibleFloor(); Position getCameraPosition(); TilePtr getTile(const Point& mousePos, const Rect& mapRect); Size getVisibleDimension() { return m_visibleDimension; }