#include "stdafx.h" #include "ObjectFactory.h" #include #include "Object.h" #include "Player.h" #include "Item.h" #include "MapObject.h" #include "Monster.h" #include "Summoned.h" #include "MapNPC.h" #include "Merchant.h" #include "LuckyMonster.h" #include "TotemNpc.h" #include "SSQMonster.h" #include "Collection.h" #include "CrystalWarp.h" #include "FriendMonster.h" #include "SyncMerchant.h" #include "ObjKeyGenerator.h" #include "MemoryPoolFactory.h" #include "MemoryPoolFactoryV.h" //////////////////////////////////////////////////////////////////////////////////////////////////// // REGION : IObjectFactoryImpl //////////////////////////////////////////////////////////////////////////////////////////////////// class IObjectFactoryImpl { public: IObjectFactoryImpl() {} virtual ~IObjectFactoryImpl() {} public: virtual void Init( const size_t player_pool_size, const size_t monster_pool_size, const size_t item_pool_size, const size_t map_object_Pool_size, const size_t map_npc_pool_size, const size_t merchant_pool_size, const size_t lucky_monster_pool_size ) { __UNUSED(player_pool_size); __UNUSED(monster_pool_size); __UNUSED(item_pool_size); __UNUSED(map_object_Pool_size); __UNUSED(map_npc_pool_size); __UNUSED(merchant_pool_size); __UNUSED(lucky_monster_pool_size); } virtual void Release() {} virtual Object* AllocObject(const eOBJECT_TYPE object_type) = 0; virtual bool FreeObject(Object* const object) = 0; }; //////////////////////////////////////////////////////////////////////////////////////////////////// // REGION : FixedChunkImpl //////////////////////////////////////////////////////////////////////////////////////////////////// class FixedChunkImpl : public IObjectFactoryImpl { public: FixedChunkImpl() : monster_keygen_(MONSTER_OBJECT_KEY+1, NPC_OBJECT_KEY), item_keygen_(ITEM_OBJECT_KEY+1, PET_OBJECT_KEY), monster_pool_(monster_keygen_), summoned_pool_(monster_keygen_), item_pool_(item_keygen_), money_pool_(item_keygen_), map_npc_pool_(monster_keygen_), merchant_pool_(monster_keygen_), lucky_monster_pool_(monster_keygen_), totem_npc_pool_(item_keygen_), ssq_monster_pool_(monster_keygen_), crystal_warp_pool_(monster_keygen_), friend_monster_pool_(monster_keygen_), sync_merchant_pool_(monster_keygen_) { pools_[player_pool_.kType] = &player_pool_; pools_[monster_pool_.kType] = &monster_pool_; pools_[summoned_pool_.kType] = &summoned_pool_; pools_[item_pool_.kType] = &item_pool_; pools_[money_pool_.kType] = &money_pool_; pools_[map_object_pool_.kType] = &map_object_pool_; pools_[map_npc_pool_.kType] = &map_npc_pool_; pools_[merchant_pool_.kType] = &merchant_pool_; pools_[lucky_monster_pool_.kType] = &lucky_monster_pool_; pools_[totem_npc_pool_.kType] = &totem_npc_pool_; pools_[ssq_monster_pool_.kType] = &ssq_monster_pool_; pools_[collection_pool_.kType] = &collection_pool_; pools_[crystal_warp_pool_.kType] = &crystal_warp_pool_; pools_[friend_monster_pool_.kType] = &friend_monster_pool_; pools_[sync_merchant_pool_.kType] = &sync_merchant_pool_; } ~FixedChunkImpl() { } public: virtual Object* AllocObject(const eOBJECT_TYPE object_type) { Pools::iterator it = pools_.find(object_type); if (it == pools_.end()) { SUNLOG( eCRITICAL_LOG, _T("|%s|%d|Invalid object type.|ObjectType = %d|"), __FUNCTION__, __LINE__, object_type ); assert(false); return NULL; } IObjectPool* const object_pool = it->second; return object_pool->Alloc(); } virtual bool FreeObject(Object* const object) { if (object == NULL) { SUNLOG( eCRITICAL_LOG, _T("|%s|%d|Object is null.|"), __FUNCTION__, __LINE__ ); assert(false); return false; } if (object->IsDeleted()) { const Object::Key key = object->GetObjectKey(); SUNLOG( eCRITICAL_LOG, _T("|%s|%d|Object is already deleted.|ObjectKey = %d|"), __FUNCTION__, __LINE__, key ); assert(false); return false; } const eOBJECT_TYPE object_type = object->GetObjectType(); Pools::iterator it = pools_.find(object_type); if (it == pools_.end()) { SUNLOG( eCRITICAL_LOG, _T("|%s|%d|Invalid object type.|ObjectType = %d|"), __FUNCTION__, __LINE__, object_type ); assert(false); return false; } IObjectPool* const object_pool = it->second; return object_pool->Free(object); } private: // Ű »ý¼º±â class ObjectKeyGenerator { public: enum { kInvalidKey = 0 }; public: ObjectKeyGenerator(const Object::Key min_key, const Object::Key max_key) : min_key_(min_key), max_key_(max_key), key_(min_key_) { assert(min_key_ < max_key_); } ~ObjectKeyGenerator() { } public: Object::Key Alloc() { if (return_keys_.empty() == false) { const Object::Key key = return_keys_.front(); return_keys_.pop_front(); free_keys_.erase(key); return key; } if (key_ > max_key_) { assert(false); return kInvalidKey; } return key_++; } bool Free(const Object::Key key) { if (free_keys_.find(key) != free_keys_.end()) { assert(false); return false; } return_keys_.push_back(key); free_keys_.insert(key); return true; } private: typedef STLX_DEQUE ReturnKeys; typedef STLX_HASH_SET FreeKeys; const Object::Key min_key_; const Object::Key max_key_; Object::Key key_; ReturnKeys return_keys_; FreeKeys free_keys_; }; // ¸Þ¸ð¸® Ç® ÀÎÅÍÆäÀ̽º class IObjectPool { public: IObjectPool() {} virtual ~IObjectPool() {} virtual Object* Alloc() = 0; virtual bool Free(Object* const object) = 0; }; // ¸Þ¸ð¸® Ç® (ŰÁ¨ »ç¿ë) template class ObjectPool : public IObjectPool { public: enum { kType = kObjectType }; ObjectPool(ObjectKeyGenerator& keygen) : pool_impl_(kPoolSize), keygen_(keygen) { } public: virtual Object* Alloc() { const Object::Key key = keygen_.Alloc(); if (key == ObjectKeyGenerator::kInvalidKey) { return NULL; } Object* object = pool_impl_.construct(); if (object == NULL) { keygen_.Free(key); return NULL; } object->SetObjectKey(key); object->SetObjectType(kObjectType); return object; } virtual bool Free(Object* const object) { OBJECT_T* dest_obj = (OBJECT_T*)object; const Object::Key key = dest_obj->GetObjectKey(); if (keygen_.Free(key) == false) { return false; } dest_obj->Reuse(); pool_impl_.destroy(dest_obj); return true; } private: typedef boost::object_pool PoolImpl; PoolImpl pool_impl_; ObjectKeyGenerator& keygen_; }; // ¸Þ¸ð¸® Ç® (ŰÁ¨ »ç¿ë ¾ÈÇÔ) template class ObjectPool : public IObjectPool { public: enum { kType = kObjectType }; ObjectPool() : pool_impl_(kPoolSize) { } public: virtual Object* Alloc() { Object* object = pool_impl_.construct(); object->SetObjectKey(1); object->SetObjectType(kObjectType); return object; } virtual bool Free(Object* const object) { OBJECT_T* dest_obj = (OBJECT_T*)object; dest_obj->Reuse(); pool_impl_.destroy(dest_obj); return true; } private: typedef boost::object_pool PoolImpl; PoolImpl pool_impl_; }; struct PoolSize { enum { kPlayer = 10 }; enum { kMonster = 1000 }; enum { kSummoned = 10 }; enum { kItem = 1000 }; enum { kMoney = 1000 }; enum { kMapObject = 100 }; enum { kMapNpc = 10 }; enum { kMerchant = 10 }; enum { kLuckyMonster = 10 }; enum { kTotemNpc = 10 }; enum { kSSQMonster = 20 }; enum { kCollection = 20 }; enum { kCrystalWarp = 10 }; enum { kFriendMonster = 20 }; enum { kSyncMerchant = 20 }; }; typedef ObjectPool PlayerPool; typedef ObjectPool MonsterPool; typedef ObjectPool SummonedPool; typedef ObjectPool ItemPool; typedef ObjectPool MoneyPool; typedef ObjectPool MapObjectPool; typedef ObjectPool MapNpcPool; typedef ObjectPool MerchantPool; typedef ObjectPool LuckyMonsterPool; typedef ObjectPool TotemNpcPool; typedef ObjectPool SSQMonsterPool; typedef ObjectPool CollectionPool; typedef ObjectPool CrystalWarpPool; typedef ObjectPool FriendMonsterPool; typedef ObjectPool SyncMerchantPool; typedef STLX_HASH_MAP Pools; private: ObjectKeyGenerator monster_keygen_; ObjectKeyGenerator item_keygen_; PlayerPool player_pool_; MonsterPool monster_pool_; SummonedPool summoned_pool_; ItemPool item_pool_; MoneyPool money_pool_; MapObjectPool map_object_pool_; MapNpcPool map_npc_pool_; MerchantPool merchant_pool_; LuckyMonsterPool lucky_monster_pool_; TotemNpcPool totem_npc_pool_; SSQMonsterPool ssq_monster_pool_; CollectionPool collection_pool_; CrystalWarpPool crystal_warp_pool_; FriendMonsterPool friend_monster_pool_; SyncMerchantPool sync_merchant_pool_; Pools pools_; }; // FixedChunkImpl //////////////////////////////////////////////////////////////////////////////////////////////////// // REGION : VariableChunkImpl //////////////////////////////////////////////////////////////////////////////////////////////////// class VariableChunkImpl : public IObjectFactoryImpl { public: VariableChunkImpl() { typedef ObjectPoolDefault PlayerPool; typedef ObjectPoolDefault MonsterPool; typedef ObjectPoolDefault SummonedPool; typedef ObjectPoolDefault ItemPool; typedef ObjectPoolDefault MapObjectPool; typedef ObjectPoolDefault MapNpcPool; typedef ObjectPoolDefault MerchantPool; typedef ObjectPoolDefault LuckyMonsterPool; typedef ObjectPoolDefault TotemNpcPool; typedef ObjectPoolDefault SSQMonsterPool; typedef ObjectPoolDefault CollectionPool; typedef ObjectPoolDefault CrystalWarpPool; typedef ObjectPoolDefault FriendMonsterPool; typedef ObjectPoolDefault SyncMerchantPool; router_.RegisterPool(PoolIndex::kPlayer); router_.RegisterPool(PoolIndex::kMonster); router_.RegisterPool(PoolIndex::kSummoned); router_.RegisterPool(PoolIndex::kItem); router_.RegisterPool(PoolIndex::kMapObject); router_.RegisterPool(PoolIndex::kMapNpc); router_.RegisterPool(PoolIndex::kMerchant); router_.RegisterPool(PoolIndex::kLuckyMonster); router_.RegisterPool(PoolIndex::kTotemNpc); router_.RegisterPool(PoolIndex::kSSQMonster); router_.RegisterPool(PoolIndex::kCollection); router_.RegisterPool(PoolIndex::kCrystalWarp); router_.RegisterPool(PoolIndex::kFriendMonster); router_.RegisterPool(PoolIndex::kSyncMerchant); KeyGenerator* keygens[PoolIndex::kMax] = { NULL, // PoolIndex::kPlayer &monster_keygen_, // PoolIndex::kMonster &monster_keygen_, // PoolIndex::kSummoned &field_item_keygen_, // PoolIndex::kItem NULL, // PoolIndex::kMapObject &monster_keygen_, // PoolIndex::kMapNpc &monster_keygen_, // PoolIndex::kMerchant &monster_keygen_, // PoolIndex::kLuckyMonster &field_item_keygen_, // PoolIndex::kTotemNpc &monster_keygen_, // PoolIndex::kSSQMonster NULL, // PoolIndex::kCollection &monster_keygen_, // PoolIndex::kCrystalWarp &monster_keygen_, // PoolIndex::kFriendMonster &monster_keygen_ // PoolIndex::kSyncMerchant }; for (int i = PoolIndex::kPlayer; i < PoolIndex::kMax; ++i) { IObjectAllocator* const alloc = dynamic_cast(router_.GetPool(i)); alloc->RegisterKeyGenerator(keygens[i]); } } ~VariableChunkImpl() { } public: virtual void Init( const size_t player_pool_size, const size_t monster_pool_size, const size_t item_pool_size, const size_t map_object_Pool_size, const size_t map_npc_pool_size, const size_t merchant_pool_size, const size_t lucky_monster_pool_size ) { __UNUSED(player_pool_size); __UNUSED(monster_pool_size); __UNUSED(item_pool_size); __UNUSED(map_object_Pool_size); __UNUSED(map_npc_pool_size); __UNUSED(merchant_pool_size); __UNUSED(lucky_monster_pool_size); if (router_.Initialize(PoolIndex::kPlayer, 10, 20, "Player") == false) { SUNLOG( eCRITICAL_LOG, _T("|%s|%d|Failed to initialize memory pool.|PoolIndex = %d|"), __FUNCTION__, __LINE__, PoolIndex::kPlayer ); assert(false); } if (router_.Initialize(PoolIndex::kMonster, 100, 100, "Monster") == false) { SUNLOG( eCRITICAL_LOG, _T("|%s|%d|Failed to initialize memory pool.|PoolIndex = %d|"), __FUNCTION__, __LINE__, PoolIndex::kMonster ); assert(false); } if (router_.Initialize(PoolIndex::kSummoned, 10, 20, "Summoned") == false) { SUNLOG( eCRITICAL_LOG, _T("|%s|%d|Failed to initialize memory pool.|PoolIndex = %d|"), __FUNCTION__, __LINE__, PoolIndex::kSummoned ); assert(false); } if (router_.Initialize(PoolIndex::kItem, 100, 100, "Item") == false) { SUNLOG( eCRITICAL_LOG, _T("|%s|%d|Failed to initialize memory pool.|PoolIndex = %d|"), __FUNCTION__, __LINE__, PoolIndex::kItem ); assert(false); } if (router_.Initialize(PoolIndex::kMapObject, 100, 100, "MapObject") == false) { SUNLOG( eCRITICAL_LOG, _T("|%s|%d|Failed to initialize memory pool.|PoolIndex = %d|"), __FUNCTION__, __LINE__, PoolIndex::kMapObject ); assert(false); } if (router_.Initialize(PoolIndex::kMapNpc, 10, 20, "MapNpc") == false) { SUNLOG( eCRITICAL_LOG, _T("|%s|%d|Failed to initialize memory pool.|PoolIndex = %d|"), __FUNCTION__, __LINE__, PoolIndex::kMapNpc ); assert(false); } if (router_.Initialize(PoolIndex::kMerchant, 10, 20, "Merchant") == false) { SUNLOG( eCRITICAL_LOG, _T("|%s|%d|Failed to initialize memory pool.|PoolIndex = %d|"), __FUNCTION__, __LINE__, PoolIndex::kMerchant ); assert(false); } if (router_.Initialize(PoolIndex::kLuckyMonster, 10, 10, "LuckyMonster") == false) { SUNLOG( eCRITICAL_LOG, _T("|%s|%d|Failed to initialize memory pool.|PoolIndex = %d|"), __FUNCTION__, __LINE__, PoolIndex::kLuckyMonster ); assert(false); } if (router_.Initialize(PoolIndex::kTotemNpc, 10, 20, "TotemNpc") == false) { SUNLOG( eCRITICAL_LOG, _T("|%s|%d|Failed to initialize memory pool.|PoolIndex = %d|"), __FUNCTION__, __LINE__, PoolIndex::kTotemNpc ); assert(false); } if (router_.Initialize(PoolIndex::kSSQMonster, 20, 20, "SSQMonster") == false) { SUNLOG( eCRITICAL_LOG, _T("|%s|%d|Failed to initialize memory pool.|PoolIndex = %d|"), __FUNCTION__, __LINE__, PoolIndex::kSSQMonster ); assert(false); } if (router_.Initialize(PoolIndex::kCollection, 20, 20, "Collection") == false) { SUNLOG( eCRITICAL_LOG, _T("|%s|%d|Failed to initialize memory pool.|PoolIndex = %d|"), __FUNCTION__, __LINE__, PoolIndex::kCollection ); assert(false); } if (router_.Initialize(PoolIndex::kCrystalWarp, 10, 10, "CrystalWarp") == false) { SUNLOG( eCRITICAL_LOG, _T("|%s|%d|Failed to initialize memory pool.|PoolIndex = %d|"), __FUNCTION__, __LINE__, PoolIndex::kCrystalWarp ); assert(false); } if (router_.Initialize(PoolIndex::kFriendMonster, 20, 20, "FriendMonster") == false) { SUNLOG( eCRITICAL_LOG, _T("|%s|%d|Failed to initialize memory pool.|PoolIndex = %d|"), __FUNCTION__, __LINE__, PoolIndex::kFriendMonster ); assert(false); } if (router_.Initialize(PoolIndex::kSyncMerchant, 20, 20, "SyncMerchant") == false) { SUNLOG( eCRITICAL_LOG, _T("|%s|%d|Failed to initialize memory pool.|PoolIndex = %d|"), __FUNCTION__, __LINE__, PoolIndex::kSyncMerchant ); assert(false); } monster_keygen_.Create(MONSTER_OBJECT_KEY+1, NPC_OBJECT_KEY); field_item_keygen_.Create(ITEM_OBJECT_KEY+1, PET_OBJECT_KEY); } virtual void Release() { router_.Release(); } virtual Object* AllocObject(const eOBJECT_TYPE object_type) { const PoolIndex::Value pool_index = GetPoolIndex(object_type); if (pool_index >= PoolIndex::kMax) { SUNLOG( eCRITICAL_LOG, _T("|%s|%d|Invalid object type.|ObjectType = %d|"), __FUNCTION__, __LINE__, object_type ); assert(false); return NULL; } Object* const object = (Object*)router_.Alloc(pool_index); if (object == NULL) { SUNLOG( eCRITICAL_LOG, _T("|%s|%d|Fail to create object.|ObjectType = %d, PoolIndex = %d|"), __FUNCTION__, __LINE__, object_type, pool_index ); assert(false); return NULL; } if (object_type == ITEM_OBJECT || object_type == MONEY_OBJECT) { object->SetObjectType(object_type); } return object; } virtual bool FreeObject(Object* const object) { if (object == NULL) { return false; } const eOBJECT_TYPE object_type = object->GetObjectType(); const PoolIndex::Value pool_index = GetPoolIndex(object_type); if (pool_index >= PoolIndex::kMax) { SUNLOG( eCRITICAL_LOG, _T("|%s|%d|Invalid object type.|ObjectType = %d|"), __FUNCTION__, __LINE__, object_type ); assert(false); return false; } return !!router_.Free(pool_index, object); } private: struct PoolIndex { enum Value { kPlayer = 0, kMonster, kSummoned, kItem, kMapObject, kMapNpc, kMerchant, kLuckyMonster, kTotemNpc, kSSQMonster, kCollection, kCrystalWarp, kFriendMonster, kSyncMerchant, kMax }; }; typedef util::CObjKeyGenerator<> KeyGenerator; // IObjectAllocator class IObjectAllocator { public: IObjectAllocator() : keygen_(NULL) { } virtual void RegisterKeyGenerator(KeyGenerator* const keygen) { keygen_ = keygen; } virtual void ActionPostAlloc(Object* const object, const eOBJECT_TYPE object_type) { if (keygen_ != NULL) { const DWORD key = keygen_->GetKey(); object->SetObjectKey(key); } else { object->SetObjectKey(1); } object->SetObjectType(object_type); } virtual void ActionPrevFree(Object* const object) { if (keygen_ != NULL) { const DWORD key = object->GetObjectKey(); keygen_->RestoreKey(key); } object->Reuse(); } private: KeyGenerator* keygen_; }; // ObjectPoolDefault template class ObjectPoolDefault : public util::CMemoryPoolFactory, public IObjectAllocator { public: ObjectPoolDefault() { } virtual void* Alloc() { Object* const object = (Object*)Base::Alloc(); IObjectAllocator::ActionPostAlloc(object, object->GetObjectType()); return object; } virtual BOOL Free(void* node) { Object* const object = (Object*)node; IObjectAllocator::ActionPrevFree(object); return Base::Free(object); } private: typedef util::CMemoryPoolFactory Base; }; private: PoolIndex::Value GetPoolIndex(const eOBJECT_TYPE object_type) const { switch (object_type) { case PLAYER_OBJECT: return PoolIndex::kPlayer; case MONSTER_OBJECT: return PoolIndex::kMonster; case SUMMON_OBJECT: return PoolIndex::kSummoned; case ITEM_OBJECT: case MONEY_OBJECT: return PoolIndex::kItem; case MAP_OBJECT: return PoolIndex::kMapObject; case MAPNPC_OBJECT: return PoolIndex::kMapNpc; case MERCHANT_OBJECT: return PoolIndex::kMerchant; case LUCKYMON_OBJECT: return PoolIndex::kLuckyMonster; case TOTEMNPC_OBJECT: return PoolIndex::kTotemNpc; case SSQMONSTER_OBJECT: return PoolIndex::kSSQMonster; case COLLECTION_OBJECT: return PoolIndex::kCollection; case CRYSTALWARP_OBJECT: return PoolIndex::kCrystalWarp; case FRIEND_MONSTER_OBJECT: return PoolIndex::kFriendMonster; case SYNC_MERCHANT_OBJECT: return PoolIndex::kSyncMerchant; } return PoolIndex::kMax; } private: util::PoolRouter router_; KeyGenerator monster_keygen_; KeyGenerator field_item_keygen_; }; // VariableChunkImpl //////////////////////////////////////////////////////////////////////////////////////////////////// // REGION : ObjectFactory //////////////////////////////////////////////////////////////////////////////////////////////////// ObjectFactory::ObjectFactory() { } ObjectFactory::~ObjectFactory() { } void ObjectFactory::CreateImpl(const int chunk_mode) { SUNLOG( eCRITICAL_LOG, _T("|%s|%d|Creating object factory implement...|ChunkMode = %d|"), __FUNCTION__, __LINE__, chunk_mode ); //#ifdef USE_FIXED_SIZE_MEMORY_POOL typedef FixedChunkImpl DefaultImpl; //#else // typedef VariableChunkImpl DefaultImpl; //#endif switch (chunk_mode) { case kVariableChunk: impl_.reset(new VariableChunkImpl()); return; case kFixedChunk: impl_.reset(new FixedChunkImpl()); return; default: impl_.reset(new DefaultImpl()); return; } } void ObjectFactory::Init( const size_t player_pool_size, const size_t monster_pool_size, const size_t item_pool_size, const size_t map_object_Pool_size, const size_t map_npc_pool_size, const size_t merchant_pool_size, const size_t lucky_monster_pool_size ) { int chunk_mode = kDefaultChunkMode; { char path_buf[MAX_PATH] = { 0 }; const size_t written = ::GetModuleFileName(NULL, path_buf, _countof(path_buf)); if (written > 0) { std::string ini_path(path_buf, written); const size_t deli_pos = ini_path.find_last_of('\\'); if (deli_pos > 0) { ini_path = ini_path.substr(0, deli_pos); ini_path += "\\MemoryPool.ini"; chunk_mode = ::GetPrivateProfileInt( "OBJECT_FACTORY", "CHUNK_MODE", kDefaultChunkMode, ini_path.c_str()); } } } CreateImpl(chunk_mode); return impl_->Init( player_pool_size, monster_pool_size, item_pool_size, map_object_Pool_size, map_npc_pool_size, merchant_pool_size, lucky_monster_pool_size); } void ObjectFactory::Release() { return impl_->Release(); } Object* ObjectFactory::AllocObject(const eOBJECT_TYPE object_type) { return impl_->AllocObject(object_type); } bool ObjectFactory::FreeObject(Object* const object) { return impl_->FreeObject(object); }