Rework stdext classes

Implement new classes:
* stdext::any => ligher replacement for boost::any
* stdext::packed_any => like any but optimized to use less memory
* stdext::shared_object => ligher replacement for std::shared_ptr
* stdext::shared_object_ptr => replacement for boost::intrusive_ptr
* stdext::fast_storage => for storing dynamic data
* stdext::packed_storage => same but with less memory
* stdext::packed_vector => std::vector with less memory

Compiling should be a little faster now because global boost including
is not needed anymore
This commit is contained in:
Eduardo Bart 2012-08-01 04:49:09 -03:00
parent 1dc7dc0cfc
commit 3bac3dcbb4
92 changed files with 1885 additions and 1208 deletions

View File

@ -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/stdext.h
${CMAKE_CURRENT_LIST_DIR}/stdext/string.h
${CMAKE_CURRENT_LIST_DIR}/stdext/time.h
${CMAKE_CURRENT_LIST_DIR}/stdext/types.h
${CMAKE_CURRENT_LIST_DIR}/stdext/attrib_storage.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
# core
${CMAKE_CURRENT_LIST_DIR}/core/application.cpp

View File

@ -33,11 +33,11 @@ class ScheduledEvent;
class FileStream;
class BinaryTree;
typedef boost::intrusive_ptr<Module> ModulePtr;
typedef boost::intrusive_ptr<Event> EventPtr;
typedef boost::intrusive_ptr<ScheduledEvent> ScheduledEventPtr;
typedef boost::intrusive_ptr<FileStream> FileStreamPtr;
typedef boost::intrusive_ptr<BinaryTree> BinaryTreePtr;
typedef stdext::shared_object_ptr<Module> ModulePtr;
typedef stdext::shared_object_ptr<Event> EventPtr;
typedef stdext::shared_object_ptr<ScheduledEvent> ScheduledEventPtr;
typedef stdext::shared_object_ptr<FileStream> FileStreamPtr;
typedef stdext::shared_object_ptr<BinaryTree> BinaryTreePtr;
typedef std::vector<BinaryTreePtr> BinaryTreeVec;

View File

@ -26,6 +26,8 @@
#include "clock.h"
#include "scheduledevent.h"
#include <queue>
// @bindsingleton g_dispatcher
class EventDispatcher
{

View File

@ -62,7 +62,7 @@ public:
void addString(const std::string& v);
BinaryTreePtr makeTree();
FileStreamPtr asFileStream() { return self_cast<FileStream>(); }
FileStreamPtr asFileStream() { return static_self_cast<FileStream>(); }
private:
void checkWrite();

View File

@ -25,6 +25,8 @@
#include "../global.h"
#include <fstream>
struct LogMessage {
LogMessage(Fw::LogLevel level, const std::string& message, std::size_t when) : level(level), message(message), when(when) { }
Fw::LogLevel level;

View File

@ -56,7 +56,7 @@ public:
int getAutoLoadPriority() { return m_autoLoadPriority; }
// @dontbind
ModulePtr asModule() { return self_cast<Module>(); }
ModulePtr asModule() { return static_self_cast<Module>(); }
protected:
void discover(const OTMLNodePtr& moduleNode);

View File

@ -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));

View File

@ -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<std::string> 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;
}

View File

@ -34,7 +34,7 @@ public:
void enableBilinearFilter();
void processAnimation();
AnimatedTexturePtr asAnimatedTexture() { return self_cast<AnimatedTexture>(); }
AnimatedTexturePtr asAnimatedTexture() { return static_self_cast<AnimatedTexture>(); }
private:
std::vector<uint> m_framesTextureId;

View File

@ -44,21 +44,21 @@ class ParticleSystem;
class ParticleEffect;
class ParticleEffectType;
typedef boost::intrusive_ptr<Image> ImagePtr;
typedef boost::intrusive_ptr<Texture> TexturePtr;
typedef boost::intrusive_ptr<AnimatedTexture> AnimatedTexturePtr;
typedef boost::intrusive_ptr<BitmapFont> BitmapFontPtr;
typedef boost::intrusive_ptr<CachedText> CachedTextPtr;
typedef boost::intrusive_ptr<FrameBuffer> FrameBufferPtr;
typedef boost::intrusive_ptr<Shader> ShaderPtr;
typedef boost::intrusive_ptr<ShaderProgram> ShaderProgramPtr;
typedef boost::intrusive_ptr<PainterShaderProgram> PainterShaderProgramPtr;
typedef boost::intrusive_ptr<Particle> ParticlePtr;
typedef boost::intrusive_ptr<ParticleEmitter> ParticleEmitterPtr;
typedef boost::intrusive_ptr<ParticleAffector> ParticleAffectorPtr;
typedef boost::intrusive_ptr<ParticleSystem> ParticleSystemPtr;
typedef boost::intrusive_ptr<ParticleEffect> ParticleEffectPtr;
typedef boost::intrusive_ptr<ParticleEffectType> ParticleEffectTypePtr;
typedef stdext::shared_object_ptr<Image> ImagePtr;
typedef stdext::shared_object_ptr<Texture> TexturePtr;
typedef stdext::shared_object_ptr<AnimatedTexture> AnimatedTexturePtr;
typedef stdext::shared_object_ptr<BitmapFont> BitmapFontPtr;
typedef stdext::shared_object_ptr<CachedText> CachedTextPtr;
typedef stdext::shared_object_ptr<FrameBuffer> FrameBufferPtr;
typedef stdext::shared_object_ptr<Shader> ShaderPtr;
typedef stdext::shared_object_ptr<ShaderProgram> ShaderProgramPtr;
typedef stdext::shared_object_ptr<PainterShaderProgram> PainterShaderProgramPtr;
typedef stdext::shared_object_ptr<Particle> ParticlePtr;
typedef stdext::shared_object_ptr<ParticleEmitter> ParticleEmitterPtr;
typedef stdext::shared_object_ptr<ParticleAffector> ParticleAffectorPtr;
typedef stdext::shared_object_ptr<ParticleSystem> ParticleSystemPtr;
typedef stdext::shared_object_ptr<ParticleEffect> ParticleEffectPtr;
typedef stdext::shared_object_ptr<ParticleEffectType> ParticleEffectTypePtr;
typedef std::vector<ShaderPtr> ShaderList;
#endif

View File

@ -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);

View File

@ -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

View File

