From 7a08fed689f476b0485c2c37a2c545d7912adbb0 Mon Sep 17 00:00:00 2001 From: Eduardo Bart Date: Sun, 15 Jul 2012 10:23:13 -0300 Subject: [PATCH] Optimize overall memory usage * Fixes in otbm loader * Rework BinaryTree --- src/framework/CMakeLists.txt | 1 + src/framework/core/binarytree.cpp | 77 ++++++++++++--- src/framework/core/binarytree.h | 23 +++-- src/framework/core/filestream.cpp | 12 +-- src/framework/core/filestream.h | 4 +- src/framework/luaengine/luainterface.cpp | 5 +- src/framework/luaengine/luaobject.h | 2 + src/framework/util/attribstorage.h | 81 ++++++++++++++++ src/main.cpp | 5 + src/otclient/creature.cpp | 24 +++-- src/otclient/creature.h | 3 + src/otclient/effect.cpp | 13 ++- src/otclient/effect.h | 3 + src/otclient/item.cpp | 70 ++++++-------- src/otclient/item.h | 49 +++++----- src/otclient/map.cpp | 34 +++---- src/otclient/map.h | 2 +- src/otclient/missile.cpp | 13 ++- src/otclient/missile.h | 5 +- src/otclient/position.h | 2 +- src/otclient/thing.cpp | 12 ++- src/otclient/thing.h | 114 ++++++++++++----------- src/otclient/thingtypemanager.cpp | 1 + src/otclient/thingtypemanager.h | 2 + src/otclient/tile.h | 5 +- 25 files changed, 376 insertions(+), 186 deletions(-) create mode 100644 src/framework/util/attribstorage.h diff --git a/src/framework/CMakeLists.txt b/src/framework/CMakeLists.txt index c706c2b6..db68c30a 100644 --- a/src/framework/CMakeLists.txt +++ b/src/framework/CMakeLists.txt @@ -33,6 +33,7 @@ set(framework_SOURCES ${framework_SOURCES} ${CMAKE_CURRENT_LIST_DIR}/util/rsa.cpp ${CMAKE_CURRENT_LIST_DIR}/util/rsa.h ${CMAKE_CURRENT_LIST_DIR}/util/size.h + ${CMAKE_CURRENT_LIST_DIR}/util/attribstorage.h # stdext ${CMAKE_CURRENT_LIST_DIR}/stdext/cast.h diff --git a/src/framework/core/binarytree.cpp b/src/framework/core/binarytree.cpp index 6fc1ba4c..10b85660 100644 --- a/src/framework/core/binarytree.cpp +++ b/src/framework/core/binarytree.cpp @@ -23,36 +23,89 @@ #include "binarytree.h" #include "filestream.h" -void BinaryTree::unserialize(const FileStreamPtr& fin) +BinaryTree::BinaryTree(const FileStreamPtr& fin) : + m_fin(fin), m_pos(0xFFFFFFFF) +{ + m_startPos = fin->tell(); +} + +BinaryTree::~BinaryTree() +{ +} + +void BinaryTree::skipNodes() { while(true) { - uint8 byte = fin->getU8(); + uint8 byte = m_fin->getU8(); switch(byte) { case BINARYTREE_NODE_START: { - BinaryTreePtr node(new BinaryTree(shared_from_this())); - m_children.push_back(node); - node->unserialize(fin); + skipNodes(); break; } case BINARYTREE_NODE_END: return; case BINARYTREE_ESCAPE_CHAR: - m_buffer.add(fin->getU8()); + m_fin->getU8(); break; default: - m_buffer.add(byte); break; } } } -void BinaryTree::serialize(const FileStreamPtr& fin) +void BinaryTree::unserialize() { + if(m_pos != 0xFFFFFFFF) + return; + m_pos = 0; + m_fin->seek(m_startPos); + while(true) { + uint8 byte = m_fin->getU8(); + switch(byte) { + case BINARYTREE_NODE_START: { + skipNodes(); + break; + } + case BINARYTREE_NODE_END: + return; + case BINARYTREE_ESCAPE_CHAR: + m_buffer.add(m_fin->getU8()); + break; + default: + m_buffer.add(byte); + break; + } + } +} + +BinaryTreeVec BinaryTree::getChildren() +{ + BinaryTreeVec children; + m_fin->seek(m_startPos); + while(true) { + uint8 byte = m_fin->getU8(); + switch(byte) { + case BINARYTREE_NODE_START: { + BinaryTreePtr node(new BinaryTree(m_fin)); + children.push_back(node); + node->skipNodes(); + break; + } + case BINARYTREE_NODE_END: + return children; + case BINARYTREE_ESCAPE_CHAR: + m_fin->getU8(); + break; + default: + break; + } + } } void BinaryTree::seek(uint pos) { + unserialize(); if(pos > m_buffer.size()) stdext::throw_exception("BinaryTree: seek failed"); m_pos = pos; @@ -60,6 +113,7 @@ void BinaryTree::seek(uint pos) uint8 BinaryTree::getU8() { + unserialize(); if(m_pos+1 > m_buffer.size()) stdext::throw_exception("BinaryTree: getU8 failed"); uint8 v = m_buffer[m_pos]; @@ -69,6 +123,7 @@ uint8 BinaryTree::getU8() uint16 BinaryTree::getU16() { + unserialize(); if(m_pos+2 > m_buffer.size()) stdext::throw_exception("BinaryTree: getU16 failed"); uint16 v = stdext::readLE16(&m_buffer[m_pos]); @@ -78,6 +133,7 @@ uint16 BinaryTree::getU16() uint32 BinaryTree::getU32() { + unserialize(); if(m_pos+4 > m_buffer.size()) stdext::throw_exception("BinaryTree: getU32 failed"); uint32 v = stdext::readLE32(&m_buffer[m_pos]); @@ -87,6 +143,7 @@ uint32 BinaryTree::getU32() uint64 BinaryTree::getU64() { + unserialize(); if(m_pos+8 > m_buffer.size()) stdext::throw_exception("BinaryTree: getU64 failed"); uint64 v = stdext::readLE64(&m_buffer[m_pos]); @@ -96,10 +153,8 @@ uint64 BinaryTree::getU64() std::string BinaryTree::getString() { + unserialize(); uint16 len = getU16(); - if(len == 0 || len > 8192) - stdext::throw_exception("BinaryTree: getString failed: invalid or too large string length"); - if(m_pos+len > m_buffer.size()) stdext::throw_exception("BinaryTree: getString failed: string length exceeded buffer size."); diff --git a/src/framework/core/binarytree.h b/src/framework/core/binarytree.h index b9a52c96..9acb1b9e 100644 --- a/src/framework/core/binarytree.h +++ b/src/framework/core/binarytree.h @@ -32,18 +32,16 @@ enum { BINARYTREE_NODE_END = 0xFF }; -class BinaryTree : public std::enable_shared_from_this +class BinaryTree { public: - BinaryTree(const BinaryTreePtr& parent = nullptr) : m_pos(0), m_parent(parent) { } - - void unserialize(const FileStreamPtr& fin); - void serialize(const FileStreamPtr& fin); + BinaryTree(const FileStreamPtr& fin); + ~BinaryTree(); void seek(uint pos); void skip(uint len) { seek(tell() + len); } uint tell() { return m_pos; } - uint size() { return m_buffer.size(); } + uint size() { unserialize(); return m_buffer.size(); } uint8 getU8(); uint16 getU16(); @@ -51,16 +49,17 @@ public: uint64 getU64(); std::string getString(); - BinaryTreeVec getChildren() { return m_children; } - BinaryTreePtr getParent() { return m_parent.lock(); } - bool canRead() { return m_pos < m_buffer.size(); } + BinaryTreeVec getChildren(); + bool canRead() { unserialize(); return m_pos < m_buffer.size(); } private: - uint m_pos; + void unserialize(); + void skipNodes(); - BinaryTreeVec m_children; - BinaryTreeWeakPtr m_parent; + FileStreamPtr m_fin; DataBuffer m_buffer; + uint m_pos; + uint m_startPos; }; #endif diff --git a/src/framework/core/filestream.cpp b/src/framework/core/filestream.cpp index 3e671405..df40b576 100644 --- a/src/framework/core/filestream.cpp +++ b/src/framework/core/filestream.cpp @@ -143,7 +143,7 @@ void FileStream::skip(uint len) seek(tell() + len); } -int FileStream::size() +uint FileStream::size() { if(!m_caching) return PHYSFS_fileLength(m_fileHandle); @@ -151,7 +151,7 @@ int FileStream::size() return m_data.size(); } -int FileStream::tell() +uint FileStream::tell() { if(!m_caching) return PHYSFS_tell(m_fileHandle); @@ -249,13 +249,11 @@ std::string FileStream::getString() BinaryTreePtr FileStream::getBinaryTree() { - BinaryTreePtr root = BinaryTreePtr(new BinaryTree); uint8 byte = getU8(); - if(byte == BINARYTREE_NODE_START) - root->unserialize(asFileStream()); - else + if(byte != BINARYTREE_NODE_START) stdext::throw_exception(stdext::format("failed to read node start (getBinaryTree): %d", byte)); - return root; + + return BinaryTreePtr(new BinaryTree(asFileStream())); } void FileStream::addU8(uint8 v) diff --git a/src/framework/core/filestream.h b/src/framework/core/filestream.h index 18b2223b..bac90f10 100644 --- a/src/framework/core/filestream.h +++ b/src/framework/core/filestream.h @@ -43,8 +43,8 @@ public: int read(void *buffer, uint size, uint nmemb = 1); void seek(uint pos); void skip(uint len); - int size(); - int tell(); + uint size(); + uint tell(); std::string name() { return m_name; } uint8 getU8(); diff --git a/src/framework/luaengine/luainterface.cpp b/src/framework/luaengine/luainterface.cpp index e91079e5..ee58ffe6 100644 --- a/src/framework/luaengine/luainterface.cpp +++ b/src/framework/luaengine/luainterface.cpp @@ -721,7 +721,10 @@ void LuaInterface::error() int LuaInterface::ref() { - return luaL_ref(L, LUA_REGISTRYINDEX); + int ref = luaL_ref(L, LUA_REGISTRYINDEX); + assert(ref != LUA_NOREF); + assert(ref < 2147483647); + return ref; } int LuaInterface::weakRef() diff --git a/src/framework/luaengine/luaobject.h b/src/framework/luaengine/luaobject.h index dd694148..e26ee774 100644 --- a/src/framework/luaengine/luaobject.h +++ b/src/framework/luaengine/luaobject.h @@ -27,6 +27,7 @@ /// LuaObject, all script-able classes have it as base // @bindclass +#pragma pack(push,1) // disable memory alignment class LuaObject : public std::enable_shared_from_this { public: @@ -88,6 +89,7 @@ private: int m_fieldsTableRef; int m_metatableRef; }; +#pragma pack(pop) #include "luainterface.h" diff --git a/src/framework/util/attribstorage.h b/src/framework/util/attribstorage.h new file mode 100644 index 00000000..2643925a --- /dev/null +++ b/src/framework/util/attribstorage.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2010-2012 OTClient + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef ATTRIBSTORAGE_H +#define ATTRIBSTORAGE_H + +#include "../stdext/types.h" +#include +#include + + +#pragma pack(push,1) // disable memory alignment + +// this class was designed to use less memory as possible +class AttribStorage { +public: + AttribStorage() : m_attribs(nullptr), m_size(0) { } + ~AttribStorage() { if(m_attribs) delete[] m_attribs; } + + template + void set(uint8 id, T value) { + bool done = false; + for(int i=0;i(m_attribs[i]) == id) { + std::get<1>(m_attribs[i]) = value; + done = true; + break; + } + } + if(!done) { + auto attribs = new std::tuple[m_size+1]; + if(m_size > 0) { + for(int i=0;i + T get(uint8 id) const { + for(int i=0;i(m_attribs[i]) == id) + return boost::any_cast(std::get<1>(m_attribs[i])); + return T(); + } + + bool has(uint8 id) const { + for(int i=0;i(m_attribs[i]) == id) + return true; + return false; + } +private: + std::tuple* m_attribs; + uint8 m_size; +}; +#pragma pack(pop) + +#endif diff --git a/src/main.cpp b/src/main.cpp index c3162f42..5a074e10 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -25,6 +25,11 @@ #include #include +#include +#include +#include +#include + int main(int argc, const char* argv[]) { std::vector args(argv, argv + argc); diff --git a/src/otclient/creature.cpp b/src/otclient/creature.cpp index b5496b16..e6f5c61b 100644 --- a/src/otclient/creature.cpp +++ b/src/otclient/creature.cpp @@ -113,20 +113,21 @@ void Creature::internalDrawOutfit(const Point& dest, float scaleFactor, bool ani if(yPattern > 0 && !(m_outfit.getAddons() & (1 << (yPattern-1)))) continue; - m_datType->draw(dest, scaleFactor, 0, xPattern, yPattern, 0, animationPhase); + auto datType = rawGetDatType(); + datType->draw(dest, scaleFactor, 0, xPattern, yPattern, 0, animationPhase); if(getLayers() > 1) { Color oldColor = g_painter->getColor(); Painter::CompositionMode oldComposition = g_painter->getCompositionMode(); g_painter->setCompositionMode(Painter::CompositionMode_Multiply); g_painter->setColor(m_outfit.getHeadColor()); - m_datType->draw(dest, scaleFactor, DatYellowMask, xPattern, yPattern, 0, animationPhase); + datType->draw(dest, scaleFactor, DatYellowMask, xPattern, yPattern, 0, animationPhase); g_painter->setColor(m_outfit.getBodyColor()); - m_datType->draw(dest, scaleFactor, DatRedMask, xPattern, yPattern, 0, animationPhase); + datType->draw(dest, scaleFactor, DatRedMask, xPattern, yPattern, 0, animationPhase); g_painter->setColor(m_outfit.getLegsColor()); - m_datType->draw(dest, scaleFactor, DatGreenMask, xPattern, yPattern, 0, animationPhase); + datType->draw(dest, scaleFactor, DatGreenMask, xPattern, yPattern, 0, animationPhase); g_painter->setColor(m_outfit.getFeetColor()); - m_datType->draw(dest, scaleFactor, DatBlueMask, xPattern, yPattern, 0, animationPhase); + datType->draw(dest, scaleFactor, DatBlueMask, xPattern, yPattern, 0, animationPhase); g_painter->setColor(oldColor); g_painter->setCompositionMode(oldComposition); } @@ -154,7 +155,7 @@ void Creature::internalDrawOutfit(const Point& dest, float scaleFactor, bool ani if(m_outfit.getCategory() == DatEffectCategory) animationPhase = std::min(animationPhase+1, getAnimationPhases()); - m_datType->draw(dest, scaleFactor, 0, 0, 0, 0, animationPhase); + rawGetDatType()->draw(dest, scaleFactor, 0, 0, 0, 0, animationPhase); } } @@ -462,7 +463,6 @@ void Creature::setOutfit(const Outfit& outfit) { m_walkAnimationPhase = 0; // might happen when player is walking and outfit is changed. m_outfit = outfit; - m_datType = g_things.getDatType(outfit.getId(), outfit.getCategory()); } void Creature::setSkull(uint8 skull) @@ -548,3 +548,13 @@ Point Creature::getDrawOffset() } return drawOffset; } + +const ThingTypeDatPtr& Creature::getDatType() +{ + return g_things.getDatType(m_outfit.getId(), m_outfit.getCategory()); +} + +ThingTypeDat* Creature::rawGetDatType() +{ + return g_things.rawGetDatType(m_outfit.getId(), m_outfit.getCategory()); +} diff --git a/src/otclient/creature.h b/src/otclient/creature.h index 2d009372..98e816d6 100644 --- a/src/otclient/creature.h +++ b/src/otclient/creature.h @@ -96,6 +96,9 @@ public: CreaturePtr asCreature() { return std::static_pointer_cast(shared_from_this()); } bool isCreature() { return true; } + const ThingTypeDatPtr& getDatType(); + ThingTypeDat *rawGetDatType(); + protected: virtual void updateWalkAnimation(int totalPixelsWalked); virtual void updateWalkOffset(int totalPixelsWalked); diff --git a/src/otclient/effect.cpp b/src/otclient/effect.cpp index 01c16abc..529df785 100644 --- a/src/otclient/effect.cpp +++ b/src/otclient/effect.cpp @@ -32,7 +32,7 @@ void Effect::draw(const Point& dest, float scaleFactor, bool animate) int animationPhase = 0; if(animate) animationPhase = std::min((int)(m_animationTimer.ticksElapsed() / Otc::EFFECT_TICKS_PER_FRAME), getAnimationPhases() - 1); - m_datType->draw(dest, scaleFactor, 0, 0, 0, 0, animationPhase); + rawGetDatType()->draw(dest, scaleFactor, 0, 0, 0, 0, animationPhase); } void Effect::startAnimation() @@ -47,5 +47,14 @@ void Effect::startAnimation() void Effect::setId(uint32 id) { m_id = id; - m_datType = g_things.getDatType(m_id, DatEffectCategory); +} + +const ThingTypeDatPtr& Effect::getDatType() +{ + return g_things.getDatType(m_id, DatEffectCategory); +} + +ThingTypeDat *Effect::rawGetDatType() +{ + return g_things.rawGetDatType(m_id, DatEffectCategory); } diff --git a/src/otclient/effect.h b/src/otclient/effect.h index 1b8d0dd3..4c969072 100644 --- a/src/otclient/effect.h +++ b/src/otclient/effect.h @@ -41,6 +41,9 @@ public: EffectPtr asEffect() { return std::static_pointer_cast(shared_from_this()); } bool isEffect() { return true; } + const ThingTypeDatPtr& getDatType(); + ThingTypeDat *rawGetDatType(); + private: Timer m_animationTimer; uint16 m_id; diff --git a/src/otclient/item.cpp b/src/otclient/item.cpp index c4e9de30..65dc375e 100644 --- a/src/otclient/item.cpp +++ b/src/otclient/item.cpp @@ -38,11 +38,8 @@ Item::Item() : m_id(0), - m_countOrSubType(1), - m_actionId(0), - m_uniqueId(0), - m_shaderProgram(g_shaders.getDefaultItemShader()), - m_otbType(g_things.getNullOtbType()) + m_otbId(0), + m_countOrSubType(1) { } @@ -174,32 +171,20 @@ void Item::draw(const Point& dest, float scaleFactor, bool animate) zPattern = m_position.z % getNumPatternZ(); } - bool useShader = g_painter->hasShaders() && m_shaderProgram; - if(useShader) { - m_shaderProgram->bind(); - m_shaderProgram->setUniformValue(ShaderManager::ITEM_ID_UNIFORM, (int)m_id); - - g_painter->setShaderProgram(m_shaderProgram); - } - - m_datType->draw(dest, scaleFactor, 0, xPattern, yPattern, zPattern, animationPhase); - - if(useShader) - g_painter->resetShaderProgram(); + rawGetDatType()->draw(dest, scaleFactor, 0, xPattern, yPattern, zPattern, animationPhase); } void Item::setId(uint32 id) { - m_datType = g_things.getDatType(id, DatItemCategory); - m_otbType = g_things.findOtbForClientId(id); - m_id = m_datType->getId(); + m_otbId = g_things.findOtbForClientId(id)->getServerId(); + m_id = id; } void Item::setOtbId(uint16 id) { - m_otbType = g_things.getOtbType(id); - m_datType = g_things.getDatType(m_otbType->getClientId(), DatItemCategory); - m_id = m_datType->getId(); + auto otbType = g_things.getOtbType(id); + m_otbId = id; + m_id = otbType->getClientId(); } bool Item::isValid() @@ -229,29 +214,29 @@ void Item::unserializeItem(const BinaryTreePtr &in) setUniqueId(in->getU16()); break; case ATTR_NAME: - setName(in->getString()); + m_attribs.set(ATTR_NAME, in->getString()); break; case ATTR_TEXT: - setText(in->getString()); + m_attribs.set(ATTR_TEXT, in->getString()); break; case ATTR_DESC: - m_description = in->getString(); + m_attribs.set(ATTR_DESC, in->getString()); break; case ATTR_CONTAINER_ITEMS: - m_isContainer = true; - in->skip(4); + m_attribs.set(ATTR_CONTAINER_ITEMS, in->getU32()); break; case ATTR_HOUSEDOORID: - m_isDoor = true; - m_doorId = in->getU8(); + m_attribs.set(ATTR_HOUSEDOORID, in->getU8()); break; case ATTR_DEPOT_ID: - m_depotId = in->getU16(); + m_attribs.set(ATTR_DEPOT_ID, in->getU16()); break; case ATTR_TELE_DEST: { - m_teleportDestination.x = in->getU16(); - m_teleportDestination.y = in->getU16(); - m_teleportDestination.z = in->getU8(); + Position teleportDestination; + teleportDestination.x = in->getU16(); + teleportDestination.y = in->getU16(); + teleportDestination.z = in->getU8(); + m_attribs.set(ATTR_TELE_DEST, teleportDestination); break; } case ATTR_ARTICLE: @@ -286,12 +271,7 @@ void Item::unserializeItem(const BinaryTreePtr &in) bool Item::isMoveable() { - if(m_datType) - return !m_datType->isNotMoveable(); - - g_logger.warning(stdext::format( - "Invalid dat type for item %d", m_id)); - return false; + return !rawGetDatType()->isNotMoveable(); } ItemPtr Item::clone() @@ -300,3 +280,13 @@ ItemPtr Item::clone() *(item.get()) = *this; return item; } + +const ThingTypeDatPtr& Item::getDatType() +{ + return g_things.getDatType(m_id, DatItemCategory); +} + +ThingTypeDat* Item::rawGetDatType() +{ + return g_things.rawGetDatType(m_id, DatItemCategory); +} diff --git a/src/otclient/item.h b/src/otclient/item.h index c68a879c..2ef23e82 100644 --- a/src/otclient/item.h +++ b/src/otclient/item.h @@ -24,6 +24,7 @@ #define ITEM_H #include +#include #include "thing.h" #include "thingtypeotb.h" @@ -66,10 +67,12 @@ enum AttrTypes_t }; // @bindclass +#pragma pack(push,1) // disable memory alignment class Item : public Thing { public: Item(); + virtual ~Item() { } static ItemPtr create(int id); static ItemPtr createFromOtb(int id); @@ -81,43 +84,45 @@ public: void setCountOrSubType(int value) { m_countOrSubType = value; } void setCount(int count) { m_countOrSubType = count; } void setSubType(int subType) { m_countOrSubType = subType; } - void setActionId(int actionId) { m_actionId = actionId; } - void setUniqueId(int uniqueId) { m_uniqueId = uniqueId; } - void setDoorId(int doorId) { m_doorId = doorId; } - void setName(const std::string &name) { m_name = name; } - void setText(const std::string &text) { m_text = text; } - void setDescription(const std::string &description) { m_description = description; } int getCountOrSubType() { return m_countOrSubType; } int getSubType() { return m_countOrSubType; } int getCount() { return m_countOrSubType; } uint32 getId() { return m_id; } - std::string getName() { return m_name; } - uint8 getDoorId() { return m_doorId; } bool isValid(); ItemPtr clone(); - ItemPtr asItem() { return std::static_pointer_cast(shared_from_this()); } - bool isItem() { return true; } void unserializeItem(const BinaryTreePtr &in); bool isMoveable(); - bool isContainer() { return m_isContainer; } - bool isDoor() { return m_isDoor; } + + void setDepotId(uint16 depotId) { m_attribs.set(ATTR_DEPOT_ID, depotId); } + uint16 getDepotId() { return m_attribs.get(ATTR_DEPOT_ID); } + + void setDoorId(uint8 doorId) { m_attribs.set(ATTR_HOUSEDOORID, doorId); } + uint8 getDoorId() { return m_attribs.get(ATTR_HOUSEDOORID); } + + void setActionId(uint16 actionId) { m_attribs.set(ATTR_ACTION_ID, actionId); } + void setUniqueId(uint16 uniqueId) { m_attribs.set(ATTR_UNIQUE_ID, uniqueId); } + + bool isDepot() { return m_attribs.has(ATTR_DEPOT_ID); } + bool isContainer() { return m_attribs.has(ATTR_CONTAINER_ITEMS); } + bool isDoor() { return m_attribs.has(ATTR_HOUSEDOORID); } + bool isTeleport() { return m_attribs.has(ATTR_TELE_DEST); } + + ItemPtr asItem() { return std::static_pointer_cast(shared_from_this()); } + bool isItem() { return true; } + + const ThingTypeDatPtr& getDatType(); + ThingTypeDat *rawGetDatType(); private: uint16 m_id; + uint16 m_otbId; uint8 m_countOrSubType; - uint32 m_actionId, m_uniqueId; - uint16 m_depotId; - uint8 m_doorId; - Boolean m_isContainer; - Boolean m_isDoor; - - std::string m_name, m_text, m_description; - PainterShaderProgramPtr m_shaderProgram; - ThingTypeOtbPtr m_otbType; - Position m_teleportDestination; + AttribStorage m_attribs; }; +#pragma pack(pop) + #endif diff --git a/src/otclient/map.cpp b/src/otclient/map.cpp index 49af4a55..b19ed5f8 100644 --- a/src/otclient/map.cpp +++ b/src/otclient/map.cpp @@ -136,7 +136,6 @@ void Map::loadOtbm(const std::string& fileName) if(type != OTBM_TILE && type != OTBM_HOUSETILE) stdext::throw_exception(stdext::format("invalid node tile type %d", (int)type)); - TilePtr tile = nullptr; ItemPtr ground = nullptr; HousePtr house = nullptr; uint32 flags = TILESTATE_NONE; @@ -146,7 +145,7 @@ void Map::loadOtbm(const std::string& fileName) if(type == OTBM_HOUSETILE) { uint32 hId = nodeTile->getU32(); - tile = createTile(pos); + TilePtr tile = getOrCreateTile(pos); if(!(house = m_houses.getHouse(hId))) { house = HousePtr(new House(hId)); m_houses.addHouse(house); @@ -175,13 +174,7 @@ void Map::loadOtbm(const std::string& fileName) break; } case OTBM_ATTR_ITEM: { - ItemPtr item = Item::createFromOtb(nodeTile->getU16()); - if(tile) - addThing(item, pos, 255); - else if(item->isGround()) - ground = item; - else - tile = createTileEx(pos, ground, item); + addThing(Item::createFromOtb(nodeTile->getU16()), pos); break; } default: @@ -196,6 +189,7 @@ void Map::loadOtbm(const std::string& fileName) ItemPtr item = Item::createFromOtb(nodeItem->getU16()); item->unserializeItem(nodeItem); + if(item->isContainer()) { // This is a temporary way for reading container items. MapContainerPtr mapContainer(new MapContainer); @@ -217,18 +211,13 @@ void Map::loadOtbm(const std::string& fileName) item = nullptr; } else if(item->isDoor()) house->addDoor(item->getDoorId(), pos); - } else if(tile) - addThing(item, pos); - else if(item->isGround()) - ground = item; - else - tile = createTileEx(pos, ground, item); - } + } - if(!tile) - tile = createTileEx(pos, ground); + addThing(item, pos); + } - tile->setFlags((tileflags_t)flags); + if(const TilePtr& tile = getTile(pos)) + tile->setFlags((tileflags_t)flags); } } else if(mapDataType == OTBM_TOWNS) { TownPtr town = nullptr; @@ -263,6 +252,13 @@ void Map::loadOtbm(const std::string& fileName) stdext::throw_exception("Unknown map data node"); } + + int numItems = 0; + for(const auto& it : m_tiles) + numItems += it.second->getThingCount(); + + g_logger.debug(stdext::format("Total items: %d", numItems)); + g_logger.debug(stdext::format("Total tiles: %d", m_tiles.size())); g_logger.debug("OTBM read successfully."); fin->close(); /// TODO read XML Stuff (houses & spawns). diff --git a/src/otclient/map.h b/src/otclient/map.h index b83ab285..cde5c46d 100644 --- a/src/otclient/map.h +++ b/src/otclient/map.h @@ -122,6 +122,7 @@ public: // thing related void addThing(const ThingPtr& thing, const Position& pos, int stackPos = -1); ThingPtr getThing(const Position& pos, int stackPos); + bool removeThing(const ThingPtr& thing); bool removeThingByPos(const Position& pos, int stackPos); // tile related @@ -131,7 +132,6 @@ public: const TilePtr& getTile(const Position& pos); TilePtr getOrCreateTile(const Position& pos); void cleanTile(const Position& pos); - bool removeThing(const ThingPtr& thing); // known creature related void addCreature(const CreaturePtr& creature); diff --git a/src/otclient/missile.cpp b/src/otclient/missile.cpp index 79588517..dcd6db2e 100644 --- a/src/otclient/missile.cpp +++ b/src/otclient/missile.cpp @@ -63,7 +63,7 @@ void Missile::draw(const Point& dest, float scaleFactor, bool animate) } float fraction = m_animationTimer.ticksElapsed() / m_duration; - m_datType->draw(dest + m_delta * fraction * scaleFactor, scaleFactor, 0, xPattern, yPattern, 0, 0); + rawGetDatType()->draw(dest + m_delta * fraction * scaleFactor, scaleFactor, 0, xPattern, yPattern, 0, 0); } void Missile::setPath(const Position& fromPosition, const Position& toPosition) @@ -84,5 +84,14 @@ void Missile::setPath(const Position& fromPosition, const Position& toPosition) void Missile::setId(uint32 id) { m_id = id; - m_datType = g_things.getDatType(m_id, DatMissileCategory); +} + +const ThingTypeDatPtr& Missile::getDatType() +{ + return g_things.getDatType(m_id, DatMissileCategory); +} + +ThingTypeDat* Missile::rawGetDatType() +{ + return g_things.rawGetDatType(m_id, DatMissileCategory); } diff --git a/src/otclient/missile.h b/src/otclient/missile.h index 666c2599..4f03ca8e 100644 --- a/src/otclient/missile.h +++ b/src/otclient/missile.h @@ -37,8 +37,6 @@ class Missile : public Thing public: void draw(const Point& dest, float scaleFactor, bool animate); - void updateAnimation(); - void setId(uint32 id); void setPath(const Position& fromPosition, const Position& toPosition); @@ -47,6 +45,9 @@ public: MissilePtr asMissile() { return std::static_pointer_cast(shared_from_this()); } bool isMissile() { return true; } + const ThingTypeDatPtr& getDatType(); + ThingTypeDat *rawGetDatType(); + private: Timer m_animationTimer; Point m_delta; diff --git a/src/otclient/position.h b/src/otclient/position.h index 3a39c38f..d10aa6ab 100644 --- a/src/otclient/position.h +++ b/src/otclient/position.h @@ -214,7 +214,7 @@ public: struct PositionHasher : std::unary_function { std::size_t operator()(const Position& pos) const { - return ((((pos.x * 2048) + pos.y) * 16) + pos.z) % (2048*2048); + return (((((pos.x * 2048) + pos.y) * 16) + pos.z) % (2048*2048)) % 1000000; } }; diff --git a/src/otclient/thing.cpp b/src/otclient/thing.cpp index a22e92c1..69ea1e51 100644 --- a/src/otclient/thing.cpp +++ b/src/otclient/thing.cpp @@ -29,7 +29,7 @@ #include "game.h" Thing::Thing() : - m_datType(g_things.getNullDatType()) + m_datId(0) { } @@ -74,3 +74,13 @@ int Thing::getStackpos() return -1; } } + +const ThingTypeDatPtr& Thing::getDatType() +{ + return g_things.getNullDatType(); +} + +ThingTypeDat* Thing::rawGetDatType() +{ + return g_things.getNullDatType().get(); +} diff --git a/src/otclient/thing.h b/src/otclient/thing.h index 7dc4a514..ef606e73 100644 --- a/src/otclient/thing.h +++ b/src/otclient/thing.h @@ -25,6 +25,7 @@ #include "declarations.h" #include "thingtypedat.h" +#include "thingtypemanager.h" #include struct Light @@ -34,6 +35,7 @@ struct Light }; // @bindclass +#pragma pack(push,1) // disable memory alignment class Thing : public LuaObject { public: @@ -77,65 +79,67 @@ public: virtual bool isStaticText() { return false; } // type shortcuts - ThingTypeDatPtr getType() { return m_datType; } - Size getSize() { return m_datType->getSize(); } - int getWidth() { return m_datType->getWidth(); } - int getHeight() { return m_datType->getHeight(); } - Point getDisplacement() { return m_datType->getDisplacement(); } - int getDisplacementX() { return m_datType->getDisplacementX(); } - int getDisplacementY() { return m_datType->getDisplacementY(); } - int getExactSize() { return m_datType->getExactSize(); } - int getLayers() { return m_datType->getLayers(); } - int getNumPatternX() { return m_datType->getNumPatternX(); } - int getNumPatternY() { return m_datType->getNumPatternY(); } - int getNumPatternZ() { return m_datType->getNumPatternZ(); } - int getAnimationPhases() { return m_datType->getAnimationPhases(); } - int getGroundSpeed() { return m_datType->getGroundSpeed(); } - int getMaxTextLength() { return m_datType->getMaxTextLength(); } - int getLightLevel() { return m_datType->getLightLevel(); } - int getLightColor() { return m_datType->getLightColor(); } - int getMinimapColor() { return m_datType->getMinimapColor(); } - int getLensHelp() { return m_datType->getLensHelp(); } - int getClothSlot() { return m_datType->getClothSlot(); } - int getElevation() { return m_datType->getElevation(); } - bool isGround() { return m_datType->isGround(); } - bool isGroundBorder() { return m_datType->isGroundBorder(); } - bool isOnBottom() { return m_datType->isOnBottom(); } - bool isOnTop() { return m_datType->isOnTop(); } - bool isContainer() { return m_datType->isContainer(); } - bool isStackable() { return m_datType->isStackable(); } - bool isForceUse() { return m_datType->isForceUse(); } - bool isMultiUse() { return m_datType->isMultiUse(); } - bool isWritable() { return m_datType->isWritable(); } - bool isWritableOnce() { return m_datType->isWritableOnce(); } - bool isFluidContainer() { return m_datType->isFluidContainer(); } - bool isFluid() { return m_datType->isFluid(); } - bool isNotWalkable() { return m_datType->isNotWalkable(); } - bool isNotMoveable() { return m_datType->isNotMoveable(); } - bool blockProjectile() { return m_datType->blockProjectile(); } - bool isNotPathable() { return m_datType->isNotPathable(); } - bool isPickupable() { return m_datType->isPickupable(); } - bool isHangable() { return m_datType->isHangable(); } - bool isHookSouth() { return m_datType->isHookSouth(); } - bool isHookEast() { return m_datType->isHookEast(); } - bool isRotateable() { return m_datType->isRotateable(); } - bool hasLight() { return m_datType->hasLight(); } - bool isDontHide() { return m_datType->isDontHide(); } - bool isTranslucent() { return m_datType->isTranslucent(); } - bool hasDisplacement() { return m_datType->hasDisplacement(); } - bool hasElevation() { return m_datType->hasElevation(); } - bool isLyingCorpse() { return m_datType->isLyingCorpse(); } - bool isAnimateAlways() { return m_datType->isAnimateAlways(); } - bool hasMiniMapColor() { return m_datType->hasMiniMapColor(); } - bool hasLensHelp() { return m_datType->hasLensHelp(); } - bool isFullGround() { return m_datType->isFullGround(); } - bool isIgnoreLook() { return m_datType->isIgnoreLook(); } - bool isCloth() { return m_datType->isCloth(); } + virtual const ThingTypeDatPtr& getDatType(); + virtual ThingTypeDat *rawGetDatType(); + Size getSize() { return rawGetDatType()->getSize(); } + int getWidth() { return rawGetDatType()->getWidth(); } + int getHeight() { return rawGetDatType()->getHeight(); } + Point getDisplacement() { return rawGetDatType()->getDisplacement(); } + int getDisplacementX() { return rawGetDatType()->getDisplacementX(); } + int getDisplacementY() { return rawGetDatType()->getDisplacementY(); } + int getExactSize() { return rawGetDatType()->getExactSize(); } + int getLayers() { return rawGetDatType()->getLayers(); } + int getNumPatternX() { return rawGetDatType()->getNumPatternX(); } + int getNumPatternY() { return rawGetDatType()->getNumPatternY(); } + int getNumPatternZ() { return rawGetDatType()->getNumPatternZ(); } + int getAnimationPhases() { return rawGetDatType()->getAnimationPhases(); } + int getGroundSpeed() { return rawGetDatType()->getGroundSpeed(); } + int getMaxTextLength() { return rawGetDatType()->getMaxTextLength(); } + int getLightLevel() { return rawGetDatType()->getLightLevel(); } + int getLightColor() { return rawGetDatType()->getLightColor(); } + int getMinimapColor() { return rawGetDatType()->getMinimapColor(); } + int getLensHelp() { return rawGetDatType()->getLensHelp(); } + int getClothSlot() { return rawGetDatType()->getClothSlot(); } + int getElevation() { return rawGetDatType()->getElevation(); } + bool isGround() { return rawGetDatType()->isGround(); } + bool isGroundBorder() { return rawGetDatType()->isGroundBorder(); } + bool isOnBottom() { return rawGetDatType()->isOnBottom(); } + bool isOnTop() { return rawGetDatType()->isOnTop(); } + bool isContainer() { return rawGetDatType()->isContainer(); } + bool isStackable() { return rawGetDatType()->isStackable(); } + bool isForceUse() { return rawGetDatType()->isForceUse(); } + bool isMultiUse() { return rawGetDatType()->isMultiUse(); } + bool isWritable() { return rawGetDatType()->isWritable(); } + bool isWritableOnce() { return rawGetDatType()->isWritableOnce(); } + bool isFluidContainer() { return rawGetDatType()->isFluidContainer(); } + bool isFluid() { return rawGetDatType()->isFluid(); } + bool isNotWalkable() { return rawGetDatType()->isNotWalkable(); } + bool isNotMoveable() { return rawGetDatType()->isNotMoveable(); } + bool blockProjectile() { return rawGetDatType()->blockProjectile(); } + bool isNotPathable() { return rawGetDatType()->isNotPathable(); } + bool isPickupable() { return rawGetDatType()->isPickupable(); } + bool isHangable() { return rawGetDatType()->isHangable(); } + bool isHookSouth() { return rawGetDatType()->isHookSouth(); } + bool isHookEast() { return rawGetDatType()->isHookEast(); } + bool isRotateable() { return rawGetDatType()->isRotateable(); } + bool hasLight() { return rawGetDatType()->hasLight(); } + bool isDontHide() { return rawGetDatType()->isDontHide(); } + bool isTranslucent() { return rawGetDatType()->isTranslucent(); } + bool hasDisplacement() { return rawGetDatType()->hasDisplacement(); } + bool hasElevation() { return rawGetDatType()->hasElevation(); } + bool isLyingCorpse() { return rawGetDatType()->isLyingCorpse(); } + bool isAnimateAlways() { return rawGetDatType()->isAnimateAlways(); } + bool hasMiniMapColor() { return rawGetDatType()->hasMiniMapColor(); } + bool hasLensHelp() { return rawGetDatType()->hasLensHelp(); } + bool isFullGround() { return rawGetDatType()->isFullGround(); } + bool isIgnoreLook() { return rawGetDatType()->isIgnoreLook(); } + bool isCloth() { return rawGetDatType()->isCloth(); } protected: Position m_position; - ThingTypeDatPtr m_datType; + uint16 m_datId; }; +#pragma pack(pop) #endif diff --git a/src/otclient/thingtypemanager.cpp b/src/otclient/thingtypemanager.cpp index 690bf279..37119353 100644 --- a/src/otclient/thingtypemanager.cpp +++ b/src/otclient/thingtypemanager.cpp @@ -211,3 +211,4 @@ const ThingTypeOtbPtr& ThingTypeManager::getOtbType(uint16 id) } return m_otbTypes[id]; } + diff --git a/src/otclient/thingtypemanager.h b/src/otclient/thingtypemanager.h index 904ba12a..20f903bb 100644 --- a/src/otclient/thingtypemanager.h +++ b/src/otclient/thingtypemanager.h @@ -47,6 +47,8 @@ public: const ThingTypeDatPtr& getDatType(uint16 id, DatCategory category); const ThingTypeOtbPtr& getOtbType(uint16 id); + ThingTypeDat *rawGetDatType(uint16 id, DatCategory category) { return m_datTypes[category][id].get(); } + ThingTypeOtb *rawGetOtbType(uint16 id) { return m_otbTypes[id].get(); } uint32 getDatSignature() { return m_datSignature; } uint32 getOtbMajorVersion() { return m_otbMajorVersion; } diff --git a/src/otclient/tile.h b/src/otclient/tile.h index a2bc9d46..f69832e1 100644 --- a/src/otclient/tile.h +++ b/src/otclient/tile.h @@ -46,6 +46,7 @@ enum tileflags_t TILESTATE_DEPOT = 1 << 22 }; +#pragma pack(push,1) // disable memory alignment class Tile : public LuaObject { public: @@ -99,10 +100,11 @@ public: bool limitsFloorsView(); bool canErase(); - TilePtr asTile() { return std::static_pointer_cast(shared_from_this()); } void setFlags(tileflags_t flags) { m_flags |= (uint32)flags; } uint32 flags() { return m_flags; } + TilePtr asTile() { return std::static_pointer_cast(shared_from_this()); } + private: void update(); @@ -114,5 +116,6 @@ private: uint32 m_flags; uint8 m_minimapColorByte; }; +#pragma pack(pop) #endif