diff --git a/src/framework/CMakeLists.txt b/src/framework/CMakeLists.txt index 9d9a40ec..7080c619 100644 --- a/src/framework/CMakeLists.txt +++ b/src/framework/CMakeLists.txt @@ -34,18 +34,29 @@ set(framework_SOURCES ${framework_SOURCES} ${CMAKE_CURRENT_LIST_DIR}/util/size.h # stdext + ${CMAKE_CURRENT_LIST_DIR}/stdext/any.h + ${CMAKE_CURRENT_LIST_DIR}/stdext/boolean.h ${CMAKE_CURRENT_LIST_DIR}/stdext/cast.h ${CMAKE_CURRENT_LIST_DIR}/stdext/compiler.h + ${CMAKE_CURRENT_LIST_DIR}/stdext/demangle.cpp ${CMAKE_CURRENT_LIST_DIR}/stdext/demangle.h ${CMAKE_CURRENT_LIST_DIR}/stdext/dumper.h + ${CMAKE_CURRENT_LIST_DIR}/stdext/dynamic_storage.h ${CMAKE_CURRENT_LIST_DIR}/stdext/exception.h + ${CMAKE_CURRENT_LIST_DIR}/stdext/format.h + ${CMAKE_CURRENT_LIST_DIR}/stdext/math.cpp ${CMAKE_CURRENT_LIST_DIR}/stdext/math.h + ${CMAKE_CURRENT_LIST_DIR}/stdext/packed_any.h + ${CMAKE_CURRENT_LIST_DIR}/stdext/packed_storage.h + ${CMAKE_CURRENT_LIST_DIR}/stdext/packed_vector.h + ${CMAKE_CURRENT_LIST_DIR}/stdext/shared_object.h ${CMAKE_CURRENT_LIST_DIR}/stdext/stdext.h + ${CMAKE_CURRENT_LIST_DIR}/stdext/string.cpp ${CMAKE_CURRENT_LIST_DIR}/stdext/string.h + ${CMAKE_CURRENT_LIST_DIR}/stdext/time.cpp ${CMAKE_CURRENT_LIST_DIR}/stdext/time.h + ${CMAKE_CURRENT_LIST_DIR}/stdext/traits.h ${CMAKE_CURRENT_LIST_DIR}/stdext/types.h - ${CMAKE_CURRENT_LIST_DIR}/stdext/attrib_storage.h - ${CMAKE_CURRENT_LIST_DIR}/stdext/shared_object.h # core ${CMAKE_CURRENT_LIST_DIR}/core/application.cpp diff --git a/src/framework/core/declarations.h b/src/framework/core/declarations.h index e9ff38f8..e6c90614 100644 --- a/src/framework/core/declarations.h +++ b/src/framework/core/declarations.h @@ -33,11 +33,11 @@ class ScheduledEvent; class FileStream; class BinaryTree; -typedef boost::intrusive_ptr ModulePtr; -typedef boost::intrusive_ptr EventPtr; -typedef boost::intrusive_ptr ScheduledEventPtr; -typedef boost::intrusive_ptr FileStreamPtr; -typedef boost::intrusive_ptr BinaryTreePtr; +typedef stdext::shared_object_ptr ModulePtr; +typedef stdext::shared_object_ptr EventPtr; +typedef stdext::shared_object_ptr ScheduledEventPtr; +typedef stdext::shared_object_ptr FileStreamPtr; +typedef stdext::shared_object_ptr BinaryTreePtr; typedef std::vector BinaryTreeVec; diff --git a/src/framework/core/eventdispatcher.h b/src/framework/core/eventdispatcher.h index 0ff483cd..16d6209a 100644 --- a/src/framework/core/eventdispatcher.h +++ b/src/framework/core/eventdispatcher.h @@ -26,6 +26,8 @@ #include "clock.h" #include "scheduledevent.h" +#include + // @bindsingleton g_dispatcher class EventDispatcher { diff --git a/src/framework/core/filestream.h b/src/framework/core/filestream.h index 0d219e6a..b03f8c18 100644 --- a/src/framework/core/filestream.h +++ b/src/framework/core/filestream.h @@ -62,7 +62,7 @@ public: void addString(const std::string& v); BinaryTreePtr makeTree(); - FileStreamPtr asFileStream() { return self_cast(); } + FileStreamPtr asFileStream() { return static_self_cast(); } private: void checkWrite(); diff --git a/src/framework/core/logger.h b/src/framework/core/logger.h index 275b7fb2..d34c7c1d 100644 --- a/src/framework/core/logger.h +++ b/src/framework/core/logger.h @@ -25,6 +25,8 @@ #include "../global.h" +#include + struct LogMessage { LogMessage(Fw::LogLevel level, const std::string& message, std::size_t when) : level(level), message(message), when(when) { } Fw::LogLevel level; diff --git a/src/framework/core/module.h b/src/framework/core/module.h index bf3eb866..30814f08 100644 --- a/src/framework/core/module.h +++ b/src/framework/core/module.h @@ -56,7 +56,7 @@ public: int getAutoLoadPriority() { return m_autoLoadPriority; } // @dontbind - ModulePtr asModule() { return self_cast(); } + ModulePtr asModule() { return static_self_cast(); } protected: void discover(const OTMLNodePtr& moduleNode); diff --git a/src/framework/core/modulemanager.cpp b/src/framework/core/modulemanager.cpp index 5a45b820..dc7d115b 100644 --- a/src/framework/core/modulemanager.cpp +++ b/src/framework/core/modulemanager.cpp @@ -43,7 +43,7 @@ void ModuleManager::discoverModules() for(const std::string& moduleDir : moduleDirs) { auto moduleFiles = g_resources.listDirectoryFiles("/" + moduleDir); for(const std::string& moduleFile : moduleFiles) { - if(boost::ends_with(moduleFile, ".otmod")) { + if(stdext::ends_with(moduleFile, ".otmod")) { ModulePtr module = discoverModule("/" + moduleDir + "/" + moduleFile); if(module && module->isAutoLoad()) m_autoLoadModules.insert(std::make_pair(module->getAutoLoadPriority(), module)); diff --git a/src/framework/core/resourcemanager.cpp b/src/framework/core/resourcemanager.cpp index 2dacba5e..52adf907 100644 --- a/src/framework/core/resourcemanager.cpp +++ b/src/framework/core/resourcemanager.cpp @@ -125,7 +125,7 @@ void ResourceManager::searchAndAddPackages(const std::string& packagesDir, const auto files = listDirectoryFiles(packagesDir); for(auto it = files.rbegin(); it != files.rend(); ++it) { const std::string& file = *it; - if(!boost::ends_with(file, packageExt)) + if(!stdext::ends_with(file, packageExt)) continue; std::string package = getRealDir(packagesDir) + "/" + file; if(!addSearchPath(package, true)) @@ -262,7 +262,7 @@ std::list ResourceManager::listDirectoryFiles(const std::string& di std::string ResourceManager::resolvePath(const std::string& path) { std::string fullPath; - if(boost::starts_with(path, "/")) + if(stdext::starts_with(path, "/")) fullPath = path; else { std::string scriptPath = "/" + g_lua.getCurrentSourcePath(); @@ -270,9 +270,9 @@ std::string ResourceManager::resolvePath(const std::string& path) fullPath += scriptPath + "/"; fullPath += path; } - if(!(boost::starts_with(fullPath, "/"))) + if(!(stdext::starts_with(fullPath, "/"))) g_logger.traceWarning(stdext::format("the following file path is not fully resolved: %s", path)); - boost::replace_all(fullPath, "//", "/"); + stdext::replace_all(fullPath, "//", "/"); return fullPath; } diff --git a/src/framework/graphics/animatedtexture.h b/src/framework/graphics/animatedtexture.h index aef89173..977ab4e1 100644 --- a/src/framework/graphics/animatedtexture.h +++ b/src/framework/graphics/animatedtexture.h @@ -34,7 +34,7 @@ public: void enableBilinearFilter(); void processAnimation(); - AnimatedTexturePtr asAnimatedTexture() { return self_cast(); } + AnimatedTexturePtr asAnimatedTexture() { return static_self_cast(); } private: std::vector m_framesTextureId; diff --git a/src/framework/graphics/declarations.h b/src/framework/graphics/declarations.h index 65b5f76a..1533faf4 100644 --- a/src/framework/graphics/declarations.h +++ b/src/framework/graphics/declarations.h @@ -44,21 +44,21 @@ class ParticleSystem; class ParticleEffect; class ParticleEffectType; -typedef boost::intrusive_ptr ImagePtr; -typedef boost::intrusive_ptr TexturePtr; -typedef boost::intrusive_ptr AnimatedTexturePtr; -typedef boost::intrusive_ptr BitmapFontPtr; -typedef boost::intrusive_ptr CachedTextPtr; -typedef boost::intrusive_ptr FrameBufferPtr; -typedef boost::intrusive_ptr ShaderPtr; -typedef boost::intrusive_ptr ShaderProgramPtr; -typedef boost::intrusive_ptr PainterShaderProgramPtr; -typedef boost::intrusive_ptr ParticlePtr; -typedef boost::intrusive_ptr ParticleEmitterPtr; -typedef boost::intrusive_ptr ParticleAffectorPtr; -typedef boost::intrusive_ptr ParticleSystemPtr; -typedef boost::intrusive_ptr ParticleEffectPtr; -typedef boost::intrusive_ptr ParticleEffectTypePtr; +typedef stdext::shared_object_ptr ImagePtr; +typedef stdext::shared_object_ptr TexturePtr; +typedef stdext::shared_object_ptr AnimatedTexturePtr; +typedef stdext::shared_object_ptr BitmapFontPtr; +typedef stdext::shared_object_ptr CachedTextPtr; +typedef stdext::shared_object_ptr FrameBufferPtr; +typedef stdext::shared_object_ptr ShaderPtr; +typedef stdext::shared_object_ptr ShaderProgramPtr; +typedef stdext::shared_object_ptr PainterShaderProgramPtr; +typedef stdext::shared_object_ptr ParticlePtr; +typedef stdext::shared_object_ptr ParticleEmitterPtr; +typedef stdext::shared_object_ptr ParticleAffectorPtr; +typedef stdext::shared_object_ptr ParticleSystemPtr; +typedef stdext::shared_object_ptr ParticleEffectPtr; +typedef stdext::shared_object_ptr ParticleEffectTypePtr; typedef std::vector ShaderList; #endif diff --git a/src/framework/graphics/fontmanager.cpp b/src/framework/graphics/fontmanager.cpp index 15367330..0f2480d0 100644 --- a/src/framework/graphics/fontmanager.cpp +++ b/src/framework/graphics/fontmanager.cpp @@ -48,7 +48,7 @@ void FontManager::clearFonts() bool FontManager::importFont(std::string fontFile) { try { - if(!boost::ends_with(fontFile, ".otfont")) + if(!stdext::ends_with(fontFile, ".otfont")) fontFile += ".otfont"; OTMLDocumentPtr doc = OTMLDocument::parse(fontFile); diff --git a/src/framework/graphics/image.cpp b/src/framework/graphics/image.cpp index dd9f3e1d..2561925e 100644 --- a/src/framework/graphics/image.cpp +++ b/src/framework/graphics/image.cpp @@ -40,7 +40,7 @@ ImagePtr Image::load(const std::string& file) ImagePtr image; try { // currently only png images are supported - if(!boost::ends_with(file, ".png")) + if(!stdext::ends_with(file, ".png")) stdext::throw_exception("image file format no supported"); // load image file data diff --git a/src/framework/graphics/particlesystem.cpp b/src/framework/graphics/particlesystem.cpp index 664ea844..cd71ff4b 100644 --- a/src/framework/graphics/particlesystem.cpp +++ b/src/framework/graphics/particlesystem.cpp @@ -84,7 +84,7 @@ void ParticleSystem::update() return; m_lastUpdateTime = g_clock.seconds() - std::fmod(elapsedTime, delay); - auto self = self_cast(); + auto self = static_self_cast(); for(int i = 0; i < elapsedTime / delay; ++i) { // update emitters diff --git a/src/framework/graphics/texturemanager.cpp b/src/framework/graphics/texturemanager.cpp index 1f4ca7ea..4bc9ea00 100644 --- a/src/framework/graphics/texturemanager.cpp +++ b/src/framework/graphics/texturemanager.cpp @@ -63,7 +63,7 @@ TexturePtr TextureManager::getTexture(const std::string& fileName) if(!texture) { try { // currently only png textures are supported - if(!boost::ends_with(filePath, ".png")) + if(!stdext::ends_with(filePath, ".png")) stdext::throw_exception("texture file format no supported"); // load texture file data diff --git a/src/framework/luaengine/declarations.h b/src/framework/luaengine/declarations.h index 717b210f..f34d0204 100644 --- a/src/framework/luaengine/declarations.h +++ b/src/framework/luaengine/declarations.h @@ -25,11 +25,13 @@ #include +#include + class LuaInterface; class LuaObject; typedef std::function LuaCppFunction; typedef std::unique_ptr LuaCppFunctionPtr; -typedef boost::intrusive_ptr LuaObjectPtr; +typedef stdext::shared_object_ptr LuaObjectPtr; #endif diff --git a/src/framework/luaengine/luabinder.h b/src/framework/luaengine/luabinder.h index d3df7543..0c3b9757 100644 --- a/src/framework/luaengine/luabinder.h +++ b/src/framework/luaengine/luabinder.h @@ -27,6 +27,9 @@ #include "luainterface.h" #include "luaexception.h" +#include +#include + /// This namespace contains some dirty metaprogamming that uses a lot of C++0x features /// The purpose here is to create templates that can bind any function from C++ /// and expose in lua environment. This is done combining variadic templates, @@ -36,12 +39,6 @@ /// pushes the result to lua. namespace luabinder { - /// Removes const references, transforming 'const T&' into 'T' - template - struct remove_const_ref { - typedef typename std::remove_const::type>::type type; - }; - /// Pack arguments from lua stack into a tuple recursively template struct pack_values_into_tuple { @@ -117,8 +114,8 @@ namespace luabinder /// Bind a std::function template LuaCppFunction bind_fun(const std::function& f) { - typedef typename std::tuple::type...> Tuple; - return bind_fun_specializer::type, + typedef typename std::tuple::type...> Tuple; + return bind_fun_specializer::type, decltype(f), Tuple>(f); } @@ -130,8 +127,8 @@ namespace luabinder template struct bind_lambda_fun { static LuaCppFunction call(const Lambda& f) { - typedef typename std::tuple::type...> Tuple; - return bind_fun_specializer::type, + typedef typename std::tuple::type...> Tuple; + return bind_fun_specializer::type, decltype(f), Tuple>(f); @@ -152,18 +149,18 @@ namespace luabinder /// Create member function lambdas template - std::function&, const Args&...)> make_mem_func(Ret (C::* f)(Args...)) { + std::function&, const Args&...)> make_mem_func(Ret (C::* f)(Args...)) { auto mf = std::mem_fn(f); - return [=](const boost::intrusive_ptr& obj, const Args&... args) mutable -> Ret { + return [=](const stdext::shared_object_ptr& obj, const Args&... args) mutable -> Ret { if(!obj) throw LuaException("failed to call a member function because the passed object is nil"); return mf(obj.get(), args...); }; } template - std::function&, const Args&...)> make_mem_func(void (C::* f)(Args...)) { + std::function&, const Args&...)> make_mem_func(void (C::* f)(Args...)) { auto mf = std::mem_fn(f); - return [=](const boost::intrusive_ptr& obj, const Args&... args) mutable -> void { + return [=](const stdext::shared_object_ptr& obj, const Args&... args) mutable -> void { if(!obj) throw LuaException("failed to call a member function because the passed object is nil"); mf(obj.get(), args...); @@ -186,9 +183,9 @@ namespace luabinder /// Bind member functions template LuaCppFunction bind_mem_fun(Ret (FC::* f)(Args...)) { - typedef typename std::tuple, typename remove_const_ref::type...> Tuple; + typedef typename std::tuple, typename stdext::remove_const_ref::type...> Tuple; auto lambda = make_mem_func(f); - return bind_fun_specializer::type, + return bind_fun_specializer::type, decltype(lambda), Tuple>(lambda); } @@ -196,10 +193,10 @@ namespace luabinder /// Bind singleton member functions template LuaCppFunction bind_singleton_mem_fun(Ret (FC::*f)(Args...), C *instance) { - typedef typename std::tuple::type...> Tuple; + typedef typename std::tuple::type...> Tuple; assert(instance); auto lambda = make_mem_func_singleton(f, static_cast(instance)); - return bind_fun_specializer::type, + return bind_fun_specializer::type, decltype(lambda), Tuple>(lambda); } @@ -209,7 +206,7 @@ namespace luabinder LuaCppFunction bind_mem_fun(int (C::*f)(LuaInterface*)) { auto mf = std::mem_fn(f); return [=](LuaInterface* lua) -> int { - auto obj = lua->castValue>(1); + auto obj = lua->castValue>(1); lua->remove(1); return mf(obj, lua); }; diff --git a/src/framework/luaengine/luainterface.cpp b/src/framework/luaengine/luainterface.cpp index 6b7725b7..fc7a7ce0 100644 --- a/src/framework/luaengine/luainterface.cpp +++ b/src/framework/luaengine/luainterface.cpp @@ -325,7 +325,7 @@ void LuaInterface::loadScript(const std::string& fileName) { // resolve file full path std::string filePath = fileName; - if(!boost::starts_with(fileName, "/")) + if(!stdext::starts_with(fileName, "/")) filePath = getCurrentSourcePath() + "/" + filePath; std::string buffer = g_resources.loadFile(fileName); @@ -341,7 +341,7 @@ void LuaInterface::loadFunction(const std::string& buffer, const std::string& so } std::string buf; - if(boost::starts_with(buffer, "function")) + if(stdext::starts_with(buffer, "function")) buf = stdext::format("__func = %s", buffer); else buf = stdext::format("__func = function(self)\n%s\nend", buffer); @@ -553,7 +553,7 @@ int LuaInterface::luaScriptLoader(lua_State* L) g_lua.loadScript(fileName); return 1; } catch(stdext::exception& e) { - g_lua.pushString(stdext::mkstr("\n\t", e.what())); + g_lua.pushString(std::string("\n\t") + e.what()); return 1; } } @@ -561,7 +561,7 @@ int LuaInterface::luaScriptLoader(lua_State* L) int LuaInterface::lua_dofile(lua_State* L) { std::string fileName = g_lua.popString(); - if(!boost::ends_with(fileName, ".lua")) + if(!stdext::ends_with(fileName, ".lua")) fileName += ".lua"; try { @@ -580,7 +580,7 @@ int LuaInterface::lua_dofiles(lua_State* L) std::string directory = g_lua.popString(); for(const std::string& fileName : g_resources.listDirectoryFiles(directory)) { - if(!boost::ends_with(fileName, ".lua")) + if(!stdext::ends_with(fileName, ".lua")) continue; try { @@ -597,7 +597,7 @@ int LuaInterface::lua_dofiles(lua_State* L) int LuaInterface::lua_loadfile(lua_State* L) { std::string fileName = g_lua.popString(); - if(!boost::ends_with(fileName, ".lua")) + if(!stdext::ends_with(fileName, ".lua")) fileName += ".lua"; try { diff --git a/src/framework/luaengine/luainterface.h b/src/framework/luaengine/luainterface.h index eb2ce366..2a223899 100644 --- a/src/framework/luaengine/luainterface.h +++ b/src/framework/luaengine/luainterface.h @@ -320,7 +320,7 @@ public: /// Pushes any type onto the stack template - int polymorphicPush(T v, Args... args); + int polymorphicPush(const T& v, const Args&... args); int polymorphicPush() { return 0; } /// Casts a value from stack to any type @@ -349,7 +349,7 @@ extern LuaInterface g_lua; #include "luavaluecasts.h" template -int LuaInterface::polymorphicPush(T v, Args... args) { +int LuaInterface::polymorphicPush(const T& v, const Args&... args) { int r = push_luavalue(v); return r + polymorphicPush(args...); } diff --git a/src/framework/luaengine/luaobject.h b/src/framework/luaengine/luaobject.h index 242044b5..b2e61571 100644 --- a/src/framework/luaengine/luaobject.h +++ b/src/framework/luaengine/luaobject.h @@ -24,6 +24,7 @@ #define LUAOBJECT_H #include "declarations.h" +#include /// LuaObject, all script-able classes have it as base // @bindclass @@ -80,7 +81,7 @@ public: return stdext::demangle_name(typeid(*this).name()); } - LuaObjectPtr asLuaObject() { return self_cast(); } + LuaObjectPtr asLuaObject() { return static_self_cast(); } void operator=(const LuaObject& other) { } diff --git a/src/framework/luaengine/luavaluecasts.h b/src/framework/luaengine/luavaluecasts.h index d7e98ae4..d93361b8 100644 --- a/src/framework/luaengine/luavaluecasts.h +++ b/src/framework/luaengine/luavaluecasts.h @@ -111,7 +111,7 @@ bool luavalue_cast(int index, LuaObjectPtr& obj); template typename std::enable_if::value, bool>::type -luavalue_cast(int index, boost::intrusive_ptr& ptr); +luavalue_cast(int index, stdext::shared_object_ptr& ptr); // std::function template @@ -186,7 +186,7 @@ push_luavalue(const T& obj) { template typename std::enable_if::value, bool>::type -luavalue_cast(int index, boost::intrusive_ptr& ptr) { +luavalue_cast(int index, stdext::shared_object_ptr& ptr) { LuaObjectPtr obj; if(!luavalue_cast(index, obj)) return false; diff --git a/src/framework/net/connection.cpp b/src/framework/net/connection.cpp index d02397b1..d907a4e8 100644 --- a/src/framework/net/connection.cpp +++ b/src/framework/net/connection.cpp @@ -69,7 +69,7 @@ void Connection::connect(const std::string& host, uint16 port, const std::functi auto self = asConnection(); m_resolver.async_resolve(query, [=](const boost::system::error_code& error, asio::ip::tcp::resolver::iterator endpointIterator) { - if(self->is_unique_ref()) + if(self.is_unique()) return; m_readTimer.cancel(); @@ -130,7 +130,7 @@ void Connection::write(uint8* buffer, uint16 size) // wait 1 ms to do the real send m_sendEvent = g_dispatcher.scheduleEvent([=] { - if(self->is_unique_ref()) + if(self.is_unique()) return; //m_writeTimer.cancel(); diff --git a/src/framework/net/connection.h b/src/framework/net/connection.h index 8ebfbabf..32270685 100644 --- a/src/framework/net/connection.h +++ b/src/framework/net/connection.h @@ -62,7 +62,7 @@ public: bool isConnecting() { return m_connecting; } bool isConnected() { return m_connected; } - ConnectionPtr asConnection() { return self_cast(); } + ConnectionPtr asConnection() { return static_self_cast(); } protected: void onConnect(const boost::system::error_code& error); void onWrite(const boost::system::error_code& error, size_t); diff --git a/src/framework/net/declarations.h b/src/framework/net/declarations.h index d4bbef67..e1c189ff 100644 --- a/src/framework/net/declarations.h +++ b/src/framework/net/declarations.h @@ -34,10 +34,10 @@ class Connection; class Protocol; class Server; -typedef boost::intrusive_ptr InputMessagePtr; -typedef boost::intrusive_ptr OutputMessagePtr; -typedef boost::intrusive_ptr ConnectionPtr; -typedef boost::intrusive_ptr ProtocolPtr; -typedef boost::intrusive_ptr ServerPtr; +typedef stdext::shared_object_ptr InputMessagePtr; +typedef stdext::shared_object_ptr OutputMessagePtr; +typedef stdext::shared_object_ptr ConnectionPtr; +typedef stdext::shared_object_ptr ProtocolPtr; +typedef stdext::shared_object_ptr ServerPtr; #endif diff --git a/src/framework/net/protocol.h b/src/framework/net/protocol.h index 7bc75c04..468f8cef 100644 --- a/src/framework/net/protocol.h +++ b/src/framework/net/protocol.h @@ -54,7 +54,7 @@ public: virtual void send(const OutputMessagePtr& outputMessage); void recv(); - ProtocolPtr asProtocol() { return self_cast(); } + ProtocolPtr asProtocol() { return static_self_cast(); } protected: virtual void onConnect(); diff --git a/src/framework/otml/declarations.h b/src/framework/otml/declarations.h index 141680e9..35de3b56 100644 --- a/src/framework/otml/declarations.h +++ b/src/framework/otml/declarations.h @@ -30,8 +30,8 @@ class OTMLDocument; class OTMLParser; class OTMLEmitter; -typedef boost::intrusive_ptr OTMLNodePtr; -typedef boost::intrusive_ptr OTMLDocumentPtr; +typedef stdext::shared_object_ptr OTMLNodePtr; +typedef stdext::shared_object_ptr OTMLDocumentPtr; typedef std::vector OTMLNodeList; #endif diff --git a/src/framework/otml/otmlnode.cpp b/src/framework/otml/otmlnode.cpp index d6afd9dc..9c873cf4 100644 --- a/src/framework/otml/otmlnode.cpp +++ b/src/framework/otml/otmlnode.cpp @@ -84,7 +84,7 @@ OTMLNodePtr OTMLNode::at(const std::string& childTag) OTMLNodePtr OTMLNode::atIndex(int childIndex) { if(childIndex >= size() || childIndex < 0) - throw OTMLException(asOTMLNode(), stdext::mkstr("child node with index '%d' not found", childIndex)); + throw OTMLException(asOTMLNode(), stdext::format("child node with index '%d' not found", childIndex)); return m_children[childIndex]; } diff --git a/src/framework/otml/otmlnode.h b/src/framework/otml/otmlnode.h index 6e9fac2a..6f732b6f 100644 --- a/src/framework/otml/otmlnode.h +++ b/src/framework/otml/otmlnode.h @@ -89,7 +89,7 @@ public: virtual std::string emit(); - OTMLNodePtr asOTMLNode() { return self_cast(); } + OTMLNodePtr asOTMLNode() { return static_self_cast(); } protected: OTMLNode() : m_unique(false), m_null(false) { } @@ -107,13 +107,13 @@ protected: template<> inline std::string OTMLNode::value() { std::string value = m_value; - if(boost::starts_with(value, "\"") && boost::ends_with(value, "\"")) { + if(stdext::starts_with(value, "\"") && stdext::ends_with(value, "\"")) { value = value.substr(1, value.length()-2); - boost::replace_all(value, "\\\\", "\\"); - boost::replace_all(value, "\\\"", "\""); - boost::replace_all(value, "\\t", "\t"); - boost::replace_all(value, "\\n", "\n"); - boost::replace_all(value, "\\'", "\'"); + stdext::replace_all(value, "\\\\", "\\"); + stdext::replace_all(value, "\\\"", "\""); + stdext::replace_all(value, "\\t", "\t"); + stdext::replace_all(value, "\\n", "\n"); + stdext::replace_all(value, "\\'", "\'"); } return value; } diff --git a/src/framework/otml/otmlparser.cpp b/src/framework/otml/otmlparser.cpp index cfc2c3e9..cda76338 100644 --- a/src/framework/otml/otmlparser.cpp +++ b/src/framework/otml/otmlparser.cpp @@ -80,14 +80,14 @@ void OTMLParser::parseLine(std::string line) return; // remove line sides spaces - boost::trim(line); + stdext::trim(line); // skip empty lines if(line.empty()) return; // skip comments - if(boost::starts_with(line, "//")) + if(stdext::starts_with(line, "//")) return; // a depth above, change current parent to the previous added node @@ -119,7 +119,7 @@ void OTMLParser::parseNode(const std::string& data) // node that has no tag and may have a value if(!data.empty() && data[0] == '-') { value = data.substr(1); - boost::trim(value); + stdext::trim(value); // node that has tag and possible a value } else if(dotsPos != std::string::npos) { tag = data.substr(0, dotsPos); @@ -130,8 +130,8 @@ void OTMLParser::parseNode(const std::string& data) tag = data; } - boost::trim(tag); - boost::trim(value); + stdext::trim(tag); + stdext::trim(value); // process multitine values if(value == "|" || value == "|-" || value == "|+") { @@ -148,7 +148,7 @@ void OTMLParser::parseNode(const std::string& data) // it has contents below the current depth } else { // if not empty, its a node - boost::trim(line); + stdext::trim(line); if(!line.empty()) { // rewind and break in.seekg(lastPos, std::ios::beg); @@ -188,11 +188,13 @@ void OTMLParser::parseNode(const std::string& data) if(value == "~") node->setNull(true); else { - if(boost::starts_with(value, "[") && boost::ends_with(value, "]")) { + if(stdext::starts_with(value, "[") && stdext::ends_with(value, "]")) { std::string tmp = value.substr(1, value.length()-2); boost::tokenizer> tokens(tmp); - for(std::string v : tokens) - node->writeIn(stdext::trim(v)); + for(std::string v : tokens) { + stdext::trim(v); + node->writeIn(v); + } } else node->setValue(value); } diff --git a/src/framework/pch.h b/src/framework/pch.h index 3c408a6b..de9da521 100644 --- a/src/framework/pch.h +++ b/src/framework/pch.h @@ -28,40 +28,19 @@ #include #include #include -#include #include -#include // common STL headers #include #include -#include #include #include #include -#include -#include #include -#include #include #include -#include -#include -#include -#include #include -#include #include -#include #include -#include -#include -#include -#include -#include -#include - -// boost utilities -#include #endif diff --git a/src/framework/platform/win32window.cpp b/src/framework/platform/win32window.cpp index 970b8f86..93c6b1d9 100644 --- a/src/framework/platform/win32window.cpp +++ b/src/framework/platform/win32window.cpp @@ -948,7 +948,7 @@ std::string WIN32Window::getClipboardText() if(hglb) { LPTSTR lptstr = (LPTSTR)GlobalLock(hglb); if(lptstr) { - text = stdext::utf8StringToLatin1((uchar*)lptstr); + text = stdext::utf8_to_latin1((uchar*)lptstr); GlobalUnlock(hglb); } } diff --git a/src/framework/platform/x11window.cpp b/src/framework/platform/x11window.cpp index 546d8b80..aa978eb2 100644 --- a/src/framework/platform/x11window.cpp +++ b/src/framework/platform/x11window.cpp @@ -1037,7 +1037,7 @@ std::string X11Window::getClipboardText() // hack to wait SelectioNotify event, otherwise we will get wrong clipboard pastes // TODO: fix this in a correct way - usleep(100 * 1000); + stdext::millisleep(100); // check for data Atom type; @@ -1052,7 +1052,7 @@ std::string X11Window::getClipboardText() &bytesLeft, &data); if(len > 0) { - clipboardText = stdext::utf8StringToLatin1(data); + clipboardText = stdext::utf8_to_latin1(data); } } diff --git a/src/framework/sound/declarations.h b/src/framework/sound/declarations.h index f91cb2dd..251d7790 100644 --- a/src/framework/sound/declarations.h +++ b/src/framework/sound/declarations.h @@ -38,11 +38,11 @@ class StreamSoundSource; class CombinedSoundSource; class OggSoundFile; -typedef boost::intrusive_ptr SoundSourcePtr; -typedef boost::intrusive_ptr SoundFilePtr; -typedef boost::intrusive_ptr SoundBufferPtr; -typedef boost::intrusive_ptr StreamSoundSourcePtr; -typedef boost::intrusive_ptr CombinedSoundSourcePtr; -typedef boost::intrusive_ptr OggSoundFilePtr; +typedef stdext::shared_object_ptr SoundSourcePtr; +typedef stdext::shared_object_ptr SoundFilePtr; +typedef stdext::shared_object_ptr SoundBufferPtr; +typedef stdext::shared_object_ptr StreamSoundSourcePtr; +typedef stdext::shared_object_ptr CombinedSoundSourcePtr; +typedef stdext::shared_object_ptr OggSoundFilePtr; #endif diff --git a/src/framework/stdext/any.h b/src/framework/stdext/any.h new file mode 100644 index 00000000..47f979b7 --- /dev/null +++ b/src/framework/stdext/any.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2010-2012 OTClient + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef STDEXT_ANY_H +#define STDEXT_ANY_H + +#include +#include +#include + +namespace stdext { + +class any { +public: + struct placeholder { + virtual ~placeholder() { } + virtual const std::type_info& type() const = 0; + virtual placeholder* clone() const = 0; + }; + + template + struct holder : public placeholder { + holder(const T& value) : held(value) { } + const std::type_info& type() const { return typeid(T); } + placeholder* clone() const { return new holder(held); } + T held; + private: + holder& operator=(const holder &); + }; + + placeholder* content; + + any() : content(nullptr) { } + any(const any& other) : content(other.content ? other.content->clone() : nullptr) { } + template any(const T& value) : content(new holder(value)) { } + ~any() { if(content) delete content; } + + any& swap(any& rhs) { std::swap(content, rhs.content); return *this; } + + template any& operator=(const T& rhs) { any(rhs).swap(*this); return *this; } + any& operator=(any rhs) { rhs.swap(*this); return *this; } + + bool empty() const { return !content; } + template const T& cast() const; + const std::type_info & type() const { return content ? content->type() : typeid(void); } +}; + +template +const T& any_cast(const any& operand) { + assert(operand.type() == typeid(T)); + return static_cast*>(operand.content)->held; +} + +template const T& any::cast() const { return any_cast(*this); } + +} + +#endif diff --git a/src/framework/stdext/cast.h b/src/framework/stdext/cast.h index 2126af22..26337d76 100644 --- a/src/framework/stdext/cast.h +++ b/src/framework/stdext/cast.h @@ -23,15 +23,13 @@ #ifndef STDEXT_CAST_H #define STDEXT_CAST_H -namespace stdext { -template R safe_cast(const T& t); -template R unsafe_cast(const T& t, R def = R()); -} - -#include "string.h" #include "exception.h" #include "demangle.h" +#include +#include +#include + namespace stdext { // cast a type to another type @@ -142,7 +140,9 @@ public: virtual ~cast_exception() throw() { } template void update_what() { - m_what = format("failed to cast value of type '%s' to type '%s'", demangle_type(), demangle_type()); + std::stringstream ss; + ss << "failed to cast value of type '" << demangle_type() << "' to type '" << demangle_type() << "'"; + m_what = ss.str(); } virtual const char* what() const throw() { return m_what.c_str(); } private: @@ -163,14 +163,15 @@ R safe_cast(const T& t) { // cast a type to another type, cast errors are ignored template -R unsafe_cast(const T& t, R def) { +R unsafe_cast(const T& t, R def = R()) { try { return safe_cast(t); } catch(cast_exception& e) { - std::cout << "CAST ERROR: " << e.what() << std::endl; + std::cerr << "CAST ERROR: " << e.what() << std::endl; return def; } } + } #endif diff --git a/src/framework/stdext/compiler.h b/src/framework/stdext/compiler.h index 061dcf7a..555bff2e 100644 --- a/src/framework/stdext/compiler.h +++ b/src/framework/stdext/compiler.h @@ -25,7 +25,6 @@ #ifdef __clang__ // clang is supported - #undef _GLIBCXX_USE_FLOAT128 #elif defined(__GNUC__) #if !(__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) #error "Sorry, you need gcc 4.6 or greater to compile." diff --git a/src/framework/stdext/demangle.cpp b/src/framework/stdext/demangle.cpp new file mode 100644 index 00000000..9ba35f21 --- /dev/null +++ b/src/framework/stdext/demangle.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2010-2012 OTClient + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "demangle.h" + +#include +#include +#include + +namespace stdext { + +const char* demangle_name(const char* name) +{ + size_t len; + int status; + static char buffer[1024]; + char* demangled = abi::__cxa_demangle(name, 0, &len, &status); + if(demangled) { + strcpy(buffer, demangled); + free(demangled); + } + return buffer; +} + +} diff --git a/src/framework/stdext/demangle.h b/src/framework/stdext/demangle.h index 01fcf872..b834ef53 100644 --- a/src/framework/stdext/demangle.h +++ b/src/framework/stdext/demangle.h @@ -23,29 +23,16 @@ #ifndef STDEXT_DEMANGLE_H #define STDEXT_DEMANGLE_H -#include +#include #include namespace stdext { /// Demangle names for GNU g++ compiler -inline std::string demangle_name(const char* name) { - size_t len; - int status; - std::string ret; - char* demangled = abi::__cxa_demangle(name, 0, &len, &status); - if(demangled) { - ret = demangled; - free(demangled); - } - return ret; -} +const char* demangle_name(const char* name); /// Returns the name of a type -template -std::string demangle_type() { - return demangle_name(typeid(T).name()); -} +template std::string demangle_type() { return demangle_name(typeid(T).name()); } } diff --git a/src/framework/stdext/dumper.h b/src/framework/stdext/dumper.h index a0147d3f..3a5bb957 100644 --- a/src/framework/stdext/dumper.h +++ b/src/framework/stdext/dumper.h @@ -27,30 +27,13 @@ namespace stdext { -namespace dumper { - -struct dumper_dummy { - ~dumper_dummy() { std::cout << std::endl; } - template - dumper_dummy& operator<<(const T& v) { - std::cout << v << " "; - return *this; - } -}; - -struct dumper_util { - dumper_util() { } - template - dumper_dummy operator<<(const T& v) const { - dumper_dummy d; - d << v; - return d; - } -}; - -} - -const static dumper::dumper_util dump; +static struct { + struct dumper_dummy { + ~dumper_dummy() { std::cout << std::endl; } + template dumper_dummy& operator<<(const T& v) { std::cout << v << " "; return *this; } + }; + template dumper_dummy operator<<(const T& v) const { dumper_dummy d; d << v; return d; } +} dump; } diff --git a/src/framework/stdext/dynamic_storage.h b/src/framework/stdext/dynamic_storage.h new file mode 100644 index 00000000..9d8f230e --- /dev/null +++ b/src/framework/stdext/dynamic_storage.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2010-2012 OTClient + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef STDEXT_DYNAMICSTORAGE_H +#define STDEXT_DYNAMICSTORAGE_H + +#include "types.h" +#include "any.h" +#include + +namespace stdext { + +template +class dynamic_storage { +public: + template void set(const Key& k, const T& value) { m_map[k] = value; } + template T get(const Key& k) const { + auto it = m_map.find(k); + if(it != m_map.end()) + return any_cast(it->second); + return T(); + } + bool has(const Key& k) const { return m_map.find(k) != m_map.end(); } + + std::size_t size() const { return m_map.size(); } + void clear() { m_map.clear(); } + +private: + std::unordered_map m_map; +}; + +} + +#endif diff --git a/src/framework/stdext/exception.h b/src/framework/stdext/exception.h index cc795aa9..e717884a 100644 --- a/src/framework/stdext/exception.h +++ b/src/framework/stdext/exception.h @@ -34,9 +34,7 @@ public: exception() { } exception(const std::string& what) : m_what(what) { } virtual ~exception() throw() { }; - virtual const char* what() const throw() { return m_what.c_str(); } - protected: std::string m_what; }; diff --git a/src/framework/stdext/format.h b/src/framework/stdext/format.h new file mode 100644 index 00000000..2b47464a --- /dev/null +++ b/src/framework/stdext/format.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2010-2012 OTClient + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef STDEXT_FORMAT_H +#define STDEXT_FORMAT_H + +#include "traits.h" + +#include +#include +#include +#include +#include +#include +#include + +namespace stdext { + +template void print_ostream(std::ostringstream& stream, const T& last) { stream << last; } +template +void print_ostream(std::ostringstream& stream, const T& first, const Args&... rest) { stream << "\t" << first; print_ostream(stream, rest...); } +template + +/// Utility for printing variables just like lua +void print(const T&... args) { std::ostringstream buf; print_ostream(buf, args...); std::cout << buf.str() << std::endl; } + +template +typename std::enable_if::value || + std::is_pointer::value || + std::is_floating_point::value || + std::is_enum::value, T>::type sprintf_cast(const T& t) { return t; } +inline const char *sprintf_cast(const std::string& s) { return s.c_str(); } + +template struct expand_snprintf { + template static int call(char *s, size_t maxlen, const char *format, const Tuple& tuple, const Args&... args) { + return expand_snprintf::call(s, maxlen, format, tuple, sprintf_cast(std::get(tuple)), args...); }}; +template<> struct expand_snprintf<0> { + template static int call(char *s, size_t maxlen, const char *format, const Tuple& tuple, const Args&... args) { + return snprintf(s, maxlen, format, args...); }}; + +/// Improved snprintf that accepts std::string and other types +template +int snprintf(char *s, size_t maxlen, const char *format, const Args&... args) { + std::tuple::type...> tuple(args...); + return expand_snprintf::value>::call(s, maxlen, format, tuple); +} + +/// Format strings with the sprintf style, accepting std::string and string convertible types for %s +template +std::string format(const std::string& format, const Args&... args) { + int n, size = 1024; + std::string str; + while(true) { + str.resize(size); + n = snprintf(&str[0], size, format.c_str(), args...); + assert(n != -1); + if(n < size) { + str.resize(n); + return str; + } + size *= 2; + } +} + +} + +#endif diff --git a/src/framework/stdext/math.cpp b/src/framework/stdext/math.cpp new file mode 100644 index 00000000..ad92e556 --- /dev/null +++ b/src/framework/stdext/math.cpp @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2010-2012 OTClient + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "math.h" +#include + +namespace stdext { + +uint32_t adler32(const uint8_t *buffer, size_t size) { + register size_t a = 1, b = 0, tlen; + while(size > 0) { + tlen = size > 5552 ? 5552 : size; + size -= tlen; + do { + a += *buffer++; + b += a; + } while (--tlen); + + a %= 65521; + b %= 65521; + } + return (b << 16) | a; +} + +long random_range(long min, long max) +{ + static std::random_device rd; + static std::mt19937 gen(rd()); + static std::uniform_int_distribution dis(0, 2147483647); + return min + (dis(gen) % (max - min + 1)); +} + +float random_range(float min, float max) +{ + static std::random_device rd; + static std::mt19937 gen(rd()); + static std::uniform_real_distribution dis(0.0, 1.0); + return min + (max - min)*dis(gen); +} + +} \ No newline at end of file diff --git a/src/framework/stdext/math.h b/src/framework/stdext/math.h index 86370c53..c5bbeecf 100644 --- a/src/framework/stdext/math.h +++ b/src/framework/stdext/math.h @@ -24,65 +24,24 @@ #define STDEXT_MATH_H #include "types.h" -#include namespace stdext { -inline uint32 adler32(const uint8 *buffer, uint16 size) { - register uint32 a = 1, b = 0, tlen; - while(size > 0) { - tlen = size > 5552 ? 5552 : size; - size -= tlen; - do { - a += *buffer++; - b += a; - } while (--tlen); +inline bool is_power_of_two(size_t v) { return ((v != 0) && !(v & (v - 1))); } +inline size_t to_power_of_two(size_t v) { if(v == 0) return 0; size_t r = 1; while(r < v && r != 0xffffffff) r <<= 1; return r; } - a %= 65521; - b %= 65521; - } - return (b << 16) | a; -} - -inline bool is_power_of_two(uint32 v) { - return ((v != 0) && !(v & (v - 1))); -} - -inline uint32 to_power_of_two(uint32 v) { - if(v == 0) - return 0; - uint32 r = 1; - while(r < v && r != 0xffffffff) - r <<= 1; - return r; -} +inline uint16_t readLE16(const uchar *addr) { return (uint16_t)addr[1] << 8 | addr[0]; } +inline uint32_t readLE32(const uchar *addr) { return (uint32_t)readLE16(addr + 2) << 16 | readLE16(addr); } +inline uint64_t readLE64(const uchar *addr) { return (uint64_t)readLE32(addr + 4) << 32 | readLE32(addr); } -inline uint16 readLE16(const uchar *addr) { return (uint16)addr[1] << 8 | addr[0]; } -inline uint32 readLE32(const uchar *addr) { return (uint32)readLE16(addr + 2) << 16 | readLE16(addr); } -inline uint64 readLE64(const uchar *addr) { return (uint64)readLE32(addr + 4) << 32 | readLE32(addr); } +inline void writeLE16(uchar *addr, uint16_t value) { addr[1] = value >> 8; addr[0] = (uint8_t)value; } +inline void writeLE32(uchar *addr, uint32_t value) { writeLE16(addr + 2, value >> 16); writeLE16(addr, (uint16_t)value); } +inline void writeLE64(uchar *addr, uint64_t value) { writeLE32(addr + 4, value >> 32); writeLE32(addr, (uint32_t)value); } -inline void writeLE16(uchar *addr, uint16 value) { addr[1] = value >> 8; addr[0] = (uint8)value; } -inline void writeLE32(uchar *addr, uint32 value) { writeLE16(addr + 2, value >> 16); writeLE16(addr, (uint16)value); } -inline void writeLE64(uchar *addr, uint64 value) { writeLE32(addr + 4, value >> 32); writeLE32(addr, (uint32)value); } +uint32_t adler32(const uint8_t *buffer, size_t size); -template -T random_range(T min, T max); - -template<> -inline int random_range(int min, int max) { - static std::random_device rd; - static std::mt19937 gen(rd()); - static std::uniform_int_distribution dis(0, 2147483647); - return min + (dis(gen) % (max - min + 1)); -} - -template<> -inline float random_range(float min, float max) { - static std::random_device rd; - static std::mt19937 gen(rd()); - static std::uniform_real_distribution dis(0.0, 1.0); - return min + (max - min)*dis(gen); -} +long random_range(long min, long max); +float random_range(float min, float max); } diff --git a/src/framework/stdext/packed_any.h b/src/framework/stdext/packed_any.h new file mode 100644 index 00000000..02ca7ace --- /dev/null +++ b/src/framework/stdext/packed_any.h @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2010-2012 OTClient + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef STDEXT_PACKEDANY_H +#define STDEXT_PACKEDANY_H + +#include +#include +#include +#include + +namespace stdext { + +// disable memory alignment +#pragma pack(push,1) + +template +struct can_pack_in_any : std::integral_constant::value)> {}; + +// improved to use less memory +class packed_any { +public: + struct placeholder { + virtual ~placeholder() { } + virtual const std::type_info& type() const = 0; + virtual placeholder* clone() const = 0; + }; + + template + struct holder : public placeholder { + holder(const T& value) : held(value) { } + const std::type_info& type() const { return typeid(T); } + placeholder* clone() const { return new holder(held); } + T held; + private: + holder& operator=(const holder &); + }; + + placeholder* content; + bool scalar; + + packed_any() : + content(nullptr), scalar(false) { } + packed_any(const packed_any& other) : + content(!other.scalar && other.content ? other.content->clone() : other.content), + scalar(other.scalar) { } + template + packed_any(const T& value, typename std::enable_if<(can_pack_in_any::value)>::type* = nullptr) : + content(reinterpret_cast(static_cast(value))), scalar(true) { } + template + packed_any(const T& value, typename std::enable_if::value)>::type* = nullptr) : + content(new holder(value)), scalar(false) { } + ~packed_any() + { if(!scalar && content) delete content; } + + packed_any& swap(packed_any& rhs) { std::swap(content, rhs.content); std::swap(scalar, rhs.scalar); return *this; } + + template packed_any& operator=(const T& rhs) { packed_any(rhs).swap(*this); return *this; } + packed_any& operator=(packed_any rhs) { rhs.swap(*this); return *this; } + + bool empty() const { return !scalar && !content; } + template T cast() const; + const std::type_info& type() const { + if(scalar) + return content ? content->type() : typeid(void); + else + return typeid(std::size_t); + } +}; + +template +T packed_any_cast(const packed_any& operand) { + if(operand.scalar) { + union { + T v; + packed_any::placeholder* content; + }; + content = operand.content; + return v; + } else { + assert(operand.type() == typeid(T)); + return static_cast*>(operand.content)->held; + } +} + +template T packed_any::cast() const { return packed_any_cast(*this); } + +// restore memory alignment +#pragma pack(pop) + +} + +#endif diff --git a/src/framework/stdext/attrib_storage.h b/src/framework/stdext/packed_storage.h similarity index 55% rename from src/framework/stdext/attrib_storage.h rename to src/framework/stdext/packed_storage.h index d203573c..840ca2ee 100644 --- a/src/framework/stdext/attrib_storage.h +++ b/src/framework/stdext/packed_storage.h @@ -20,63 +20,73 @@ * THE SOFTWARE. */ -#ifndef STDEXT_ATTRIBSTORAGE_H -#define STDEXT_ATTRIBSTORAGE_H +#ifndef STDEXT_PACKEDSTORAGE_H +#define STDEXT_PACKEDSTORAGE_H #include "types.h" -#include -#include +#include "packed_any.h" + +namespace stdext { // disable memory alignment #pragma pack(push,1) // this class was designed to use less memory as possible -namespace stdext { -class attrib_storage { +template +class packed_storage { + struct value_pair { + Key id; + packed_any value; + }; + public: - attrib_storage() : m_attribs(nullptr), m_size(0) { } - ~attrib_storage() { if(m_attribs) delete[] m_attribs; } + packed_storage() : m_values(nullptr), m_size(0) { } + ~packed_storage() { if(m_values) delete[] m_values; } template - void set(uint8 id, T value) { - bool done = false; - for(int i=0;i(m_attribs[i]) == id) { - std::get<1>(m_attribs[i]) = value; - done = true; - break; + void set(Key id, T value) { + for(SizeType i=0;i[m_size+1]; - if(m_size > 0) { - for(int i=0;i 0) { + std::copy(m_values, m_values + m_size, tmp); + delete[] m_values; } + m_values = tmp; + m_values[m_size++] = { id, packed_any(value) }; } template - T get(uint8 id) const { - for(int i=0;i(m_attribs[i]) == id) - return boost::any_cast(std::get<1>(m_attribs[i])); + T get(Key id) const { + for(SizeType i=0;i(m_values[i].value); return T(); } - bool has(uint8 id) const { - for(int i=0;i(m_attribs[i]) == id) + bool has(Key id) const { + for(SizeType i=0;i* m_attribs; - uint8 m_size; + value_pair *m_values; + SizeType m_size; }; // restore memory alignment diff --git a/src/framework/stdext/packed_vector.h b/src/framework/stdext/packed_vector.h new file mode 100644 index 00000000..6ac1a0fd --- /dev/null +++ b/src/framework/stdext/packed_vector.h @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2010-2012 OTClient + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef STDEXT_PACKEDVECTOR_H +#define STDEXT_PACKEDVECTOR_H + +#include + +namespace stdext { + +// disable memory alignment +#pragma pack(push,1) + +template +class packed_vector +{ +public: + typedef U size_type; + typedef T* iterator; + typedef const T* const_iterator; + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; + + packed_vector() : m_size(0), m_data(nullptr) { } + packed_vector(size_type size) : m_size(size), m_data(new T[size]) { } + packed_vector(size_type size, const T& value) : m_size(size), m_data(new T[size](value)) { } + template + packed_vector(InputIterator first, InputIterator last) : m_size(last - first), m_data(new T[m_size]) { std::copy(first, last, m_data); } + packed_vector(const packed_vector& other) : m_size(other.m_size), m_data(new T[other.m_size]) { std::copy(other.begin(), other.end(), m_data); } + ~packed_vector() { if(m_data) delete[] m_data; } + + packed_vector& operator=(packed_vector other) { other.swap(*this); return *this; } + + iterator begin() { return m_data; } + const_iterator begin() const { return m_data; } + const_iterator cbegin() const { return m_data; } + iterator end() { return m_data + m_size; } + const_iterator end() const { return m_data + m_size; } + const_iterator cend() const { return m_data + m_size; } + + reverse_iterator rbegin() { return reverse_iterator(end()); } + const_reverse_iterator rbegin() const { return reverse_iterator(end()); } + const_reverse_iterator crbegin() const { return const_reverse_iterator(end()); } + reverse_iterator rend() { return reverse_iterator(begin()); } + const_reverse_iterator rend() const { return reverse_iterator(begin()); } + const_reverse_iterator crend() const { return const_reverse_iterator(begin()); } + + size_type size() const { return m_size; } + bool empty() const { return m_size == 0; } + + T& operator[](size_type i) { return m_data[i]; } + const T& operator[](size_type i) const { return m_data[i]; } + T& at(size_type i) { return m_data[i]; } + const T& at(size_type i) const { return m_data[i]; } + + T& front() { return m_data[0]; } + const T& front() const { return m_data[0]; } + T& back() { return m_data[m_size-1]; } + const T& back() const { return m_data[m_size-1]; } + + T *data() { return m_data; } + const T *data() const { return m_data; } + + void clear() { + if(m_data) { + delete[] m_data; + m_data = nullptr; + } + m_size = 0; + } + + void resize(size_type size) { + clear(); + if(size > 0) { + m_data = new T[size]; + m_size = size; + } + } + + void push_back(const T& x) { + T *tmp = new T[m_size+1]; + std::copy(m_data, m_data + m_size, tmp); + tmp[m_size] = x; + delete[] m_data; + m_data = tmp; + m_size++; + } + + void pop_back() { + T *tmp = new T[m_size-1]; + std::copy(m_data, m_data + m_size - 1, tmp); + delete[] m_data; + m_data = tmp; + m_size--; + } + + iterator insert(const_iterator position, const T& x) { + T *tmp = new T[m_size+1]; + size_type i = position - m_data; + std::copy(m_data, m_data + i, tmp); + tmp[i] = x; + std::copy(m_data + i, m_data + m_size, tmp + i + 1); + delete[] m_data; + m_data = tmp; + m_size++; + return tmp + i; + } + + iterator erase(const_iterator position) { + T *tmp = new T[m_size-1]; + size_type i = position - m_data; + std::copy(m_data, m_data + i, tmp); + std::copy(m_data + i + 1, m_data + m_size, tmp + i); + delete[] m_data; + m_data = tmp; + m_size--; + return tmp + i; + } + + void swap(packed_vector& other) { std::swap(m_size, other.m_size); std::swap(m_data, other.m_data); return *this; } + + operator std::vector() const { return std::vector(begin(), end()); } + +private: + size_type m_size; + T* m_data; +}; + +// restore memory alignment +#pragma pack(pop) + +namespace std { +template void swap(stdext::packed_vector& lhs, stdext::packed_vector& rhs) { lhs.swap(rhs); } +} + +} + +#endif diff --git a/src/framework/stdext/shared_object.h b/src/framework/stdext/shared_object.h index a18c0857..730f966a 100644 --- a/src/framework/stdext/shared_object.h +++ b/src/framework/stdext/shared_object.h @@ -23,55 +23,107 @@ #ifndef STDEXT_SHARED_OBJECT_H #define STDEXT_SHARED_OBJECT_H -#include -#include +#include +#include +#include +#include namespace stdext { +template +class shared_object_ptr; + +typedef unsigned int refcount_t; + class shared_object { public: shared_object() : m_refs(0) { } virtual ~shared_object() { } void add_ref() { ++m_refs; assert(m_refs != 0xffffffff); } - void dec_ref() { - if(--m_refs == 0) - boost::checked_delete(this); - } - bool is_unique_ref() { return m_refs == 1; } - unsigned long ref_count() { return m_refs; } - template - boost::intrusive_ptr self_cast() { return boost::intrusive_ptr(static_cast(this)); } - template - boost::intrusive_ptr dynamic_self_cast() { return boost::intrusive_ptr(dynamic_cast(this)); } + void dec_ref() { if(--m_refs == 0) delete this; } + refcount_t ref_count() { return m_refs; } + + template stdext::shared_object_ptr static_self_cast() { return stdext::shared_object_ptr(static_cast(this)); } + template stdext::shared_object_ptr dynamic_self_cast() { return stdext::shared_object_ptr(dynamic_cast(this)); } + template stdext::shared_object_ptr const_self_cast() { return stdext::shared_object_ptr(const_cast(this)); } private: - unsigned int m_refs; + refcount_t m_refs; }; -template -boost::intrusive_ptr make_shared_object(Args... args) { return boost::intrusive_ptr(new T(args...)); } +template +class shared_object_ptr +{ +public: + typedef T element_type; -} + shared_object_ptr(): px(nullptr) { } + shared_object_ptr(T* p, bool add_ref = true) : px(p) { if(px != nullptr && add_ref) this->add_ref(); } + shared_object_ptr(shared_object_ptr const& rhs): px(rhs.px) { if(px != nullptr) add_ref(); } + template + shared_object_ptr(shared_object_ptr const& rhs, typename std::is_convertible::type* = nullptr) : px(rhs.get()) { if(px != nullptr) add_ref(); } + ~shared_object_ptr() { if(px != nullptr) dec_ref(); } -namespace std { -template -struct hash> : public __hash_base> { - size_t operator()(const boost::intrusive_ptr& p) const noexcept { return std::hash()(p.get()); } -}; -} + void reset() { shared_object_ptr().swap(*this); } + void reset(T* rhs) { shared_object_ptr( rhs ).swap(*this); } + void swap(shared_object_ptr& rhs) { std::swap(px, rhs.px); } + T* get() const { return px; } + + refcount_t use_count() const { return ((shared_object*)px)->ref_count(); } + bool is_unique() const { return use_count() == 1; } + + template shared_object_ptr& operator=(shared_object_ptr const& rhs) { shared_object_ptr(rhs).swap(*this); return *this; } + + T& operator*() const { assert(px != nullptr); return *px; } + T* operator->() const { assert(px != nullptr); return px; } + + shared_object_ptr& operator=(shared_object_ptr const& rhs) { shared_object_ptr(rhs).swap(*this); return *this; } + shared_object_ptr& operator=(T* rhs) { shared_object_ptr(rhs).swap(*this); return *this; } -template -struct remove_const_ref { - typedef typename std::remove_const::type>::type type; + // implicit conversion to bool + typedef T* shared_object_ptr::*unspecified_bool_type; + operator unspecified_bool_type() const { return px == nullptr ? nullptr : &shared_object_ptr::px; } + bool operator!() const { return px == nullptr; } + + // std::move support + shared_object_ptr(shared_object_ptr&& rhs): px(rhs.px) { rhs.px = nullptr; } + shared_object_ptr& operator=(shared_object_ptr&& rhs) { shared_object_ptr(static_cast(rhs)).swap(*this); return *this; } + +private: + void add_ref() { ((shared_object*)px)->add_ref(); } + void dec_ref() { ((shared_object*)px)->dec_ref(); } + + T* px; }; -template -void intrusive_ptr_add_ref(T* p) { (static_cast(p))->add_ref(); } +template bool operator==(shared_object_ptr const& a, shared_object_ptr const& b) { return a.get() == b.get(); } +template bool operator!=(shared_object_ptr const& a, shared_object_ptr const& b) { return a.get() != b.get(); } +template bool operator==(shared_object_ptr const& a, U* b) { return a.get() == b; } +template bool operator!=(shared_object_ptr const& a, U* b) { return a.get() != b; } +template bool operator==(T * a, shared_object_ptr const& b) { return a == b.get(); } +template bool operator!=(T * a, shared_object_ptr const& b) { return a != b.get(); } +template bool operator<(shared_object_ptr const& a, shared_object_ptr const& b) { return std::less()(a.get(), b.get()); } -template -void intrusive_ptr_release(T* p) { (static_cast(p))->dec_ref(); } +template T* get_pointer(shared_object_ptr const& p) { return p.get(); } +template shared_object_ptr static_pointer_cast(shared_object_ptr const& p) { return static_cast(p.get()); } +template shared_object_ptr const_pointer_cast(shared_object_ptr const& p) { return const_cast(p.get()); } +template shared_object_ptr dynamic_pointer_cast(shared_object_ptr const& p) { return dynamic_cast(p.get()); } +template stdext::shared_object_ptr make_shared_object(Args... args) { return stdext::shared_object_ptr(new T(args...)); } -#endif +// operator<< support +template std::basic_ostream& operator<<(std::basic_ostream& os, shared_object_ptr const& p) { os << p.get(); return os; } +} +namespace std { + +// hash, for unordered_map support +template struct hash> { size_t operator()(const stdext::shared_object_ptr& p) const { return std::hash()(p.get()); } }; + +// swap support +template void swap(stdext::shared_object_ptr& lhs, stdext::shared_object_ptr& rhs) { lhs.swap(rhs); } + +} + +#endif diff --git a/src/framework/stdext/stdext.h b/src/framework/stdext/stdext.h index 87e02fc6..01213698 100644 --- a/src/framework/stdext/stdext.h +++ b/src/framework/stdext/stdext.h @@ -24,16 +24,21 @@ #define STDEXT_H #include "compiler.h" +#include "dumper.h" #include "types.h" #include "exception.h" #include "demangle.h" #include "cast.h" #include "math.h" #include "string.h" -#include "dumper.h" #include "time.h" -#include "shared_object.h" -#include "attrib_storage.h" #include "boolean.h" +#include "shared_object.h" +#include "any.h" +#include "packed_any.h" +#include "dynamic_storage.h" +#include "packed_storage.h" +#include "format.h" +#include "packed_vector.h" #endif diff --git a/src/framework/stdext/string.cpp b/src/framework/stdext/string.cpp new file mode 100644 index 00000000..eccb32e0 --- /dev/null +++ b/src/framework/stdext/string.cpp @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2010-2012 OTClient + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "string.h" +#include "format.h" +#include + +namespace stdext { + +std::string resolve_path(const std::string& filePath, std::string sourcePath) +{ + if(stdext::starts_with(filePath, "/")) + return filePath; + if(!stdext::ends_with(sourcePath, "/")) { + std::size_t slashPos = sourcePath.find_last_of("/"); + if(slashPos == std::string::npos) + throw_exception(format("invalid source path '%s', for file '%s'", sourcePath, filePath)); + sourcePath = sourcePath.substr(0, slashPos + 1); + } + return sourcePath + filePath; +} + +std::string date_time_string() +{ + char date[32]; + std::time_t tnow; + std::time(&tnow); + std::tm *ts = std::localtime(&tnow); + std::strftime(date, 32, "%b %d %Y %H:%M:%S", ts); + return std::string(date); +} + +std::string dec_to_hex(uint64_t num) +{ + std::string str; + std::ostringstream o; + o << std::hex << num; + str = o.str(); + return str; +} + +uint64_t hex_to_dec(const std::string& str) +{ + uint64_t num; + std::istringstream i(str); + i >> std::hex >> num; + return num; +} + +std::string ip_to_string(uint32_t ip) +{ + char host[16]; + sprintf(host, "%d.%d.%d.%d", (uint8_t)ip, (uint8_t)(ip >> 8), (uint8_t)(ip >> 16), (uint8_t)(ip >> 24)); + return std::string(host); +} + +std::string utf8_to_latin1(uchar *utf8) +{ + auto utf8CharToLatin1 = [](uchar *utf8, int *read) -> char { + char c = '?'; + uchar opt1 = utf8[0]; + *read = 1; + if(opt1 == 0xc3) { + *read = 2; + uchar opt2 = utf8[1]; + c = 64 + opt2; + } else if(opt1 == 0xc2) { + *read = 2; + uchar opt2 = utf8[1]; + if(opt2 > 0xa1 && opt2 < 0xbb) + c = opt2; + } else if(opt1 < 0xc2) { + c = opt1; + } + return c; + }; + + std::string out; + int len = strlen((char*)utf8); + for(int i=0; i split(const std::string& str, const std::string& separators) +{ + std::vector splitted; + boost::split(splitted, str, boost::is_any_of(std::string(separators))); + return splitted; +} + +} \ No newline at end of file diff --git a/src/framework/stdext/string.h b/src/framework/stdext/string.h index bac7b72d..eb6ab4f7 100644 --- a/src/framework/stdext/string.h +++ b/src/framework/stdext/string.h @@ -25,234 +25,41 @@ #include #include -#include -#include -#include #include -#include #include "types.h" #include "cast.h" -#include "exception.h" namespace stdext { -/// Convert any type to std::string -template -std::string to_string(const T& t) { return unsafe_cast(t); } +template std::string to_string(const T& t) { return unsafe_cast(t); } +template T from_string(const std::string& str, T def = T()) { return unsafe_cast(str, def); } -/// Convert any type from std::string -template -T from_string(const std::string& str, T def = T()) { return unsafe_cast(str, def); } - -/// Cast non-class types like int, char, float, double and pointers -template -typename std::enable_if::value || - std::is_pointer::value || - std::is_floating_point::value || - std::is_enum::value, T>::type sprintf_cast(const T& t) { return t; } - -/// Cast std::string -inline const char *sprintf_cast(const std::string& s) { return s.c_str(); } - -template -struct expand_snprintf{ - template - static int call(char *s, size_t maxlen, const char *format, const Tuple& tuple, const Args&... args) { - return expand_snprintf::call(s, maxlen, format, tuple, sprintf_cast(std::get(tuple)), args...); - } -}; -template<> -struct expand_snprintf<0> { - template - static int call(char *s, size_t maxlen, const char *format, const Tuple& tuple, const Args&... args) { - return snprintf(s, maxlen, format, args...); - } -}; - -template -struct replace_extent { typedef T type; }; - -template -struct replace_extent { typedef const T* type; }; - -template -struct replace_extent { typedef const T* type;}; - -/// Improved sprintf that accepts std::string and other types -template -int snprintf(char *s, size_t maxlen, const char *format, const Args&... args) { - typedef typename std::tuple::type...> Tuple; - enum { N = std::tuple_size::value }; - Tuple tuple(args...); - return expand_snprintf::call(s, maxlen, format, tuple); -} - -/// Format strings with the sprintf style, accepting std::string and string convertible types for %s -template -std::string format(const std::string& format, const Args&... args) { - int n, size = 1024; - std::string str; - while(true) { - str.resize(size); - n = snprintf(&str[0], size, format.c_str(), args...); - assert(n != -1); - if(n < size) { - str.resize(n); - return str; - } - size *= 2; - } -} - -inline void fill_ostream(std::ostringstream&) { } - -/// Fills an ostream by concatenating args -template -void fill_ostream(std::ostringstream& stream, const T& first, const Args&... rest) { - stream << first; - fill_ostream(stream, rest...); -} - -/// Makes a std::string by concatenating args -template -std::string mkstr(const T&... args) { - std::ostringstream buf; - fill_ostream(buf, args...); - return buf.str(); -} - -/// Easy of use split -template -std::vector split(const std::string& str, const std::string& separators = " ") { - std::vector splitted; - boost::split(splitted, str, boost::is_any_of(std::string(separators))); +/// Resolve a file path by combining sourcePath with filePath +std::string resolve_path(const std::string& filePath, std::string sourcePath); +/// Get current date and time in a std::string +std::string date_time_string(); + +std::string dec_to_hex(uint64_t num); +uint64_t hex_to_dec(const std::string& str); +std::string ip_to_string(uint32_t ip); +std::string utf8_to_latin1(uchar *utf8); +void tolower(std::string& str); +void toupper(std::string& str); +void trim(std::string& str); +bool ends_with(const std::string& str, const std::string& test); +bool starts_with(const std::string& str, const std::string& test); +void replace_all(std::string& str, const std::string& search, const std::string& replacement); + +std::vector split(const std::string& str, const std::string& separators = " "); +template std::vector split(const std::string& str, const std::string& separators = " ") { + std::vector splitted = split(str, separators); std::vector results(splitted.size()); for(uint i=0;i(splitted[i]); return results; } -/// Resolve a file path by combining sourcePath with filePath -inline std::string resolve_path(const std::string& filePath, std::string sourcePath) { - if(boost::starts_with(filePath, "/")) - return filePath; - if(!boost::ends_with(sourcePath, "/")) { - std::size_t slashPos = sourcePath.find_last_of("/"); - if(slashPos == std::string::npos) - throw_exception(format("invalid source path '%s', for file '%s'", sourcePath, filePath)); - sourcePath = sourcePath.substr(0, slashPos + 1); - } - return sourcePath + filePath; -} - -/// Get current date and time in a std::string -inline std::string date_time_string() { - char date[32]; - std::time_t tnow; - std::time(&tnow); - std::tm *ts = std::localtime(&tnow); - std::strftime(date, 32, "%b %d %Y %H:%M:%S", ts); - return std::string(date); -} - -/// Convert decimal to hexadecimal -inline std::string dec_to_hex(uint64 num) { - std::string str; - std::ostringstream o; - o << std::hex << num; - str = o.str(); - return str; -} - -/// Convert hexadecimal to decimal -inline uint64 hex_to_dec(const std::string& str) { - uint64 num; - std::istringstream i(str); - i >> std::hex >> num; - return num; -} - -/// Convert ip to string -inline std::string ip_to_string(uint32 ip) { - char host[16]; - sprintf(host, "%d.%d.%d.%d", (uint8)ip, (uint8)(ip >> 8), (uint8)(ip >> 16), (uint8)(ip >> 24)); - return std::string(host); -} - -/// Convert utf8 characters to latin1 -inline char utf8CharToLatin1(uchar *utf8, int *read) { - char c = '?'; - uchar opt1 = utf8[0]; - *read = 1; - if(opt1 == 0xc3) { - *read = 2; - uchar opt2 = utf8[1]; - c = 64 + opt2; - } else if(opt1 == 0xc2) { - *read = 2; - uchar opt2 = utf8[1]; - if(opt2 > 0xa1 && opt2 < 0xbb) - c = opt2; - } else if(opt1 < 0xc2) { - c = opt1; - } - return c; -} - -/// Convert utf8 strings to latin1 -inline std::string utf8StringToLatin1(uchar *utf8) { - std::string out; - int len = strlen((char*)utf8); - for(int i=0; i -void print(const T&... args) { - std::ostringstream buf; - fill_ostream(buf, args...); - std::cout << buf.str(); -} - -template -void println(const T&... args) { - print(args...); - std::cout << std::endl; -} - -} - -#include "cast.h" - #endif diff --git a/src/framework/stdext/time.cpp b/src/framework/stdext/time.cpp new file mode 100644 index 00000000..7b72671b --- /dev/null +++ b/src/framework/stdext/time.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2010-2012 OTClient + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "time.h" +#include +#include + +namespace stdext { + +const static auto startup_time = std::chrono::high_resolution_clock::now(); + +ticks_t millis() +{ + return std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - startup_time).count(); +} +ticks_t micros() { + return std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - startup_time).count(); +} + +void millisleep(size_t ms) +{ + usleep(ms * 1000); +}; + +void microsleep(size_t us) +{ + usleep(us); +}; + +} diff --git a/src/framework/stdext/time.h b/src/framework/stdext/time.h index e647f9f5..c71e77a0 100644 --- a/src/framework/stdext/time.h +++ b/src/framework/stdext/time.h @@ -24,16 +24,13 @@ #define STDEXT_TIME_H #include "types.h" -#include -#include namespace stdext { -const static auto startup_time = std::chrono::high_resolution_clock::now(); -inline ticks_t millis() { return std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - startup_time).count(); } -inline ticks_t micros() { return std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - startup_time).count(); } -inline void millisleep(uint32 ms) { usleep(ms * 1000); }; -inline void microsleep(uint32 us) { usleep(us); }; +ticks_t millis(); +ticks_t micros(); +void millisleep(size_t ms); +void microsleep(size_t us); struct timer { public: diff --git a/src/framework/stdext/traits.h b/src/framework/stdext/traits.h new file mode 100644 index 00000000..f4685ea3 --- /dev/null +++ b/src/framework/stdext/traits.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2010-2012 OTClient + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef STDEXT_TRAITS_H +#define STDEXT_TRAITS_H + +#include + +namespace stdext { + +template struct replace_extent { typedef T type; }; +template struct replace_extent { typedef const T* type; }; +template struct replace_extent { typedef const T* type;}; +template struct remove_const_ref { typedef typename std::remove_const::type>::type type; }; + +}; + +#endif diff --git a/src/framework/stdext/types.h b/src/framework/stdext/types.h index b169cdf3..f3aa528b 100644 --- a/src/framework/stdext/types.h +++ b/src/framework/stdext/types.h @@ -23,13 +23,13 @@ #ifndef STDEXT_TYPES_H #define STDEXT_TYPES_H -#include +#include -// easy handwriting types typedef unsigned char uchar; typedef unsigned short ushort; typedef unsigned int uint; typedef unsigned long ulong; + typedef uint64_t uint64; typedef uint32_t uint32; typedef uint16_t uint16; @@ -39,19 +39,9 @@ typedef int32_t int32; typedef int16_t int16; typedef int8_t int8; -typedef unsigned char fast_uchar; -typedef unsigned long fast_ushort; -typedef unsigned long fast_uint; -typedef unsigned long fast_ulong; -typedef uint_fast64_t fast_uint64; -typedef uint_fast32_t fast_uint32; -typedef uint_fast16_t fast_uint16; -typedef uint_fast8_t fast_uint8; -typedef int_fast64_t fast_int64; -typedef int_fast32_t fast_int32; -typedef int_fast16_t fast_int16; -typedef int_fast8_t fast_int8; +typedef int64 ticks_t; -typedef int64_t ticks_t; +using std::size_t; +using std::ptrdiff_t; #endif diff --git a/src/framework/ui/declarations.h b/src/framework/ui/declarations.h index 012a853a..5fc04ef5 100644 --- a/src/framework/ui/declarations.h +++ b/src/framework/ui/declarations.h @@ -36,15 +36,15 @@ class UIGridLayout; class UIAnchorLayout; class UIParticles; -typedef boost::intrusive_ptr UIWidgetPtr; -typedef boost::intrusive_ptr UIParticlesPtr; -typedef boost::intrusive_ptr UITextEditPtr; -typedef boost::intrusive_ptr UILayoutPtr; -typedef boost::intrusive_ptr UIBoxLayoutPtr; -typedef boost::intrusive_ptr UIHorizontalLayoutPtr; -typedef boost::intrusive_ptr UIVerticalLayoutPtr; -typedef boost::intrusive_ptr UIGridLayoutPtr; -typedef boost::intrusive_ptr UIAnchorLayoutPtr; +typedef stdext::shared_object_ptr UIWidgetPtr; +typedef stdext::shared_object_ptr UIParticlesPtr; +typedef stdext::shared_object_ptr UITextEditPtr; +typedef stdext::shared_object_ptr UILayoutPtr; +typedef stdext::shared_object_ptr UIBoxLayoutPtr; +typedef stdext::shared_object_ptr UIHorizontalLayoutPtr; +typedef stdext::shared_object_ptr UIVerticalLayoutPtr; +typedef stdext::shared_object_ptr UIGridLayoutPtr; +typedef stdext::shared_object_ptr UIAnchorLayoutPtr; typedef std::deque UIWidgetList; diff --git a/src/framework/ui/uilayout.cpp b/src/framework/ui/uilayout.cpp index 3efdcd92..6f17c28e 100644 --- a/src/framework/ui/uilayout.cpp +++ b/src/framework/ui/uilayout.cpp @@ -63,7 +63,7 @@ void UILayout::updateLater() if(!getParentWidget()) return; - auto self = self_cast(); + auto self = static_self_cast(); g_dispatcher.addEvent([self] { self->m_updateScheduled = false; self->update(); diff --git a/src/framework/ui/uimanager.cpp b/src/framework/ui/uimanager.cpp index 2143f969..5ea30b18 100644 --- a/src/framework/ui/uimanager.cpp +++ b/src/framework/ui/uimanager.cpp @@ -321,8 +321,7 @@ bool UIManager::importStyle(const std::string& file) void UIManager::importStyleFromOTML(const OTMLNodePtr& styleNode) { std::string tag = styleNode->tag(); - std::vector split; - boost::split(split, tag, boost::is_any_of(std::string("<"))); + std::vector split = stdext::split(tag, "<"); if(split.size() != 2) throw OTMLException(styleNode, "not a valid style declaration"); @@ -330,8 +329,8 @@ void UIManager::importStyleFromOTML(const OTMLNodePtr& styleNode) std::string base = split[1]; bool unique = false; - boost::trim(name); - boost::trim(base); + stdext::trim(name); + stdext::trim(base); if(name[0] == '#') { name = name.substr(1); @@ -367,7 +366,7 @@ OTMLNodePtr UIManager::getStyle(const std::string& styleName) return m_styles[styleName]; // styles starting with UI are automatically defined - if(boost::starts_with(styleName, "UI")) { + if(stdext::starts_with(styleName, "UI")) { OTMLNodePtr node = OTMLNode::create(styleName); node->writeAt("__class", styleName); m_styles[styleName] = node; diff --git a/src/framework/ui/uitextedit.cpp b/src/framework/ui/uitextedit.cpp index 9fd82ee2..f20d8004 100644 --- a/src/framework/ui/uitextedit.cpp +++ b/src/framework/ui/uitextedit.cpp @@ -278,8 +278,8 @@ void UITextEdit::appendText(std::string text) if(m_cursorPos >= 0) { // replace characters that are now allowed if(!m_multiline) - boost::replace_all(text, "\n", ""); - boost::replace_all(text, "\r", " "); + stdext::replace_all(text, "\n", ""); + stdext::replace_all(text, "\r", " "); if(text.length() > 0) { // only add text if textedit can add it diff --git a/src/framework/ui/uitranslator.cpp b/src/framework/ui/uitranslator.cpp index c6c01a39..c9fddd15 100644 --- a/src/framework/ui/uitranslator.cpp +++ b/src/framework/ui/uitranslator.cpp @@ -21,6 +21,7 @@ */ #include "uitranslator.h" +#include #include Fw::AlignmentFlag Fw::translateAlignment(std::string aligment) diff --git a/src/framework/ui/uiwidget.cpp b/src/framework/ui/uiwidget.cpp index 7ae8d151..d4348828 100644 --- a/src/framework/ui/uiwidget.cpp +++ b/src/framework/ui/uiwidget.cpp @@ -141,11 +141,11 @@ void UIWidget::addChild(const UIWidgetPtr& child) UIWidgetPtr oldLastChild = getLastChild(); m_children.push_back(child); - child->setParent(self_cast()); + child->setParent(static_self_cast()); // create default layout if(!m_layout) - m_layout = UIAnchorLayoutPtr(new UIAnchorLayout(self_cast())); + m_layout = UIAnchorLayoutPtr(new UIAnchorLayout(static_self_cast())); // add to layout and updates it m_layout->addWidget(child); @@ -184,11 +184,11 @@ void UIWidget::insertChild(int index, const UIWidgetPtr& child) // retrieve child by index auto it = m_children.begin() + index; m_children.insert(it, child); - child->setParent(self_cast()); + child->setParent(static_self_cast()); // create default layout if needed if(!m_layout) - m_layout = UIAnchorLayoutPtr(new UIAnchorLayout(self_cast())); + m_layout = UIAnchorLayoutPtr(new UIAnchorLayout(static_self_cast())); // add to layout and updates it m_layout->addWidget(child); @@ -218,7 +218,7 @@ void UIWidget::removeChild(UIWidgetPtr child) m_children.erase(it); // reset child parent - assert(child->getParent() == self_cast()); + assert(child->getParent() == static_self_cast()); child->setParent(nullptr); m_layout->removeWidget(child); @@ -504,7 +504,7 @@ void UIWidget::applyStyle(const OTMLNodePtr& styleNode) callLuaField("onStyleApply", styleNode->tag(), styleNode); if(m_firstOnStyle) { - auto self = self_cast(); + auto self = static_self_cast(); g_dispatcher.addEvent([self] { self->callLuaField("onSetup"); }); @@ -525,7 +525,7 @@ void UIWidget::addAnchor(Fw::AnchorEdge anchoredEdge, const std::string& hookedW return; if(UIAnchorLayoutPtr anchorLayout = getAnchoredLayout()) - anchorLayout->addAnchor(self_cast(), anchoredEdge, hookedWidgetId, hookedEdge); + anchorLayout->addAnchor(static_self_cast(), anchoredEdge, hookedWidgetId, hookedEdge); else g_logger.error(stdext::format("cannot add anchors to widget '%s': the parent doesn't use anchors layout", m_id)); } @@ -541,8 +541,8 @@ void UIWidget::centerIn(const std::string& hookedWidgetId) return; if(UIAnchorLayoutPtr anchorLayout = getAnchoredLayout()) { - anchorLayout->addAnchor(self_cast(), Fw::AnchorHorizontalCenter, hookedWidgetId, Fw::AnchorHorizontalCenter); - anchorLayout->addAnchor(self_cast(), Fw::AnchorVerticalCenter, hookedWidgetId, Fw::AnchorVerticalCenter); + anchorLayout->addAnchor(static_self_cast(), Fw::AnchorHorizontalCenter, hookedWidgetId, Fw::AnchorHorizontalCenter); + anchorLayout->addAnchor(static_self_cast(), Fw::AnchorVerticalCenter, hookedWidgetId, Fw::AnchorVerticalCenter); } else g_logger.error(stdext::format("cannot add anchors to widget '%s': the parent doesn't use anchors layout", m_id)); } @@ -553,10 +553,10 @@ void UIWidget::fill(const std::string& hookedWidgetId) return; if(UIAnchorLayoutPtr anchorLayout = getAnchoredLayout()) { - anchorLayout->addAnchor(self_cast(), Fw::AnchorLeft, hookedWidgetId, Fw::AnchorLeft); - anchorLayout->addAnchor(self_cast(), Fw::AnchorRight, hookedWidgetId, Fw::AnchorRight); - anchorLayout->addAnchor(self_cast(), Fw::AnchorTop, hookedWidgetId, Fw::AnchorTop); - anchorLayout->addAnchor(self_cast(), Fw::AnchorBottom, hookedWidgetId, Fw::AnchorBottom); + anchorLayout->addAnchor(static_self_cast(), Fw::AnchorLeft, hookedWidgetId, Fw::AnchorLeft); + anchorLayout->addAnchor(static_self_cast(), Fw::AnchorRight, hookedWidgetId, Fw::AnchorRight); + anchorLayout->addAnchor(static_self_cast(), Fw::AnchorTop, hookedWidgetId, Fw::AnchorTop); + anchorLayout->addAnchor(static_self_cast(), Fw::AnchorBottom, hookedWidgetId, Fw::AnchorBottom); } else g_logger.error(stdext::format("cannot add anchors to widget '%s': the parent doesn't use anchors layout", m_id)); } @@ -567,7 +567,7 @@ void UIWidget::breakAnchors() return; if(UIAnchorLayoutPtr anchorLayout = getAnchoredLayout()) - anchorLayout->removeAnchors(self_cast()); + anchorLayout->removeAnchors(static_self_cast()); } void UIWidget::updateParentLayout() @@ -601,7 +601,7 @@ void UIWidget::lock() return; if(UIWidgetPtr parent = getParent()) - parent->lockChild(self_cast()); + parent->lockChild(static_self_cast()); } void UIWidget::unlock() @@ -610,7 +610,7 @@ void UIWidget::unlock() return; if(UIWidgetPtr parent = getParent()) - parent->unlockChild(self_cast()); + parent->unlockChild(static_self_cast()); } void UIWidget::focus() @@ -622,7 +622,7 @@ void UIWidget::focus() return; if(UIWidgetPtr parent = getParent()) - parent->focusChild(self_cast(), Fw::ActiveFocusReason); + parent->focusChild(static_self_cast(), Fw::ActiveFocusReason); } void UIWidget::recursiveFocus(Fw::FocusReason reason) @@ -632,7 +632,7 @@ void UIWidget::recursiveFocus(Fw::FocusReason reason) if(UIWidgetPtr parent = getParent()) { if(m_focusable) - parent->focusChild(self_cast(), reason); + parent->focusChild(static_self_cast(), reason); parent->recursiveFocus(reason); } } @@ -644,7 +644,7 @@ void UIWidget::lower() UIWidgetPtr parent = getParent(); if(parent) - parent->lowerChild(self_cast()); + parent->lowerChild(static_self_cast()); } void UIWidget::raise() @@ -654,7 +654,7 @@ void UIWidget::raise() UIWidgetPtr parent = getParent(); if(parent) - parent->raiseChild(self_cast()); + parent->raiseChild(static_self_cast()); } void UIWidget::grabMouse() @@ -662,12 +662,12 @@ void UIWidget::grabMouse() if(m_destroyed) return; - g_ui.setMouseReceiver(self_cast()); + g_ui.setMouseReceiver(static_self_cast()); } void UIWidget::ungrabMouse() { - if(g_ui.getMouseReceiver() == self_cast()) + if(g_ui.getMouseReceiver() == static_self_cast()) g_ui.resetMouseReceiver(); } @@ -676,12 +676,12 @@ void UIWidget::grabKeyboard() if(m_destroyed) return; - g_ui.setKeyboardReceiver(self_cast()); + g_ui.setKeyboardReceiver(static_self_cast()); } void UIWidget::ungrabKeyboard() { - if(g_ui.getKeyboardReceiver() == self_cast()) + if(g_ui.getKeyboardReceiver() == static_self_cast()) g_ui.resetKeyboardReceiver(); } @@ -721,7 +721,7 @@ void UIWidget::internalDestroy() releaseLuaFieldsTable(); - g_ui.onWidgetDestroy(self_cast()); + g_ui.onWidgetDestroy(static_self_cast()); } void UIWidget::destroy() @@ -730,7 +730,7 @@ void UIWidget::destroy() g_logger.warning(stdext::format("attempt to destroy widget '%s' two times", m_id)); // hold itself reference - UIWidgetPtr self = self_cast(); + UIWidgetPtr self = static_self_cast(); m_destroyed = true; // remove itself from parent @@ -775,7 +775,7 @@ void UIWidget::setParent(const UIWidgetPtr& parent) if(oldParent == parent) return; - UIWidgetPtr self = self_cast(); + UIWidgetPtr self = static_self_cast(); if(oldParent && oldParent->hasChild(self)) oldParent->removeChild(self); @@ -797,7 +797,7 @@ void UIWidget::setLayout(const UILayoutPtr& layout) if(m_layout) m_layout->disableUpdates(); - layout->setParent(self_cast()); + layout->setParent(static_self_cast()); layout->disableUpdates(); for(const UIWidgetPtr& child : m_children) { @@ -836,7 +836,7 @@ bool UIWidget::setRect(const Rect& rect) // avoid massive update events if(!m_updateEventScheduled) { - UIWidgetPtr self = self_cast(); + UIWidgetPtr self = static_self_cast(); g_dispatcher.addEvent([self, oldRect]() { self->m_updateEventScheduled = false; if(oldRect != self->getRect()) @@ -896,9 +896,9 @@ void UIWidget::setVisible(bool visible) // visibility can change the current hovered widget if(visible) - g_ui.onWidgetAppear(self_cast()); + g_ui.onWidgetAppear(static_self_cast()); else - g_ui.onWidgetDisappear(self_cast()); + g_ui.onWidgetDisappear(static_self_cast()); callLuaField("onVisibilityChange", visible); } @@ -963,14 +963,14 @@ bool UIWidget::isVisible() else if(UIWidgetPtr parent = getParent()) return parent->isVisible(); else - return self_cast() == g_ui.getRootWidget(); + return static_self_cast() == g_ui.getRootWidget(); } bool UIWidget::isAnchored() { if(UIWidgetPtr parent = getParent()) if(UIAnchorLayoutPtr anchorLayout = parent->getAnchoredLayout()) - return anchorLayout->hasAnchors(self_cast()); + return anchorLayout->hasAnchors(static_self_cast()); return false; } @@ -1046,7 +1046,7 @@ UIAnchorLayoutPtr UIWidget::getAnchoredLayout() UILayoutPtr layout = parent->getLayout(); if(layout->isUIAnchorLayout()) - return layout->self_cast(); + return layout->static_self_cast(); return nullptr; } @@ -1055,7 +1055,7 @@ UIWidgetPtr UIWidget::getRootParent() if(UIWidgetPtr parent = getParent()) return parent->getRootParent(); else - return self_cast(); + return static_self_cast(); } UIWidgetPtr UIWidget::getChildAfter(const UIWidgetPtr& relativeChild) @@ -1231,7 +1231,7 @@ void UIWidget::updateState(Fw::WidgetState state) switch(state) { case Fw::ActiveState: { - UIWidgetPtr widget = self_cast(); + UIWidgetPtr widget = static_self_cast(); UIWidgetPtr parent; do { parent = widget->getParent(); @@ -1246,24 +1246,24 @@ void UIWidget::updateState(Fw::WidgetState state) break; } case Fw::FocusState: { - newStatus = (getParent() && getParent()->getFocusedChild() == self_cast()); + newStatus = (getParent() && getParent()->getFocusedChild() == static_self_cast()); break; } case Fw::HoverState: { - newStatus = (g_ui.getHoveredWidget() == self_cast() && isEnabled()); + newStatus = (g_ui.getHoveredWidget() == static_self_cast() && isEnabled()); break; } case Fw::PressedState: { - newStatus = (g_ui.getPressedWidget() == self_cast()); + newStatus = (g_ui.getPressedWidget() == static_self_cast()); break; } case Fw::DraggingState: { - newStatus = (g_ui.getDraggingWidget() == self_cast()); + newStatus = (g_ui.getDraggingWidget() == static_self_cast()); break; } case Fw::DisabledState: { bool enabled = true; - UIWidgetPtr widget = self_cast(); + UIWidgetPtr widget = static_self_cast(); do { if(!widget->isExplicitlyEnabled()) { enabled = false; @@ -1275,19 +1275,19 @@ void UIWidget::updateState(Fw::WidgetState state) break; } case Fw::FirstState: { - newStatus = (getParent() && getParent()->getFirstChild() == self_cast()); + newStatus = (getParent() && getParent()->getFirstChild() == static_self_cast()); break; } case Fw::MiddleState: { - newStatus = (getParent() && getParent()->getFirstChild() != self_cast() && getParent()->getLastChild() != self_cast()); + newStatus = (getParent() && getParent()->getFirstChild() != static_self_cast() && getParent()->getLastChild() != static_self_cast()); break; } case Fw::LastState: { - newStatus = (getParent() && getParent()->getLastChild() == self_cast()); + newStatus = (getParent() && getParent()->getLastChild() == static_self_cast()); break; } case Fw::AlternateState: { - newStatus = (getParent() && (getParent()->getChildIndex(self_cast()) % 2) == 1); + newStatus = (getParent() && (getParent()->getChildIndex(static_self_cast()) % 2) == 1); break; } default: @@ -1337,7 +1337,7 @@ void UIWidget::updateStyle() return; if(m_loadingStyle && !m_updateStyleScheduled) { - UIWidgetPtr self = self_cast(); + UIWidgetPtr self = static_self_cast(); g_dispatcher.addEvent([self] { self->m_updateStyleScheduled = false; self->updateStyle(); @@ -1361,10 +1361,9 @@ void UIWidget::updateStyle() // checks for states combination for(const OTMLNodePtr& style : m_style->children()) { - if(boost::starts_with(style->tag(), "$")) { + if(stdext::starts_with(style->tag(), "$")) { std::string statesStr = style->tag().substr(1); - std::vector statesSplit; - boost::split(statesSplit, statesStr, boost::is_any_of(std::string(" "))); + std::vector statesSplit = stdext::split(statesStr, " "); bool match = true; for(std::string stateStr : statesSplit) { @@ -1642,7 +1641,7 @@ bool UIWidget::propagateOnMouseEvent(const Point& mousePos, UIWidgetList& widget } } - widgetList.push_back(self_cast()); + widgetList.push_back(static_self_cast()); if(!isPhantom()) ret = true; @@ -1657,6 +1656,6 @@ bool UIWidget::propagateOnMouseMove(const Point& mousePos, const Point& mouseMov child->propagateOnMouseMove(mousePos, mouseMoved, widgetList); } - widgetList.push_back(self_cast()); + widgetList.push_back(static_self_cast()); return true; } diff --git a/src/framework/ui/uiwidgetbasestyle.cpp b/src/framework/ui/uiwidgetbasestyle.cpp index d6b87ad8..13a53761 100644 --- a/src/framework/ui/uiwidgetbasestyle.cpp +++ b/src/framework/ui/uiwidgetbasestyle.cpp @@ -162,8 +162,7 @@ void UIWidget::parseBaseStyle(const OTMLNodePtr& styleNode) setMarginLeft(node->value()); else if(node->tag() == "margin") { std::string marginDesc = node->value(); - std::vector split; - boost::split(split, marginDesc, boost::is_any_of(std::string(" "))); + std::vector split = stdext::split(marginDesc, " "); if(split.size() == 4) { setMarginTop(stdext::safe_cast(split[0])); setMarginRight(stdext::safe_cast(split[1])); @@ -202,8 +201,7 @@ void UIWidget::parseBaseStyle(const OTMLNodePtr& styleNode) setPaddingLeft(node->value()); else if(node->tag() == "padding") { std::string paddingDesc = node->value(); - std::vector split; - boost::split(split, paddingDesc, boost::is_any_of(std::string(" "))); + std::vector split = stdext::split(paddingDesc, " "); if(split.size() == 4) { setPaddingTop(stdext::safe_cast(split[0])); setPaddingRight(stdext::safe_cast(split[1])); @@ -243,13 +241,13 @@ void UIWidget::parseBaseStyle(const OTMLNodePtr& styleNode) if(!layoutType.empty()) { UILayoutPtr layout; if(layoutType == "horizontalBox") - layout = UIHorizontalLayoutPtr(new UIHorizontalLayout(self_cast())); + layout = UIHorizontalLayoutPtr(new UIHorizontalLayout(static_self_cast())); else if(layoutType == "verticalBox") - layout = UIVerticalLayoutPtr(new UIVerticalLayout(self_cast())); + layout = UIVerticalLayoutPtr(new UIVerticalLayout(static_self_cast())); else if(layoutType == "grid") - layout = UIGridLayoutPtr(new UIGridLayout(self_cast())); + layout = UIGridLayoutPtr(new UIGridLayout(static_self_cast())); else if(layoutType == "anchor") - layout = UIAnchorLayoutPtr(new UIAnchorLayout(self_cast())); + layout = UIAnchorLayoutPtr(new UIAnchorLayout(static_self_cast())); else throw OTMLException(node, "cannot determine layout type"); setLayout(layout); @@ -259,7 +257,7 @@ void UIWidget::parseBaseStyle(const OTMLNodePtr& styleNode) m_layout->applyStyle(node); } // anchors - else if(boost::starts_with(node->tag(), "anchors.")) { + else if(stdext::starts_with(node->tag(), "anchors.")) { UIWidgetPtr parent = getParent(); if(!parent) { if(m_firstOnStyle) @@ -271,7 +269,7 @@ void UIWidget::parseBaseStyle(const OTMLNodePtr& styleNode) UILayoutPtr layout = parent->getLayout(); UIAnchorLayoutPtr anchorLayout; if(layout->isUIAnchorLayout()) - anchorLayout = layout->self_cast(); + anchorLayout = layout->static_self_cast(); if(!anchorLayout) throw OTMLException(node, "cannot create anchor, the parent widget doesn't use anchor layout!"); @@ -304,7 +302,7 @@ void UIWidget::parseBaseStyle(const OTMLNodePtr& styleNode) } } // lua functions - } else if(boost::starts_with(node->tag(), "@")) { + } else if(stdext::starts_with(node->tag(), "@")) { // load once if(m_firstOnStyle) { std::string funcName = node->tag().substr(1); @@ -313,7 +311,7 @@ void UIWidget::parseBaseStyle(const OTMLNodePtr& styleNode) luaSetField(funcName); } // lua fields value - } else if(boost::starts_with(node->tag(), "&")) { + } else if(stdext::starts_with(node->tag(), "&")) { std::string fieldName = node->tag().substr(1); std::string fieldOrigin = "@" + node->source() + "[" + node->tag() + "]"; diff --git a/src/framework/util/color.h b/src/framework/util/color.h index c13946b3..7e5933d0 100644 --- a/src/framework/util/color.h +++ b/src/framework/util/color.h @@ -25,7 +25,9 @@ #include "../stdext/types.h" #include "../stdext/cast.h" +#include "../stdext/string.h" #include "../const.h" +#include class Color { diff --git a/src/otclient/CMakeLists.txt b/src/otclient/CMakeLists.txt index ff285112..713e9524 100644 --- a/src/otclient/CMakeLists.txt +++ b/src/otclient/CMakeLists.txt @@ -41,6 +41,7 @@ set(otclient_SOURCES ${otclient_SOURCES} ${CMAKE_CURRENT_LIST_DIR}/localplayer.h ${CMAKE_CURRENT_LIST_DIR}/map.cpp ${CMAKE_CURRENT_LIST_DIR}/map.h + ${CMAKE_CURRENT_LIST_DIR}/mapio.cpp ${CMAKE_CURRENT_LIST_DIR}/mapview.cpp ${CMAKE_CURRENT_LIST_DIR}/mapview.h ${CMAKE_CURRENT_LIST_DIR}/missile.cpp diff --git a/src/otclient/animatedtext.cpp b/src/otclient/animatedtext.cpp index e24b69c0..adcfb855 100644 --- a/src/otclient/animatedtext.cpp +++ b/src/otclient/animatedtext.cpp @@ -47,7 +47,7 @@ void AnimatedText::drawText(const Point& dest, const Rect& visibleRect) } } -void AnimatedText::startAnimation() +void AnimatedText::onAppear() { m_animationTimer.restart(); diff --git a/src/otclient/animatedtext.h b/src/otclient/animatedtext.h index 7c34c17f..02fa6759 100644 --- a/src/otclient/animatedtext.h +++ b/src/otclient/animatedtext.h @@ -35,14 +35,16 @@ public: AnimatedText(); void drawText(const Point& dest, const Rect& visibleRect); - void startAnimation(); void setColor(int color); void setText(const std::string& text); - AnimatedTextPtr asAnimatedText() { return self_cast(); } + AnimatedTextPtr asAnimatedText() { return static_self_cast(); } bool isAnimatedText() { return true; } +protected: + virtual void onAppear(); + private: Color m_color; Timer m_animationTimer; diff --git a/src/otclient/creature.cpp b/src/otclient/creature.cpp index 6d00ec12..e24d53eb 100644 --- a/src/otclient/creature.cpp +++ b/src/otclient/creature.cpp @@ -302,6 +302,11 @@ void Creature::stopWalk() terminateWalk(); } +void Creature::onMove(const Position& newPos, const Position& oldPos) +{ + walk(oldPos, newPos); +} + void Creature::updateWalkAnimation(int totalPixelsWalked) { // update outfit animation @@ -353,9 +358,9 @@ void Creature::updateWalkingTile() if(newWalkingTile != m_walkingTile) { if(m_walkingTile) - m_walkingTile->removeWalkingCreature(self_cast()); + m_walkingTile->removeWalkingCreature(static_self_cast()); if(newWalkingTile) - newWalkingTile->addWalkingCreature(self_cast()); + newWalkingTile->addWalkingCreature(static_self_cast()); m_walkingTile = newWalkingTile; } } @@ -371,7 +376,7 @@ void Creature::nextWalkUpdate() // schedules next update if(m_walking) { - auto self = self_cast(); + auto self = static_self_cast(); m_walkUpdateEvent = g_dispatcher.scheduleEvent([self] { self->m_walkUpdateEvent = nullptr; self->nextWalkUpdate(); @@ -409,7 +414,7 @@ void Creature::terminateWalk() } if(m_walkingTile) { - m_walkingTile->removeWalkingCreature(self_cast()); + m_walkingTile->removeWalkingCreature(static_self_cast()); m_walkingTile = nullptr; } @@ -496,7 +501,7 @@ void Creature::setShieldTexture(const std::string& filename, bool blink) m_showShieldTexture = true; if(blink && !m_shieldBlink) { - auto self = self_cast(); + auto self = static_self_cast(); g_dispatcher.scheduleEvent([self]() { self->updateShield(); }, SHIELD_BLINK_TICKS); @@ -516,7 +521,7 @@ void Creature::addTimedSquare(uint8 color) m_timedSquareColor = Color::from8bit(color); // schedule removal - auto self = self_cast(); + auto self = static_self_cast(); g_dispatcher.scheduleEvent([self]() { self->removeTimedSquare(); }, VOLATILE_SQUARE_DURATION); @@ -527,7 +532,7 @@ void Creature::updateShield() m_showShieldTexture = !m_showShieldTexture; if(m_shield != Otc::ShieldNone && m_shieldBlink) { - auto self = self_cast(); + auto self = static_self_cast(); g_dispatcher.scheduleEvent([self]() { self->updateShield(); }, SHIELD_BLINK_TICKS); diff --git a/src/otclient/creature.h b/src/otclient/creature.h index 42795f2d..9003ed31 100644 --- a/src/otclient/creature.h +++ b/src/otclient/creature.h @@ -100,6 +100,9 @@ public: const ThingTypePtr& getThingType(); ThingType *rawGetThingType(); +protected: + virtual void onMove(const Position& newPos, const Position& oldPos); + protected: virtual void updateWalkAnimation(int totalPixelsWalked); virtual void updateWalkOffset(int totalPixelsWalked); diff --git a/src/otclient/creatures.cpp b/src/otclient/creatures.cpp index 091969e6..fcb83007 100644 --- a/src/otclient/creatures.cpp +++ b/src/otclient/creatures.cpp @@ -80,7 +80,11 @@ void Creatures::loadCreatureBuffer(const std::string &buffer) if(!root || (root->ValueStr() != "monster" && root->ValueStr() != "npc")) stdext::throw_exception("invalid root tag name"); - CreatureTypePtr newType(new CreatureType(stdext::trim(stdext::tolower(root->Attribute("name"))))); + std::string cName = root->Attribute("name"); + stdext::tolower(cName); + stdext::trim(cName); + + CreatureTypePtr newType(new CreatureType(cName)); for(TiXmlElement* attrib = root->FirstChildElement(); attrib; attrib = attrib->NextSiblingElement()) { if(attrib->ValueStr() != "look") continue; @@ -120,9 +124,11 @@ bool Creatures::m_loadCreatureBuffer(TiXmlElement* attrib, const CreatureTypePtr return type >= 0; } -CreatureTypePtr Creatures::getCreature(const std::string& name) +CreatureTypePtr Creatures::getCreature(std::string name) { + stdext::tolower(name); + stdext::trim(name); auto it = std::find_if(m_creatures.begin(), m_creatures.end(), - [=] (const CreatureTypePtr& m) -> bool { return m->getName() == stdext::trim(stdext::tolower(name)); }); + [=] (const CreatureTypePtr& m) -> bool { return m->getName() == name; }); return it != m_creatures.end() ? *it : nullptr; } diff --git a/src/otclient/creatures.h b/src/otclient/creatures.h index af887b1e..de3731ac 100644 --- a/src/otclient/creatures.h +++ b/src/otclient/creatures.h @@ -50,7 +50,7 @@ public: int getSpawnTime() { return m_attribs.get(CreatureAttrSpawnTime); } private: - stdext::attrib_storage m_attribs; + stdext::dynamic_storage m_attribs; }; class Creatures @@ -63,7 +63,7 @@ public: void loadNpcs(const std::string& folder); void loadCreatureBuffer(const std::string& buffer); - CreatureTypePtr getCreature(const std::string& name); + CreatureTypePtr getCreature(std::string name); bool isLoaded() const { return m_loaded; } protected: diff --git a/src/otclient/declarations.h b/src/otclient/declarations.h index 1a922922..fa06e51f 100644 --- a/src/otclient/declarations.h +++ b/src/otclient/declarations.h @@ -50,25 +50,25 @@ class House; class Town; class CreatureType; -typedef boost::intrusive_ptr MapViewPtr; -typedef boost::intrusive_ptr TilePtr; -typedef boost::intrusive_ptr ThingPtr; -typedef boost::intrusive_ptr ItemPtr; -typedef boost::intrusive_ptr ContainerPtr; -typedef boost::intrusive_ptr CreaturePtr; -typedef boost::intrusive_ptr MonsterPtr; -typedef boost::intrusive_ptr NpcPtr; -typedef boost::intrusive_ptr PlayerPtr; -typedef boost::intrusive_ptr LocalPlayerPtr; -typedef boost::intrusive_ptr EffectPtr; -typedef boost::intrusive_ptr MissilePtr; -typedef boost::intrusive_ptr AnimatedTextPtr; -typedef boost::intrusive_ptr StaticTextPtr; -typedef boost::intrusive_ptr ThingTypePtr; -typedef boost::intrusive_ptr ItemTypePtr; -typedef boost::intrusive_ptr HousePtr; -typedef boost::intrusive_ptr TownPtr; -typedef boost::intrusive_ptr CreatureTypePtr; +typedef stdext::shared_object_ptr MapViewPtr; +typedef stdext::shared_object_ptr TilePtr; +typedef stdext::shared_object_ptr ThingPtr; +typedef stdext::shared_object_ptr ItemPtr; +typedef stdext::shared_object_ptr ContainerPtr; +typedef stdext::shared_object_ptr CreaturePtr; +typedef stdext::shared_object_ptr MonsterPtr; +typedef stdext::shared_object_ptr NpcPtr; +typedef stdext::shared_object_ptr PlayerPtr; +typedef stdext::shared_object_ptr LocalPlayerPtr; +typedef stdext::shared_object_ptr EffectPtr; +typedef stdext::shared_object_ptr MissilePtr; +typedef stdext::shared_object_ptr AnimatedTextPtr; +typedef stdext::shared_object_ptr StaticTextPtr; +typedef stdext::shared_object_ptr ThingTypePtr; +typedef stdext::shared_object_ptr ItemTypePtr; +typedef stdext::shared_object_ptr HousePtr; +typedef stdext::shared_object_ptr TownPtr; +typedef stdext::shared_object_ptr CreatureTypePtr; typedef std::vector ThingList; typedef std::vector ThingTypeList; @@ -81,8 +81,8 @@ typedef std::unordered_map TileMap; class ProtocolLogin; class ProtocolGame; -typedef boost::intrusive_ptr ProtocolGamePtr; -typedef boost::intrusive_ptr ProtocolLoginPtr; +typedef stdext::shared_object_ptr ProtocolGamePtr; +typedef stdext::shared_object_ptr ProtocolLoginPtr; // ui class UIItem; @@ -90,9 +90,9 @@ class UICreature; class UIMap; class UIProgressRect; -typedef boost::intrusive_ptr UIItemPtr; -typedef boost::intrusive_ptr UICreaturePtr; -typedef boost::intrusive_ptr UIMapPtr; -typedef boost::intrusive_ptr UIProgressRectPtr; +typedef stdext::shared_object_ptr UIItemPtr; +typedef stdext::shared_object_ptr UICreaturePtr; +typedef stdext::shared_object_ptr UIMapPtr; +typedef stdext::shared_object_ptr UIProgressRectPtr; #endif diff --git a/src/otclient/effect.cpp b/src/otclient/effect.cpp index 385fbb5b..ef52c9ec 100644 --- a/src/otclient/effect.cpp +++ b/src/otclient/effect.cpp @@ -35,7 +35,7 @@ void Effect::draw(const Point& dest, float scaleFactor, bool animate) rawGetThingType()->draw(dest, scaleFactor, 0, 0, 0, 0, animationPhase); } -void Effect::startAnimation() +void Effect::onAppear() { m_animationTimer.restart(); m_phaseDuration = EFFECT_TICKS_PER_FRAME; diff --git a/src/otclient/effect.h b/src/otclient/effect.h index 694070db..97a95a36 100644 --- a/src/otclient/effect.h +++ b/src/otclient/effect.h @@ -33,20 +33,22 @@ class Effect : public Thing enum { EFFECT_TICKS_PER_FRAME = 75 }; + public: void draw(const Point& dest, float scaleFactor, bool animate); void setId(uint32 id); - void startAnimation(); - uint32 getId() { return m_id; } - EffectPtr asEffect() { return self_cast(); } + EffectPtr asEffect() { return static_self_cast(); } bool isEffect() { return true; } const ThingTypePtr& getThingType(); ThingType *rawGetThingType(); +protected: + void onAppear(); + private: Timer m_animationTimer; uint m_phaseDuration; diff --git a/src/otclient/game.h b/src/otclient/game.h index a440687c..5268ea1d 100644 --- a/src/otclient/game.h +++ b/src/otclient/game.h @@ -34,6 +34,8 @@ #include "outfit.h" #include +#include + typedef std::tuple Vip; //@bindsingleton g_game diff --git a/src/otclient/houses.h b/src/otclient/houses.h index 443c7edb..cfa82c78 100644 --- a/src/otclient/houses.h +++ b/src/otclient/houses.h @@ -63,7 +63,7 @@ protected: void save(TiXmlElement &elem) { } // TODO private: - stdext::attrib_storage m_attribs; + stdext::packed_storage m_attribs; TileMap m_tiles; stdext::boolean m_isGuildHall; diff --git a/src/otclient/item.h b/src/otclient/item.h index 991a7fa2..258d7dbb 100644 --- a/src/otclient/item.h +++ b/src/otclient/item.h @@ -115,7 +115,7 @@ public: bool isTeleport() { return m_attribs.has(ATTR_TELE_DEST); } bool isMoveable(); - ItemPtr asItem() { return self_cast(); } + ItemPtr asItem() { return static_self_cast(); } bool isItem() { return true; } const ThingTypePtr& getThingType(); @@ -125,7 +125,7 @@ private: uint16 m_id; uint16 m_otbId; uint8 m_countOrSubType; - stdext::attrib_storage m_attribs; + stdext::packed_storage m_attribs; }; #pragma pack(pop) diff --git a/src/otclient/itemtype.h b/src/otclient/itemtype.h index 228c5f82..7dbd16fc 100644 --- a/src/otclient/itemtype.h +++ b/src/otclient/itemtype.h @@ -103,7 +103,7 @@ private: ItemCategory m_category; stdext::boolean m_null; - stdext::attrib_storage m_attribs; + stdext::dynamic_storage m_attribs; }; #endif diff --git a/src/otclient/localplayer.h b/src/otclient/localplayer.h index 97668a90..cb00aa7a 100644 --- a/src/otclient/localplayer.h +++ b/src/otclient/localplayer.h @@ -77,7 +77,7 @@ public: bool isAutoWalking() { return m_autoWalking; } bool isPremium() { return m_premium; } - LocalPlayerPtr asLocalPlayer() { return self_cast(); } + LocalPlayerPtr asLocalPlayer() { return static_self_cast(); } bool isLocalPlayer() { return true; } protected: diff --git a/src/otclient/map.cpp b/src/otclient/map.cpp index 68da1704..47abee1b 100644 --- a/src/otclient/map.cpp +++ b/src/otclient/map.cpp @@ -27,14 +27,10 @@ #include "item.h" #include "missile.h" #include "statictext.h" +#include "mapview.h" #include -#include "mapview.h" -#include -#include -#include #include -#include Map g_map; TilePtr Map::m_nulltile; @@ -62,513 +58,6 @@ void Map::notificateTileUpdateToMapViews(const Position& pos) mapView->onTileUpdate(pos); } -void Map::loadOtbm(const std::string& fileName) -{ - FileStreamPtr fin = g_resources.openFile(fileName); - if(!fin) - stdext::throw_exception(stdext::format("Unable to load map '%s'", fileName)); - - fin->cache(); - if(!g_things.isOtbLoaded()) - stdext::throw_exception("OTB isn't loaded yet to load a map."); - - if(fin->getU32()) - stdext::throw_exception("Unknown file version detected"); - - BinaryTreePtr root = fin->getBinaryTree(); - if(root->getU8()) - stdext::throw_exception("could not read root property!"); - - uint32 headerVersion = root->getU32(); - if(!headerVersion || headerVersion > 3) - stdext::throw_exception(stdext::format("Unknown OTBM version detected: %u.", headerVersion)); - - setWidth(root->getU16()); - setHeight(root->getU16()); - - uint32 headerMajorItems = root->getU8(); - if(headerMajorItems < 3) { - stdext::throw_exception(stdext::format("This map needs to be upgraded. read %d what it's supposed to be: %u", - headerMajorItems, g_things.getOtbMajorVersion())); - } - - if(headerMajorItems > g_things.getOtbMajorVersion()) { - stdext::throw_exception(stdext::format("This map was saved with different OTB version. read %d what it's supposed to be: %d", - headerMajorItems, g_things.getOtbMajorVersion())); - } - - root->skip(3); - uint32 headerMinorItems = root->getU32(); - if(headerMinorItems > g_things.getOtbMinorVersion()) { - g_logger.warning(stdext::format("This map needs an updated OTB. read %d what it's supposed to be: %d or less", - headerMinorItems, g_things.getOtbMinorVersion())); - } - - BinaryTreePtr node = root->getChildren()[0]; - if(node->getU8() != OTBM_MAP_DATA) - stdext::throw_exception("Could not read root data node"); - - while (node->canRead()) { - uint8 attribute = node->getU8(); - std::string tmp = node->getString(); - switch (attribute) { - case OTBM_ATTR_DESCRIPTION: - setDescription(tmp); - break; - case OTBM_ATTR_SPAWN_FILE: - setSpawnFile(fileName.substr(0, fileName.rfind('/') + 1) + tmp); - break; - case OTBM_ATTR_HOUSE_FILE: - setHouseFile(fileName.substr(0, fileName.rfind('/') + 1) + tmp); - break; - default: - stdext::throw_exception(stdext::format("Invalid attribute '%d'", (int)attribute)); - } - } - - for(const BinaryTreePtr &nodeMapData : node->getChildren()) { - uint8 mapDataType = nodeMapData->getU8(); - if(mapDataType == OTBM_TILE_AREA) { - Position basePos = nodeMapData->getPosition(); - - for(const BinaryTreePtr &nodeTile : nodeMapData->getChildren()) { - uint8 type = nodeTile->getU8(); - if(type != OTBM_TILE && type != OTBM_HOUSETILE) - stdext::throw_exception(stdext::format("invalid node tile type %d", (int)type)); - - HousePtr house = nullptr; - uint32 flags = TILESTATE_NONE; - Position pos = basePos + nodeTile->getPoint(); - - if(type == OTBM_HOUSETILE) { - uint32 hId = nodeTile->getU32(); - TilePtr tile = getOrCreateTile(pos); - if(!(house = m_houses.getHouse(hId))) { - house = HousePtr(new House(hId)); - m_houses.addHouse(house); - } - house->setTile(tile); - } - - while(nodeTile->canRead()) { - uint8 tileAttr = nodeTile->getU8(); - switch (tileAttr) { - case OTBM_ATTR_TILE_FLAGS: { - uint32 _flags = nodeTile->getU32(); - if((_flags & TILESTATE_PROTECTIONZONE) == TILESTATE_PROTECTIONZONE) - flags |= TILESTATE_PROTECTIONZONE; - else if((_flags & TILESTATE_OPTIONALZONE) == TILESTATE_OPTIONALZONE) - flags |= TILESTATE_OPTIONALZONE; - else if((_flags & TILESTATE_HARDCOREZONE) == TILESTATE_HARDCOREZONE) - flags |= TILESTATE_HARDCOREZONE; - - if((_flags & TILESTATE_NOLOGOUT) == TILESTATE_NOLOGOUT) - flags |= TILESTATE_NOLOGOUT; - - if((_flags & TILESTATE_REFRESH) == TILESTATE_REFRESH) - flags |= TILESTATE_REFRESH; - - break; - } - case OTBM_ATTR_ITEM: { - addThing(Item::createFromOtb(nodeTile->getU16()), pos); - break; - } - default: { - stdext::throw_exception(stdext::format("invalid tile attribute %d at pos %s", (int)tileAttr, stdext::to_string(pos))); - } - } - } - - for(const BinaryTreePtr &nodeItem : nodeTile->getChildren()) { - if(nodeItem->getU8() != OTBM_ITEM) - stdext::throw_exception("invalid item node"); - - ItemPtr item = Item::createFromOtb(nodeItem->getU16()); - item->unserializeItem(nodeItem); - - if(item->isContainer()) { - for(const BinaryTreePtr& containerItem : nodeItem->getChildren()) { - if(containerItem->getU8() != OTBM_ITEM) - stdext::throw_exception("invalid container item node"); - - ItemPtr cItem = Item::createFromOtb(containerItem->getU16()); - cItem->unserializeItem(containerItem); - //item->addContainerItem(cItem); - } - } - - if(house && item->isMoveable()) { - g_logger.warning(stdext::format("Movable item found in house: %d at pos %s - escaping...", item->getId(), stdext::to_string(pos))); - item.reset(); - } - - addThing(item, pos); - } - - if(const TilePtr& tile = getTile(pos)) - tile->setFlags((tileflags_t)flags); - } - } else if(mapDataType == OTBM_TOWNS) { - TownPtr town = nullptr; - for(const BinaryTreePtr &nodeTown : nodeMapData->getChildren()) { - if(nodeTown->getU8() != OTBM_TOWN) - stdext::throw_exception("invalid town node."); - - uint32 townId = nodeTown->getU32(); - std::string townName = nodeTown->getString(); - Position townCoords = nodeTown->getPosition(); - if(!(town = m_towns.getTown(townId))) { - town = TownPtr(new Town(townId, townName, townCoords)); - m_towns.addTown(town); - } - } - } else if(mapDataType == OTBM_WAYPOINTS && headerVersion > 1) { - for(const BinaryTreePtr &nodeWaypoint : nodeMapData->getChildren()) { - if(nodeWaypoint->getU8() != OTBM_WAYPOINT) - stdext::throw_exception("invalid waypoint node."); - - std::string name = nodeWaypoint->getString(); - Position waypointPos = nodeWaypoint->getPosition(); - if(waypointPos.isValid() && !name.empty() && m_waypoints.find(waypointPos) == m_waypoints.end()) - m_waypoints.insert(std::make_pair(waypointPos, name)); - } - } else - stdext::throw_exception(stdext::format("Unknown map data node %d", (int)mapDataType)); - } - - g_logger.debug("OTBM read successfully."); - fin->close(); - - loadSpawns(getSpawnFile()); - m_houses.load(getHouseFile()); -} - -void Map::saveOtbm(const std::string &fileName) -{ -#if 0 - /// FIXME: Untested code - FileStreamPtr fin = g_resources.appendFile(fileName); - if(!fin) - stdext::throw_exception(stdext::format("failed to open file '%s' for write", fileName)); - - std::string dir; - if(fileName.find_last_of('/') == std::string::npos) - dir = g_resources.getWorkDir(); - else - dir = fileName.substr(0, fileName.find_last_of('/')); - - uint32 version = 0; - /// Support old versions (< 810 or 860 IIRC) - /// TODO: Use constants? - if(g_things.getOtbMajorVersion() < 10) - version = 1; - else - version = 2; - - /// Usually when a map has empty house/spawn file it means the map is new. - /// TODO: Ask the user for a map name instead of those ugly uses of substr - std::string houseFile = getHouseFile(), spawnFile = getSpawnFile(); - if(houseFile.empty() && version > 1) - houseFile = fileName.substr(fileName.find_last_of('/')) + "-houses.xml"; - if(spawnFile.empty()) - spawnFile = fileName.substr(fileName.find_last_of('/')) + "-spawns.xml"; - -#if 0 - if(version > 1) - m_houses->save(dir + "/" + houseFile); - - saveSpawns(dir + "/" + spawnFile); -#endif - - time_t start = time(0); - fin->addU32(0); // file version - BinaryTreePtr root = fin->makeTree(); - { - root->writeU32(version); - - Size mapSize = getSize(); - root->writeU16(mapSize.width()); - root->writeU16(mapSize.height()); - - root->writeU32(g_things.getOtbMajorVersion()); - root->writeU32(g_things.getOtbMinorVersion()); - - BinaryTreePtr mapData = root->makeChild(OTBM_MAP_DATA); - { - // own description. - for(const auto& desc : getDescriptions()) { - mapData->writeU8(OTBM_ATTR_DESCRIPTION); - mapData->writeString(desc); - } - - // special one - mapData->writeU8(OTBM_ATTR_DESCRIPTION); - mapData->writeString(stdext::format("Saved with %s v%d", g_app.getName(), stdext::unsafe_cast(g_app.getVersion()))); - - // spawn file. - mapData->writeU8(OTBM_ATTR_SPAWN_FILE); - mapData->writeString(spawnFile); - - // house file. - if(version > 1) { - mapData->writeU8(OTBM_ATTR_HOUSE_FILE); - mapData->writeString(houseFile); - } - - /// write tiles first - BinaryTreePtr tileArea = mapData->makeChild(OTBM_TILE_AREA); - Position base(-1, -1, -1); - for(const auto& pair : m_tiles) { - Position pos = pair.first; - TilePtr tile = pair.second; - - /// base position - if(pos.x < base.x || pos.x >= base.x + 256 || pos.y < base.y|| pos.y >= base.y + 256 || - pos.z != base.z) { - tileArea->writePos(base = pos & 0xFF00); - } - - BinaryTreePtr tileNode(nullptr); - uint32 flags = tile->getFlags(); - if((flags & TILESTATE_HOUSE) == TILESTATE_HOUSE) - tileNode = tileArea->makeChild(OTBM_HOUSETILE); - else - tileNode = tileArea->makeChild(OTBM_TILE); - - tileNode->writePoint(Point(pos.x, pos.y)); -// if(tileNode->getType() == OTBM_HOUSETILE) -// tileNode->writeU32(tile->getHouseId()); - - /// Tile flags - if(flags != 0) { - tileNode->writeU8(OTBM_ATTR_TILE_FLAGS); - tileNode->writeU32(flags); - } - - /// start writing tile items - for(const ItemPtr& item : tile->getItems()) { - BinaryTreePtr itemNode = tileNode->makeChild(OTBM_ATTR_ITEM); - item->serializeItem(itemNode); - } - } - - /// write towns - BinaryTreePtr townNode = mapData->makeChild(OTBM_TOWNS); - for(const TownPtr& town : m_towns.getTowns()) { - BinaryTreePtr newTown = townNode->makeChild(OTBM_TOWN); - { - newTown->writeU32(town->getId()); - newTown->writeString(town->getName()); - newTown->writePos(town->getPos()); - } - } - - /// write waypoints - if(version > 1) { - BinaryTreePtr waypointNode = mapData->makeChild(OTBM_WAYPOINTS); - for(const auto& it : m_waypoints) { - BinaryTreePtr newWaypoint = waypointNode->makeChild(OTBM_WAYPOINT); - { - newWaypoint->writeString(it.second); - newWaypoint->writePos(it.first); - } - } - } - } - } - - root->writeToFile(); - g_logger.debug(stdext::format("OTBM saving took %ld", time(0) - start)); -#endif -} - -void Map::loadSpawns(const std::string &fileName) -{ - if(!m_creatures.isLoaded()) - stdext::throw_exception("cannot load spawns; monsters/nps aren't loaded."); - - TiXmlDocument doc; - doc.Parse(g_resources.loadFile(fileName).c_str()); - if(doc.Error()) - stdext::throw_exception(stdext::format("cannot load spawns xml file '%s: '%s'", fileName, doc.ErrorDesc())); - - TiXmlElement* root = doc.FirstChildElement(); - if(!root || root->ValueStr() != "spawns") - stdext::throw_exception("malformed spawns file"); - - CreatureTypePtr cType(nullptr); - for(TiXmlElement* node = root->FirstChildElement(); node; node = node->NextSiblingElement()) { - if(node->ValueTStr() != "spawn") - stdext::throw_exception("invalid spawn node"); - - Position centerPos = node->readPos("center"); - for(TiXmlElement* cNode = node->FirstChildElement(); cNode; cNode = cNode->NextSiblingElement()) { - if(cNode->ValueStr() != "monster" && cNode->ValueStr() != "npc") - stdext::throw_exception(stdext::format("invalid spawn-subnode %s", cNode->ValueStr())); - - std::string cName = stdext::trim(stdext::tolower(cNode->Attribute("name"))); - if (!(cType = m_creatures.getCreature(cName))) - continue; - - cType->setSpawnTime(cNode->readType("spawntime")); - CreaturePtr creature(new Creature); - creature->setOutfit(cType->getOutfit()); - creature->setName(cType->getName()); - - addThing(creature, centerPos + cNode->readPoint()); - } - } - - doc.Clear(); -} - -bool Map::loadOtcm(const std::string& fileName) -{ - try { - FileStreamPtr fin = g_resources.openFile(fileName); - if(!fin) - stdext::throw_exception("unable to open file"); - - stdext::timer loadTimer; - fin->cache(); - - uint32 signature = fin->getU32(); - if(signature != OTCM_SIGNATURE) - stdext::throw_exception("invalid otcm file"); - - uint16 start = fin->getU16(); - uint16 version = fin->getU16(); - fin->getU32(); // flags - - switch(version) { - case 1: { - fin->getString(); // description - uint32 datSignature = fin->getU32(); - fin->getU16(); // protocol version - fin->getString(); // world name - - if(datSignature != g_things.getDatSignature()) - g_logger.warning("otcm map loaded was created with a different dat signature"); - - break; - } - default: - stdext::throw_exception("otcm version not supported"); - } - - fin->seek(start); - - while(true) { - Position pos; - - pos.x = fin->getU16(); - pos.y = fin->getU16(); - pos.z = fin->getU8(); - - // end of file - if(!pos.isValid()) - break; - - const TilePtr& tile = g_map.createTile(pos); - - int stackPos = 0; - while(true) { - int id = fin->getU16(); - - // end of tile - if(id == 0xFFFF) - break; - - int countOrSubType = fin->getU8(); - - ItemPtr item = Item::create(id); - item->setCountOrSubType(countOrSubType); - - if(item->isValid()) - tile->addThing(item, stackPos++); - } - } - - fin->close(); - - g_logger.debug(stdext::format("Otcm load time: %.2f seconds", loadTimer.elapsed_seconds())); - return true; - } catch(stdext::exception& e) { - g_logger.error(stdext::format("failed to load OTCM map: %s", e.what())); - return false; - } -} - -void Map::saveOtcm(const std::string& fileName) -{ -#if 0 - try { - g_clock.update(); - - FileStreamPtr fin = g_resources.createFile(fileName); - fin->cache(); - - //TODO: compression flag with zlib - uint32 flags = 0; - - // header - fin->addU32(OTCM_SIGNATURE); - fin->addU16(0); // data start, will be overwritten later - fin->addU16(OTCM_VERSION); - fin->addU32(flags); - - // version 1 header - fin->addString("OTCM 1.0"); // map description - fin->addU32(g_things.getDatSignature()); - fin->addU16(g_game.getClientVersion()); - fin->addString(g_game.getWorldName()); - - // go back and rewrite where the map data starts - uint32 start = fin->tell(); - fin->seek(4); - fin->addU16(start); - fin->seek(start); - - for(auto& pair : m_tiles) { - const TilePtr& tile = pair.second; - if(!tile || tile->isEmpty()) - continue; - - Position pos = pair.first; - fin->addU16(pos.x); - fin->addU16(pos.y); - fin->addU8(pos.z); - - const auto& list = tile->getThings(); - auto first = std::find_if(list.begin(), list.end(), [](const ThingPtr& thing) { return thing->isItem(); }); - for(auto it = first, end = list.end(); it != end; ++it) { - const ThingPtr& thing = *it; - if(thing->isItem()) { - ItemPtr item = thing->self_cast(); - fin->addU16(item->getId()); - fin->addU8(item->getCountOrSubType()); - } - } - - // end of tile - fin->addU16(0xFFFF); - } - - // end of file - Position invalidPos; - fin->addU16(invalidPos.x); - fin->addU16(invalidPos.y); - fin->addU8(invalidPos.z); - - fin->flush(); - fin->close(); - } catch(stdext::exception& e) { - g_logger.error(stdext::format("failed to save OTCM map: %s", e.what())); - } -#endif -} - void Map::clean() { cleanDynamicThings(); @@ -617,11 +106,11 @@ void Map::addThing(const ThingPtr& thing, const Position& pos, int stackPos) if(thing->isItem() || thing->isCreature() || thing->isEffect()) { tile->addThing(thing, stackPos); } else if(thing->isMissile()) { - m_floorMissiles[pos.z].push_back(thing->self_cast()); + m_floorMissiles[pos.z].push_back(thing->static_self_cast()); } else if(thing->isAnimatedText()) { - m_animatedTexts.push_back(thing->self_cast()); + m_animatedTexts.push_back(thing->static_self_cast()); } else if(thing->isStaticText()) { - StaticTextPtr staticText = thing->self_cast(); + StaticTextPtr staticText = thing->static_self_cast(); bool mustAdd = true; for(auto it = m_staticTexts.begin(), end = m_staticTexts.end(); it != end; ++it) { StaticTextPtr cStaticText = *it; @@ -641,11 +130,13 @@ void Map::addThing(const ThingPtr& thing, const Position& pos, int stackPos) m_staticTexts.push_back(staticText); } - thing->startAnimation(); + if(!thing->isCreature()) + thing->onAppear(); + thing->setPosition(pos); if(thing->isCreature()) { - CreaturePtr creature = thing->self_cast(); + CreaturePtr creature = thing->static_self_cast(); if(oldPos != pos) { if(oldPos.isInRange(pos,1,1)) g_game.processCreatureMove(creature, oldPos, pos); @@ -672,7 +163,7 @@ bool Map::removeThing(const ThingPtr& thing) notificateTileUpdateToMapViews(thing->getPosition()); if(thing->isMissile()) { - MissilePtr missile = thing->self_cast(); + MissilePtr missile = thing->static_self_cast(); int z = missile->getPosition().z; auto it = std::find(m_floorMissiles[z].begin(), m_floorMissiles[z].end(), missile); if(it != m_floorMissiles[z].end()) { @@ -680,14 +171,14 @@ bool Map::removeThing(const ThingPtr& thing) return true; } } else if(thing->isAnimatedText()) { - AnimatedTextPtr animatedText = thing->self_cast(); + AnimatedTextPtr animatedText = thing->static_self_cast(); auto it = std::find(m_animatedTexts.begin(), m_animatedTexts.end(), animatedText); if(it != m_animatedTexts.end()) { m_animatedTexts.erase(it); return true; } } else if(thing->isStaticText()) { - StaticTextPtr staticText = thing->self_cast(); + StaticTextPtr staticText = thing->static_self_cast(); auto it = std::find(m_staticTexts.begin(), m_staticTexts.end(), staticText); if(it != m_staticTexts.end()) { m_staticTexts.erase(it); diff --git a/src/otclient/map.h b/src/otclient/map.h index 31d2be6c..ecbb7cb8 100644 --- a/src/otclient/map.h +++ b/src/otclient/map.h @@ -267,7 +267,7 @@ private: Position m_centralPosition; Rect m_tilesRect; - stdext::attrib_storage m_attribs; + stdext::packed_storage m_attribs; Houses m_houses; Towns m_towns; Creatures m_creatures; diff --git a/src/otclient/mapio.cpp b/src/otclient/mapio.cpp new file mode 100644 index 00000000..c9d58bb9 --- /dev/null +++ b/src/otclient/mapio.cpp @@ -0,0 +1,540 @@ +/* + * Copyright (c) 2010-2012 OTClient + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "map.h" +#include "tile.h" + +#include +#include +#include +#include +#include + +void Map::loadOtbm(const std::string& fileName) +{ + FileStreamPtr fin = g_resources.openFile(fileName); + if(!fin) + stdext::throw_exception(stdext::format("Unable to load map '%s'", fileName)); + + fin->cache(); + if(!g_things.isOtbLoaded()) + stdext::throw_exception("OTB isn't loaded yet to load a map."); + + if(fin->getU32()) + stdext::throw_exception("Unknown file version detected"); + + BinaryTreePtr root = fin->getBinaryTree(); + if(root->getU8()) + stdext::throw_exception("could not read root property!"); + + uint32 headerVersion = root->getU32(); + if(!headerVersion || headerVersion > 3) + stdext::throw_exception(stdext::format("Unknown OTBM version detected: %u.", headerVersion)); + + setWidth(root->getU16()); + setHeight(root->getU16()); + + uint32 headerMajorItems = root->getU8(); + if(headerMajorItems < 3) { + stdext::throw_exception(stdext::format("This map needs to be upgraded. read %d what it's supposed to be: %u", + headerMajorItems, g_things.getOtbMajorVersion())); + } + + if(headerMajorItems > g_things.getOtbMajorVersion()) { + stdext::throw_exception(stdext::format("This map was saved with different OTB version. read %d what it's supposed to be: %d", + headerMajorItems, g_things.getOtbMajorVersion())); + } + + root->skip(3); + uint32 headerMinorItems = root->getU32(); + if(headerMinorItems > g_things.getOtbMinorVersion()) { + g_logger.warning(stdext::format("This map needs an updated OTB. read %d what it's supposed to be: %d or less", + headerMinorItems, g_things.getOtbMinorVersion())); + } + + BinaryTreePtr node = root->getChildren()[0]; + if(node->getU8() != OTBM_MAP_DATA) + stdext::throw_exception("Could not read root data node"); + + while (node->canRead()) { + uint8 attribute = node->getU8(); + std::string tmp = node->getString(); + switch (attribute) { + case OTBM_ATTR_DESCRIPTION: + setDescription(tmp); + break; + case OTBM_ATTR_SPAWN_FILE: + setSpawnFile(fileName.substr(0, fileName.rfind('/') + 1) + tmp); + break; + case OTBM_ATTR_HOUSE_FILE: + setHouseFile(fileName.substr(0, fileName.rfind('/') + 1) + tmp); + break; + default: + stdext::throw_exception(stdext::format("Invalid attribute '%d'", (int)attribute)); + } + } + + for(const BinaryTreePtr &nodeMapData : node->getChildren()) { + uint8 mapDataType = nodeMapData->getU8(); + if(mapDataType == OTBM_TILE_AREA) { + Position basePos = nodeMapData->getPosition(); + + for(const BinaryTreePtr &nodeTile : nodeMapData->getChildren()) { + uint8 type = nodeTile->getU8(); + if(type != OTBM_TILE && type != OTBM_HOUSETILE) + stdext::throw_exception(stdext::format("invalid node tile type %d", (int)type)); + + HousePtr house = nullptr; + uint32 flags = TILESTATE_NONE; + Position pos = basePos + nodeTile->getPoint(); + + if(type == OTBM_HOUSETILE) { + uint32 hId = nodeTile->getU32(); + TilePtr tile = getOrCreateTile(pos); + if(!(house = m_houses.getHouse(hId))) { + house = HousePtr(new House(hId)); + m_houses.addHouse(house); + } + house->setTile(tile); + } + + while(nodeTile->canRead()) { + uint8 tileAttr = nodeTile->getU8(); + switch (tileAttr) { + case OTBM_ATTR_TILE_FLAGS: { + uint32 _flags = nodeTile->getU32(); + if((_flags & TILESTATE_PROTECTIONZONE) == TILESTATE_PROTECTIONZONE) + flags |= TILESTATE_PROTECTIONZONE; + else if((_flags & TILESTATE_OPTIONALZONE) == TILESTATE_OPTIONALZONE) + flags |= TILESTATE_OPTIONALZONE; + else if((_flags & TILESTATE_HARDCOREZONE) == TILESTATE_HARDCOREZONE) + flags |= TILESTATE_HARDCOREZONE; + + if((_flags & TILESTATE_NOLOGOUT) == TILESTATE_NOLOGOUT) + flags |= TILESTATE_NOLOGOUT; + + if((_flags & TILESTATE_REFRESH) == TILESTATE_REFRESH) + flags |= TILESTATE_REFRESH; + + break; + } + case OTBM_ATTR_ITEM: { + addThing(Item::createFromOtb(nodeTile->getU16()), pos); + break; + } + default: { + stdext::throw_exception(stdext::format("invalid tile attribute %d at pos %s", (int)tileAttr, stdext::to_string(pos))); + } + } + } + + for(const BinaryTreePtr &nodeItem : nodeTile->getChildren()) { + if(nodeItem->getU8() != OTBM_ITEM) + stdext::throw_exception("invalid item node"); + + ItemPtr item = Item::createFromOtb(nodeItem->getU16()); + item->unserializeItem(nodeItem); + + if(item->isContainer()) { + for(const BinaryTreePtr& containerItem : nodeItem->getChildren()) { + if(containerItem->getU8() != OTBM_ITEM) + stdext::throw_exception("invalid container item node"); + + ItemPtr cItem = Item::createFromOtb(containerItem->getU16()); + cItem->unserializeItem(containerItem); + //item->addContainerItem(cItem); + } + } + + if(house && item->isMoveable()) { + g_logger.warning(stdext::format("Movable item found in house: %d at pos %s - escaping...", item->getId(), stdext::to_string(pos))); + item.reset(); + } + + addThing(item, pos); + } + + if(const TilePtr& tile = getTile(pos)) + tile->setFlags((tileflags_t)flags); + } + } else if(mapDataType == OTBM_TOWNS) { + TownPtr town = nullptr; + for(const BinaryTreePtr &nodeTown : nodeMapData->getChildren()) { + if(nodeTown->getU8() != OTBM_TOWN) + stdext::throw_exception("invalid town node."); + + uint32 townId = nodeTown->getU32(); + std::string townName = nodeTown->getString(); + Position townCoords = nodeTown->getPosition(); + if(!(town = m_towns.getTown(townId))) { + town = TownPtr(new Town(townId, townName, townCoords)); + m_towns.addTown(town); + } + } + } else if(mapDataType == OTBM_WAYPOINTS && headerVersion > 1) { + for(const BinaryTreePtr &nodeWaypoint : nodeMapData->getChildren()) { + if(nodeWaypoint->getU8() != OTBM_WAYPOINT) + stdext::throw_exception("invalid waypoint node."); + + std::string name = nodeWaypoint->getString(); + Position waypointPos = nodeWaypoint->getPosition(); + if(waypointPos.isValid() && !name.empty() && m_waypoints.find(waypointPos) == m_waypoints.end()) + m_waypoints.insert(std::make_pair(waypointPos, name)); + } + } else + stdext::throw_exception(stdext::format("Unknown map data node %d", (int)mapDataType)); + } + + g_logger.debug("OTBM read successfully."); + fin->close(); + + loadSpawns(getSpawnFile()); + m_houses.load(getHouseFile()); +} + +void Map::saveOtbm(const std::string &fileName) +{ +#if 0 + /// FIXME: Untested code + FileStreamPtr fin = g_resources.appendFile(fileName); + if(!fin) + stdext::throw_exception(stdext::format("failed to open file '%s' for write", fileName)); + + std::string dir; + if(fileName.find_last_of('/') == std::string::npos) + dir = g_resources.getWorkDir(); + else + dir = fileName.substr(0, fileName.find_last_of('/')); + + uint32 version = 0; + /// Support old versions (< 810 or 860 IIRC) + /// TODO: Use constants? + if(g_things.getOtbMajorVersion() < 10) + version = 1; + else + version = 2; + + /// Usually when a map has empty house/spawn file it means the map is new. + /// TODO: Ask the user for a map name instead of those ugly uses of substr + std::string houseFile = getHouseFile(), spawnFile = getSpawnFile(); + if(houseFile.empty() && version > 1) + houseFile = fileName.substr(fileName.find_last_of('/')) + "-houses.xml"; + if(spawnFile.empty()) + spawnFile = fileName.substr(fileName.find_last_of('/')) + "-spawns.xml"; + +#if 0 + if(version > 1) + m_houses->save(dir + "/" + houseFile); + + saveSpawns(dir + "/" + spawnFile); +#endif + + time_t start = time(0); + fin->addU32(0); // file version + BinaryTreePtr root = fin->makeTree(); + { + root->writeU32(version); + + Size mapSize = getSize(); + root->writeU16(mapSize.width()); + root->writeU16(mapSize.height()); + + root->writeU32(g_things.getOtbMajorVersion()); + root->writeU32(g_things.getOtbMinorVersion()); + + BinaryTreePtr mapData = root->makeChild(OTBM_MAP_DATA); + { + // own description. + for(const auto& desc : getDescriptions()) { + mapData->writeU8(OTBM_ATTR_DESCRIPTION); + mapData->writeString(desc); + } + + // special one + mapData->writeU8(OTBM_ATTR_DESCRIPTION); + mapData->writeString(stdext::format("Saved with %s v%d", g_app.getName(), stdext::unsafe_cast(g_app.getVersion()))); + + // spawn file. + mapData->writeU8(OTBM_ATTR_SPAWN_FILE); + mapData->writeString(spawnFile); + + // house file. + if(version > 1) { + mapData->writeU8(OTBM_ATTR_HOUSE_FILE); + mapData->writeString(houseFile); + } + + /// write tiles first + BinaryTreePtr tileArea = mapData->makeChild(OTBM_TILE_AREA); + Position base(-1, -1, -1); + for(const auto& pair : m_tiles) { + Position pos = pair.first; + TilePtr tile = pair.second; + + /// base position + if(pos.x < base.x || pos.x >= base.x + 256 || pos.y < base.y|| pos.y >= base.y + 256 || + pos.z != base.z) { + tileArea->writePos(base = pos & 0xFF00); + } + + BinaryTreePtr tileNode(nullptr); + uint32 flags = tile->getFlags(); + if((flags & TILESTATE_HOUSE) == TILESTATE_HOUSE) + tileNode = tileArea->makeChild(OTBM_HOUSETILE); + else + tileNode = tileArea->makeChild(OTBM_TILE); + + tileNode->writePoint(Point(pos.x, pos.y)); +// if(tileNode->getType() == OTBM_HOUSETILE) +// tileNode->writeU32(tile->getHouseId()); + + /// Tile flags + if(flags != 0) { + tileNode->writeU8(OTBM_ATTR_TILE_FLAGS); + tileNode->writeU32(flags); + } + + /// start writing tile items + for(const ItemPtr& item : tile->getItems()) { + BinaryTreePtr itemNode = tileNode->makeChild(OTBM_ATTR_ITEM); + item->serializeItem(itemNode); + } + } + + /// write towns + BinaryTreePtr townNode = mapData->makeChild(OTBM_TOWNS); + for(const TownPtr& town : m_towns.getTowns()) { + BinaryTreePtr newTown = townNode->makeChild(OTBM_TOWN); + { + newTown->writeU32(town->getId()); + newTown->writeString(town->getName()); + newTown->writePos(town->getPos()); + } + } + + /// write waypoints + if(version > 1) { + BinaryTreePtr waypointNode = mapData->makeChild(OTBM_WAYPOINTS); + for(const auto& it : m_waypoints) { + BinaryTreePtr newWaypoint = waypointNode->makeChild(OTBM_WAYPOINT); + { + newWaypoint->writeString(it.second); + newWaypoint->writePos(it.first); + } + } + } + } + } + + root->writeToFile(); + g_logger.debug(stdext::format("OTBM saving took %ld", time(0) - start)); +#endif +} + +void Map::loadSpawns(const std::string &fileName) +{ + if(!m_creatures.isLoaded()) + stdext::throw_exception("cannot load spawns; monsters/nps aren't loaded."); + + TiXmlDocument doc; + doc.Parse(g_resources.loadFile(fileName).c_str()); + if(doc.Error()) + stdext::throw_exception(stdext::format("cannot load spawns xml file '%s: '%s'", fileName, doc.ErrorDesc())); + + TiXmlElement* root = doc.FirstChildElement(); + if(!root || root->ValueStr() != "spawns") + stdext::throw_exception("malformed spawns file"); + + CreatureTypePtr cType(nullptr); + for(TiXmlElement* node = root->FirstChildElement(); node; node = node->NextSiblingElement()) { + if(node->ValueTStr() != "spawn") + stdext::throw_exception("invalid spawn node"); + + Position centerPos = node->readPos("center"); + for(TiXmlElement* cNode = node->FirstChildElement(); cNode; cNode = cNode->NextSiblingElement()) { + if(cNode->ValueStr() != "monster" && cNode->ValueStr() != "npc") + stdext::throw_exception(stdext::format("invalid spawn-subnode %s", cNode->ValueStr())); + + std::string cName = cNode->Attribute("name"); + stdext::tolower(cName); + stdext::trim(cName); + + if (!(cType = m_creatures.getCreature(cName))) + continue; + + cType->setSpawnTime(cNode->readType("spawntime")); + CreaturePtr creature(new Creature); + creature->setOutfit(cType->getOutfit()); + creature->setName(cType->getName()); + + addThing(creature, centerPos + cNode->readPoint()); + } + } + + doc.Clear(); +} + +bool Map::loadOtcm(const std::string& fileName) +{ + try { + FileStreamPtr fin = g_resources.openFile(fileName); + if(!fin) + stdext::throw_exception("unable to open file"); + + stdext::timer loadTimer; + fin->cache(); + + uint32 signature = fin->getU32(); + if(signature != OTCM_SIGNATURE) + stdext::throw_exception("invalid otcm file"); + + uint16 start = fin->getU16(); + uint16 version = fin->getU16(); + fin->getU32(); // flags + + switch(version) { + case 1: { + fin->getString(); // description + uint32 datSignature = fin->getU32(); + fin->getU16(); // protocol version + fin->getString(); // world name + + if(datSignature != g_things.getDatSignature()) + g_logger.warning("otcm map loaded was created with a different dat signature"); + + break; + } + default: + stdext::throw_exception("otcm version not supported"); + } + + fin->seek(start); + + while(true) { + Position pos; + + pos.x = fin->getU16(); + pos.y = fin->getU16(); + pos.z = fin->getU8(); + + // end of file + if(!pos.isValid()) + break; + + const TilePtr& tile = g_map.createTile(pos); + + int stackPos = 0; + while(true) { + int id = fin->getU16(); + + // end of tile + if(id == 0xFFFF) + break; + + int countOrSubType = fin->getU8(); + + ItemPtr item = Item::create(id); + item->setCountOrSubType(countOrSubType); + + if(item->isValid()) + tile->addThing(item, stackPos++); + } + } + + fin->close(); + + g_logger.debug(stdext::format("Otcm load time: %.2f seconds", loadTimer.elapsed_seconds())); + return true; + } catch(stdext::exception& e) { + g_logger.error(stdext::format("failed to load OTCM map: %s", e.what())); + return false; + } +} + +void Map::saveOtcm(const std::string& fileName) +{ +#if 0 + try { + g_clock.update(); + + FileStreamPtr fin = g_resources.createFile(fileName); + fin->cache(); + + //TODO: compression flag with zlib + uint32 flags = 0; + + // header + fin->addU32(OTCM_SIGNATURE); + fin->addU16(0); // data start, will be overwritten later + fin->addU16(OTCM_VERSION); + fin->addU32(flags); + + // version 1 header + fin->addString("OTCM 1.0"); // map description + fin->addU32(g_things.getDatSignature()); + fin->addU16(g_game.getClientVersion()); + fin->addString(g_game.getWorldName()); + + // go back and rewrite where the map data starts + uint32 start = fin->tell(); + fin->seek(4); + fin->addU16(start); + fin->seek(start); + + for(auto& pair : m_tiles) { + const TilePtr& tile = pair.second; + if(!tile || tile->isEmpty()) + continue; + + Position pos = pair.first; + fin->addU16(pos.x); + fin->addU16(pos.y); + fin->addU8(pos.z); + + const auto& list = tile->getThings(); + auto first = std::find_if(list.begin(), list.end(), [](const ThingPtr& thing) { return thing->isItem(); }); + for(auto it = first, end = list.end(); it != end; ++it) { + const ThingPtr& thing = *it; + if(thing->isItem()) { + ItemPtr item = thing->static_self_cast(); + fin->addU16(item->getId()); + fin->addU8(item->getCountOrSubType()); + } + } + + // end of tile + fin->addU16(0xFFFF); + } + + // end of file + Position invalidPos; + fin->addU16(invalidPos.x); + fin->addU16(invalidPos.y); + fin->addU8(invalidPos.z); + + fin->flush(); + fin->close(); + } catch(stdext::exception& e) { + g_logger.error(stdext::format("failed to save OTCM map: %s", e.what())); + } +#endif +} \ No newline at end of file diff --git a/src/otclient/mapview.h b/src/otclient/mapview.h index 42fdffd2..ef72231e 100644 --- a/src/otclient/mapview.h +++ b/src/otclient/mapview.h @@ -103,7 +103,7 @@ public: // get tile TilePtr getTile(const Point& mousePos, const Rect& mapRect); - MapViewPtr asMapView() { return self_cast(); } + MapViewPtr asMapView() { return static_self_cast(); } private: int calcFirstVisibleFloor(); diff --git a/src/otclient/missile.h b/src/otclient/missile.h index de16a60c..6dc63088 100644 --- a/src/otclient/missile.h +++ b/src/otclient/missile.h @@ -42,7 +42,7 @@ public: uint32 getId() { return m_id; } - MissilePtr asMissile() { return self_cast(); } + MissilePtr asMissile() { return static_self_cast(); } bool isMissile() { return true; } const ThingTypePtr& getThingType(); diff --git a/src/otclient/player.h b/src/otclient/player.h index c2f58952..aa68b600 100644 --- a/src/otclient/player.h +++ b/src/otclient/player.h @@ -32,7 +32,7 @@ public: Player() { } virtual ~Player() { } - PlayerPtr asPlayer() { return self_cast(); } + PlayerPtr asPlayer() { return static_self_cast(); } bool isPlayer() { return true; } }; diff --git a/src/otclient/position.h b/src/otclient/position.h index 9c49c5b1..4d140829 100644 --- a/src/otclient/position.h +++ b/src/otclient/position.h @@ -151,6 +151,7 @@ public: return Otc::InvalidDirection; } + bool isMapPosition() const { return (x < 65535 && y < 65535 && z <= Otc::MAX_Z); } bool isValid() const { return !(x == 65535 && y == 65535 && z == 255); } float distance(const Position& pos) const { return sqrt(pow((pos.x - x), 2) + pow((pos.y - y), 2)); } int manhattanDistance(const Position& pos) const { return std::abs(pos.x - x) + std::abs(pos.y - y); } diff --git a/src/otclient/protocolgameparse.cpp b/src/otclient/protocolgameparse.cpp index 844df6be..b69517f0 100644 --- a/src/otclient/protocolgameparse.cpp +++ b/src/otclient/protocolgameparse.cpp @@ -499,7 +499,6 @@ void ProtocolGame::parseCreatureMove(const InputMessagePtr& msg) return; } - int stackPos = -2; // newer protocols stores creatures in reverse order if(!g_game.getClientVersion() >= 854) @@ -507,6 +506,10 @@ void ProtocolGame::parseCreatureMove(const InputMessagePtr& msg) g_map.removeThing(thing); g_map.addThing(thing, newPos, stackPos); + + //CreaturePtr creature = thing->static_self_cast(); + //Position oldPos = thing->getPosition(); + //creature->onMove(newPos, oldPos); } void ProtocolGame::parseOpenContainer(const InputMessagePtr& msg) diff --git a/src/otclient/statictext.h b/src/otclient/statictext.h index 381287bb..006e9372 100644 --- a/src/otclient/statictext.h +++ b/src/otclient/statictext.h @@ -43,7 +43,7 @@ public: bool addMessage(const std::string& name, Otc::MessageMode mode, const std::string& text); - StaticTextPtr asStaticText() { return self_cast(); } + StaticTextPtr asStaticText() { return static_self_cast(); } bool isStaticText() { return true; } private: diff --git a/src/otclient/thing.cpp b/src/otclient/thing.cpp index 0bb66220..8cf233bb 100644 --- a/src/otclient/thing.cpp +++ b/src/otclient/thing.cpp @@ -33,6 +33,13 @@ Thing::Thing() : { } +void Thing::setPosition(const Position& position) +{ + Position oldPos = m_position; + m_position = position; + onPositionChange(position, oldPos); +} + int Thing::getStackPriority() { if(isGround()) @@ -68,7 +75,7 @@ int Thing::getStackpos() if(m_position.x == 65535 && isItem()) // is inside a container return m_position.z; else if(const TilePtr& tile = getTile()) - return tile->getThingStackpos(self_cast()); + return tile->getThingStackpos(static_self_cast()); else { g_logger.traceError("got a thing with invalid stackpos"); return -1; diff --git a/src/otclient/thing.h b/src/otclient/thing.h index a7f7c8dc..2373e547 100644 --- a/src/otclient/thing.h +++ b/src/otclient/thing.h @@ -36,11 +36,10 @@ public: Thing(); virtual ~Thing() { } - virtual void startAnimation() { } virtual void draw(const Point& dest, float scaleFactor, bool animate) { } virtual void setId(uint32 id) { } - void setPosition(const Position& position) { m_position = position; } + void setPosition(const Position& position); virtual uint32 getId() { return 0; } Position getPosition() { return m_position; } @@ -119,8 +118,13 @@ public: bool isMarketable() { return rawGetThingType()->isMarketable(); } MarketData getMarketData() { return rawGetThingType()->getMarketData(); } - protected: + virtual void onPositionChange(const Position& newPos, const Position& oldPos) { } + virtual void onAppear() { } + virtual void onDisappear() { } + + friend class Map; + Position m_position; uint16 m_datId; }; diff --git a/src/otclient/thingtype.cpp b/src/otclient/thingtype.cpp index 568bad1d..5fe00ec8 100644 --- a/src/otclient/thingtype.cpp +++ b/src/otclient/thingtype.cpp @@ -39,6 +39,7 @@ ThingType::ThingType() m_numPatternX = m_numPatternY = m_numPatternZ = 0; m_animationPhases = 0; m_layers = 0; + m_elevation = 0; } void ThingType::unserialize(uint16 clientId, ThingCategory category, const FileStreamPtr& fin) @@ -88,10 +89,14 @@ void ThingType::unserialize(uint16 clientId, ThingCategory category, const FileS m_attribs.set(attr, market); break; } + case ThingAttrElevation: { + m_elevation = fin->getU16(); + m_attribs.set(attr, m_elevation); + break; + } case ThingAttrGround: case ThingAttrWritable: case ThingAttrWritableOnce: - case ThingAttrElevation: case ThingAttrMinimapColor: case ThingAttrCloth: case ThingAttrLensHelp: diff --git a/src/otclient/thingtype.h b/src/otclient/thingtype.h index 36752419..74be2afa 100644 --- a/src/otclient/thingtype.h +++ b/src/otclient/thingtype.h @@ -126,6 +126,7 @@ public: Point getDisplacement() { return m_displacement; } int getDisplacementX() { return getDisplacement().x; } int getDisplacementY() { return getDisplacement().y; } + int getElevation() { return m_elevation; } int getGroundSpeed() { return m_attribs.get(ThingAttrGround); } int getMaxTextLength() { return m_attribs.has(ThingAttrWritableOnce) ? m_attribs.get(ThingAttrWritableOnce) : m_attribs.get(ThingAttrWritable); } @@ -133,7 +134,6 @@ public: int getMinimapColor() { return m_attribs.get(ThingAttrMinimapColor); } int getLensHelp() { return m_attribs.get(ThingAttrLensHelp); } int getClothSlot() { return m_attribs.get(ThingAttrCloth); } - int getElevation() { return m_attribs.get(ThingAttrElevation); } MarketData getMarketData() { return m_attribs.get(ThingAttrMarket); } bool isGround() { return m_attribs.has(ThingAttrGround); } bool isGroundBorder() { return m_attribs.has(ThingAttrGroundBorder); } @@ -180,7 +180,7 @@ private: ThingCategory m_category; uint16 m_id; bool m_null; - stdext::attrib_storage m_attribs; + stdext::dynamic_storage m_attribs; Size m_size; Point m_displacement; @@ -188,6 +188,7 @@ private: int m_numPatternX, m_numPatternY, m_numPatternZ; int m_animationPhases; int m_layers; + int m_elevation; std::vector m_spritesIndex; std::vector m_textures; diff --git a/src/otclient/tile.cpp b/src/otclient/tile.cpp index b1155f93..0048eefe 100644 --- a/src/otclient/tile.cpp +++ b/src/otclient/tile.cpp @@ -113,7 +113,7 @@ void Tile::draw(const Point& dest, float scaleFactor, int drawFlags) const ThingPtr& thing = *it; if(!thing->isCreature()) continue; - CreaturePtr creature = thing->self_cast(); + CreaturePtr creature = thing->static_self_cast(); if(creature && (!creature->isWalking() || !animate)) creature->draw(dest - m_drawElevation*scaleFactor, scaleFactor, animate); } @@ -158,7 +158,7 @@ void Tile::addThing(const ThingPtr& thing, int stackPos) return; if(thing->isEffect()) { - m_effects.push_back(thing->self_cast()); + m_effects.push_back(thing->static_self_cast()); return; } @@ -205,7 +205,7 @@ bool Tile::removeThing(ThingPtr thing) bool removed = false; if(thing->isEffect()) { - EffectPtr effect = thing->self_cast(); + EffectPtr effect = thing->static_self_cast(); auto it = std::find(m_effects.begin(), m_effects.end(), effect); if(it != m_effects.end()) { m_effects.erase(it); @@ -267,7 +267,7 @@ std::vector Tile::getItems() for(const ThingPtr& thing : m_things) { if(!thing->isItem()) continue; - ItemPtr item = thing->self_cast(); + ItemPtr item = thing->static_self_cast(); items.push_back(item); } return items; @@ -278,7 +278,7 @@ std::vector Tile::getCreatures() std::vector creatures; for(const ThingPtr& thing : m_things) { if(thing->isCreature()) - creatures.push_back(thing->self_cast()); + creatures.push_back(thing->static_self_cast()); } return creatures; } @@ -289,7 +289,7 @@ ItemPtr Tile::getGround() if(!firstObject) return nullptr; if(firstObject->isGround() && firstObject->isItem()) - return firstObject->self_cast(); + return firstObject->static_self_cast(); return nullptr; } @@ -348,9 +348,9 @@ CreaturePtr Tile::getTopCreature() for(uint i = 0; i < m_things.size(); ++i) { ThingPtr thing = m_things[i]; if(thing->isLocalPlayer()) // return local player if there is no other creature - creature = thing->self_cast(); + creature = thing->static_self_cast(); else if(thing->isCreature() && !thing->isLocalPlayer()) - return thing->self_cast(); + return thing->static_self_cast(); } if(!creature && !m_walkingCreatures.empty()) creature = m_walkingCreatures.back(); @@ -408,7 +408,7 @@ bool Tile::isWalkable() return false; if(thing->isCreature()) { - CreaturePtr creature = thing->self_cast(); + CreaturePtr creature = thing->static_self_cast(); if(!creature->isPassable()) return false; } diff --git a/src/otclient/tile.h b/src/otclient/tile.h index a45f0e79..bfcbf161 100644 --- a/src/otclient/tile.h +++ b/src/otclient/tile.h @@ -85,7 +85,7 @@ public: int getDrawElevation() { return m_drawElevation; } std::vector getItems(); std::vector getCreatures(); - const std::vector& getThings() { return m_things; } + std::vector getThings() { return m_things; } ItemPtr getGround(); int getGroundSpeed(); uint8 getMinimapColorByte(); @@ -109,12 +109,12 @@ public: void setHouseId(uint32 hid) { if(m_flags & TILESTATE_HOUSE) m_houseId = hid; } uint32 getHouseId() { return m_houseId; } - TilePtr asTile() { return self_cast(); } + TilePtr asTile() { return static_self_cast(); } private: - std::vector m_walkingCreatures; - std::vector m_effects; // leave this outside m_things because it has no stackpos. - std::vector m_things; + stdext::packed_vector m_walkingCreatures; + stdext::packed_vector m_effects; // leave this outside m_things because it has no stackpos. + stdext::packed_vector m_things; Position m_position; uint8 m_drawElevation; uint32 m_flags, m_houseId;