@ -84,7 +84,7 @@ void ParticleSystem::update()
return;
m_lastUpdateTime = g_clock.seconds() - std::fmod(elapsedTime, delay);
auto self = self_cast<ParticleSystem>();
auto self = static_self_cast<ParticleSystem>();
for(int i = 0; i < elapsedTime / delay; ++i) {
// update emitters

View File

@ -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

View File

@ -25,11 +25,13 @@
#include <framework/global.h>
#include <memory>
class LuaInterface;
class LuaObject;
typedef std::function<int(LuaInterface*)> LuaCppFunction;
typedef std::unique_ptr<LuaCppFunction> LuaCppFunctionPtr;
typedef boost::intrusive_ptr<LuaObject> LuaObjectPtr;
typedef stdext::shared_object_ptr<LuaObject> LuaObjectPtr;
#endif

View File

@ -27,6 +27,9 @@
#include "luainterface.h"
#include "luaexception.h"
#include <framework/stdext/traits.h>
#include <tuple>
/// 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<typename T>
struct remove_const_ref {
typedef typename std::remove_const<typename std::remove_reference<T>::type>::type type;
};
/// Pack arguments from lua stack into a tuple recursively
template<int N>
struct pack_values_into_tuple {
@ -117,8 +114,8 @@ namespace luabinder
/// Bind a std::function
template<typename Ret, typename... Args>
LuaCppFunction bind_fun(const std::function<Ret(Args...)>& f) {
typedef typename std::tuple<typename remove_const_ref<Args>::type...> Tuple;
return bind_fun_specializer<typename remove_const_ref<Ret>::type,
typedef typename std::tuple<typename stdext::remove_const_ref<Args>::type...> Tuple;
return bind_fun_specializer<typename stdext::remove_const_ref<Ret>::type,
decltype(f),
Tuple>(f);
}
@ -130,8 +127,8 @@ namespace luabinder
template<typename Lambda, typename Ret, typename... Args>
struct bind_lambda_fun<Ret(Lambda::*)(Args...) const> {
static LuaCppFunction call(const Lambda& f) {
typedef typename std::tuple<typename remove_const_ref<Args>::type...> Tuple;
return bind_fun_specializer<typename remove_const_ref<Ret>::type,
typedef typename std::tuple<typename stdext::remove_const_ref<Args>::type...> Tuple;
return bind_fun_specializer<typename stdext::remove_const_ref<Ret>::type,
decltype(f),
Tuple>(f);
@ -152,18 +149,18 @@ namespace luabinder
/// Create member function lambdas
template<typename Ret, typename C, typename... Args>
std::function<Ret(const boost::intrusive_ptr<C>&, const Args&...)> make_mem_func(Ret (C::* f)(Args...)) {
std::function<Ret(const stdext::shared_object_ptr<C>&, const Args&...)> make_mem_func(Ret (C::* f)(Args...)) {
auto mf = std::mem_fn(f);
return [=](const boost::intrusive_ptr<C>& obj, const Args&... args) mutable -> Ret {
return [=](const stdext::shared_object_ptr<C>& 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<typename C, typename... Args>
std::function<void(const boost::intrusive_ptr<C>&, const Args&...)> make_mem_func(void (C::* f)(Args...)) {
std::function<void(const stdext::shared_object_ptr<C>&, const Args&...)> make_mem_func(void (C::* f)(Args...)) {
auto mf = std::mem_fn(f);
return [=](const boost::intrusive_ptr<C>& obj, const Args&... args) mutable -> void {
return [=](const stdext::shared_object_ptr<C>& 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<typename C, typename Ret, class FC, typename... Args>
LuaCppFunction bind_mem_fun(Ret (FC::* f)(Args...)) {
typedef typename std::tuple<boost::intrusive_ptr<FC>, typename remove_const_ref<Args>::type...> Tuple;
typedef typename std::tuple<stdext::shared_object_ptr<FC>, typename stdext::remove_const_ref<Args>::type...> Tuple;
auto lambda = make_mem_func<Ret,FC>(f);
return bind_fun_specializer<typename remove_const_ref<Ret>::type,
return bind_fun_specializer<typename stdext::remove_const_ref<Ret>::type,
decltype(lambda),
Tuple>(lambda);
}
@ -196,10 +193,10 @@ namespace luabinder
/// Bind singleton member functions
template<typename C, typename Ret, class FC, typename... Args>
LuaCppFunction bind_singleton_mem_fun(Ret (FC::*f)(Args...), C *instance) {
typedef typename std::tuple<typename remove_const_ref<Args>::type...> Tuple;
typedef typename std::tuple<typename stdext::remove_const_ref<Args>::type...> Tuple;
assert(instance);
auto lambda = make_mem_func_singleton<Ret,FC>(f, static_cast<FC*>(instance));
return bind_fun_specializer<typename remove_const_ref<Ret>::type,
return bind_fun_specializer<typename stdext::remove_const_ref<Ret>::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<boost::intrusive_ptr<C>>(1);
auto obj = lua->castValue<stdext::shared_object_ptr<C>>(1);
lua->remove(1);
return mf(obj, lua);
};

View File

@ -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 {

View File

@ -320,7 +320,7 @@ public:
/// Pushes any type onto the stack
template<typename T, typename... Args>
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<typename T, typename... Args>
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...);
}

View File

@ -24,6 +24,7 @@
#define LUAOBJECT_H
#include "declarations.h"
#include <typeinfo>
/// 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<LuaObject>(); }
LuaObjectPtr asLuaObject() { return static_self_cast<LuaObject>(); }
void operator=(const LuaObject& other) { }

View File

@ -111,7 +111,7 @@ bool luavalue_cast(int index, LuaObjectPtr& obj);
template<class T>
typename std::enable_if<std::is_base_of<LuaObject, T>::value, bool>::type
luavalue_cast(int index, boost::intrusive_ptr<T>& ptr);
luavalue_cast(int index, stdext::shared_object_ptr<T>& ptr);
// std::function
template<typename Ret, typename... Args>
@ -186,7 +186,7 @@ push_luavalue(const T& obj) {
template<class T>
typename std::enable_if<std::is_base_of<LuaObject, T>::value, bool>::type
luavalue_cast(int index, boost::intrusive_ptr<T>& ptr) {
luavalue_cast(int index, stdext::shared_object_ptr<T>& ptr) {
LuaObjectPtr obj;
if(!luavalue_cast(index, obj))
return false;

View File

@ -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();

View File

@ -62,7 +62,7 @@ public:
bool isConnecting() { return m_connecting; }
bool isConnected() { return m_connected; }
ConnectionPtr asConnection() { return self_cast<Connection>(); }
ConnectionPtr asConnection() { return static_self_cast<Connection>(); }
protected:
void onConnect(const boost::system::error_code& error);
void onWrite(const boost::system::error_code& error, size_t);

View File

@ -34,10 +34,10 @@ class Connection;
class Protocol;
class Server;
typedef boost::intrusive_ptr<InputMessage> InputMessagePtr;
typedef boost::intrusive_ptr<OutputMessage> OutputMessagePtr;
typedef boost::intrusive_ptr<Connection> ConnectionPtr;
typedef boost::intrusive_ptr<Protocol> ProtocolPtr;
typedef boost::intrusive_ptr<Server> ServerPtr;
typedef stdext::shared_object_ptr<InputMessage> InputMessagePtr;
typedef stdext::shared_object_ptr<OutputMessage> OutputMessagePtr;
typedef stdext::shared_object_ptr<Connection> ConnectionPtr;
typedef stdext::shared_object_ptr<Protocol> ProtocolPtr;
typedef stdext::shared_object_ptr<Server> ServerPtr;
#endif

View File

@ -54,7 +54,7 @@ public:
virtual void send(const OutputMessagePtr& outputMessage);
void recv();
ProtocolPtr asProtocol() { return self_cast<Protocol>(); }
ProtocolPtr asProtocol() { return static_self_cast<Protocol>(); }
protected:
virtual void onConnect();

View File

@ -30,8 +30,8 @@ class OTMLDocument;
class OTMLParser;
class OTMLEmitter;
typedef boost::intrusive_ptr<OTMLNode> OTMLNodePtr;
typedef boost::intrusive_ptr<OTMLDocument> OTMLDocumentPtr;
typedef stdext::shared_object_ptr<OTMLNode> OTMLNodePtr;
typedef stdext::shared_object_ptr<OTMLDocument> OTMLDocumentPtr;
typedef std::vector<OTMLNodePtr> OTMLNodeList;
#endif

View File

@ -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];
}

View File

@ -89,7 +89,7 @@ public:
virtual std::string emit();
OTMLNodePtr asOTMLNode() { return self_cast<OTMLNode>(); }
OTMLNodePtr asOTMLNode() { return static_self_cast<OTMLNode>(); }
protected:
OTMLNode() : m_unique(false), m_null(false) { }
@ -107,13 +107,13 @@ protected:
template<>
inline std::string OTMLNode::value<std::string>() {
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;
}

View File

@ -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<boost::escaped_list_separator<char>> 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);
}

View File

@ -28,40 +28,19 @@
#include <cstdlib>
#include <cstring>
#include <cassert>
#include <ctime>
#include <cmath>
#include <csignal>
// common STL headers
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <vector>
#include <list>
#include <bitset>
#include <queue>
#include <deque>
#include <stack>
#include <map>
#include <algorithm>
#include <exception>
#include <memory>
#include <type_traits>
#include <tuple>
#include <functional>
#include <typeinfo>
#include <array>
#include <iomanip>
#include <unordered_map>
#include <random>
#include <chrono>
#include <thread>
#include <mutex>
#include <atomic>
#include <thread>
// boost utilities
#include <boost/algorithm/string.hpp>
#endif

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -38,11 +38,11 @@ class StreamSoundSource;
class CombinedSoundSource;
class OggSoundFile;
typedef boost::intrusive_ptr<SoundSource> SoundSourcePtr;
typedef boost::intrusive_ptr<SoundFile> SoundFilePtr;
typedef boost::intrusive_ptr<SoundBuffer> SoundBufferPtr;
typedef boost::intrusive_ptr<StreamSoundSource> StreamSoundSourcePtr;
typedef boost::intrusive_ptr<CombinedSoundSource> CombinedSoundSourcePtr;
typedef boost::intrusive_ptr<OggSoundFile> OggSoundFilePtr;
typedef stdext::shared_object_ptr<SoundSource> SoundSourcePtr;
typedef stdext::shared_object_ptr<SoundFile> SoundFilePtr;
typedef stdext::shared_object_ptr<SoundBuffer> SoundBufferPtr;
typedef stdext::shared_object_ptr<StreamSoundSource> StreamSoundSourcePtr;
typedef stdext::shared_object_ptr<CombinedSoundSource> CombinedSoundSourcePtr;
typedef stdext::shared_object_ptr<OggSoundFile> OggSoundFilePtr;
#endif

View File

@ -0,0 +1,77 @@
/*
* Copyright (c) 2010-2012 OTClient <https://github.com/edubart/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 <algorithm>
#include <cassert>
#include <typeinfo>
namespace stdext {
class any {
public:
struct placeholder {
virtual ~placeholder() { }
virtual const std::type_info& type() const = 0;
virtual placeholder* clone() const = 0;
};
template<typename T>
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<typename T> any(const T& value) : content(new holder<T>(value)) { }
~any() { if(content) delete content; }
any& swap(any& rhs) { std::swap(content, rhs.content); return *this; }
template<typename T> 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<typename T> const T& cast() const;
const std::type_info & type() const { return content ? content->type() : typeid(void); }
};
template<typename T>
const T& any_cast(const any& operand) {
assert(operand.type() == typeid(T));
return static_cast<any::holder<T>*>(operand.content)->held;
}
template<typename T> const T& any::cast() const { return any_cast<T>(*this); }
}
#endif

View File

@ -23,15 +23,13 @@
#ifndef STDEXT_CAST_H
#define STDEXT_CAST_H
namespace stdext {
template<typename R, typename T> R safe_cast(const T& t);
template<typename R, typename T> R unsafe_cast(const T& t, R def = R());
}
#include "string.h"
#include "exception.h"
#include "demangle.h"
#include <sstream>
#include <iostream>
#include <cstdlib>
namespace stdext {
// cast a type to another type
@ -142,7 +140,9 @@ public:
virtual ~cast_exception() throw() { }
template<class T, class R>
void update_what() {
m_what = format("failed to cast value of type '%s' to type '%s'", demangle_type<T>(), demangle_type<R>());
std::stringstream ss;
ss << "failed to cast value of type '" << demangle_type<T>() << "' to type '" << demangle_type<R>() << "'";
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<typename R, typename T>
R unsafe_cast(const T& t, R def) {
R unsafe_cast(const T& t, R def = R()) {
try {
return safe_cast<R,T>(t);
} catch(cast_exception& e) {
std::cout << "CAST ERROR: " << e.what() << std::endl;
std::cerr << "CAST ERROR: " << e.what() << std::endl;
return def;
}
}
}
#endif

View File

@ -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."

View File

@ -0,0 +1,44 @@
/*
* Copyright (c) 2010-2012 OTClient <https://github.com/edubart/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 <cxxabi.h>
#include <cstring>
#include <cstdlib>
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;
}
}

View File

@ -23,29 +23,16 @@
#ifndef STDEXT_DEMANGLE_H
#define STDEXT_DEMANGLE_H
#include <cxxabi.h>
#include <typeinfo>
#include <string>
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<typename T>
std::string demangle_type() {
return demangle_name(typeid(T).name());
}
template<typename T> std::string demangle_type() { return demangle_name(typeid(T).name()); }
}

View File

@ -27,30 +27,13 @@
namespace stdext {
namespace dumper {
struct dumper_dummy {
static struct {
struct dumper_dummy {
~dumper_dummy() { std::cout << std::endl; }
template<class T>
dumper_dummy& operator<<(const T& v) {
std::cout << v << " ";
return *this;
}
};
struct dumper_util {
dumper_util() { }
template<class T>
dumper_dummy operator<<(const T& v) const {
dumper_dummy d;
d << v;
return d;
}
};
}
const static dumper::dumper_util dump;
template<class T> dumper_dummy& operator<<(const T& v) { std::cout << v << " "; return *this; }
};
template<class T> dumper_dummy operator<<(const T& v) const { dumper_dummy d; d << v; return d; }
} dump;
}

View File

@ -0,0 +1,53 @@
/*
* Copyright (c) 2010-2012 OTClient <https://github.com/edubart/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 <unordered_map>
namespace stdext {
template<typename Key>
class dynamic_storage {
public:
template<typename T> void set(const Key& k, const T& value) { m_map[k] = value; }
template<typename T> T get(const Key& k) const {
auto it = m_map.find(k);
if(it != m_map.end())
return any_cast<T>(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<Key, any> m_map;
};
}
#endif

View File

@ -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;
};

View File

@ -0,0 +1,86 @@
/*
* Copyright (c) 2010-2012 OTClient <https://github.com/edubart/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 <string>
#include <cstdio>
#include <cassert>
#include <tuple>
#include <iostream>
#include <sstream>
#include <iomanip>
namespace stdext {
template<class T> void print_ostream(std::ostringstream& stream, const T& last) { stream << last; }
template<class T, class... Args>
void print_ostream(std::ostringstream& stream, const T& first, const Args&... rest) { stream << "\t" << first; print_ostream(stream, rest...); }
template<class... T>
/// 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 T>
typename std::enable_if<std::is_integral<T>::value ||
std::is_pointer<T>::value ||
std::is_floating_point<T>::value ||
std::is_enum<T>::value, T>::type sprintf_cast(const T& t) { return t; }
inline const char *sprintf_cast(const std::string& s) { return s.c_str(); }
template<int N> struct expand_snprintf {
template<typename Tuple, typename... Args> static int call(char *s, size_t maxlen, const char *format, const Tuple& tuple, const Args&... args) {
return expand_snprintf<N-1>::call(s, maxlen, format, tuple, sprintf_cast(std::get<N-1>(tuple)), args...); }};
template<> struct expand_snprintf<0> {
template<typename Tuple, typename... Args> 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<typename... Args>
int snprintf(char *s, size_t maxlen, const char *format, const Args&... args) {
std::tuple<typename replace_extent<Args>::type...> tuple(args...);
return expand_snprintf<std::tuple_size<decltype(tuple)>::value>::call(s, maxlen, format, tuple);
}
/// Format strings with the sprintf style, accepting std::string and string convertible types for %s
template<typename... Args>
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

View File

@ -0,0 +1,60 @@
/*
* Copyright (c) 2010-2012 OTClient <https://github.com/edubart/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 <random>
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<long> 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<float> dis(0.0, 1.0);
return min + (max - min)*dis(gen);
}
}

View File

@ -24,65 +24,24 @@
#define STDEXT_MATH_H
#include "types.h"
#include <random>
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 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 bool is_power_of_two(uint32 v) {
return ((v != 0) && !(v & (v - 1)));
}
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 uint32 to_power_of_two(uint32 v) {
if(v == 0)
return 0;
uint32 r = 1;
while(r < v && r != 0xffffffff)
r <<= 1;
return r;
}
uint32_t adler32(const uint8_t *buffer, size_t size);
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 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); }
template<typename T>
T random_range(T min, T max);
template<>
inline int random_range<int>(int min, int max) {
static std::random_device rd;
static std::mt19937 gen(rd());
static std::uniform_int_distribution<int> dis(0, 2147483647);
return min + (dis(gen) % (max - min + 1));
}
template<>
inline float random_range<float>(float min, float max) {
static std::random_device rd;
static std::mt19937 gen(rd());
static std::uniform_real_distribution<float> 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);
}

View File

@ -0,0 +1,113 @@
/*
* Copyright (c) 2010-2012 OTClient <https://github.com/edubart/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 <algorithm>
#include <cassert>
#include <type_traits>
#include <typeinfo>
namespace stdext {
// disable memory alignment
#pragma pack(push,1)
template<typename T>
struct can_pack_in_any : std::integral_constant<bool,
(sizeof(T) <= sizeof(void*) && std::is_trivial<T>::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<typename T>
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<typename T>
packed_any(const T& value, typename std::enable_if<(can_pack_in_any<T>::value)>::type* = nullptr) :
content(reinterpret_cast<placeholder*>(static_cast<std::size_t>(value))), scalar(true) { }
template<typename T>
packed_any(const T& value, typename std::enable_if<!(can_pack_in_any<T>::value)>::type* = nullptr) :
content(new holder<T>(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<typename T> 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<typename T> T cast() const;
const std::type_info& type() const {
if(scalar)
return content ? content->type() : typeid(void);
else
return typeid(std::size_t);
}
};
template<typename T>
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<packed_any::holder<T>*>(operand.content)->held;
}
}
template<typename T> T packed_any::cast() const { return packed_any_cast<T>(*this); }
// restore memory alignment
#pragma pack(pop)
}
#endif

View File

@ -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 <tuple>
#include <boost/any.hpp>
#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<typename Key, typename SizeType = uint8>
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<typename T>
void set(uint8 id, T value) {
bool done = false;
for(int i=0;i<m_size;++i) {
if(std::get<0>(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;++i) {
if(m_values[i].id == id) {
m_values[i].value = value;
return;
}
}
if(!done) {
auto attribs = new std::tuple<uint8, boost::any>[m_size+1];
auto tmp = new value_pair[m_size+1];
if(m_size > 0) {
for(int i=0;i<m_size;++i)
attribs[i] = m_attribs[i];
delete[] m_attribs;
}
m_attribs = attribs;
m_attribs[m_size++] = std::make_tuple(id, value);
std::copy(m_values, m_values + m_size, tmp);
delete[] m_values;
}
m_values = tmp;
m_values[m_size++] = { id, packed_any(value) };
}
template<typename T>
T get(uint8 id) const {
for(int i=0;i<m_size;++i)
if(std::get<0>(m_attribs[i]) == id)
return boost::any_cast<T>(std::get<1>(m_attribs[i]));
T get(Key id) const {
for(SizeType i=0;i<m_size;++i)
if(m_values[i].id == id)
return packed_any_cast<T>(m_values[i].value);
return T();
}
bool has(uint8 id) const {
for(int i=0;i<m_size;++i)
if(std::get<0>(m_attribs[i]) == id)
bool has(Key id) const {
for(SizeType i=0;i<m_size;++i)
if(m_values[i].id == id)
return true;
return false;
}
void clear() {
if(m_values)
delete [] m_values;
m_values = nullptr;
m_size = 0;
}
std::size_t size() { return m_size; }
private:
std::tuple<uint8, boost::any>* m_attribs;
uint8 m_size;
value_pair *m_values;
SizeType m_size;
};
// restore memory alignment

View File

@ -0,0 +1,157 @@
/*
* Copyright (c) 2010-2012 OTClient <https://github.com/edubart/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 <algorithm>
namespace stdext {
// disable memory alignment
#pragma pack(push,1)
template<class T, class U = uint8_t>
class packed_vector
{
public:
typedef U size_type;
typedef T* iterator;
typedef const T* const_iterator;
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_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 <class InputIterator>
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<T>& 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<T,U>& operator=(packed_vector<T,U> 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<T,U>& other) { std::swap(m_size, other.m_size); std::swap(m_data, other.m_data); return *this; }
operator std::vector<T>() const { return std::vector<T>(begin(), end()); }
private:
size_type m_size;
T* m_data;
};
// restore memory alignment
#pragma pack(pop)
namespace std {
template<class T, class U> void swap(stdext::packed_vector<T,U>& lhs, stdext::packed_vector<T,U>& rhs) { lhs.swap(rhs); }
}
}
#endif

View File

@ -23,55 +23,107 @@
#ifndef STDEXT_SHARED_OBJECT_H
#define STDEXT_SHARED_OBJECT_H
#include <boost/checked_delete.hpp>
#include <boost/intrusive_ptr.hpp>
#include <type_traits>
#include <functional>
#include <cassert>
#include <ostream>
namespace stdext {
template<class T>
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<typename T>
boost::intrusive_ptr<T> self_cast() { return boost::intrusive_ptr<T>(static_cast<T*>(this)); }
template<typename T>
boost::intrusive_ptr<T> dynamic_self_cast() { return boost::intrusive_ptr<T>(dynamic_cast<T*>(this)); }
void dec_ref() { if(--m_refs == 0) delete this; }
refcount_t ref_count() { return m_refs; }
template<typename T> stdext::shared_object_ptr<T> static_self_cast() { return stdext::shared_object_ptr<T>(static_cast<T*>(this)); }
template<typename T> stdext::shared_object_ptr<T> dynamic_self_cast() { return stdext::shared_object_ptr<T>(dynamic_cast<T*>(this)); }
template<typename T> stdext::shared_object_ptr<T> const_self_cast() { return stdext::shared_object_ptr<T>(const_cast<T*>(this)); }
private:
unsigned int m_refs;
refcount_t m_refs;
};
template<class T, typename... Args>
boost::intrusive_ptr<T> make_shared_object(Args... args) { return boost::intrusive_ptr<T>(new T(args...)); }
template<class T>
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<class U>
shared_object_ptr(shared_object_ptr<U> const& rhs, typename std::is_convertible<U,T>::type* = nullptr) : px(rhs.get()) { if(px != nullptr) add_ref(); }
~shared_object_ptr() { if(px != nullptr) dec_ref(); }
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<class U> shared_object_ptr& operator=(shared_object_ptr<U> 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; }
// 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<shared_object_ptr&&>(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<class T, class U> bool operator==(shared_object_ptr<T> const& a, shared_object_ptr<U> const& b) { return a.get() == b.get(); }
template<class T, class U> bool operator!=(shared_object_ptr<T> const& a, shared_object_ptr<U> const& b) { return a.get() != b.get(); }
template<class T, class U> bool operator==(shared_object_ptr<T> const& a, U* b) { return a.get() == b; }
template<class T, class U> bool operator!=(shared_object_ptr<T> const& a, U* b) { return a.get() != b; }
template<class T, class U> bool operator==(T * a, shared_object_ptr<U> const& b) { return a == b.get(); }
template<class T, class U> bool operator!=(T * a, shared_object_ptr<U> const& b) { return a != b.get(); }
template<class T> bool operator<(shared_object_ptr<T> const& a, shared_object_ptr<T> const& b) { return std::less<T*>()(a.get(), b.get()); }
template<class T> T* get_pointer(shared_object_ptr<T> const& p) { return p.get(); }
template<class T, class U> shared_object_ptr<T> static_pointer_cast(shared_object_ptr<U> const& p) { return static_cast<T*>(p.get()); }
template<class T, class U> shared_object_ptr<T> const_pointer_cast(shared_object_ptr<U> const& p) { return const_cast<T*>(p.get()); }
template<class T, class U> shared_object_ptr<T> dynamic_pointer_cast(shared_object_ptr<U> const& p) { return dynamic_cast<T*>(p.get()); }
template<class T, typename... Args> stdext::shared_object_ptr<T> make_shared_object(Args... args) { return stdext::shared_object_ptr<T>(new T(args...)); }
// operator<< support
template<class E, class T, class Y> std::basic_ostream<E, T>& operator<<(std::basic_ostream<E, T>& os, shared_object_ptr<Y> const& p) { os << p.get(); return os; }
}
namespace std {
template<typename T>
struct hash<boost::intrusive_ptr<T>> : public __hash_base<size_t, boost::intrusive_ptr<T>> {
size_t operator()(const boost::intrusive_ptr<T>& p) const noexcept { return std::hash<T*>()(p.get()); }
};
// hash, for unordered_map support
template<typename T> struct hash<stdext::shared_object_ptr<T>> { size_t operator()(const stdext::shared_object_ptr<T>& p) const { return std::hash<T*>()(p.get()); } };
// swap support
template<class T> void swap(stdext::shared_object_ptr<T>& lhs, stdext::shared_object_ptr<T>& rhs) { lhs.swap(rhs); }
}
template<typename T>
struct remove_const_ref {
typedef typename std::remove_const<typename std::remove_reference<T>::type>::type type;
};
template<typename T>
void intrusive_ptr_add_ref(T* p) { (static_cast<stdext::shared_object*>(p))->add_ref(); }
template<typename T>
void intrusive_ptr_release(T* p) { (static_cast<stdext::shared_object*>(p))->dec_ref(); }
#endif

View File

@ -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

View File

@ -0,0 +1,145 @@
/*
* Copyright (c) 2010-2012 OTClient <https://github.com/edubart/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 <boost/algorithm/string.hpp>
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<len;) {
int read = 0;
uchar *utf8char = &utf8[i];
out += utf8CharToLatin1(utf8char, &read);
i += read;
}
return out;
}
void tolower(std::string& str)
{
boost::to_lower(str);
}
void toupper(std::string& str)
{
boost::to_upper(str);
}
void trim(std::string& str)
{
boost::trim(str);
}
bool ends_with(const std::string& str, const std::string& test)
{
return boost::ends_with(str, test);
}
bool starts_with(const std::string& str, const std::string& test)
{
return boost::starts_with(str, test);
}
void replace_all(std::string& str, const std::string& search, const std::string& replacement)
{
return boost::replace_all(str, search, replacement);
}
std::vector<std::string> split(const std::string& str, const std::string& separators)
{
std::vector<std::string> splitted;
boost::split(splitted, str, boost::is_any_of(std::string(separators)));
return splitted;
}
}

View File

@ -25,234 +25,41 @@
#include <string>
#include <cstring>
#include <iostream>
#include <sstream>
#include <iomanip>
#include <vector>
#include <boost/algorithm/string.hpp>
#include "types.h"
#include "cast.h"
#include "exception.h"
namespace stdext {
/// Convert any type to std::string
template<typename T>
std::string to_string(const T& t) { return unsafe_cast<std::string, T>(t); }
template<typename T> std::string to_string(const T& t) { return unsafe_cast<std::string, T>(t); }
template<typename T> T from_string(const std::string& str, T def = T()) { return unsafe_cast<T, std::string>(str, def); }
/// Convert any type from std::string
template<typename T>
T from_string(const std::string& str, T def = T()) { return unsafe_cast<T, std::string>(str, def); }
/// 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();
/// Cast non-class types like int, char, float, double and pointers
template<typename T>
typename std::enable_if<std::is_integral<T>::value ||
std::is_pointer<T>::value ||
std::is_floating_point<T>::value ||
std::is_enum<T>::value, T>::type sprintf_cast(const T& t) { return t; }
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);
/// Cast std::string
inline const char *sprintf_cast(const std::string& s) { return s.c_str(); }
template<int N>
struct expand_snprintf{
template<typename Tuple, typename... Args>
static int call(char *s, size_t maxlen, const char *format, const Tuple& tuple, const Args&... args) {
return expand_snprintf<N-1>::call(s, maxlen, format, tuple, sprintf_cast(std::get<N-1>(tuple)), args...);
}
};
template<>
struct expand_snprintf<0> {
template<typename Tuple, typename... Args>
static int call(char *s, size_t maxlen, const char *format, const Tuple& tuple, const Args&... args) {
return snprintf(s, maxlen, format, args...);
}
};
template<class T>
struct replace_extent { typedef T type; };
template<class T>
struct replace_extent<T[]> { typedef const T* type; };
template<class T, std::size_t N>
struct replace_extent<T[N]> { typedef const T* type;};
/// Improved sprintf that accepts std::string and other types
template<typename... Args>
int snprintf(char *s, size_t maxlen, const char *format, const Args&... args) {
typedef typename std::tuple<typename replace_extent<Args>::type...> Tuple;
enum { N = std::tuple_size<Tuple>::value };
Tuple tuple(args...);
return expand_snprintf<N>::call(s, maxlen, format, tuple);
}
/// Format strings with the sprintf style, accepting std::string and string convertible types for %s
template<typename... Args>
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<class T, class... Args>
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<class... T>
std::string mkstr(const T&... args) {
std::ostringstream buf;
fill_ostream(buf, args...);
return buf.str();
}
/// Easy of use split
template<typename T = std::string>
std::vector<T> split(const std::string& str, const std::string& separators = " ") {
std::vector<std::string> splitted;
boost::split(splitted, str, boost::is_any_of(std::string(separators)));
std::vector<std::string> split(const std::string& str, const std::string& separators = " ");
template<typename T> std::vector<T> split(const std::string& str, const std::string& separators = " ") {
std::vector<std::string> splitted = split(str, separators);
std::vector<T> results(splitted.size());
for(uint i=0;i<splitted.size();++i)
results[i] = safe_cast<T>(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<len;) {
int read = 0;
uchar *utf8char = &utf8[i];
out += utf8CharToLatin1(utf8char, &read);
i += read;
}
return out;
}
// Convert string to lower case
inline std::string tolower(const std::string& str)
{
std::string cpy = str;
boost::algorithm::to_lower(cpy);
return cpy;
}
// Convert string to upper case
inline std::string toupper(const std::string& str)
{
std::string cpy = str;
boost::algorithm::to_upper(cpy);
return cpy;
}
// Trim string
inline std::string trim(const std::string& str)
{
std::string cpy = str;
boost::algorithm::trim(cpy);
return cpy;
}
// utility for printing messages into stdout
template<class... T>
void print(const T&... args) {
std::ostringstream buf;
fill_ostream(buf, args...);
std::cout << buf.str();
}
template<class... T>
void println(const T&... args) {
print(args...);
std::cout << std::endl;
}
}
#include "cast.h"
#endif

View File

@ -0,0 +1,49 @@
/*
* Copyright (c) 2010-2012 OTClient <https://github.com/edubart/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 <chrono>
#include <unistd.h>
namespace stdext {
const static auto startup_time = std::chrono::high_resolution_clock::now();
ticks_t millis()
{
return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - startup_time).count();
}
ticks_t micros() {
return std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now() - startup_time).count();
}
void millisleep(size_t ms)
{
usleep(ms * 1000);
};
void microsleep(size_t us)
{
usleep(us);
};
}

View File

@ -24,16 +24,13 @@
#define STDEXT_TIME_H
#include "types.h"
#include <chrono>
#include <unistd.h>
namespace stdext {
const static auto startup_time = std::chrono::high_resolution_clock::now();
inline ticks_t millis() { return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - startup_time).count(); }
inline ticks_t micros() { return std::chrono::duration_cast<std::chrono::microseconds>(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:

View File

@ -0,0 +1,37 @@
/*
* Copyright (c) 2010-2012 OTClient <https://github.com/edubart/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 <type_traits>
namespace stdext {
template<class T> struct replace_extent { typedef T type; };
template<class T> struct replace_extent<T[]> { typedef const T* type; };
template<class T, unsigned long N> struct replace_extent<T[N]> { typedef const T* type;};
template<typename T> struct remove_const_ref { typedef typename std::remove_const<typename std::remove_reference<T>::type>::type type; };
};
#endif

View File

@ -23,13 +23,13 @@
#ifndef STDEXT_TYPES_H
#define STDEXT_TYPES_H
#include <stdint.h>
#include <cstdint>
// 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

View File

@ -36,15 +36,15 @@ class UIGridLayout;
class UIAnchorLayout;
class UIParticles;
typedef boost::intrusive_ptr<UIWidget> UIWidgetPtr;
typedef boost::intrusive_ptr<UIParticles> UIParticlesPtr;
typedef boost::intrusive_ptr<UITextEdit> UITextEditPtr;
typedef boost::intrusive_ptr<UILayout> UILayoutPtr;
typedef boost::intrusive_ptr<UIBoxLayout> UIBoxLayoutPtr;
typedef boost::intrusive_ptr<UIHorizontalLayout> UIHorizontalLayoutPtr;
typedef boost::intrusive_ptr<UIVerticalLayout> UIVerticalLayoutPtr;
typedef boost::intrusive_ptr<UIGridLayout> UIGridLayoutPtr;
typedef boost::intrusive_ptr<UIAnchorLayout> UIAnchorLayoutPtr;
typedef stdext::shared_object_ptr<UIWidget> UIWidgetPtr;
typedef stdext::shared_object_ptr<UIParticles> UIParticlesPtr;
typedef stdext::shared_object_ptr<UITextEdit> UITextEditPtr;
typedef stdext::shared_object_ptr<UILayout> UILayoutPtr;
typedef stdext::shared_object_ptr<UIBoxLayout> UIBoxLayoutPtr;
typedef stdext::shared_object_ptr<UIHorizontalLayout> UIHorizontalLayoutPtr;
typedef stdext::shared_object_ptr<UIVerticalLayout> UIVerticalLayoutPtr;
typedef stdext::shared_object_ptr<UIGridLayout> UIGridLayoutPtr;
typedef stdext::shared_object_ptr<UIAnchorLayout> UIAnchorLayoutPtr;
typedef std::deque<UIWidgetPtr> UIWidgetList;

View File

@ -63,7 +63,7 @@ void UILayout::updateLater()
if(!getParentWidget())
return;
auto self = self_cast<UILayout>();
auto self = static_self_cast<UILayout>();
g_dispatcher.addEvent([self] {
self->m_updateScheduled = false;
self->update();

View File

@ -321,8 +321,7 @@ bool UIManager::importStyle(const std::string& file)
void UIManager::importStyleFromOTML(const OTMLNodePtr& styleNode)
{
std::string tag = styleNode->tag();
std::vector<std::string> split;
boost::split(split, tag, boost::is_any_of(std::string("<")));
std::vector<std::string> 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;

View File

@ -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

View File

@ -21,6 +21,7 @@
*/
#include "uitranslator.h"
#include <framework/stdext/string.h>
#include <boost/algorithm/string.hpp>
Fw::AlignmentFlag Fw::translateAlignment(std::string aligment)

View File

@ -141,11 +141,11 @@ void UIWidget::addChild(const UIWidgetPtr& child)
UIWidgetPtr oldLastChild = getLastChild();
m_children.push_back(child);
child->setParent(self_cast<UIWidget>());
child->setParent(static_self_cast<UIWidget>());
// create default layout
if(!m_layout)
m_layout = UIAnchorLayoutPtr(new UIAnchorLayout(self_cast<UIWidget>()));
m_layout = UIAnchorLayoutPtr(new UIAnchorLayout(static_self_cast<UIWidget>()));
// 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<UIWidget>());
child->setParent(static_self_cast<UIWidget>());
// create default layout if needed
if(!m_layout)
m_layout = UIAnchorLayoutPtr(new UIAnchorLayout(self_cast<UIWidget>()));
m_layout = UIAnchorLayoutPtr(new UIAnchorLayout(static_self_cast<UIWidget>()));
// 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<UIWidget>());
assert(child->getParent() == static_self_cast<UIWidget>());
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<UIWidget>();
auto self = static_self_cast<UIWidget>();
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<UIWidget>(), anchoredEdge, hookedWidgetId, hookedEdge);
anchorLayout->addAnchor(static_self_cast<UIWidget>(), 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<UIWidget>(), Fw::AnchorHorizontalCenter, hookedWidgetId, Fw::AnchorHorizontalCenter);
anchorLayout->addAnchor(self_cast<UIWidget>(), Fw::AnchorVerticalCenter, hookedWidgetId, Fw::AnchorVerticalCenter);
anchorLayout->addAnchor(static_self_cast<UIWidget>(), Fw::AnchorHorizontalCenter, hookedWidgetId, Fw::AnchorHorizontalCenter);
anchorLayout->addAnchor(static_self_cast<UIWidget>(), 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<UIWidget>(), Fw::AnchorLeft, hookedWidgetId, Fw::AnchorLeft);
anchorLayout->addAnchor(self_cast<UIWidget>(), Fw::AnchorRight, hookedWidgetId, Fw::AnchorRight);
anchorLayout->addAnchor(self_cast<UIWidget>(), Fw::AnchorTop, hookedWidgetId, Fw::AnchorTop);
anchorLayout->addAnchor(self_cast<UIWidget>(), Fw::AnchorBottom, hookedWidgetId, Fw::AnchorBottom);
anchorLayout->addAnchor(static_self_cast<UIWidget>(), Fw::AnchorLeft, hookedWidgetId, Fw::AnchorLeft);
anchorLayout->addAnchor(static_self_cast<UIWidget>(), Fw::AnchorRight, hookedWidgetId, Fw::AnchorRight);
anchorLayout->addAnchor(static_self_cast<UIWidget>(), Fw::AnchorTop, hookedWidgetId, Fw::AnchorTop);
anchorLayout->addAnchor(static_self_cast<UIWidget>(), 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<UIWidget>());
anchorLayout->removeAnchors(static_self_cast<UIWidget>());
}
void UIWidget::updateParentLayout()
@ -601,7 +601,7 @@ void UIWidget::lock()
return;
if(UIWidgetPtr parent = getParent())
parent->lockChild(self_cast<UIWidget>());
parent->lockChild(static_self_cast<UIWidget>());
}
void UIWidget::unlock()
@ -610,7 +610,7 @@ void UIWidget::unlock()
return;
if(UIWidgetPtr parent = getParent())
parent->unlockChild(self_cast<UIWidget>());
parent->unlockChild(static_self_cast<UIWidget>());
}
void UIWidget::focus()
@ -622,7 +622,7 @@ void UIWidget::focus()
return;
if(UIWidgetPtr parent = getParent())
parent->focusChild(self_cast<UIWidget>(), Fw::ActiveFocusReason);
parent->focusChild(static_self_cast<UIWidget>(), 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<UIWidget>(), reason);
parent->focusChild(static_self_cast<UIWidget>(), reason);
parent->recursiveFocus(reason);
}
}
@ -644,7 +644,7 @@ void UIWidget::lower()
UIWidgetPtr parent = getParent();
if(parent)
parent->lowerChild(self_cast<UIWidget>());
parent->lowerChild(static_self_cast<UIWidget>());
}
void UIWidget::raise()
@ -654,7 +654,7 @@ void UIWidget::raise()
UIWidgetPtr parent = getParent();
if(parent)
parent->raiseChild(self_cast<UIWidget>());
parent->raiseChild(static_self_cast<UIWidget>());
}
void UIWidget::grabMouse()
@ -662,12 +662,12 @@ void UIWidget::grabMouse()
if(m_destroyed)
return;
g_ui.setMouseReceiver(self_cast<UIWidget>());
g_ui.setMouseReceiver(static_self_cast<UIWidget>());
}
void UIWidget::ungrabMouse()
{
if(g_ui.getMouseReceiver() == self_cast<UIWidget>())
if(g_ui.getMouseReceiver() == static_self_cast<UIWidget>())
g_ui.resetMouseReceiver();
}
@ -676,12 +676,12 @@ void UIWidget::grabKeyboard()
if(m_destroyed)
return;
g_ui.setKeyboardReceiver(self_cast<UIWidget>());
g_ui.setKeyboardReceiver(static_self_cast<UIWidget>());
}
void UIWidget::ungrabKeyboard()
{
if(g_ui.getKeyboardReceiver() == self_cast<UIWidget>())
if(g_ui.getKeyboardReceiver() == static_self_cast<UIWidget>())
g_ui.resetKeyboardReceiver();
}
@ -721,7 +721,7 @@ void UIWidget::internalDestroy()
releaseLuaFieldsTable();
g_ui.onWidgetDestroy(self_cast<UIWidget>());
g_ui.onWidgetDestroy(static_self_cast<UIWidget>());
}
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<UIWidget>();
UIWidgetPtr self = static_self_cast<UIWidget>();
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<UIWidget>();
UIWidgetPtr self = static_self_cast<UIWidget>();
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<UIWidget>());
layout->setParent(static_self_cast<UIWidget>());
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<UIWidget>();
UIWidgetPtr self = static_self_cast<UIWidget>();
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<UIWidget>());
g_ui.onWidgetAppear(static_self_cast<UIWidget>());
else
g_ui.onWidgetDisappear(self_cast<UIWidget>());
g_ui.onWidgetDisappear(static_self_cast<UIWidget>());
callLuaField("onVisibilityChange", visible);
}
@ -963,14 +963,14 @@ bool UIWidget::isVisible()
else if(UIWidgetPtr parent = getParent())
return parent->isVisible();
else
return self_cast<UIWidget>() == g_ui.getRootWidget();
return static_self_cast<UIWidget>() == g_ui.getRootWidget();
}
bool UIWidget::isAnchored()
{
if(UIWidgetPtr parent = getParent())
if(UIAnchorLayoutPtr anchorLayout = parent->getAnchoredLayout())
return anchorLayout->hasAnchors(self_cast<UIWidget>());
return anchorLayout->hasAnchors(static_self_cast<UIWidget>());
return false;
}
@ -1046,7 +1046,7 @@ UIAnchorLayoutPtr UIWidget::getAnchoredLayout()
UILayoutPtr layout = parent->getLayout();
if(layout->isUIAnchorLayout())
return layout->self_cast<UIAnchorLayout>();
return layout->static_self_cast<UIAnchorLayout>();
return nullptr;
}
@ -1055,7 +1055,7 @@ UIWidgetPtr UIWidget::getRootParent()
if(UIWidgetPtr parent = getParent())
return parent->getRootParent();
else
return self_cast<UIWidget>();
return static_self_cast<UIWidget>();
}
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<UIWidget>();
UIWidgetPtr widget = static_self_cast<UIWidget>();
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<UIWidget>());
newStatus = (getParent() && getParent()->getFocusedChild() == static_self_cast<UIWidget>());
break;
}
case Fw::HoverState: {
newStatus = (g_ui.getHoveredWidget() == self_cast<UIWidget>() && isEnabled());
newStatus = (g_ui.getHoveredWidget() == static_self_cast<UIWidget>() && isEnabled());
break;
}
case Fw::PressedState: {
newStatus = (g_ui.getPressedWidget() == self_cast<UIWidget>());
newStatus = (g_ui.getPressedWidget() == static_self_cast<UIWidget>());
break;
}
case Fw::DraggingState: {
newStatus = (g_ui.getDraggingWidget() == self_cast<UIWidget>());
newStatus = (g_ui.getDraggingWidget() == static_self_cast<UIWidget>());
break;
}
case Fw::DisabledState: {
bool enabled = true;
UIWidgetPtr widget = self_cast<UIWidget>();
UIWidgetPtr widget = static_self_cast<UIWidget>();
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<UIWidget>());
newStatus = (getParent() && getParent()->getFirstChild() == static_self_cast<UIWidget>());
break;
}
case Fw::MiddleState: {
newStatus = (getParent() && getParent()->getFirstChild() != self_cast<UIWidget>() && getParent()->getLastChild() != self_cast<UIWidget>());
newStatus = (getParent() && getParent()->getFirstChild() != static_self_cast<UIWidget>() && getParent()->getLastChild() != static_self_cast<UIWidget>());
break;
}
case Fw::LastState: {
newStatus = (getParent() && getParent()->getLastChild() == self_cast<UIWidget>());
newStatus = (getParent() && getParent()->getLastChild() == static_self_cast<UIWidget>());
break;
}
case Fw::AlternateState: {
newStatus = (getParent() && (getParent()->getChildIndex(self_cast<UIWidget>()) % 2) == 1);
newStatus = (getParent() && (getParent()->getChildIndex(static_self_cast<UIWidget>()) % 2) == 1);
break;
}
default:
@ -1337,7 +1337,7 @@ void UIWidget::updateStyle()
return;
if(m_loadingStyle && !m_updateStyleScheduled) {
UIWidgetPtr self = self_cast<UIWidget>();
UIWidgetPtr self = static_self_cast<UIWidget>();
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<std::string> statesSplit;
boost::split(statesSplit, statesStr, boost::is_any_of(std::string(" ")));
std::vector<std::string> 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<UIWidget>());
widgetList.push_back(static_self_cast<UIWidget>());
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<UIWidget>());
widgetList.push_back(static_self_cast<UIWidget>());
return true;
}

