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 anymoremaster
parent
1dc7dc0cfc
commit
3bac3dcbb4
@ -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
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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
|
@ -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
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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
|
@ -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
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
};
|
||||
|
||||
}
|
@ -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
|
@ -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
|
||||
}
|
Loading…
Reference in new issue