Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make single link node pool unlimited #3986

Merged
Show file tree
Hide file tree
Changes from 6 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
192 changes: 192 additions & 0 deletions Client/game_sa/CDynamicPool.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
/*****************************************************************************
*
* 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_usedSize{0}, m_lastFreeSlot{0}
{
m_items = std::make_unique<PoolObjT[]>(size);
m_usedSlots = std::make_unique<bool[]>(size);
TheNormalnij marked this conversation as resolved.
Show resolved Hide resolved
}

PoolObjT* AllocateItem()
{
bool flipped = false;
while (true)
{
if (m_usedSlots[m_lastFreeSlot])
{
m_lastFreeSlot++;
if (m_lastFreeSlot >= m_size)
{
if (flipped)
return nullptr;
m_lastFreeSlot = 0;
flipped = true;
}
}
else
{
m_usedSlots[m_lastFreeSlot] = true;
m_usedSize++;
return &m_items[m_lastFreeSlot];
}
}
}

void RemoveItem(PoolObjT* item)
{
auto pos = item - m_items.get();
assert(m_usedSlots[pos], "Invalid item for CDynamicPoolPart::RemoveItem");

m_usedSlots[pos] = false;
m_usedSize--;
}

bool OwnsItem(PoolObjT* item) const noexcept { return item >= m_items.get() && item < m_items.get() + m_size; }
bool HasFreeSize() const noexcept { return m_size != m_usedSize; }
std::size_t GetCapacity() const noexcept { return m_size; }
std::size_t GetUsedSize() const noexcept { return m_usedSize; }

private:
std::unique_ptr<PoolObjT[]> m_items;
std::unique_ptr<bool[]> m_usedSlots;
const std::size_t m_size;
std::size_t m_usedSize;
std::size_t m_lastFreeSlot;
};

template <std::size_t InitialSize>
struct PoolGrownByHalfStrategy
{
static constexpr std::size_t GetInitialSize() { return InitialSize; }
static constexpr std::size_t GetNextSize(std::size_t index) { return InitialSize / 2; }
};

template <typename PoolObjT, typename GrownStrategy>
TheNormalnij marked this conversation as resolved.
Show resolved Hide resolved
class CDynamicPool
{
public:
CDynamicPool()
{
constexpr size_t initialSize = GrownStrategy::GetInitialSize();
m_poolParts.emplace_back(std::make_unique<CDynamicPoolPart<PoolObjT>>(initialSize));
}

PoolObjT* AllocateItem()
{
for (auto& pool : m_poolParts)
{
if (pool->HasFreeSize())
return pool->AllocateItem();
}

return AllocateNewPart()->AllocateItem();
TheNormalnij marked this conversation as resolved.
Show resolved Hide resolved
}

void RemoveItem(PoolObjT* item)
{
for (auto& pool : m_poolParts)
{
if (pool->OwnsItem(item))
{
pool->RemoveItem(item);
return;
}
}

throw std::exception("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)
{
// Grown
while (currentSize < newSize)
{
try
{
auto* nextPart = AllocateNewPart();
currentSize += nextPart->GetCapacity();
}
catch (const std::bad_alloc& ex)
{
return false;
}
}
}
else
{
// Shrink
while (true)
{
auto* part = m_poolParts.back().get();
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 = GrownStrategy::GetNextSize(m_poolParts.size());
m_poolParts.emplace_back(std::make_unique<CDynamicPoolPart<PoolObjT>>(nextSize));
TheNormalnij marked this conversation as resolved.
Show resolved Hide resolved
return m_poolParts.back().get();
}

private:
std::vector<std::unique_ptr<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
47 changes: 47 additions & 0 deletions Client/game_sa/CPtrNodeSingleLinkPoolSA.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*****************************************************************************
*
* 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;
}

void CPtrNodeSingleLinkPoolSA::StaticSetHooks()
{
EZHookInstall(SingleLinkNodeConstructor);
EZHookInstall(SingleLinkNodeDestructor);

// Skip the original pool initialization
MemCpy((void*)0x550F26, "\xEB\x2D", 2);
}

36 changes: 36 additions & 0 deletions Client/game_sa/CPtrNodeSingleLinkPoolSA.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*****************************************************************************
*
* 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, PoolGrownByHalfStrategy<MAX_POINTER_SINGLE_LINKS>>;

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); };

static auto* GetPoolInstance() { return m_customPool; }
static void StaticSetHooks();
private:
static pool_t* m_customPool;
};
5 changes: 5 additions & 0 deletions Client/mods/deathmatch/logic/luadefs/CLuaEngineDefs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <game/CColPoint.h>
#include <game/CObjectGroupPhysicalProperties.h>
#include <game/CStreaming.h>
#include <game/CPtrNodeSingleLinkPool.h>
#include <lua/CLuaFunctionParser.h>
#include "CLuaEngineDefs.h"

Expand Down Expand Up @@ -2505,6 +2506,10 @@ bool CLuaEngineDefs::EngineSetPoolCapacity(lua_State* luaVM, ePools pool, size_t
{
return m_pBuildingManager->SetPoolCapacity(newSize);
}
case ePools::POINTER_SINGLE_LINK_POOL:
{
return g_pGame->GetPools()->GetPtrNodeSingleLinkPool().Resize(newSize);
}
default:
throw std::invalid_argument("Can not change this pool capacity");
}
Expand Down
2 changes: 2 additions & 0 deletions Client/sdk/game/CPools.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "CBuildingsPool.h"
#include "CDummyPool.h"
#include "CTxdPool.h"
#include "CPtrNodeSingleLinkPool.h"

class CClientEntity;
class CEntity;
Expand Down Expand Up @@ -111,4 +112,5 @@ class CPools
virtual CBuildingsPool& GetBuildingsPool() noexcept = 0;
virtual CDummyPool& GetDummyPool() noexcept = 0;
virtual CTxdPool& GetTxdPool() noexcept = 0;
virtual CPtrNodeSingleLinkPool& GetPtrNodeSingleLinkPool() noexcept = 0;
};
19 changes: 19 additions & 0 deletions Client/sdk/game/CPtrNodeSingleLinkPool.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*****************************************************************************
*
* PROJECT: Multi Theft Auto
* LICENSE: See LICENSE in the top level directory
* FILE: sdk/game/CPtrNodeSingleLinkPool.h
*
* Multi Theft Auto is available from http://www.multitheftauto.com/
*
*****************************************************************************/

#pragma once

class CPtrNodeSingleLinkPool
{
public:
virtual bool Resize(std::size_t size) = 0;
virtual std::size_t GetCapacity() const = 0;
virtual std::size_t GetUsedSize() const = 0;
};
Loading
Loading