View File

@ -162,8 +162,7 @@ void UIWidget::parseBaseStyle(const OTMLNodePtr& styleNode)
setMarginLeft(node->value<int>());
else if(node->tag() == "margin") {
std::string marginDesc = node->value();
std::vector<std::string> split;
boost::split(split, marginDesc, boost::is_any_of(std::string(" ")));
std::vector<std::string> split = stdext::split(marginDesc, " ");
if(split.size() == 4) {
setMarginTop(stdext::safe_cast<int>(split[0]));
setMarginRight(stdext::safe_cast<int>(split[1]));
@ -202,8 +201,7 @@ void UIWidget::parseBaseStyle(const OTMLNodePtr& styleNode)
setPaddingLeft(node->value<int>());
else if(node->tag() == "padding") {
std::string paddingDesc = node->value();
std::vector<std::string> split;
boost::split(split, paddingDesc, boost::is_any_of(std::string(" ")));
std::vector<std::string> split = stdext::split(paddingDesc, " ");
if(split.size() == 4) {
setPaddingTop(stdext::safe_cast<int>(split[0]));
setPaddingRight(stdext::safe_cast<int>(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<UIWidget>()));
layout = UIHorizontalLayoutPtr(new UIHorizontalLayout(static_self_cast<UIWidget>()));
else if(layoutType == "verticalBox")
layout = UIVerticalLayoutPtr(new UIVerticalLayout(self_cast<UIWidget>()));
layout = UIVerticalLayoutPtr(new UIVerticalLayout(static_self_cast<UIWidget>()));
else if(layoutType == "grid")
layout = UIGridLayoutPtr(new UIGridLayout(self_cast<UIWidget>()));
layout = UIGridLayoutPtr(new UIGridLayout(static_self_cast<UIWidget>()));
else if(layoutType == "anchor")
layout = UIAnchorLayoutPtr(new UIAnchorLayout(self_cast<UIWidget>()));
layout = UIAnchorLayoutPtr(new UIAnchorLayout(static_self_cast<UIWidget>()));
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<UIAnchorLayout>();
anchorLayout = layout->static_self_cast<UIAnchorLayout>();
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() + "]";

View File

@ -25,7 +25,9 @@
#include "../stdext/types.h"
#include "../stdext/cast.h"
#include "../stdext/string.h"
#include "../const.h"
#include <iomanip>
class Color
{

View File

@ -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

View File

@ -47,7 +47,7 @@ void AnimatedText::drawText(const Point& dest, const Rect& visibleRect)
}
}
void AnimatedText::startAnimation()
void AnimatedText::onAppear()
{
m_animationTimer.restart();

View File

@ -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<AnimatedText>(); }
AnimatedTextPtr asAnimatedText() { return static_self_cast<AnimatedText>(); }
bool isAnimatedText() { return true; }
protected:
virtual void onAppear();
private:
Color m_color;
Timer m_animationTimer;

View File

@ -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<Creature>());
m_walkingTile->removeWalkingCreature(static_self_cast<Creature>());
if(newWalkingTile)
newWalkingTile->addWalkingCreature(self_cast<Creature>());
newWalkingTile->addWalkingCreature(static_self_cast<Creature>());
m_walkingTile = newWalkingTile;
}
}
@ -371,7 +376,7 @@ void Creature::nextWalkUpdate()
// schedules next update
if(m_walking) {
auto self = self_cast<Creature>();
auto self = static_self_cast<Creature>();
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<Creature>());
m_walkingTile->removeWalkingCreature(static_self_cast<Creature>());
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<Creature>();
auto self = static_self_cast<Creature>();
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<Creature>();
auto self = static_self_cast<Creature>();
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<Creature>();
auto self = static_self_cast<Creature>();
g_dispatcher.scheduleEvent([self]() {
self->updateShield();
}, SHIELD_BLINK_TICKS);

