-
-
Notifications
You must be signed in to change notification settings - Fork 452
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Make single link node pool unlimited (#3986)
- Loading branch information
1 parent
13c35f8
commit 12d8bbf
Showing
16 changed files
with
321 additions
and
78 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,178 @@ | ||
/***************************************************************************** | ||
* | ||
* PROJECT: Multi Theft Auto v1.0 | ||
* LICENSE: See LICENSE in the top level directory | ||
* FILE: game_sa/CDynamicPool.h | ||
* PURPOSE: Custom implementation for SA pools | ||
* | ||
* Multi Theft Auto is available from http://www.multitheftauto.com/ | ||
* | ||
*****************************************************************************/ | ||
|
||
#pragma once | ||
|
||
#include <vector> | ||
#include <array> | ||
#include <memory> | ||
|
||
template <typename PoolObjT> | ||
class CDynamicPoolPart | ||
{ | ||
public: | ||
explicit CDynamicPoolPart(std::size_t size) : m_size{size} | ||
{ | ||
m_items = std::make_unique<PoolObjT[]>(size); | ||
m_unusedIndices.reserve(size); | ||
for (std::size_t i = 0; i < size; i++) | ||
m_unusedIndices.push_back(i); | ||
} | ||
|
||
PoolObjT* AllocateItem() | ||
{ | ||
std::size_t index = m_unusedIndices.back(); | ||
m_unusedIndices.pop_back(); | ||
return &m_items[index]; | ||
} | ||
|
||
void RemoveItem(PoolObjT* item) | ||
{ | ||
auto pos = item - m_items.get(); | ||
m_unusedIndices.push_back(pos); | ||
} | ||
|
||
bool OwnsItem(PoolObjT* item) const noexcept { return item >= m_items.get() && item < m_items.get() + m_size; } | ||
bool HasFreeSize() const noexcept { return m_unusedIndices.size() != 0; } | ||
std::size_t GetCapacity() const noexcept { return m_size; } | ||
std::size_t GetUsedSize() const noexcept { return m_size - m_unusedIndices.size(); } | ||
|
||
private: | ||
std::unique_ptr<PoolObjT[]> m_items; | ||
std::vector<std::size_t> m_unusedIndices; | ||
const std::size_t m_size; | ||
}; | ||
|
||
template <std::size_t InitialSize, std::size_t AddSize> | ||
struct PoolGrowAddStrategy | ||
{ | ||
static constexpr std::size_t GetInitialSize() { return InitialSize; } | ||
static constexpr std::size_t GetNextSize(std::size_t index) { return AddSize; } | ||
}; | ||
|
||
template <typename PoolObjT, typename GrowStrategy> | ||
class CDynamicPool | ||
{ | ||
public: | ||
CDynamicPool() | ||
{ | ||
constexpr size_t initialSize = GrowStrategy::GetInitialSize(); | ||
m_poolParts.emplace_back(initialSize); | ||
} | ||
|
||
PoolObjT* AllocateItem() | ||
{ | ||
for (auto& pool : m_poolParts) | ||
{ | ||
if (pool.HasFreeSize()) | ||
return pool.AllocateItem(); | ||
} | ||
|
||
try | ||
{ | ||
return AllocateNewPart().AllocateItem(); | ||
} | ||
catch (const std::bad_alloc&) | ||
{ | ||
assert(false && "Could not allocate a memory for CDynamicPoolPart"); | ||
} | ||
} | ||
|
||
void RemoveItem(PoolObjT* item) | ||
{ | ||
for (auto& pool : m_poolParts) | ||
{ | ||
if (pool.OwnsItem(item)) | ||
{ | ||
pool.RemoveItem(item); | ||
return; | ||
} | ||
} | ||
|
||
assert(false && "Invalid item for CDynamicPool::RemoveItem"); | ||
} | ||
|
||
std::size_t GetCapacity() const noexcept | ||
{ | ||
std::size_t size = 0; | ||
for (auto& pool : m_poolParts) | ||
size += pool.GetCapacity(); | ||
|
||
return size; | ||
} | ||
|
||
std::size_t GetUsedSize() const noexcept | ||
{ | ||
std::size_t size = 0; | ||
for (auto& pool : m_poolParts) | ||
size += pool.GetUsedSize(); | ||
|
||
return size; | ||
} | ||
|
||
bool SetCapacity(std::size_t newSize) { | ||
if (newSize == 0) | ||
return false; | ||
|
||
std::size_t currentSize = GetCapacity(); | ||
|
||
if (currentSize == newSize) | ||
return false; | ||
else if (currentSize < newSize) | ||
{ | ||
// Grow | ||
while (currentSize < newSize) | ||
{ | ||
try | ||
{ | ||
auto& nextPart = AllocateNewPart(); | ||
currentSize += nextPart.GetCapacity(); | ||
} | ||
catch (const std::bad_alloc&) | ||
{ | ||
return false; | ||
} | ||
} | ||
} | ||
else | ||
{ | ||
// Shrink | ||
while (true) | ||
{ | ||
auto& part = m_poolParts.back(); | ||
if (part.GetUsedSize() != 0) | ||
return false; | ||
|
||
currentSize -= part.GetCapacity(); | ||
if (currentSize < newSize) | ||
return false; | ||
|
||
m_poolParts.pop_back(); | ||
|
||
if (currentSize == newSize) | ||
return true; | ||
} | ||
} | ||
|
||
return true; | ||
} | ||
|
||
private: | ||
CDynamicPoolPart<PoolObjT>& AllocateNewPart() | ||
{ | ||
const std::size_t nextSize = GrowStrategy::GetNextSize(m_poolParts.size()); | ||
m_poolParts.emplace_back(nextSize); | ||
return m_poolParts.back(); | ||
} | ||
|
||
private: | ||
std::list<CDynamicPoolPart<PoolObjT>> m_poolParts; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
/***************************************************************************** | ||
* | ||
* PROJECT: Multi Theft Auto v1.0 | ||
* LICENSE: See LICENSE in the top level directory | ||
* FILE: game_sa/CPtrNodeSingleLinkPoolSA.cpp | ||
* PURPOSE: Custom implementation for the CPtrNodeSingleLinkPool pool | ||
* | ||
* Multi Theft Auto is available from http://www.multitheftauto.com/ | ||
* | ||
*****************************************************************************/ | ||
|
||
#include "StdInc.h" | ||
#include "CPtrNodeSingleLinkPoolSA.h" | ||
|
||
CPtrNodeSingleLinkPoolSA::pool_t* CPtrNodeSingleLinkPoolSA::m_customPool = nullptr; | ||
|
||
CPtrNodeSingleLinkPoolSA::CPtrNodeSingleLinkPoolSA() | ||
{ | ||
if (!m_customPool) | ||
m_customPool = new CPtrNodeSingleLinkPoolSA::pool_t(); | ||
} | ||
|
||
constexpr std::uint32_t HOOKPOS_SingleLinkNodeConstructor = 0x552380; | ||
constexpr std::size_t HOOKSIZE_SingleLinkNodeConstructor = 6; | ||
static CPtrNodeSingleLinkPoolSA::pool_item_t* __cdecl HOOK_SingleLinkNodeConstructor() | ||
{ | ||
return CPtrNodeSingleLinkPoolSA::GetPoolInstance()->AllocateItem(); | ||
} | ||
|
||
constexpr std::uint32_t HOOKPOS_SingleLinkNodeDestructor = 0x552390; | ||
constexpr std::size_t HOOKSIZE_SingleLinkNodeDestructor = 6; | ||
static CPtrNodeSingleLinkPoolSA::pool_item_t* __cdecl HOOK_SingleLinkNodeDestructor(CPtrNodeSingleLinkPoolSA::pool_item_t* item) | ||
{ | ||
CPtrNodeSingleLinkPoolSA::GetPoolInstance()->RemoveItem(item); | ||
// The game doesen't use the return value | ||
return item; | ||
} | ||
|
||
// Replace pool->RemoveItem here | ||
constexpr std::uint32_t HOOKPOS_CPtrListSingleLink_Flush = 0x55243B; | ||
constexpr std::size_t HOOKSIZE_CPtrListSingleLink_Flush = 6; | ||
constexpr std::uint32_t CONTINUE_CPtrListSingleLink_Flush = 0x55245B; | ||
static void _declspec(naked) HOOK_CPtrListSingleLink_Flush() | ||
{ | ||
__asm { | ||
mov edi, ecx ; save register | ||
|
||
; CPtrNodeSingleLinkPoolSA::m_customPool->RemoveItem(eax) | ||
|
||
mov ecx, CPtrNodeSingleLinkPoolSA::m_customPool | ||
push eax | ||
call CPtrNodeSingleLinkPoolSA::pool_t::RemoveItem | ||
|
||
mov ecx, edi ; restore | ||
jmp CONTINUE_CPtrListSingleLink_Flush | ||
} | ||
} | ||
|
||
void CPtrNodeSingleLinkPoolSA::StaticSetHooks() | ||
{ | ||
EZHookInstall(SingleLinkNodeConstructor); | ||
EZHookInstall(SingleLinkNodeDestructor); | ||
EZHookInstall(CPtrListSingleLink_Flush); | ||
|
||
// Skip the original pool initialization | ||
MemCpy((void*)0x550F26, "\xEB\x2D", 2); | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
/***************************************************************************** | ||
* | ||
* PROJECT: Multi Theft Auto v1.0 | ||
* LICENSE: See LICENSE in the top level directory | ||
* FILE: game_sa/CPtrNodeSingleLinkPoolSA.h | ||
* PURPOSE: Custom implementation for the CPtrNodeSingleLinkPool pool | ||
* | ||
* Multi Theft Auto is available from http://www.multitheftauto.com/ | ||
* | ||
*****************************************************************************/ | ||
|
||
#pragma once | ||
|
||
#include "CPoolSAInterface.h" | ||
#include "CDynamicPool.h" | ||
#include "CPtrNodeSingleListSA.h" | ||
#include <game/CPtrNodeSingleLinkPool.h> | ||
|
||
class CPtrNodeSingleLinkPoolSA final : public CPtrNodeSingleLinkPool | ||
{ | ||
public: | ||
using pool_item_t = CPtrNodeSingleLink<void*>; | ||
using pool_t = CDynamicPool<pool_item_t, PoolGrowAddStrategy<MAX_POINTER_SINGLE_LINKS, MAX_POINTER_SINGLE_LINKS / 2>>; | ||
|
||
CPtrNodeSingleLinkPoolSA(); | ||
|
||
std::size_t GetCapacity() const override { return m_customPool->GetCapacity(); } | ||
std::size_t GetUsedSize() const override { return m_customPool->GetUsedSize(); } | ||
|
||
bool Resize(std::size_t newSize) override { return m_customPool->SetCapacity(newSize); }; | ||
void ResetCapacity() override { m_customPool->SetCapacity(MAX_POINTER_SINGLE_LINKS); }; | ||
|
||
static auto* GetPoolInstance() { return m_customPool; } | ||
static void StaticSetHooks(); | ||
private: | ||
static pool_t* m_customPool; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.