From a3e6cc54b58a46250534919ed2e9f0dd98257d21 Mon Sep 17 00:00:00 2001 From: Shawak Date: Sun, 22 Mar 2015 20:11:41 +0100 Subject: [PATCH 01/27] fix visual studio include paths --- vc12/otclient.vcxproj | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/vc12/otclient.vcxproj b/vc12/otclient.vcxproj index 0cc33c3d..5bcf6a68 100644 --- a/vc12/otclient.vcxproj +++ b/vc12/otclient.vcxproj @@ -66,19 +66,19 @@ - D:\otclient-msvc13-libs\libogg-1.3.1\include;D:\otclient-msvc13-libs\libvorbis-1.3.3\include;D:\otclient-msvc13-libs\physfs-2.0.3\include;D:\otclient-msvc13-libs\OpenSSL-1.0.1e\include;D:\otclient-msvc13-libs\zlib-1.2.5\include;D:\otclient-msvc13-libs\OpenAL\include\AL;D:\otclient-msvc13-libs\glew-1.10.0\include;D:\otclient-msvc13-libs\LuaJIT-2.0.2\include;D:\otclient-msvc13-libs\boost_1_55_0\include;D:\otclient\src;$(IncludePath) + D:\otclient-msvc13-libs\libogg-1.3.1\include;D:\otclient-msvc13-libs\libvorbis-1.3.3\include;D:\otclient-msvc13-libs\physfs-2.0.3\include;D:\otclient-msvc13-libs\OpenSSL-1.0.1e\include;D:\otclient-msvc13-libs\zlib-1.2.5\include;D:\otclient-msvc13-libs\OpenAL\include\AL;D:\otclient-msvc13-libs\glew-1.10.0\include;D:\otclient-msvc13-libs\LuaJIT-2.0.2\include;D:\otclient-msvc13-libs\boost_1_55_0\include;D:\otclient\src;..\src;$(IncludePath) D:\otclient-msvc13-libs\libogg-1.3.1\lib;D:\otclient-msvc13-libs\libvorbis-1.3.3\lib;D:\otclient-msvc13-libs\physfs-2.0.3\lib;D:\otclient-msvc13-libs\OpenSSL-1.0.1e\lib\VC;D:\otclient-msvc13-libs\zlib-1.2.5\lib;D:\otclient-msvc13-libs\OpenAL\lib;D:\otclient-msvc13-libs\LuaJIT-2.0.2\lib;D:\otclient-msvc13-libs\glew-1.10.0\lib;D:\otclient-msvc13-libs\boost_1_55_0\lib;$(LibraryPath) - D:\otclient-msvc13-libs\libogg-1.3.1\include;D:\otclient-msvc13-libs\libvorbis-1.3.3\include;D:\otclient-msvc13-libs\physfs-2.0.3\include;D:\otclient-msvc13-libs\OpenSSL-1.0.1e\include;D:\otclient-msvc13-libs\zlib-1.2.5\include;D:\otclient-msvc13-libs\OpenAL\include\AL;D:\otclient-msvc13-libs\glew-1.10.0\include;D:\otclient-msvc13-libs\LuaJIT-2.0.2\include;D:\otclient-msvc13-libs\boost_1_55_0\include;D:\otclient\src;$(IncludePath) + D:\otclient-msvc13-libs\libogg-1.3.1\include;D:\otclient-msvc13-libs\libvorbis-1.3.3\include;D:\otclient-msvc13-libs\physfs-2.0.3\include;D:\otclient-msvc13-libs\OpenSSL-1.0.1e\include;D:\otclient-msvc13-libs\zlib-1.2.5\include;D:\otclient-msvc13-libs\OpenAL\include\AL;D:\otclient-msvc13-libs\glew-1.10.0\include;D:\otclient-msvc13-libs\LuaJIT-2.0.2\include;D:\otclient-msvc13-libs\boost_1_55_0\include;D:\otclient\src;..\src;$(IncludePath) D:\otclient-msvc13-libs\libogg-1.3.1\lib;D:\otclient-msvc13-libs\libvorbis-1.3.3\lib;D:\otclient-msvc13-libs\physfs-2.0.3\lib;D:\otclient-msvc13-libs\OpenSSL-1.0.1e\lib\VC;D:\otclient-msvc13-libs\zlib-1.2.5\lib;D:\otclient-msvc13-libs\OpenAL\lib;D:\otclient-msvc13-libs\LuaJIT-2.0.2\lib;D:\otclient-msvc13-libs\glew-1.10.0\lib;D:\otclient-msvc13-libs\boost_1_55_0\lib;$(LibraryPath) - C:\otclient-msvc13-libs\libogg-1.3.1\include;C:\otclient-msvc13-libs\libvorbis-1.3.3\include;C:\otclient-msvc13-libs\physfs-2.0.3\include;C:\otclient-msvc13-libs\OpenSSL-1.0.1e\include;C:\otclient-msvc13-libs\zlib-1.2.5\include;C:\Users\Pedro\Documents\GitHub\otclient\src;C:\otclient-msvc13-libs\OpenAL\include\AL;C:\otclient-msvc13-libs\glew-1.10.0\include;C:\otclient-msvc13-libs\LuaJIT-2.0.2\include;C:\otclient-msvc13-libs\boost_1_55_0\include;$(IncludePath) + C:\otclient-msvc13-libs\libogg-1.3.1\include;C:\otclient-msvc13-libs\libvorbis-1.3.3\include;C:\otclient-msvc13-libs\physfs-2.0.3\include;C:\otclient-msvc13-libs\OpenSSL-1.0.1e\include;C:\otclient-msvc13-libs\zlib-1.2.5\include;C:\otclient-msvc13-libs\OpenAL\include\AL;C:\otclient-msvc13-libs\glew-1.10.0\include;C:\otclient-msvc13-libs\LuaJIT-2.0.2\include;C:\otclient-msvc13-libs\boost_1_55_0\include;..\src;$(IncludePath) C:\otclient-msvc13-libs\libogg-1.3.1\lib;C:\otclient-msvc13-libs\libvorbis-1.3.3\lib;C:\otclient-msvc13-libs\physfs-2.0.3\lib;C:\otclient-msvc13-libs\OpenSSL-1.0.1e\lib\VC;C:\otclient-msvc13-libs\zlib-1.2.5\lib;C:\otclient-msvc13-libs\OpenAL\lib;C:\otclient-msvc13-libs\LuaJIT-2.0.2\lib;C:\otclient-msvc13-libs\glew-1.10.0\lib;C:\otclient-msvc13-libs\boost_1_55_0\lib;$(LibraryPath) - D:\otclient-msvc13-libs\libogg-1.3.1\include;D:\otclient-msvc13-libs\libvorbis-1.3.3\include;D:\otclient-msvc13-libs\physfs-2.0.3\include;D:\otclient-msvc13-libs\OpenSSL-1.0.1e\include;D:\otclient-msvc13-libs\zlib-1.2.5\include;D:\otclient-msvc13-libs\OpenAL\include\AL;D:\otclient-msvc13-libs\glew-1.10.0\include;D:\otclient-msvc13-libs\LuaJIT-2.0.2\include;D:\otclient-msvc13-libs\boost_1_55_0\include;D:\otclient\src;$(IncludePath) + D:\otclient-msvc13-libs\libogg-1.3.1\include;D:\otclient-msvc13-libs\libvorbis-1.3.3\include;D:\otclient-msvc13-libs\physfs-2.0.3\include;D:\otclient-msvc13-libs\OpenSSL-1.0.1e\include;D:\otclient-msvc13-libs\zlib-1.2.5\include;D:\otclient-msvc13-libs\OpenAL\include\AL;D:\otclient-msvc13-libs\glew-1.10.0\include;D:\otclient-msvc13-libs\LuaJIT-2.0.2\include;D:\otclient-msvc13-libs\boost_1_55_0\include;D:\otclient\src;..\src;$(IncludePath) D:\otclient-msvc13-libs\libogg-1.3.1\lib;D:\otclient-msvc13-libs\libvorbis-1.3.3\lib;D:\otclient-msvc13-libs\physfs-2.0.3\lib;D:\otclient-msvc13-libs\OpenSSL-1.0.1e\lib\VC;D:\otclient-msvc13-libs\zlib-1.2.5\lib;D:\otclient-msvc13-libs\OpenAL\lib;D:\otclient-msvc13-libs\LuaJIT-2.0.2\lib;D:\otclient-msvc13-libs\glew-1.10.0\lib;D:\otclient-msvc13-libs\boost_1_55_0\lib;$(LibraryPath) @@ -496,4 +496,4 @@ - \ No newline at end of file + From 86dd7958e1001d5af8ba40014b440f05e32029b5 Mon Sep 17 00:00:00 2001 From: The Gitter Badger Date: Thu, 7 May 2015 21:42:02 +0000 Subject: [PATCH 02/27] Added Gitter badge --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 8fb26cef..b9521e15 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ [![Build Status](https://secure.travis-ci.org/edubart/otclient.svg?branch=master)](http://travis-ci.org/edubart/otclient) ### What is otclient? +[![Join the chat at https://gitter.im/edubart/otclient](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/edubart/otclient?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) + Otclient is an alternative Tibia client for usage with otserv. It aims to be complete and flexible, for that it uses LUA scripting for all game interface functionality and configurations files with a syntax similar to CSS for the client interface design. Otclient works with a modular system, this means From 53dbbd2ba3d6670477946cf0169a7a4772315f81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konrad=20Ku=C5=9Bnierz?= Date: Sat, 9 May 2015 20:27:04 +0200 Subject: [PATCH 03/27] Decrease RAM usage by at least 200MB This was quite ridiculous. TILESTATE_LAST = 1 << 24 Basically we were creating 2^24 Color structures within the array, each of them has 4 floats (16 bytes) resulting in about 256 MB of extra wasted memory. --- src/client/map.cpp | 8 ++++++++ src/client/map.h | 6 ++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/client/map.cpp b/src/client/map.cpp index dc061ee8..343b0c2d 100644 --- a/src/client/map.cpp +++ b/src/client/map.cpp @@ -394,6 +394,14 @@ void Map::setZoneColor(tileflags_t zone, const Color& color) m_zoneColors[zone] = color; } +Color Map::getZoneColor(tileflags_t flag) +{ + auto it = m_zoneColors.find(flag); + if(it == m_zoneColors.end()) + return Color::alpha; + return it->second; +} + void Map::setForceShowAnimations(bool force) { if(force) { diff --git a/src/client/map.h b/src/client/map.h index f25c9749..8dca1134 100644 --- a/src/client/map.h +++ b/src/client/map.h @@ -196,7 +196,7 @@ public: void setZoneOpacity(float opacity) { m_zoneOpacity = opacity; } float getZoneOpacity() { return m_zoneOpacity; } - Color getZoneColor(tileflags_t flag) { return m_zoneColors[flag]; } + Color getZoneColor(tileflags_t flag); tileflags_t getZoneFlags() { return (tileflags_t)m_zoneFlags; } bool showZones() { return m_zoneFlags != 0; } bool showZone(tileflags_t zone) { return (m_zoneFlags & zone) == zone; } @@ -257,7 +257,7 @@ private: uint8 m_animationFlags; uint32 m_zoneFlags; - std::array m_zoneColors; + std::map m_zoneColors; float m_zoneOpacity; Light m_light; @@ -272,5 +272,3 @@ private: extern Map g_map; #endif - -/* vim: set ts=4 sw=4 et: */ From ded8fef16bac07ae29c4260b6fa79a47edf872dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konrad=20Ku=C5=9Bnierz?= Date: Sun, 10 May 2015 22:25:46 +0200 Subject: [PATCH 04/27] Change bitter badge and made it inline with travis --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index b9521e15..3569f04b 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,6 @@ -[![Build Status](https://secure.travis-ci.org/edubart/otclient.svg?branch=master)](http://travis-ci.org/edubart/otclient) +[![Build Status](https://secure.travis-ci.org/edubart/otclient.svg?branch=master)](http://travis-ci.org/edubart/otclient) [![Join the chat at https://gitter.im/edubart/otclient](https://img.shields.io/badge/GITTER-join%20chat-green.svg)](https://gitter.im/edubart/otclient?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) ### What is otclient? -[![Join the chat at https://gitter.im/edubart/otclient](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/edubart/otclient?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) - Otclient is an alternative Tibia client for usage with otserv. It aims to be complete and flexible, for that it uses LUA scripting for all game interface functionality and configurations files with a syntax similar to CSS for the client interface design. Otclient works with a modular system, this means From 11990815a63a6e5a4ab8af565b9b4b207b3cf3e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konrad=20Ku=C5=9Bnierz?= Date: Sun, 10 May 2015 22:31:10 +0200 Subject: [PATCH 05/27] Correctly load corrupted otmm file, should fix #606 --- src/client/minimap.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/client/minimap.cpp b/src/client/minimap.cpp index 58004ad5..734b76c6 100644 --- a/src/client/minimap.cpp +++ b/src/client/minimap.cpp @@ -333,6 +333,7 @@ bool Minimap::loadOtmm(const std::string& fileName) uint blockSize = MMBLOCK_SIZE * MMBLOCK_SIZE * sizeof(MinimapTile); std::vector compressBuffer(compressBound(blockSize)); + std::vector decompressBuffer(blockSize); while(true) { Position pos; @@ -344,13 +345,19 @@ bool Minimap::loadOtmm(const std::string& fileName) if(!pos.isValid()) break; + // corrupted file + if(pos.z >= Otc::MAX_Z+1) + break; + MinimapBlock& block = getBlock(pos); ulong len = fin->getU16(); ulong destLen = blockSize; fin->read(compressBuffer.data(), len); - int ret = uncompress((uchar*)&block.getTiles(), &destLen, compressBuffer.data(), len); - assert(ret == Z_OK); - assert(destLen == blockSize); + int ret = uncompress(decompressBuffer.data(), &destLen, compressBuffer.data(), len); + if(ret != Z_OK || destLen != blockSize) + break; + + memcpy((uchar*)&block.getTiles(), decompressBuffer.data(), blockSize); block.mustUpdate(); block.justSaw(); } From 6bd0e37670535af5a967013f7e00c88b4d90e0b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konrad=20Ku=C5=9Bnierz?= Date: Tue, 12 May 2015 10:16:14 +0200 Subject: [PATCH 06/27] Correctly draw creatures bigger than 64x64 Battlelist icon --- src/client/creature.cpp | 12 ++++++------ src/client/minimap.cpp | 8 ++------ 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/src/client/creature.cpp b/src/client/creature.cpp index 6e6bb63c..e0740521 100644 --- a/src/client/creature.cpp +++ b/src/client/creature.cpp @@ -202,27 +202,27 @@ void Creature::drawOutfit(const Rect& destRect, bool resize) if(g_graphics.canUseFBO()) { const FrameBufferPtr& outfitBuffer = g_framebuffers.getTemporaryFrameBuffer(); - outfitBuffer->resize(Size(2*Otc::TILE_PIXELS, 2*Otc::TILE_PIXELS)); + outfitBuffer->resize(Size(exactSize, exactSize)); outfitBuffer->bind(); g_painter->setAlphaWriting(true); g_painter->clear(Color::alpha); - internalDrawOutfit(Point(Otc::TILE_PIXELS,Otc::TILE_PIXELS) + getDisplacement(), 1, false, true, Otc::South); + internalDrawOutfit(Point(exactSize - Otc::TILE_PIXELS, exactSize - Otc::TILE_PIXELS) + getDisplacement(), 1, false, true, Otc::South); outfitBuffer->release(); Rect srcRect; if(resize) srcRect.resize(exactSize, exactSize); else - srcRect.resize(2*Otc::TILE_PIXELS*0.75f, 2*Otc::TILE_PIXELS*0.75f); - srcRect.moveBottomRight(Point(2*Otc::TILE_PIXELS - 1, 2*Otc::TILE_PIXELS - 1)); + srcRect.resize(exactSize*0.75f, exactSize*0.75f); + srcRect.moveBottomRight(Point(exactSize - 1, exactSize - 1)); outfitBuffer->draw(destRect, srcRect); } else { float scaleFactor; if(resize) scaleFactor = destRect.width() / (float)exactSize; else - scaleFactor = destRect.width() / (float)(2*Otc::TILE_PIXELS*0.75f); - Point dest = destRect.bottomRight() - (Point(Otc::TILE_PIXELS,Otc::TILE_PIXELS) - getDisplacement())*scaleFactor; + scaleFactor = destRect.width() / (float)(exactSize*0.75f); + Point dest = destRect.bottomRight() - (Point(exactSize - Otc::TILE_PIXELS, exactSize - Otc::TILE_PIXELS) - getDisplacement()) * scaleFactor; internalDrawOutfit(dest, scaleFactor, false, true, Otc::South); } } diff --git a/src/client/minimap.cpp b/src/client/minimap.cpp index 734b76c6..304909a7 100644 --- a/src/client/minimap.cpp +++ b/src/client/minimap.cpp @@ -341,12 +341,8 @@ bool Minimap::loadOtmm(const std::string& fileName) pos.y = fin->getU16(); pos.z = fin->getU8(); - // end of file - if(!pos.isValid()) - break; - - // corrupted file - if(pos.z >= Otc::MAX_Z+1) + // end of file or file is corrupted + if(!pos.isValid() || pos.z >= Otc::MAX_Z+1) break; MinimapBlock& block = getBlock(pos); From c3c2ac80e7d930f3ed1792e108077b33e48c159a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konrad=20Ku=C5=9Bnierz?= Date: Tue, 12 May 2015 23:44:10 +0200 Subject: [PATCH 07/27] Fix drawing creatures in UICreature I will leave this ugly hack for the time being, but I do encourage to change it later on. The whole "resize" boolean makes no sense since the outfit is resized by the destination rectangle anyway. I believe we should give it a try with a real size of the object defined in dat by the user for creatures bigger than 32x32. Please keep in mind that we did cut bigger creatures to 48x48 (2*Otc::TILE_PIXELS*0.75f) before as well, so nothing really changed besides ability to properly draw bigger creatures than 64x64 on battlelist. --- src/client/creature.cpp | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/src/client/creature.cpp b/src/client/creature.cpp index e0740521..68a97d90 100644 --- a/src/client/creature.cpp +++ b/src/client/creature.cpp @@ -200,29 +200,24 @@ void Creature::drawOutfit(const Rect& destRect, bool resize) else exactSize = g_things.rawGetThingType(m_outfit.getAuxId(), m_outfit.getCategory())->getExactSize(); + int frameSize; + if(!resize) + frameSize = std::max(exactSize * 0.75f, 2 * Otc::TILE_PIXELS * 0.75f); + else if(!(frameSize = exactSize)) + return; + if(g_graphics.canUseFBO()) { const FrameBufferPtr& outfitBuffer = g_framebuffers.getTemporaryFrameBuffer(); - outfitBuffer->resize(Size(exactSize, exactSize)); + outfitBuffer->resize(Size(frameSize, frameSize)); outfitBuffer->bind(); g_painter->setAlphaWriting(true); g_painter->clear(Color::alpha); - internalDrawOutfit(Point(exactSize - Otc::TILE_PIXELS, exactSize - Otc::TILE_PIXELS) + getDisplacement(), 1, false, true, Otc::South); + internalDrawOutfit(Point(frameSize - Otc::TILE_PIXELS, frameSize - Otc::TILE_PIXELS) + getDisplacement(), 1, false, true, Otc::South); outfitBuffer->release(); - - Rect srcRect; - if(resize) - srcRect.resize(exactSize, exactSize); - else - srcRect.resize(exactSize*0.75f, exactSize*0.75f); - srcRect.moveBottomRight(Point(exactSize - 1, exactSize - 1)); - outfitBuffer->draw(destRect, srcRect); + outfitBuffer->draw(destRect, Rect(0,0,frameSize,frameSize)); } else { - float scaleFactor; - if(resize) - scaleFactor = destRect.width() / (float)exactSize; - else - scaleFactor = destRect.width() / (float)(exactSize*0.75f); - Point dest = destRect.bottomRight() - (Point(exactSize - Otc::TILE_PIXELS, exactSize - Otc::TILE_PIXELS) - getDisplacement()) * scaleFactor; + float scaleFactor = destRect.width() / (float)frameSize; + Point dest = destRect.bottomRight() - (Point(Otc::TILE_PIXELS,Otc::TILE_PIXELS) - getDisplacement()) * scaleFactor; internalDrawOutfit(dest, scaleFactor, false, true, Otc::South); } } From 7ea6c46b2cd2d0d8e5deb13e05f0868644d6553a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konrad=20Ku=C5=9Bnierz?= Date: Mon, 18 May 2015 21:31:16 +0200 Subject: [PATCH 08/27] Add binary operations for lua This is something I was always missing - posibbility to operate on binary files or streams in pure lua. In most cases we do only need to read simple variables from files such as integers with different amount of bytes. This "class" will provide that ability. It's a simple implementation of following C module for lua: http://www.inf.puc-rio.br/~roberto/struct/ It has much less, though. Following elements have been implemented: ">" flag to set mode to big endian. "<" flag to set mode to little endian. "b" a signed char. "B" an unsigned char. "h" a signed short (2 bytes). "H" an unsigned short (2 bytes). "i" a signed int (4 bytes). "I" an unsigned int (4 bytes). "l" a signed long (8 bytes). "L" an unsigned long (8 bytes). "s" a zero-terminated string. An example how to use it: ```lua local packed = Struct.pack('' then + endianness = opt == '<' and true or false + elseif opt == 'b' or opt == 'B' or opt == 'h' or opt == 'H' or opt == 'i' or opt == 'I' or opt == 'l' or opt == 'L' then + local val = tonumber(table.remove(vars, 1)) + local n = ((opt == 'h' or opt == 'H') and 2) or ((opt == 'i' or opt == 'I') and 4) or ((opt == 'l' or opt == 'L') and 8) or 1 + + if val < 0 then + val = val + 2 ^ (n * 8 - 1) + end + + local binary = '' + for j = 1, n do + binary = binary .. string.char(val % (2 ^ 8)) + val = math.floor(val / (2 ^ 8)) + end + + if not endianness then + binary = string.reverse(binary) + end + + stream = stream .. binary + elseif opt == 's' then + stream = stream .. tostring(table.remove(vars, 1)) + stream = stream .. string.char(0) + end + end + + return stream +end + +function Struct.unpack(format, stream) + local vars = {} + local endianness = true + + for i = 1, string.len(format) do + local opt = string.sub(format, i, i) + + if opt == '<' or opt == '>' then + endianness = opt == '<' and true or false + elseif opt == 'b' or opt == 'B' or opt == 'h' or opt == 'H' or opt == 'i' or opt == 'I' or opt == 'l' or opt == 'L' then + local n = ((opt == 'h' or opt == 'H') and 2) or ((opt == 'i' or opt == 'I') and 4) or ((opt == 'l' or opt == 'L') and 8) or 1 + local signed = opt == 'b' or opt == 'h' or opt == 'i' + + local val = 0 + for j = 1, n do + local byte = string.byte(string.sub(stream, 1, 1)) + if endianness then + val = val + byte * (2 ^ ((j - 1) * 8)) + else + val = val + byte * (2 ^ ((n - j) * 8)) + end + stream = string.sub(stream, 2) + end + + if signed then + val = val - 2 ^ (n * 8 - 1) + end + + table.insert(vars, val) + elseif opt == 's' then + local str = '' + for j = 1, string.len(stream) do + if string.sub(stream, j, j) == string.char(0) then + break + end + + str = str .. string.sub(stream, j, j) + end + + stream = string.sub(stream, string.len(str) + 2) + table.insert(vars, str) + end + end + + return unpack(vars) +end From 48fefb03cb985243e1369c1209557a77e4a754cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konrad=20Ku=C5=9Bnierz?= Date: Tue, 19 May 2015 13:13:14 +0200 Subject: [PATCH 09/27] Add float and double support for struct @edubart suggested it would be still better to have it done within C as extra module (just like lbitlib). "f" a float (4 bytes). "d" a double (8 bytes). http://en.wikipedia.org/wiki/IEEE_floating_point --- modules/corelib/struct.lua | 100 +++++++++++++++++++++++++++++++------ 1 file changed, 85 insertions(+), 15 deletions(-) diff --git a/modules/corelib/struct.lua b/modules/corelib/struct.lua index 6bc511b4..44fcf56b 100644 --- a/modules/corelib/struct.lua +++ b/modules/corelib/struct.lua @@ -1,7 +1,7 @@ Struct = {} function Struct.pack(format, ...) - local stream = '' + local stream = {} local vars = {...} local endianness = true @@ -11,35 +11,78 @@ function Struct.pack(format, ...) if opt == '<' or opt == '>' then endianness = opt == '<' and true or false elseif opt == 'b' or opt == 'B' or opt == 'h' or opt == 'H' or opt == 'i' or opt == 'I' or opt == 'l' or opt == 'L' then - local val = tonumber(table.remove(vars, 1)) local n = ((opt == 'h' or opt == 'H') and 2) or ((opt == 'i' or opt == 'I') and 4) or ((opt == 'l' or opt == 'L') and 8) or 1 + local val = tonumber(table.remove(vars, 1)) if val < 0 then val = val + 2 ^ (n * 8 - 1) end - local binary = '' + local bytes = {} for j = 1, n do - binary = binary .. string.char(val % (2 ^ 8)) + table.insert(bytes, string.char(val % (2 ^ 8))) val = math.floor(val / (2 ^ 8)) end if not endianness then - binary = string.reverse(binary) + table.insert(stream, string.reverse(table.concat(bytes))) + else + table.insert(stream, table.concat(bytes)) + end + elseif opt == 'f' or opt == 'd' then + local val = tonumber(table.remove(vars, 1)) + local sign = 0 + + if val < 0 then + sign = 1 + val = -val end - stream = stream .. binary + local mantissa, exponent = math.frexp(val) + if val == 0 then + mantissa = 0 + exponent = 0 + else + mantissa = (mantissa * 2 - 1) * math.ldexp(0.5, (opt == 'd') and 53 or 24) + exponent = exponent + ((opt == 'd') and 1022 or 126) + end + + local bytes = {} + if opt == 'd' then + val = mantissa + for i = 1, 6 do + table.insert(bytes, string.char(math.floor(val) % (2 ^ 8))) + val = math.floor(val / (2 ^ 8)) + end + else + table.insert(bytes, string.char(math.floor(mantissa) % (2 ^ 8))) + val = math.floor(mantissa / (2 ^ 8)) + table.insert(bytes, string.char(math.floor(val) % (2 ^ 8))) + val = math.floor(val / (2 ^ 8)) + end + + table.insert(bytes, string.char(math.floor(exponent * ((opt == 'd') and 16 or 128) + val) % (2 ^ 8))) + val = math.floor((exponent * ((opt == 'd') and 16 or 128) + val) / (2 ^ 8)) + table.insert(bytes, string.char(math.floor(sign * 128 + val) % (2 ^ 8))) + val = math.floor((sign * 128 + val) / (2 ^ 8)) + + if not endianness then + table.insert(stream, string.reverse(table.concat(bytes))) + else + table.insert(stream, table.concat(bytes)) + end elseif opt == 's' then - stream = stream .. tostring(table.remove(vars, 1)) - stream = stream .. string.char(0) + table.insert(stream, tostring(table.remove(vars, 1))) + table.insert(stream, string.char(0)) end end - return stream + return table.concat(stream) end function Struct.unpack(format, stream) local vars = {} + local iterator = 1 local endianness = true for i = 1, string.len(format) do @@ -53,13 +96,13 @@ function Struct.unpack(format, stream) local val = 0 for j = 1, n do - local byte = string.byte(string.sub(stream, 1, 1)) + local byte = string.byte(string.sub(stream, iterator, iterator)) if endianness then val = val + byte * (2 ^ ((j - 1) * 8)) else val = val + byte * (2 ^ ((n - j) * 8)) end - stream = string.sub(stream, 2) + iterator = iterator + 1 end if signed then @@ -67,17 +110,44 @@ function Struct.unpack(format, stream) end table.insert(vars, val) + elseif opt == 'f' or opt == 'd' then + local n = (opt == 'd') and 8 or 4 + local x = string.sub(stream, iterator, iterator + n - 1) + iterator = iterator + n + + if not endianness then + x = string.reverse(x) + end + + local sign = 1 + local mantissa = string.byte(x, (opt == 'd') and 7 or 3) % ((opt == 'd') and 16 or 128) + for i = n - 2, 1, -1 do + mantissa = mantissa * (2 ^ 8) + string.byte(x, i) + end + + if string.byte(x, n) > 127 then + sign = -1 + end + + local exponent = (string.byte(x, n) % 128) * ((opt == 'd') and 16 or 2) + math.floor(string.byte(x, n - 1) / ((opt == 'd') and 16 or 128)) + if exponent == 0 then + table.insert(vars, 0.0) + else + mantissa = (math.ldexp(mantissa, (opt == 'd') and -52 or -23) + 1) * sign + table.insert(vars, math.ldexp(mantissa, exponent - ((opt == 'd') and 1023 or 127))) + end elseif opt == 's' then - local str = '' - for j = 1, string.len(stream) do + local bytes = {} + for j = 1 + iterator, string.len(stream) do if string.sub(stream, j, j) == string.char(0) then break end - str = str .. string.sub(stream, j, j) + table.insert(bytes, string.sub(stream, j, j)) end - stream = string.sub(stream, string.len(str) + 2) + local str = table.concat(bytes) + iterator = iterator + string.len(str) + 1 table.insert(vars, str) end end From 02ab50d8dd162f7ecc90effe15fe4adbc1f4e8ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konrad=20Ku=C5=9Bnierz?= Date: Tue, 19 May 2015 13:41:40 +0200 Subject: [PATCH 10/27] Minor mistake in unpacking string --- modules/corelib/struct.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/corelib/struct.lua b/modules/corelib/struct.lua index 44fcf56b..32993151 100644 --- a/modules/corelib/struct.lua +++ b/modules/corelib/struct.lua @@ -138,7 +138,7 @@ function Struct.unpack(format, stream) end elseif opt == 's' then local bytes = {} - for j = 1 + iterator, string.len(stream) do + for j = iterator, string.len(stream) do if string.sub(stream, j, j) == string.char(0) then break end From c5ea8c98fbce1a686b45472252e293f6b04593fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konrad=20Ku=C5=9Bnierz?= Date: Tue, 19 May 2015 18:50:02 +0200 Subject: [PATCH 11/27] Add cn option to struct "cn" a sequence of exactly n chars corresponding to a single lua string. --- modules/corelib/struct.lua | 59 ++++++++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 21 deletions(-) diff --git a/modules/corelib/struct.lua b/modules/corelib/struct.lua index 32993151..2ed134d8 100644 --- a/modules/corelib/struct.lua +++ b/modules/corelib/struct.lua @@ -5,13 +5,13 @@ function Struct.pack(format, ...) local vars = {...} local endianness = true - for i = 1, string.len(format) do - local opt = string.sub(format, i, i) + for i = 1, format:len() do + local opt = format:sub(i, i) - if opt == '<' or opt == '>' then - endianness = opt == '<' and true or false - elseif opt == 'b' or opt == 'B' or opt == 'h' or opt == 'H' or opt == 'i' or opt == 'I' or opt == 'l' or opt == 'L' then - local n = ((opt == 'h' or opt == 'H') and 2) or ((opt == 'i' or opt == 'I') and 4) or ((opt == 'l' or opt == 'L') and 8) or 1 + if opt == '>' then + endianness = false + elseif opt:find('[bBhHiIlL]') then + local n = opt:find('[hH]') and 2 or opt:find('[iI]') and 4 or opt:find('[lL]') and 8 or 1 local val = tonumber(table.remove(vars, 1)) if val < 0 then @@ -29,7 +29,7 @@ function Struct.pack(format, ...) else table.insert(stream, table.concat(bytes)) end - elseif opt == 'f' or opt == 'd' then + elseif opt:find('[fd]') then local val = tonumber(table.remove(vars, 1)) local sign = 0 @@ -74,6 +74,18 @@ function Struct.pack(format, ...) elseif opt == 's' then table.insert(stream, tostring(table.remove(vars, 1))) table.insert(stream, string.char(0)) + elseif opt == 'c' then + local n = format:sub(i + 1):match('%d+') + local length = tonumber(n) + + if length > 0 then + local str = tostring(table.remove(vars, 1)) + if length - str:len() > 0 then + str = str .. string.rep(' ', length - str:len()) + end + table.insert(stream, str:sub(1, length)) + end + i = i + n:len() end end @@ -85,18 +97,18 @@ function Struct.unpack(format, stream) local iterator = 1 local endianness = true - for i = 1, string.len(format) do - local opt = string.sub(format, i, i) + for i = 1, format:len() do + local opt = format:sub(i, i) - if opt == '<' or opt == '>' then - endianness = opt == '<' and true or false - elseif opt == 'b' or opt == 'B' or opt == 'h' or opt == 'H' or opt == 'i' or opt == 'I' or opt == 'l' or opt == 'L' then - local n = ((opt == 'h' or opt == 'H') and 2) or ((opt == 'i' or opt == 'I') and 4) or ((opt == 'l' or opt == 'L') and 8) or 1 - local signed = opt == 'b' or opt == 'h' or opt == 'i' + if opt == '>' then + endianness = false + elseif opt:find('[bBhHiIlL]') then + local n = opt:find('[hH]') and 2 or opt:find('[iI]') and 4 or opt:find('[lL]') and 8 or 1 + local signed = opt:lower() == opt local val = 0 for j = 1, n do - local byte = string.byte(string.sub(stream, iterator, iterator)) + local byte = string.byte(stream:sub(iterator, iterator)) if endianness then val = val + byte * (2 ^ ((j - 1) * 8)) else @@ -110,9 +122,9 @@ function Struct.unpack(format, stream) end table.insert(vars, val) - elseif opt == 'f' or opt == 'd' then + elseif opt:find('[fd]') then local n = (opt == 'd') and 8 or 4 - local x = string.sub(stream, iterator, iterator + n - 1) + local x = stream:sub(iterator, iterator + n - 1) iterator = iterator + n if not endianness then @@ -138,17 +150,22 @@ function Struct.unpack(format, stream) end elseif opt == 's' then local bytes = {} - for j = iterator, string.len(stream) do - if string.sub(stream, j, j) == string.char(0) then + for j = iterator, stream:len() do + if stream:sub(j, j) == string.char(0) then break end - table.insert(bytes, string.sub(stream, j, j)) + table.insert(bytes, stream:sub(j, j)) end local str = table.concat(bytes) - iterator = iterator + string.len(str) + 1 + iterator = iterator + str:len() + 1 table.insert(vars, str) + elseif opt == 'c' then + local n = format:sub(i + 1):match('%d+') + table.insert(vars, stream:sub(iterator, iterator + tonumber(n))) + iterator = iterator + tonumber(n) + i = i + n:len() end end From 944b220c90cdb2463899a2d51560370143310805 Mon Sep 17 00:00:00 2001 From: Ranieri Althoff Date: Mon, 25 May 2015 00:59:39 -0300 Subject: [PATCH 12/27] Use native optimizations instead of hardcoded defaults --- src/framework/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/framework/CMakeLists.txt b/src/framework/CMakeLists.txt index 7ba95996..2a32609d 100644 --- a/src/framework/CMakeLists.txt +++ b/src/framework/CMakeLists.txt @@ -170,7 +170,7 @@ set(CMAKE_CXX_FLAGS_COMPILESPEED "-O0") set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g") set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O1 -g -fno-omit-frame-pointer") set(CMAKE_CXX_FLAGS_RELEASE "-O2") -set(CMAKE_CXX_FLAGS_PERFORMANCE "-Ofast -mmmx -msse -msse2") +set(CMAKE_CXX_FLAGS_PERFORMANCE "-Ofast -march=native") if(USE_LTO) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fwhole-program -flto") From f35c939fc3781482443d0d3cf134b72831a70518 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konrad=20Ku=C5=9Bnierz?= Date: Tue, 2 Jun 2015 19:16:41 +0200 Subject: [PATCH 13/27] Start working on multi-line selection for console Unfortunately UITextEdit is really bad in terms of performance. It cannot be used as overlying widget (just like in terminal). On the other hand we could optimize it by rewriting (unfortunately) the whole widget. There still is a lot of things to do, but for now it is possible to select several lines of text and copy it using CTRL + C. In order to make text copyable in context menu it will be required to override onMousePress (return true). --- modules/game_console/console.lua | 64 ++++++++++++++++++++++++++++++-- src/framework/ui/uitextedit.cpp | 6 ++- 2 files changed, 65 insertions(+), 5 deletions(-) diff --git a/modules/game_console/console.lua b/modules/game_console/console.lua index 904bf9ea..71615de7 100644 --- a/modules/game_console/console.lua +++ b/modules/game_console/console.lua @@ -117,9 +117,15 @@ function init() if not consoleBuffer then return false end local consoleLabel = consoleBuffer:getFocusedChild() - if not consoleLabel or not consoleLabel:hasSelection() then return false end + if not consoleLabel.selectionChildFirst or not consoleLabel.selectionChildLast then return false end - g_window.setClipboardText(consoleLabel:getSelection()) + local text = {} + for selectionChild = consoleLabel.selectionChildFirst, consoleLabel.selectionChildLast do + local label = consoleLabel:getParent():getChildByIndex(selectionChild) + table.insert(text, label:getSelection()) + end + + g_window.setClipboardText(table.concat(text, '\r\n')) return true end @@ -576,10 +582,62 @@ function addTabText(text, speaktype, tab, creatureName) end end + -- remove selection + local removeSelectedText = function(self) + local parent = self:getParent() + if self.selectionChildFirst and self.selectionChildLast then + for selectionChild = self.selectionChildFirst, self.selectionChildLast do + local label = parent:getChildByIndex(selectionChild) + if label ~= self then + label:clearSelection() + end + end + end + end + label.name = creatureName - label.onMouseRelease = function (self, mousePos, mouseButton) + label.onMouseRelease = function(self, mousePos, mouseButton) + -- TODO: regain lost selection processMessageMenu(mousePos, mouseButton, creatureName, text, self, tab) end + label.onFocusChange = function(self, focused, reason) + -- TODO: we are losing focus on context menu and therefore the selection + if not focused then removeSelectedText(self) end + end + label.onMousePress = function(self, mousePos, button) + if button == MouseLeftButton then removeSelectedText(self) end + end + label.onMouseMove = function(self, mousePos, mouseMoved) + if self:isPressed() then + local parent = self:getParent() + local selfIndex = parent:getChildIndex(self) + local child = parent:getChildByPos(mousePos) + local childIndex = parent:getChildIndex(child) + + -- remove old selection + removeSelectedText(self) + + -- choose new selection + if child and child ~= self then + self.selectionChildFirst = math.min(selfIndex, childIndex) + self.selectionChildLast = math.max(selfIndex, childIndex) + + for selectionChild = self.selectionChildFirst + 1, self.selectionChildLast - 1 do + local label = parent:getChildByIndex(selectionChild) + label:selectAll() + end + + local textPos = child:getTextPos(mousePos) + if childIndex > selfIndex then + child:setSelection(0, textPos) + else + child:setSelection(string.len(child:getText()), textPos) + end + elseif not child then + -- TODO: out of bonding rect selection + end + end + end if consoleBuffer:getChildCount() > MAX_LINES then consoleBuffer:getFirstChild():destroy() diff --git a/src/framework/ui/uitextedit.cpp b/src/framework/ui/uitextedit.cpp index 2c5aceaa..d3006346 100644 --- a/src/framework/ui/uitextedit.cpp +++ b/src/framework/ui/uitextedit.cpp @@ -796,7 +796,6 @@ bool UITextEdit::onMousePress(const Point& mousePos, Fw::MouseButton button) } return true; } - return false; } @@ -807,6 +806,9 @@ bool UITextEdit::onMouseRelease(const Point& mousePos, Fw::MouseButton button) bool UITextEdit::onMouseMove(const Point& mousePos, const Point& mouseMoved) { + if(UIWidget::onMouseMove(mousePos, mouseMoved)) + return true; + if(m_selectable && isPressed()) { int pos = getTextPos(mousePos); if(pos >= 0) { @@ -815,7 +817,7 @@ bool UITextEdit::onMouseMove(const Point& mousePos, const Point& mouseMoved) } return true; } - return UIWidget::onMouseMove(mousePos, mouseMoved); + return false; } bool UITextEdit::onDoubleClick(const Point& mousePos) From cf90bb9807e7c52b1a0bd3fd5810de697825a569 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konrad=20Ku=C5=9Bnierz?= Date: Tue, 2 Jun 2015 20:04:34 +0200 Subject: [PATCH 14/27] Fix selection Perhaps it would be wise to move widget local variables to some sort of global variable for each tab. --- modules/game_console/console.lua | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/modules/game_console/console.lua b/modules/game_console/console.lua index 71615de7..85360a03 100644 --- a/modules/game_console/console.lua +++ b/modules/game_console/console.lua @@ -117,15 +117,9 @@ function init() if not consoleBuffer then return false end local consoleLabel = consoleBuffer:getFocusedChild() - if not consoleLabel.selectionChildFirst or not consoleLabel.selectionChildLast then return false end + if not consoleLabel then return false end - local text = {} - for selectionChild = consoleLabel.selectionChildFirst, consoleLabel.selectionChildLast do - local label = consoleLabel:getParent():getChildByIndex(selectionChild) - table.insert(text, label:getSelection()) - end - - g_window.setClipboardText(table.concat(text, '\r\n')) + g_window.setClipboardText(getSelection(consoleLabel)) return true end @@ -153,6 +147,20 @@ function init() end end +function getSelection(widget) + if not widget.selectionChildFirst or not widget.selectionChildLast then + return widget:getSelection() + end + + local text = {} + for selectionChild = widget.selectionChildFirst, widget.selectionChildLast do + local label = widget:getParent():getChildByIndex(selectionChild) + table.insert(text, label:getSelection()) + end + + return table.concat(text, '\r\n') +end + function toggleChat() if consoleToggleChat:isChecked() then disableChat() @@ -592,6 +600,8 @@ function addTabText(text, speaktype, tab, creatureName) label:clearSelection() end end + self.selectionChildFirst = nil + self.selectionChildLast = nil end end @@ -703,7 +713,7 @@ function processMessageMenu(mousePos, mouseButton, creatureName, text, label, ta menu:addOption(tr('Copy name'), function () g_window.setClipboardText(creatureName) end) end if label:hasSelection() then - menu:addOption(tr('Copy'), function() g_window.setClipboardText(label:getSelection()) end, '(Ctrl+C)') + menu:addOption(tr('Copy'), function() g_window.setClipboardText(getSelection(label)) end, '(Ctrl+C)') end menu:addOption(tr('Copy message'), function() g_window.setClipboardText(text) end) menu:addOption(tr('Select all'), function() label:selectAll() end) From 559e545e3636873634e6cc7994cc9336aec36452 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konrad=20Ku=C5=9Bnierz?= Date: Tue, 2 Jun 2015 22:46:33 +0200 Subject: [PATCH 15/27] Few more minor fixes to selection in game console --- modules/game_console/console.lua | 56 +++++++++++++++----------------- 1 file changed, 27 insertions(+), 29 deletions(-) diff --git a/modules/game_console/console.lua b/modules/game_console/console.lua index 85360a03..c9cb62e9 100644 --- a/modules/game_console/console.lua +++ b/modules/game_console/console.lua @@ -148,12 +148,12 @@ function init() end function getSelection(widget) - if not widget.selectionChildFirst or not widget.selectionChildLast then + if not widget.selection then return widget:getSelection() end local text = {} - for selectionChild = widget.selectionChildFirst, widget.selectionChildLast do + for selectionChild = widget.selection.first, widget.selection.last do local label = widget:getParent():getChildByIndex(selectionChild) table.insert(text, label:getSelection()) end @@ -161,6 +161,19 @@ function getSelection(widget) return table.concat(text, '\r\n') end +function invalidateSelection(widget) + local parent = widget:getParent() + if widget.selection then + for selectionChild = widget.selection.first, widget.selection.last do + local label = parent:getChildByIndex(selectionChild) + if label ~= widget then + label:clearSelection() + end + end + widget.selection = nil + end +end + function toggleChat() if consoleToggleChat:isChecked() then disableChat() @@ -590,21 +603,6 @@ function addTabText(text, speaktype, tab, creatureName) end end - -- remove selection - local removeSelectedText = function(self) - local parent = self:getParent() - if self.selectionChildFirst and self.selectionChildLast then - for selectionChild = self.selectionChildFirst, self.selectionChildLast do - local label = parent:getChildByIndex(selectionChild) - if label ~= self then - label:clearSelection() - end - end - self.selectionChildFirst = nil - self.selectionChildLast = nil - end - end - label.name = creatureName label.onMouseRelease = function(self, mousePos, mouseButton) -- TODO: regain lost selection @@ -612,10 +610,10 @@ function addTabText(text, speaktype, tab, creatureName) end label.onFocusChange = function(self, focused, reason) -- TODO: we are losing focus on context menu and therefore the selection - if not focused then removeSelectedText(self) end + if not focused then invalidateSelection(self) end end label.onMousePress = function(self, mousePos, button) - if button == MouseLeftButton then removeSelectedText(self) end + if button == MouseLeftButton then invalidateSelection(self) end end label.onMouseMove = function(self, mousePos, mouseMoved) if self:isPressed() then @@ -625,16 +623,13 @@ function addTabText(text, speaktype, tab, creatureName) local childIndex = parent:getChildIndex(child) -- remove old selection - removeSelectedText(self) + invalidateSelection(self) -- choose new selection if child and child ~= self then - self.selectionChildFirst = math.min(selfIndex, childIndex) - self.selectionChildLast = math.max(selfIndex, childIndex) - - for selectionChild = self.selectionChildFirst + 1, self.selectionChildLast - 1 do - local label = parent:getChildByIndex(selectionChild) - label:selectAll() + self.selection = {first = math.min(selfIndex, childIndex), last = math.max(selfIndex, childIndex)} + for selectionChild = self.selection.first + 1, self.selection.last - 1 do + parent:getChildByIndex(selectionChild):selectAll() end local textPos = child:getTextPos(mousePos) @@ -650,7 +645,9 @@ function addTabText(text, speaktype, tab, creatureName) end if consoleBuffer:getChildCount() > MAX_LINES then - consoleBuffer:getFirstChild():destroy() + local child = consoleBuffer:getFirstChild() + if child.selection then invalidateSelection(child) end + child:destroy() end end @@ -712,8 +709,9 @@ function processMessageMenu(mousePos, mouseButton, creatureName, text, label, ta menu:addOption(tr('Copy name'), function () g_window.setClipboardText(creatureName) end) end - if label:hasSelection() then - menu:addOption(tr('Copy'), function() g_window.setClipboardText(getSelection(label)) end, '(Ctrl+C)') + local selectedText = getSelection(label) + if #selectedText > 0 then + menu:addOption(tr('Copy'), function() g_window.setClipboardText(selectedText) end, '(Ctrl+C)') end menu:addOption(tr('Copy message'), function() g_window.setClipboardText(text) end) menu:addOption(tr('Select all'), function() label:selectAll() end) From 6893a5e98ac98c9ddbf08399e62d9e76df2aa745 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konrad=20Ku=C5=9Bnierz?= Date: Wed, 3 Jun 2015 14:56:43 +0200 Subject: [PATCH 16/27] Optimize UITextEdit rendering --- src/framework/graphics/ogl/painterogl1.cpp | 6 +++ src/framework/graphics/ogl/painterogl1.h | 1 + src/framework/graphics/ogl/painterogl2.cpp | 7 ++++ src/framework/graphics/ogl/painterogl2.h | 1 + src/framework/graphics/painter.h | 1 + src/framework/ui/uitextedit.cpp | 49 ++++++++++++---------- src/framework/ui/uitextedit.h | 5 +++ 7 files changed, 48 insertions(+), 22 deletions(-) diff --git a/src/framework/graphics/ogl/painterogl1.cpp b/src/framework/graphics/ogl/painterogl1.cpp index 7223e4c9..f47e5353 100644 --- a/src/framework/graphics/ogl/painterogl1.cpp +++ b/src/framework/graphics/ogl/painterogl1.cpp @@ -135,6 +135,12 @@ void PainterOGL1::drawCoords(CoordsBuffer& coordsBuffer, DrawMode drawMode) #endif } +void PainterOGL1::drawFillCoords(CoordsBuffer& coordsBuffer) +{ + setTexture(nullptr); + drawCoords(coordsBuffer); +} + void PainterOGL1::drawTextureCoords(CoordsBuffer& coordsBuffer, const TexturePtr& texture) { if(texture->isEmpty()) diff --git a/src/framework/graphics/ogl/painterogl1.h b/src/framework/graphics/ogl/painterogl1.h index 8799fb51..66c5dfae 100644 --- a/src/framework/graphics/ogl/painterogl1.h +++ b/src/framework/graphics/ogl/painterogl1.h @@ -50,6 +50,7 @@ public: void refreshState(); void drawCoords(CoordsBuffer& coordsBuffer, DrawMode drawMode = Triangles); + void drawFillCoords(CoordsBuffer& coordsBuffer); void drawTextureCoords(CoordsBuffer& coordsBuffer, const TexturePtr& texture); void drawTexturedRect(const Rect& dest, const TexturePtr& texture, const Rect& src); void drawUpsideDownTexturedRect(const Rect& dest, const TexturePtr& texture, const Rect& src); diff --git a/src/framework/graphics/ogl/painterogl2.cpp b/src/framework/graphics/ogl/painterogl2.cpp index fa4caa51..9e6ab4c5 100644 --- a/src/framework/graphics/ogl/painterogl2.cpp +++ b/src/framework/graphics/ogl/painterogl2.cpp @@ -120,6 +120,13 @@ void PainterOGL2::drawCoords(CoordsBuffer& coordsBuffer, DrawMode drawMode) PainterShaderProgram::enableAttributeArray(PainterShaderProgram::TEXCOORD_ATTR); } +void PainterOGL2::drawFillCoords(CoordsBuffer& coordsBuffer) +{ + setDrawProgram(m_shaderProgram ? m_shaderProgram : m_drawSolidColorProgram.get()); + setTexture(nullptr); + drawCoords(coordsBuffer); +} + void PainterOGL2::drawTextureCoords(CoordsBuffer& coordsBuffer, const TexturePtr& texture) { if(texture && texture->isEmpty()) diff --git a/src/framework/graphics/ogl/painterogl2.h b/src/framework/graphics/ogl/painterogl2.h index 2b02474e..f6d40582 100644 --- a/src/framework/graphics/ogl/painterogl2.h +++ b/src/framework/graphics/ogl/painterogl2.h @@ -41,6 +41,7 @@ public: void unbind(); void drawCoords(CoordsBuffer& coordsBuffer, DrawMode drawMode = Triangles); + void drawFillCoords(CoordsBuffer& coordsBuffer); void drawTextureCoords(CoordsBuffer& coordsBuffer, const TexturePtr& texture); void drawTexturedRect(const Rect& dest, const TexturePtr& texture, const Rect& src); void drawUpsideDownTexturedRect(const Rect& dest, const TexturePtr& texture, const Rect& src); diff --git a/src/framework/graphics/painter.h b/src/framework/graphics/painter.h index 1c710cdf..c8145aa4 100644 --- a/src/framework/graphics/painter.h +++ b/src/framework/graphics/painter.h @@ -62,6 +62,7 @@ public: virtual void clear(const Color& color) = 0; virtual void drawCoords(CoordsBuffer& coordsBuffer, DrawMode drawMode = Triangles) = 0; + virtual void drawFillCoords(CoordsBuffer& coordsBuffer) = 0; virtual void drawTextureCoords(CoordsBuffer& coordsBuffer, const TexturePtr& texture) = 0; virtual void drawTexturedRect(const Rect& dest, const TexturePtr& texture, const Rect& src) = 0; void drawTexturedRect(const Rect& dest, const TexturePtr& texture) { drawTexturedRect(dest, texture, Rect(Point(0,0), texture->getSize())); } diff --git a/src/framework/ui/uitextedit.cpp b/src/framework/ui/uitextedit.cpp index d3006346..cffec788 100644 --- a/src/framework/ui/uitextedit.cpp +++ b/src/framework/ui/uitextedit.cpp @@ -49,6 +49,9 @@ UITextEdit::UITextEdit() m_updatesEnabled = true; m_selectionColor = Color::white; m_selectionBackgroundColor = Color::black; + m_glyphsTextCoordsBuffer.enableHardwareCaching(); + m_glyphsSelectCoordsBuffer.enableHardwareCaching(); + m_glyphsMustRecache = true; blinkCursor(); } @@ -62,38 +65,36 @@ void UITextEdit::drawSelf(Fw::DrawPane drawPane) drawImage(m_rect); drawIcon(m_rect); - //TODO: text rendering could be much optimized by using vertex buffer or caching the render into a texture - int textLength = m_text.length(); const TexturePtr& texture = m_font->getTexture(); if(!texture) return; - if(hasSelection()) { - if(m_color != Color::alpha) { - g_painter->setColor(m_color); - for(int i=0;idrawTexturedRect(m_glyphsCoords[i], texture, m_glyphsTexCoords[i]); - } + bool glyphsMustRecache = m_glyphsMustRecache; + if(glyphsMustRecache) + m_glyphsMustRecache = false; - for(int i=m_selectionStart;isetColor(m_selectionBackgroundColor); - g_painter->drawFilledRect(m_glyphsCoords[i]); - g_painter->setColor(m_selectionColor); - g_painter->drawTexturedRect(m_glyphsCoords[i], texture, m_glyphsTexCoords[i]); + if(m_color != Color::alpha) { + if(glyphsMustRecache) { + m_glyphsTextCoordsBuffer.clear(); + for(int i=0;isetColor(m_color); - for(int i=m_selectionEnd;idrawTexturedRect(m_glyphsCoords[i], texture, m_glyphsTexCoords[i]); - } - } else if(m_color != Color::alpha) { g_painter->setColor(m_color); - for(int i=0;idrawTexturedRect(m_glyphsCoords[i], texture, m_glyphsTexCoords[i]); + g_painter->drawTextureCoords(m_glyphsTextCoordsBuffer, texture); } + if(hasSelection()) { + if(glyphsMustRecache) { + m_glyphsSelectCoordsBuffer.clear(); + for(int i=m_selectionStart;isetColor(m_selectionBackgroundColor); + g_painter->drawFillCoords(m_glyphsSelectCoordsBuffer); + g_painter->setColor(m_selectionColor); + g_painter->drawTextureCoords(m_glyphsSelectCoordsBuffer, texture); + } // render cursor if(isExplicitlyEnabled() && m_cursorVisible && m_cursorInRange && isActive() && m_cursorPos >= 0) { @@ -136,6 +137,9 @@ void UITextEdit::update(bool focusCursor) if(m_rect.isEmpty()) return; + // recache coords buffers + recacheGlyphs(); + // map glyphs positions Size textBoxSize; const std::vector& glyphsPositions = m_font->calculateGlyphsPositions(text, m_textAlign, &textBoxSize); @@ -360,6 +364,7 @@ void UITextEdit::setSelection(int start, int end) m_selectionStart = stdext::clamp(start, 0, (int)m_text.length()); m_selectionEnd = stdext::clamp(end, 0, (int)m_text.length()); + recacheGlyphs(); } void UITextEdit::setTextHidden(bool hidden) diff --git a/src/framework/ui/uitextedit.h b/src/framework/ui/uitextedit.h index 2b9bb93b..79508bb4 100644 --- a/src/framework/ui/uitextedit.h +++ b/src/framework/ui/uitextedit.h @@ -108,6 +108,7 @@ protected: private: void disableUpdates() { m_updatesEnabled = false; } void enableUpdates() { m_updatesEnabled = true; } + void recacheGlyphs() { m_glyphsMustRecache = true; } Rect m_drawArea; int m_cursorPos; @@ -137,6 +138,10 @@ private: std::vector m_glyphsCoords; std::vector m_glyphsTexCoords; + + CoordsBuffer m_glyphsTextCoordsBuffer; + CoordsBuffer m_glyphsSelectCoordsBuffer; + bool m_glyphsMustRecache; }; #endif From 0c1540e531c62840fe603f8b25f7ce2eb6cdaadd Mon Sep 17 00:00:00 2001 From: Eduardo Bart Date: Wed, 3 Jun 2015 10:51:26 -0300 Subject: [PATCH 17/27] Improve multiline text selection, closes #507 --- modules/game_console/console.lua | 142 +++++++++++++++--------------- modules/game_console/console.otui | 2 + src/framework/ui/uitextedit.cpp | 2 +- 3 files changed, 76 insertions(+), 70 deletions(-) diff --git a/modules/game_console/console.lua b/modules/game_console/console.lua index c9cb62e9..ac9ffd03 100644 --- a/modules/game_console/console.lua +++ b/modules/game_console/console.lua @@ -113,13 +113,7 @@ function init() local tab = consoleTabBar:getCurrentTab() if not tab then return false end - local consoleBuffer = tab.tabPanel:getChildById('consoleBuffer') - if not consoleBuffer then return false end - - local consoleLabel = consoleBuffer:getFocusedChild() - if not consoleLabel then return false end - - g_window.setClipboardText(getSelection(consoleLabel)) + g_window.setClipboardText(selectioText) return true end @@ -147,31 +141,12 @@ function init() end end -function getSelection(widget) - if not widget.selection then - return widget:getSelection() - end - - local text = {} - for selectionChild = widget.selection.first, widget.selection.last do - local label = widget:getParent():getChildByIndex(selectionChild) - table.insert(text, label:getSelection()) - end - - return table.concat(text, '\r\n') -end - -function invalidateSelection(widget) - local parent = widget:getParent() - if widget.selection then - for selectionChild = widget.selection.first, widget.selection.last do - local label = parent:getChildByIndex(selectionChild) - if label ~= widget then - label:clearSelection() - end - end - widget.selection = nil +function clearSelection(consoleBuffer) + for _,label in pairs(consoleBuffer:getChildren()) do + label:clearSelection() end + consoleBuffer.selectionText = nil + consoleBuffer.selection = nil end function toggleChat() @@ -604,49 +579,76 @@ function addTabText(text, speaktype, tab, creatureName) end label.name = creatureName + consoleBuffer.onMouseRelease = function(self, mousePos, mouseButton) + processMessageMenu(mousePos, mouseButton, nil, nil, nil, tab) + end label.onMouseRelease = function(self, mousePos, mouseButton) - -- TODO: regain lost selection processMessageMenu(mousePos, mouseButton, creatureName, text, self, tab) end - label.onFocusChange = function(self, focused, reason) - -- TODO: we are losing focus on context menu and therefore the selection - if not focused then invalidateSelection(self) end - end label.onMousePress = function(self, mousePos, button) - if button == MouseLeftButton then invalidateSelection(self) end + if button == MouseLeftButton then clearSelection(consoleBuffer) end end - label.onMouseMove = function(self, mousePos, mouseMoved) - if self:isPressed() then - local parent = self:getParent() - local selfIndex = parent:getChildIndex(self) - local child = parent:getChildByPos(mousePos) - local childIndex = parent:getChildIndex(child) - - -- remove old selection - invalidateSelection(self) - - -- choose new selection - if child and child ~= self then - self.selection = {first = math.min(selfIndex, childIndex), last = math.max(selfIndex, childIndex)} - for selectionChild = self.selection.first + 1, self.selection.last - 1 do - parent:getChildByIndex(selectionChild):selectAll() - end - - local textPos = child:getTextPos(mousePos) - if childIndex > selfIndex then - child:setSelection(0, textPos) - else - child:setSelection(string.len(child:getText()), textPos) - end - elseif not child then - -- TODO: out of bonding rect selection + label.onDragEnter = function(self, mousePos) + clearSelection(consoleBuffer) + return true + end + label.onDragLeave = function(self, droppedWidget, mousePos) + local text = {} + for selectionChild = consoleBuffer.selection.first, consoleBuffer.selection.last do + local label = self:getParent():getChildByIndex(selectionChild) + table.insert(text, label:getSelection()) + end + consoleBuffer.selectionText = table.concat(text, '\r\n') + return true + end + label.onDragMove = function(self, mousePos, mouseMoved) + local parent = self:getParent() + local selfIndex = parent:getChildIndex(self) + local child = parent:getChildByPos(mousePos) + + -- find out bounds children + if not child then + if mousePos.y >= parent:getLastChild():getY() then + child = parent:getLastChild() + elseif mousePos.y <= parent:getFirstChild():getY() then + child = parent:getFirstChild() end end + + if not child then return false end + + local childIndex = parent:getChildIndex(child) + + -- remove old selection + clearSelection(consoleBuffer) + + -- update self selection + local textBegin = self:getTextPos(self:getLastClickPosition()) + local textPos = self:getTextPos(mousePos) + self:setSelection(textBegin, textPos) + + consoleBuffer.selection = { first = math.min(selfIndex, childIndex), last = math.max(selfIndex, childIndex) } + + -- update siblings selection + if child ~= self then + for selectionChild = consoleBuffer.selection.first + 1, consoleBuffer.selection.last - 1 do + parent:getChildByIndex(selectionChild):selectAll() + end + + local textPos = child:getTextPos(mousePos) + if childIndex > selfIndex then + child:setSelection(0, textPos) + else + child:setSelection(string.len(child:getText()), textPos) + end + end + + return true end if consoleBuffer:getChildCount() > MAX_LINES then local child = consoleBuffer:getFirstChild() - if child.selection then invalidateSelection(child) end + clearSelection(consoleBuffer) child:destroy() end end @@ -709,13 +711,15 @@ function processMessageMenu(mousePos, mouseButton, creatureName, text, label, ta menu:addOption(tr('Copy name'), function () g_window.setClipboardText(creatureName) end) end - local selectedText = getSelection(label) - if #selectedText > 0 then - menu:addOption(tr('Copy'), function() g_window.setClipboardText(selectedText) end, '(Ctrl+C)') + local selection = tab.tabPanel:getChildById('consoleBuffer').selectionText + if selection and #selection > 0 then + menu:addOption(tr('Copy'), function() g_window.setClipboardText(selection) end, '(Ctrl+C)') end - menu:addOption(tr('Copy message'), function() g_window.setClipboardText(text) end) - menu:addOption(tr('Select all'), function() label:selectAll() end) - if tab.violations then + if text then + menu:addOption(tr('Copy message'), function() g_window.setClipboardText(text) end) + end + --menu:addOption(tr('Select all'), function() label:selectAll() end) + if tab.violations and creatureName then menu:addSeparator() menu:addOption(tr('Process') .. ' ' .. creatureName, function() processViolation(creatureName, text) end) menu:addOption(tr('Remove') .. ' ' .. creatureName, function() g_game.closeRuleViolation(creatureName) end) diff --git a/modules/game_console/console.otui b/modules/game_console/console.otui index 346df542..9a31a3aa 100644 --- a/modules/game_console/console.otui +++ b/modules/game_console/console.otui @@ -10,6 +10,8 @@ ConsoleLabel < UITextEdit change-cursor-image: false cursor-visible: false editable: false + draggable: true + selectable: false ConsolePhantomLabel < UILabel font: verdana-11px-antialised diff --git a/src/framework/ui/uitextedit.cpp b/src/framework/ui/uitextedit.cpp index cffec788..b694ac08 100644 --- a/src/framework/ui/uitextedit.cpp +++ b/src/framework/ui/uitextedit.cpp @@ -659,7 +659,7 @@ void UITextEdit::onFocusChange(bool focused, Fw::FocusReason reason) else blinkCursor(); update(true); - } else + } else if(m_selectable) clearSelection(); UIWidget::onFocusChange(focused, reason); } From 02c6b1b6c71b076667aa30ef0a0f2b632cca2ac2 Mon Sep 17 00:00:00 2001 From: Eduardo Bart Date: Wed, 3 Jun 2015 10:59:28 -0300 Subject: [PATCH 18/27] Missing changes for multiline text --- modules/game_console/console.lua | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/modules/game_console/console.lua b/modules/game_console/console.lua index ac9ffd03..ebb8ed1b 100644 --- a/modules/game_console/console.lua +++ b/modules/game_console/console.lua @@ -113,7 +113,10 @@ function init() local tab = consoleTabBar:getCurrentTab() if not tab then return false end - g_window.setClipboardText(selectioText) + local selection = tab.tabPanel:getChildById('consoleBuffer').selectionText + if not selection then return false end + + g_window.setClipboardText(selection) return true end From f9d183837a7385e8f2b97fff4e4ec39705f040d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konrad=20Ku=C5=9Bnierz?= Date: Wed, 3 Jun 2015 16:46:49 +0200 Subject: [PATCH 19/27] Add option to save messages from channel --- modules/game_console/console.lua | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/modules/game_console/console.lua b/modules/game_console/console.lua index ebb8ed1b..d33f8b47 100644 --- a/modules/game_console/console.lua +++ b/modules/game_console/console.lua @@ -679,8 +679,28 @@ function processChannelTabMenu(tab, mousePos, mouseButton) if consoleTabBar:getCurrentTab() == tab then menu:addOption(tr('Clear Messages'), function() clearChannel(consoleTabBar) end) + menu:addOption(tr('Save Messages'), function() + local panel = consoleTabBar:getTabPanel(tab) + local consoleBuffer = panel:getChildById('consoleBuffer') + local lines = {} + for _,label in pairs(consoleBuffer:getChildren()) do + table.insert(lines, label:getText()) + end + + local filename = channelName .. '.txt' + local filepath = '/' .. filename + + -- extra information at the beginning + table.insert(lines, 1, os.date('\nChannel saved at %a %b %d %H:%M:%S %Y')) + + if g_resources.fileExists(filepath) then + table.insert(lines, 1, signalcall(g_resources.readFileContents, filepath) or '') + end + + g_resources.writeFileContents(filepath, table.concat(lines, '\n')) + modules.game_textmessage.displayStatusMessage(tr('Channel appended to %s', filename)) + end) end - --menu:addOption(tr('Save Messages'), function() --[[TODO]] end) menu:display(mousePos) end From 7f2f70e1a60d2a89bded7b7ac93ab607efce286d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konrad=20Ku=C5=9Bnierz?= Date: Wed, 3 Jun 2015 17:03:49 +0200 Subject: [PATCH 20/27] Change signalcall to protectedcall in console Even though they kind of do the same (calling function in protected mode), @edubart suggested to use a different function for the sake of readability. --- modules/corelib/util.lua | 10 ++++++++++ modules/game_console/console.lua | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/modules/corelib/util.lua b/modules/corelib/util.lua index 0691fc88..157c28b0 100644 --- a/modules/corelib/util.lua +++ b/modules/corelib/util.lua @@ -296,6 +296,16 @@ function numbertoboolean(number) end end +function protectedcall(func, ...) + local status, ret = pcall(func, ...) + if status then + return ret + end + + perror(ret) + return false +end + function signalcall(param, ...) if type(param) == 'function' then local status, ret = pcall(param, ...) diff --git a/modules/game_console/console.lua b/modules/game_console/console.lua index d33f8b47..74e51249 100644 --- a/modules/game_console/console.lua +++ b/modules/game_console/console.lua @@ -694,7 +694,7 @@ function processChannelTabMenu(tab, mousePos, mouseButton) table.insert(lines, 1, os.date('\nChannel saved at %a %b %d %H:%M:%S %Y')) if g_resources.fileExists(filepath) then - table.insert(lines, 1, signalcall(g_resources.readFileContents, filepath) or '') + table.insert(lines, 1, protectedcall(g_resources.readFileContents, filepath) or '') end g_resources.writeFileContents(filepath, table.concat(lines, '\n')) From a33fcd19b41492f8c769b2b538f3f914a608e72c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konrad=20Ku=C5=9Bnierz?= Date: Wed, 3 Jun 2015 23:00:39 +0200 Subject: [PATCH 21/27] Improve multi-line selection (find bouding children) --- modules/game_console/console.lua | 35 +++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/modules/game_console/console.lua b/modules/game_console/console.lua index 74e51249..c7dfbd8e 100644 --- a/modules/game_console/console.lua +++ b/modules/game_console/console.lua @@ -606,15 +606,40 @@ function addTabText(text, speaktype, tab, creatureName) end label.onDragMove = function(self, mousePos, mouseMoved) local parent = self:getParent() + local parentRect = parent:getPaddingRect() local selfIndex = parent:getChildIndex(self) local child = parent:getChildByPos(mousePos) - -- find out bounds children + -- find bouding children if not child then - if mousePos.y >= parent:getLastChild():getY() then - child = parent:getLastChild() - elseif mousePos.y <= parent:getFirstChild():getY() then - child = parent:getFirstChild() + if mousePos.y < self:getY() then + for index = selfIndex - 1, 1, -1 do + local label = parent:getChildByIndex(index) + if label:getY() + label:getHeight() > parentRect.y then + if (mousePos.y >= label:getY() and mousePos.y <= label:getY() + label:getHeight()) or index == 1 then + child = label + break + end + else + child = parent:getChildByIndex(index + 1) + break + end + end + elseif mousePos.y > self:getY() + self:getHeight() then + for index = selfIndex + 1, parent:getChildCount(), 1 do + local label = parent:getChildByIndex(index) + if label:getY() <= parentRect.y + parentRect.height then + if (mousePos.y >= label:getY() and mousePos.y <= label:getY() + label:getHeight()) or index == parent:getChildCount() then + child = label + break + end + else + child = parent:getChildByIndex(index - 1) + break + end + end + else + child = self end end From 471b8362e22ee5b1f762a6b0292e7dc765a9b9ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konrad=20Ku=C5=9Bnierz?= Date: Thu, 4 Jun 2015 15:31:15 +0200 Subject: [PATCH 22/27] ConsoleLabel should not be focusable Avoid scrolling by ensureChildVisible of UIScrollArea --- modules/game_console/console.otui | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/game_console/console.otui b/modules/game_console/console.otui index 9a31a3aa..c946f88d 100644 --- a/modules/game_console/console.otui +++ b/modules/game_console/console.otui @@ -12,6 +12,7 @@ ConsoleLabel < UITextEdit editable: false draggable: true selectable: false + focusable: false ConsolePhantomLabel < UILabel font: verdana-11px-antialised From e4302562ff45c7fe9d7296a30b774761d1f3d785 Mon Sep 17 00:00:00 2001 From: Eduardo Bart Date: Thu, 4 Jun 2015 12:10:32 -0300 Subject: [PATCH 23/27] Change new line from CR LF to LF when copying console text --- modules/game_console/console.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/game_console/console.lua b/modules/game_console/console.lua index c7dfbd8e..c5afccd0 100644 --- a/modules/game_console/console.lua +++ b/modules/game_console/console.lua @@ -601,7 +601,7 @@ function addTabText(text, speaktype, tab, creatureName) local label = self:getParent():getChildByIndex(selectionChild) table.insert(text, label:getSelection()) end - consoleBuffer.selectionText = table.concat(text, '\r\n') + consoleBuffer.selectionText = table.concat(text, '\n') return true end label.onDragMove = function(self, mousePos, mouseMoved) From b5a14ddb6821fd7d57c41b4926d6a08c1090d159 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konrad=20Ku=C5=9Bnierz?= Date: Thu, 4 Jun 2015 22:08:42 +0200 Subject: [PATCH 24/27] Add context menu option "Select all" for channel --- modules/game_console/console.lua | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/modules/game_console/console.lua b/modules/game_console/console.lua index c5afccd0..cf6178ca 100644 --- a/modules/game_console/console.lua +++ b/modules/game_console/console.lua @@ -152,6 +152,19 @@ function clearSelection(consoleBuffer) consoleBuffer.selection = nil end +function selectAll(consoleBuffer) + clearSelection(consoleBuffer) + if consoleBuffer:getChildCount() > 0 then + local text = {} + for _,label in pairs(consoleBuffer:getChildren()) do + label:selectAll() + table.insert(text, label:getSelection()) + end + consoleBuffer.selectionText = table.concat(text, '\n') + consoleBuffer.selection = { first = consoleBuffer:getChildIndex(consoleBuffer:getFirstChild()), last = consoleBuffer:getChildIndex(consoleBuffer:getLastChild()) } + end +end + function toggleChat() if consoleToggleChat:isChecked() then disableChat() @@ -609,8 +622,8 @@ function addTabText(text, speaktype, tab, creatureName) local parentRect = parent:getPaddingRect() local selfIndex = parent:getChildIndex(self) local child = parent:getChildByPos(mousePos) - - -- find bouding children + + -- find bonding children if not child then if mousePos.y < self:getY() then for index = selfIndex - 1, 1, -1 do @@ -628,7 +641,7 @@ function addTabText(text, speaktype, tab, creatureName) elseif mousePos.y > self:getY() + self:getHeight() then for index = selfIndex + 1, parent:getChildCount(), 1 do local label = parent:getChildByIndex(index) - if label:getY() <= parentRect.y + parentRect.height then + if label:getY() < parentRect.y + parentRect.height then if (mousePos.y >= label:getY() and mousePos.y <= label:getY() + label:getHeight()) or index == parent:getChildCount() then child = label break @@ -766,7 +779,7 @@ function processMessageMenu(mousePos, mouseButton, creatureName, text, label, ta if text then menu:addOption(tr('Copy message'), function() g_window.setClipboardText(text) end) end - --menu:addOption(tr('Select all'), function() label:selectAll() end) + menu:addOption(tr('Select all'), function() selectAll(tab.tabPanel:getChildById('consoleBuffer')) end) if tab.violations and creatureName then menu:addSeparator() menu:addOption(tr('Process') .. ' ' .. creatureName, function() processViolation(creatureName, text) end) From b9848f360c74f7ff9ef9a262eb80d0570eeab09a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konrad=20Ku=C5=9Bnierz?= Date: Sun, 21 Jun 2015 12:44:19 +0200 Subject: [PATCH 25/27] Check for Otc::GameAttackSeq feature --- src/client/protocolgamesend.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/client/protocolgamesend.cpp b/src/client/protocolgamesend.cpp index c3bbed03..5eb6a97d 100644 --- a/src/client/protocolgamesend.cpp +++ b/src/client/protocolgamesend.cpp @@ -583,10 +583,8 @@ void ProtocolGame::sendChangeFightModes(Otc::FightModes fightMode, Otc::ChaseMod msg->addU8(fightMode); msg->addU8(chaseMode); msg->addU8(safeFight ? 0x01: 0x00); - if(g_game.getFeature(Otc::GamePVPMode)) msg->addU8(pvpMode); - send(msg); } @@ -595,7 +593,8 @@ void ProtocolGame::sendAttack(uint creatureId, uint seq) OutputMessagePtr msg(new OutputMessage); msg->addU8(Proto::ClientAttack); msg->addU32(creatureId); - msg->addU32(seq); + if(g_game.getFeature(Otc::GameAttackSeq)) + msg->addU32(seq); send(msg); } @@ -604,7 +603,8 @@ void ProtocolGame::sendFollow(uint creatureId, uint seq) OutputMessagePtr msg(new OutputMessage); msg->addU8(Proto::ClientFollow); msg->addU32(creatureId); - msg->addU32(seq); + if(g_game.getFeature(Otc::GameAttackSeq)) + msg->addU32(seq); send(msg); } @@ -652,10 +652,8 @@ void ProtocolGame::sendShareExperience(bool active) OutputMessagePtr msg(new OutputMessage); msg->addU8(Proto::ClientShareExperience); msg->addU8(active ? 0x01 : 0x00); - if(g_game.getClientVersion() < 910) msg->addU8(0); - send(msg); } From 5ef55307f50d7a7541296a5b8989733832d7164c Mon Sep 17 00:00:00 2001 From: Nailson Date: Sun, 5 Jul 2015 13:05:12 -0300 Subject: [PATCH 26/27] Fix #664 --- src/client/thingtype.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client/thingtype.cpp b/src/client/thingtype.cpp index fad20257..41fbf9d7 100644 --- a/src/client/thingtype.cpp +++ b/src/client/thingtype.cpp @@ -244,12 +244,12 @@ void ThingType::unserialize(uint16 clientId, ThingCategory category, const FileS m_attribs.set(attr, market); break; } - case ThingAttrUsable: case ThingAttrElevation: { m_elevation = fin->getU16(); m_attribs.set(attr, m_elevation); break; } + case ThingAttrUsable: case ThingAttrGround: case ThingAttrWritable: case ThingAttrWritableOnce: From 78bdf20603a9603b07de581874368621534cd138 Mon Sep 17 00:00:00 2001 From: Kamil Chojnowski Date: Mon, 6 Jul 2015 07:38:01 +0200 Subject: [PATCH 27/27] Fix last motd number saving --- modules/client_entergame/entergame.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/client_entergame/entergame.lua b/modules/client_entergame/entergame.lua index 81ab23cf..2356ec41 100644 --- a/modules/client_entergame/entergame.lua +++ b/modules/client_entergame/entergame.lua @@ -78,7 +78,7 @@ local function onCharacterList(protocol, characters, account, otui) if motdEnabled then local lastMotdNumber = g_settings.getNumber("motd") if G.motdNumber and G.motdNumber ~= lastMotdNumber then - g_settings.set("motd", motdNumber) + g_settings.set("motd", G.motdNumber) motdWindow = displayInfoBox(tr('Message of the day'), G.motdMessage) connect(motdWindow, { onOk = function() CharacterList.show() motdWindow = nil end }) CharacterList.hide()