View File

@ -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);

View File

@ -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;
}

View File

@ -50,7 +50,7 @@ public:
int getSpawnTime() { return m_attribs.get<int>(CreatureAttrSpawnTime); }
private:
stdext::attrib_storage m_attribs;
stdext::dynamic_storage<uint8> 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:

View File

@ -50,25 +50,25 @@ class House;
class Town;
class CreatureType;
typedef boost::intrusive_ptr<MapView> MapViewPtr;
typedef boost::intrusive_ptr<Tile> TilePtr;
typedef boost::intrusive_ptr<Thing> ThingPtr;
typedef boost::intrusive_ptr<Item> ItemPtr;
typedef boost::intrusive_ptr<Container> ContainerPtr;
typedef boost::intrusive_ptr<Creature> CreaturePtr;
typedef boost::intrusive_ptr<Monster> MonsterPtr;
typedef boost::intrusive_ptr<Npc> NpcPtr;
typedef boost::intrusive_ptr<Player> PlayerPtr;
typedef boost::intrusive_ptr<LocalPlayer> LocalPlayerPtr;
typedef boost::intrusive_ptr<Effect> EffectPtr;
typedef boost::intrusive_ptr<Missile> MissilePtr;
typedef boost::intrusive_ptr<AnimatedText> AnimatedTextPtr;
typedef boost::intrusive_ptr<StaticText> StaticTextPtr;
typedef boost::intrusive_ptr<ThingType> ThingTypePtr;
typedef boost::intrusive_ptr<ItemType> ItemTypePtr;
typedef boost::intrusive_ptr<House> HousePtr;
typedef boost::intrusive_ptr<Town> TownPtr;
typedef boost::intrusive_ptr<CreatureType> CreatureTypePtr;
typedef stdext::shared_object_ptr<MapView> MapViewPtr;
typedef stdext::shared_object_ptr<Tile> TilePtr;
typedef stdext::shared_object_ptr<Thing> ThingPtr;
typedef stdext::shared_object_ptr<Item> ItemPtr;
typedef stdext::shared_object_ptr<Container> ContainerPtr;
typedef stdext::shared_object_ptr<Creature> CreaturePtr;
typedef stdext::shared_object_ptr<Monster> MonsterPtr;
typedef stdext::shared_object_ptr<Npc> NpcPtr;
typedef stdext::shared_object_ptr<Player> PlayerPtr;
typedef stdext::shared_object_ptr<LocalPlayer> LocalPlayerPtr;
typedef stdext::shared_object_ptr<Effect> EffectPtr;
typedef stdext::shared_object_ptr<Missile> MissilePtr;
typedef stdext::shared_object_ptr<AnimatedText> AnimatedTextPtr;
typedef stdext::shared_object_ptr<StaticText> StaticTextPtr;
typedef stdext::shared_object_ptr<ThingType> ThingTypePtr;
typedef stdext::shared_object_ptr<ItemType> ItemTypePtr;
typedef stdext::shared_object_ptr<House> HousePtr;
typedef stdext::shared_object_ptr<Town> TownPtr;
typedef stdext::shared_object_ptr<CreatureType> CreatureTypePtr;
typedef std::vector<ThingPtr> ThingList;
typedef std::vector<ThingTypePtr> ThingTypeList;
@ -81,8 +81,8 @@ typedef std::unordered_map<Position, TilePtr, PositionHasher> TileMap;
class ProtocolLogin;
class ProtocolGame;
typedef boost::intrusive_ptr<ProtocolGame> ProtocolGamePtr;
typedef boost::intrusive_ptr<ProtocolLogin> ProtocolLoginPtr;
typedef stdext::shared_object_ptr<ProtocolGame> ProtocolGamePtr;
typedef stdext::shared_object_ptr<ProtocolLogin> ProtocolLoginPtr;
// ui
class UIItem;
@ -90,9 +90,9 @@ class UICreature;
class UIMap;
class UIProgressRect;
typedef boost::intrusive_ptr<UIItem> UIItemPtr;
typedef boost::intrusive_ptr<UICreature> UICreaturePtr;
typedef boost::intrusive_ptr<UIMap> UIMapPtr;
typedef boost::intrusive_ptr<UIProgressRect> UIProgressRectPtr;
typedef stdext::shared_object_ptr<UIItem> UIItemPtr;
typedef stdext::shared_object_ptr<UICreature> UICreaturePtr;
typedef stdext::shared_object_ptr<UIMap> UIMapPtr;
typedef stdext::shared_object_ptr<UIProgressRect> UIProgressRectPtr;
#endif

