Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
178 changes: 178 additions & 0 deletions Client/game_sa/CDynamicPool.h
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;
};
2 changes: 2 additions & 0 deletions Client/game_sa/CGameSA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
#include "CIplStoreSA.h"
#include "CBuildingRemovalSA.h"
#include "CCheckpointSA.h"
#include "CPtrNodeSingleLinkPoolSA.h"

extern CGameSA* pGame;

Expand Down Expand Up @@ -245,6 +246,7 @@ CGameSA::CGameSA()
CVehicleSA::StaticSetHooks();
CCheckpointSA::StaticSetHooks();
CHudSA::StaticSetHooks();
CPtrNodeSingleLinkPoolSA::StaticSetHooks();
}
catch (const std::bad_alloc& e)
{
Expand Down
7 changes: 2 additions & 5 deletions Client/game_sa/CPoolsSA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -900,8 +900,7 @@ int CPoolsSA::GetPoolCapacity(ePools pool)
iPtr = 0x550F82;
break;
case POINTER_SINGLE_LINK_POOL:
iPtr = 0x550F46;
break;
return GetPtrNodeSingleLinkPool().GetCapacity();
case ENV_MAP_MATERIAL_POOL:
iPtr = 0x5DA08E;
break;
Expand Down Expand Up @@ -1067,9 +1066,7 @@ int CPoolsSA::GetNumberOfUsedSpaces(ePools pool)
dwThis = CLASS_CPtrNodeDoubleLinkPool;
break;
case POINTER_SINGLE_LINK_POOL:
dwFunc = FUNC_CPtrNodeSingleLinkPool_GetNoOfUsedSpaces;
dwThis = CLASS_CPtrNodeSingleLinkPool;
break;
return GetPtrNodeSingleLinkPool().GetUsedSize();
default:
return -1;
}
Expand Down
3 changes: 3 additions & 0 deletions Client/game_sa/CPoolsSA.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "CBuildingsPoolSA.h"
#include "CDummyPoolSA.h"
#include "CTxdPoolSA.h"
#include "CPtrNodeSingleLinkPoolSA.h"

#define INVALID_POOL_ARRAY_ID 0xFFFFFFFF

Expand Down Expand Up @@ -97,6 +98,7 @@ class CPoolsSA : public CPools
CBuildingsPool& GetBuildingsPool() noexcept override { return m_BuildingsPool; };
CDummyPool& GetDummyPool() noexcept { return m_DummyPool; };
CTxdPool& GetTxdPool() noexcept { return m_TxdPool; };
CPtrNodeSingleLinkPool& GetPtrNodeSingleLinkPool() noexcept override { return m_PtrNodeSingleLinkPool; };

private:
// Pools
Expand All @@ -111,6 +113,7 @@ class CPoolsSA : public CPools
CBuildingsPoolSA m_BuildingsPool;
CDummyPoolSA m_DummyPool;
CTxdPoolSA m_TxdPool;
CPtrNodeSingleLinkPoolSA m_PtrNodeSingleLinkPool;

bool m_bGetVehicleEnabled;
};
Expand Down
68 changes: 68 additions & 0 deletions Client/game_sa/CPtrNodeSingleLinkPoolSA.cpp
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);
}

37 changes: 37 additions & 0 deletions Client/game_sa/CPtrNodeSingleLinkPoolSA.h
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;
};
1 change: 1 addition & 0 deletions Client/mods/deathmatch/logic/CClientGame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -515,6 +515,7 @@ CClientGame::~CClientGame()
g_pGame->SetPreWeaponFireHandler(NULL);
g_pGame->SetPostWeaponFireHandler(NULL);
g_pGame->SetTaskSimpleBeHitHandler(NULL);
g_pGame->GetPools()->GetPtrNodeSingleLinkPool().ResetCapacity();
g_pGame->GetAudioEngine()->SetWorldSoundHandler(NULL);
g_pCore->SetMessageProcessor(NULL);
g_pCore->GetKeyBinds()->SetKeyStrokeHandler(NULL);
Expand Down
21 changes: 2 additions & 19 deletions Client/mods/deathmatch/logic/CClientObjectManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -230,22 +230,7 @@ void CClientObjectManager::OnDestruction(CClientObject* pObject)
void CClientObjectManager::UpdateLimitInfo()
{
m_iEntryInfoNodeEntries = g_pMultiplayer->EntryInfoNodePool_NoOfUsedSpaces();
m_iPointerNodeSingleLinkEntries = g_pMultiplayer->PtrNodeSingleLinkPool_NoOfUsedSpaces();
m_iPointerNodeDoubleLinkEntries = g_pMultiplayer->PtrNodeDoubleLinkPool_NoOfUsedSpaces();

/*
CPools* pPools = g_pGame->GetPools();
unsigned int nEntryInfoNodeEntries = pPools->GetEntryInfoNodePool()->GetNumberOfUsedSpaces();
unsigned int nPointerNodeSingleLinkEntries = pPools->GetPointerNodeSingleLinkPool()->GetNumberOfUsedSpaces();
unsigned int nPointerNodeDoubleLinkEntries = pPools->GetPointerNodeDoubleLinkPool()->GetNumberOfUsedSpaces();

g_pCore->ChatPrintf("%d = %d ### %d = %d ### %d = %d", false, nEntryInfoNodeEntries, m_iEntryInfoNodeEntries, nPointerNodeSingleLinkEntries,
m_iPointerNodeSingleLinkEntries, nPointerNodeDoubleLinkEntries, m_iPointerNodeDoubleLinkEntries);

assert(nEntryInfoNodeEntries == m_iEntryInfoNodeEntries);
assert(nPointerNodeSingleLinkEntries == m_iPointerNodeSingleLinkEntries);
assert(nPointerNodeDoubleLinkEntries == m_iPointerNodeDoubleLinkEntries);
*/
}

bool CClientObjectManager::StaticIsObjectLimitReached()
Expand Down Expand Up @@ -278,18 +263,16 @@ bool CClientObjectManager::IsHardObjectLimitReached()
return true;

// If we've run out of either of these limit, don't allow more objects
if (m_iEntryInfoNodeEntries >= MAX_ENTRY_INFO_NODES_MTA || m_iPointerNodeSingleLinkEntries >= MAX_POINTER_SINGLE_LINKS_MTA ||
m_iPointerNodeDoubleLinkEntries >= MAX_POINTER_DOUBLE_LINKS_MTA)
if (m_iEntryInfoNodeEntries >= MAX_ENTRY_INFO_NODES_MTA || m_iPointerNodeDoubleLinkEntries >= MAX_POINTER_DOUBLE_LINKS_MTA)
{
if (!m_bDoneLimitWarning)
{
m_bDoneLimitWarning = true;
SString strMessage(
"CClientObjectManager reached limit -"
" ENTRY_INFO_NODES:%d/%d"
" POINTER_SINGLE_LINKS:%d/%d"
" POINTER_DOUBLE_LINKS:%d/%d",
m_iEntryInfoNodeEntries, MAX_ENTRY_INFO_NODES_MTA, m_iPointerNodeSingleLinkEntries, MAX_POINTER_SINGLE_LINKS_MTA,
m_iEntryInfoNodeEntries, MAX_ENTRY_INFO_NODES_MTA,
m_iPointerNodeDoubleLinkEntries, MAX_POINTER_DOUBLE_LINKS_MTA);
g_pCore->GetConsole()->Echo(strMessage);
AddReportLog(7430, strMessage);
Expand Down
Loading
Loading