View File

@ -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;

View File

@ -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<Effect>(); }
EffectPtr asEffect() { return static_self_cast<Effect>(); }
bool isEffect() { return true; }
const ThingTypePtr& getThingType();
ThingType *rawGetThingType();
protected:
void onAppear();
private:
Timer m_animationTimer;
uint m_phaseDuration;

View File

@ -34,6 +34,8 @@
#include "outfit.h"
#include <framework/core/timer.h>
#include <bitset>
typedef std::tuple<std::string, bool> Vip;
//@bindsingleton g_game

View File

@ -63,7 +63,7 @@ protected:
void save(TiXmlElement &elem) { } // TODO
private:
stdext::attrib_storage m_attribs;
stdext::packed_storage<uint8> m_attribs;
TileMap m_tiles;
stdext::boolean<false> m_isGuildHall;

View File

@ -115,7 +115,7 @@ public:
bool isTeleport() { return m_attribs.has(ATTR_TELE_DEST); }
bool isMoveable();
ItemPtr asItem() { return self_cast<Item>(); }
ItemPtr asItem() { return static_self_cast<Item>(); }
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<uint8> m_attribs;
};
#pragma pack(pop)

View File

@ -103,7 +103,7 @@ private:
ItemCategory m_category;
stdext::boolean<true> m_null;
stdext::attrib_storage m_attribs;
stdext::dynamic_storage<uint8> m_attribs;
};
#endif

View File

@ -77,7 +77,7 @@ public:
bool isAutoWalking() { return m_autoWalking; }
bool isPremium() { return m_premium; }
LocalPlayerPtr asLocalPlayer() { return self_cast<LocalPlayer>(); }
LocalPlayerPtr asLocalPlayer() { return static_self_cast<LocalPlayer>(); }
bool isLocalPlayer() { return true; }
protected:

View File

@ -27,14 +27,10 @@
#include "item.h"
#include "missile.h"
#include "statictext.h"
#include "mapview.h"
#include <framework/core/eventdispatcher.h>
#include "mapview.h"
#include <framework/core/resourcemanager.h>
#include <framework/core/filestream.h>
#include <framework/core/binarytree.h>
#include <framework/core/application.h>
#include <framework/xml/tinyxml.h>
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<int>(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<int>("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<Item>();
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<Missile>());
m_floorMissiles[pos.z].push_back(thing->static_self_cast<Missile>());
} else if(thing->isAnimatedText()) {
m_animatedTexts.push_back(thing->self_cast<AnimatedText>());
m_animatedTexts.push_back(thing->static_self_cast<AnimatedText>());
} else if(thing->isStaticText()) {
StaticTextPtr staticText = thing->self_cast<StaticText>();
StaticTextPtr staticText = thing->static_self_cast<StaticText>();
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<Creature>();
CreaturePtr creature = thing->static_self_cast<Creature>();
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<Missile>();
MissilePtr missile = thing->static_self_cast<Missile>();
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<AnimatedText>();
AnimatedTextPtr animatedText = thing->static_self_cast<AnimatedText>();
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<StaticText>();
StaticTextPtr staticText = thing->static_self_cast<StaticText>();
auto it = std::find(m_staticTexts.begin(), m_staticTexts.end(), staticText);
if(it != m_staticTexts.end()) {
m_staticTexts.erase(it);

View File

@ -267,7 +267,7 @@ private:
Position m_centralPosition;
Rect m_tilesRect;
stdext::attrib_storage m_attribs;
stdext::packed_storage<uint8> m_attribs;
Houses m_houses;
Towns m_towns;
Creatures m_creatures;

540
src/otclient/mapio.cpp Normal file
View File

@ -0,0 +1,540 @@
/*
* Copyright (c) 2010-2012 OTClient <https://github.com/edubart/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 <framework/core/eventdispatcher.h>
#include <framework/core/resourcemanager.h>
#include <framework/core/filestream.h>
#include <framework/core/binarytree.h>
#include <framework/xml/tinyxml.h>
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<int>(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<int>("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<Item>();
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
}

View File

@ -103,7 +103,7 @@ public:
// get tile
TilePtr getTile(const Point& mousePos, const Rect& mapRect);
MapViewPtr asMapView() { return self_cast<MapView>(); }
MapViewPtr asMapView() { return static_self_cast<MapView>(); }
private:
int calcFirstVisibleFloor();

View File

@ -42,7 +42,7 @@ public:
uint32 getId() { return m_id; }
MissilePtr asMissile() { return self_cast<Missile>(); }
MissilePtr asMissile() { return static_self_cast<Missile>(); }
bool isMissile() { return true; }
const ThingTypePtr& getThingType();

View File

@ -32,7 +32,7 @@ public:
Player() { }
virtual ~Player() { }
PlayerPtr asPlayer() { return self_cast<Player>(); }
PlayerPtr asPlayer() { return static_self_cast<Player>(); }
bool isPlayer() { return true; }
};

View File

@ -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); }

View File

@ -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<Creature>();
//Position oldPos = thing->getPosition();
//creature->onMove(newPos, oldPos);
}
void ProtocolGame::parseOpenContainer(const InputMessagePtr& msg)

View File

@ -43,7 +43,7 @@ public:
bool addMessage(const std::string& name, Otc::MessageMode mode, const std::string& text);
StaticTextPtr asStaticText() { return self_cast<StaticText>(); }
StaticTextPtr asStaticText() { return static_self_cast<StaticText>(); }
bool isStaticText() { return true; }
private:

View File

@ -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<Thing>());
return tile->getThingStackpos(static_self_cast<Thing>());
else {
g_logger.traceError("got a thing with invalid stackpos");
return -1;

View File

@ -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;
};

View File

@ -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:

View File

@ -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<uint16>(ThingAttrGround); }
int getMaxTextLength() { return m_attribs.has(ThingAttrWritableOnce) ? m_attribs.get<uint16>(ThingAttrWritableOnce) : m_attribs.get<uint16>(ThingAttrWritable); }
@ -133,7 +134,6 @@ public:
int getMinimapColor() { return m_attribs.get<uint16>(ThingAttrMinimapColor); }
int getLensHelp() { return m_attribs.get<uint16>(ThingAttrLensHelp); }
int getClothSlot() { return m_attribs.get<uint16>(ThingAttrCloth); }
int getElevation() { return m_attribs.get<uint16>(ThingAttrElevation); }
MarketData getMarketData() { return m_attribs.get<MarketData>(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<uint8> 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<int> m_spritesIndex;
std::vector<TexturePtr> m_textures;

View File

@ -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<Creature>();
CreaturePtr creature = thing->static_self_cast<Creature>();
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<Effect>());
m_effects.push_back(thing->static_self_cast<Effect>());
return;
}
@ -205,7 +205,7 @@ bool Tile::removeThing(ThingPtr thing)
bool removed = false;
if(thing->isEffect()) {
EffectPtr effect = thing->self_cast<Effect>();
EffectPtr effect = thing->static_self_cast<Effect>();
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<ItemPtr> Tile::getItems()
for(const ThingPtr& thing : m_things) {
if(!thing->isItem())
continue;
ItemPtr item = thing->self_cast<Item>();
ItemPtr item = thing->static_self_cast<Item>();
items.push_back(item);
}
return items;
@ -278,7 +278,7 @@ std::vector<CreaturePtr> Tile::getCreatures()
std::vector<CreaturePtr> creatures;
for(const ThingPtr& thing : m_things) {
if(thing->isCreature())
creatures.push_back(thing->self_cast<Creature>());
creatures.push_back(thing->static_self_cast<Creature>());
}
return creatures;
}
@ -289,7 +289,7 @@ ItemPtr Tile::getGround()
if(!firstObject)
return nullptr;
if(firstObject->isGround() && firstObject->isItem())
return firstObject->self_cast<Item>();
return firstObject->static_self_cast<Item>();
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>();
creature = thing->static_self_cast<Creature>();
else if(thing->isCreature() && !thing->isLocalPlayer())
return thing->self_cast<Creature>();
return thing->static_self_cast<Creature>();
}
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<Creature>();
CreaturePtr creature = thing->static_self_cast<Creature>();
if(!creature->isPassable())
return false;
}

View File

@ -85,7 +85,7 @@ public:
int getDrawElevation() { return m_drawElevation; }
std::vector<ItemPtr> getItems();
std::vector<CreaturePtr> getCreatures();
const std::vector<ThingPtr>& getThings() { return m_things; }
std::vector<ThingPtr> 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<Tile>(); }
TilePtr asTile() { return static_self_cast<Tile>(); }
private:
std::vector<CreaturePtr> m_walkingCreatures;
std::vector<EffectPtr> m_effects; // leave this outside m_things because it has no stackpos.
std::vector<ThingPtr> m_things;
stdext::packed_vector<CreaturePtr> m_walkingCreatures;
stdext::packed_vector<EffectPtr> m_effects; // leave this outside m_things because it has no stackpos.
stdext::packed_vector<ThingPtr> m_things;
Position m_position;
uint8 m_drawElevation;
uint32 m_flags, m_houseId;