mirror of
https://github.com/JezuzLizard/T4SP-Server-Plugin.git
synced 2025-04-19 21:22:54 +00:00
525 lines
13 KiB
C++
525 lines
13 KiB
C++
#include <stdinc.hpp>
|
|
#include "clientscript_public.hpp"
|
|
|
|
namespace codsrc
|
|
{
|
|
// Restored
|
|
game::RefVector* GetRefVector(game::scriptInstance_t inst, unsigned int id)
|
|
{
|
|
assert(id);
|
|
|
|
assert((id * MT_NODE_SIZE) < MT_SIZE);
|
|
|
|
return (game::RefVector*)&game::gScrMemTreePub[inst].mt_buffer->nodes[id];
|
|
}
|
|
|
|
// Decomp Status: Tested, Completed
|
|
int MT_GetSubTreeSize(game::scriptInstance_t inst, int nodeNum)
|
|
{
|
|
int treeSize;
|
|
|
|
if (nodeNum)
|
|
{
|
|
treeSize = game::MT_GetSubTreeSize(inst, game::gScrMemTreeGlob[inst].nodes[nodeNum].next);
|
|
return treeSize + game::MT_GetSubTreeSize(inst, game::gScrMemTreeGlob[inst].nodes[nodeNum].prev) + 1;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
// Decomp Status: Tested, Completed
|
|
void MT_DumpTree(game::scriptInstance_t inst)
|
|
{
|
|
int size;
|
|
|
|
//assert(game::gScrMemTreeGlob[inst].totalAlloc == totalAlloc);
|
|
//assert(game::gScrMemTreeGlob[inst].totalAllocBuckets == totalAllocBuckets);
|
|
|
|
game::Com_Printf(game::CON_CHANNEL_PARSERSCRIPT, "********************************\n");
|
|
for (int i = 0; i <= MT_NODE_BITS; ++i)
|
|
{
|
|
size = game::MT_GetSubTreeSize(inst, game::gScrMemTreeGlob[inst].head[i]);
|
|
game::Com_Printf(game::CON_CHANNEL_PARSERSCRIPT, "%d subtree has %d * %d = %d free buckets\n", i, size, 1 << i, size << i);
|
|
}
|
|
game::Com_Printf(game::CON_CHANNEL_PARSERSCRIPT, "********************************\n");
|
|
game::Com_Printf(game::CON_CHANNEL_PARSERSCRIPT, "********************************\n");
|
|
game::Com_Printf(game::CON_CHANNEL_PARSERSCRIPT, "********************************\n");
|
|
|
|
//assert(totalBuckets == (1 << MEMORY_NODE_BITS) - 1);
|
|
}
|
|
|
|
// Decomp Status: Tested, Completed
|
|
void MT_InitBits(game::scriptInstance_t inst)
|
|
{
|
|
char bits;
|
|
int temp;
|
|
int i;
|
|
|
|
for (i = 0; i < MT_NUM_BUCKETS; ++i)
|
|
{
|
|
bits = 0;
|
|
|
|
for (temp = i; temp; temp >>= 1)
|
|
{
|
|
if (temp & 1)
|
|
{
|
|
++bits;
|
|
}
|
|
}
|
|
|
|
game::gScrMemTreeGlob[inst].numBits[i] = bits;
|
|
|
|
for (bits = 8; i & ((1 << bits) - 1); --bits);
|
|
|
|
game::gScrMemTreeGlob[inst].leftBits[i] = bits;
|
|
bits = 0;
|
|
|
|
for (temp = i; temp; temp >>= 1)
|
|
{
|
|
++bits;
|
|
}
|
|
|
|
game::gScrMemTreeGlob[inst].logBits[i] = bits;
|
|
}
|
|
}
|
|
|
|
// Decomp Status: Tested, Completed
|
|
int MT_GetScore(game::scriptInstance_t inst, int num)
|
|
{
|
|
char bits;
|
|
|
|
union MTnum_t
|
|
{
|
|
int i;
|
|
uint8_t b[4];
|
|
};
|
|
|
|
assert(num);
|
|
|
|
assert(MT_NODE_COUNT - num);
|
|
|
|
MTnum_t mtnum;
|
|
|
|
mtnum.i = MT_NODE_COUNT - num;
|
|
|
|
bits = game::gScrMemTreeGlob[inst].leftBits[mtnum.b[0]];
|
|
|
|
if (!mtnum.b[0])
|
|
{
|
|
bits += game::gScrMemTreeGlob[inst].leftBits[mtnum.b[1]];
|
|
}
|
|
|
|
return mtnum.i - (game::gScrMemTreeGlob[inst].numBits[mtnum.b[1]] + game::gScrMemTreeGlob[inst].numBits[mtnum.b[0]]) + (1 << bits);
|
|
}
|
|
|
|
// Decomp Status: Tested, Completed
|
|
void MT_AddMemoryNode(game::scriptInstance_t inst, int newNode, int size)
|
|
{
|
|
int node;
|
|
int nodeNum;
|
|
int newScore;
|
|
uint16_t* parentNode;
|
|
int level;
|
|
int score;
|
|
|
|
assert(size >= 0 && size <= MT_NODE_BITS);
|
|
|
|
parentNode = &game::gScrMemTreeGlob[inst].head[size];
|
|
node = game::gScrMemTreeGlob[inst].head[size];
|
|
if (game::gScrMemTreeGlob[inst].head[size])
|
|
{
|
|
newScore = game::MT_GetScore(inst, newNode);
|
|
nodeNum = 0;
|
|
level = MT_NODE_COUNT;
|
|
do
|
|
{
|
|
assert(newNode != node);
|
|
|
|
score = game::MT_GetScore(inst, node);
|
|
|
|
assert(score != newScore);
|
|
|
|
if (score < newScore)
|
|
{
|
|
while (1)
|
|
{
|
|
*parentNode = (short)newNode;
|
|
game::gScrMemTreeGlob[inst].nodes[newNode] = game::gScrMemTreeGlob[inst].nodes[node];
|
|
if (!node)
|
|
{
|
|
break;
|
|
}
|
|
level >>= 1;
|
|
|
|
assert(node != nodeNum);
|
|
|
|
if (node >= nodeNum)
|
|
{
|
|
parentNode = &game::gScrMemTreeGlob[inst].nodes[newNode].next;
|
|
nodeNum += level;
|
|
}
|
|
else
|
|
{
|
|
parentNode = &game::gScrMemTreeGlob[inst].nodes[newNode].prev;
|
|
nodeNum -= level;
|
|
}
|
|
|
|
newNode = node;
|
|
node = *parentNode;
|
|
}
|
|
return;
|
|
}
|
|
level >>= 1;
|
|
|
|
assert(newNode != nodeNum);
|
|
|
|
if (newNode >= nodeNum)
|
|
{
|
|
parentNode = &game::gScrMemTreeGlob[inst].nodes[node].next;
|
|
nodeNum += level;
|
|
}
|
|
else
|
|
{
|
|
parentNode = &game::gScrMemTreeGlob[inst].nodes[node].prev;
|
|
nodeNum -= level;
|
|
}
|
|
|
|
node = *parentNode;
|
|
} while (node);
|
|
}
|
|
|
|
*parentNode = (short)newNode;
|
|
|
|
game::gScrMemTreeGlob[inst].nodes[newNode].prev = 0;
|
|
game::gScrMemTreeGlob[inst].nodes[newNode].next = 0;
|
|
}
|
|
|
|
// Decomp Status: Tested, Completed
|
|
char MT_RemoveMemoryNode(game::scriptInstance_t inst, int oldNode, int size)
|
|
{
|
|
game::MemoryNode tempNodeValue;
|
|
int node;
|
|
game::MemoryNode oldNodeValue;
|
|
int nodeNum;
|
|
uint16_t* parentNode;
|
|
int prevScore;
|
|
int nextScore;
|
|
int level;
|
|
|
|
assert(size >= 0 && size <= MT_NODE_BITS);
|
|
|
|
nodeNum = 0;
|
|
level = MT_NODE_COUNT;
|
|
parentNode = &game::gScrMemTreeGlob[inst].head[size];
|
|
|
|
for (node = *parentNode; node; node = *parentNode)
|
|
{
|
|
if (oldNode == node)
|
|
{
|
|
oldNodeValue = game::gScrMemTreeGlob[inst].nodes[oldNode];
|
|
|
|
while (1)
|
|
{
|
|
if (oldNodeValue.prev)
|
|
{
|
|
if (oldNodeValue.next)
|
|
{
|
|
prevScore = game::MT_GetScore(inst, oldNodeValue.prev);
|
|
nextScore = game::MT_GetScore(inst, oldNodeValue.next);
|
|
|
|
assert(prevScore != nextScore);
|
|
|
|
if (prevScore >= nextScore)
|
|
{
|
|
oldNode = oldNodeValue.prev;
|
|
*parentNode = oldNodeValue.prev;
|
|
parentNode = &game::gScrMemTreeGlob[inst].nodes[oldNodeValue.prev].prev;
|
|
}
|
|
else
|
|
{
|
|
oldNode = oldNodeValue.next;
|
|
*parentNode = oldNodeValue.next;
|
|
parentNode = &game::gScrMemTreeGlob[inst].nodes[oldNodeValue.next].next;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
oldNode = oldNodeValue.prev;
|
|
*parentNode = oldNodeValue.prev;
|
|
parentNode = &game::gScrMemTreeGlob[inst].nodes[oldNodeValue.prev].prev;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
oldNode = oldNodeValue.next;
|
|
*parentNode = oldNodeValue.next;
|
|
|
|
if (!oldNodeValue.next)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
parentNode = &game::gScrMemTreeGlob[inst].nodes[oldNodeValue.next].next;
|
|
}
|
|
|
|
assert(oldNode);
|
|
|
|
tempNodeValue = oldNodeValue;
|
|
oldNodeValue = game::gScrMemTreeGlob[inst].nodes[oldNode];
|
|
game::gScrMemTreeGlob[inst].nodes[oldNode] = tempNodeValue;
|
|
}
|
|
}
|
|
|
|
if (oldNode == nodeNum)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
level >>= 1;
|
|
|
|
if (oldNode >= nodeNum)
|
|
{
|
|
parentNode = &game::gScrMemTreeGlob[inst].nodes[node].next;
|
|
nodeNum += level;
|
|
}
|
|
else
|
|
{
|
|
parentNode = &game::gScrMemTreeGlob[inst].nodes[node].prev;
|
|
nodeNum -= level;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// Decomp Status: Tested, Completed
|
|
void MT_RemoveHeadMemoryNode(game::scriptInstance_t inst, int size)
|
|
{
|
|
game::MemoryNode tempNodeValue;
|
|
int oldNode;
|
|
game::MemoryNode oldNodeValue;
|
|
uint16_t* parentNode;
|
|
int prevScore;
|
|
int nextScore;
|
|
|
|
assert(size >= 0 && size <= MT_NODE_BITS);
|
|
|
|
parentNode = &game::gScrMemTreeGlob[inst].head[size];
|
|
oldNodeValue = game::gScrMemTreeGlob[inst].nodes[*parentNode];
|
|
|
|
while (1)
|
|
{
|
|
if (!oldNodeValue.prev)
|
|
{
|
|
oldNode = oldNodeValue.next;
|
|
*parentNode = oldNodeValue.next;
|
|
if (!oldNode)
|
|
{
|
|
break;
|
|
}
|
|
parentNode = &game::gScrMemTreeGlob[inst].nodes[oldNode].next;
|
|
}
|
|
else
|
|
{
|
|
if (oldNodeValue.next)
|
|
{
|
|
prevScore = game::MT_GetScore(inst, oldNodeValue.prev);
|
|
nextScore = game::MT_GetScore(inst, oldNodeValue.next);
|
|
|
|
assert(prevScore != nextScore);
|
|
|
|
if (prevScore >= nextScore)
|
|
{
|
|
oldNode = oldNodeValue.prev;
|
|
*parentNode = (short)oldNode;
|
|
parentNode = &game::gScrMemTreeGlob[inst].nodes[oldNode].prev;
|
|
}
|
|
else
|
|
{
|
|
oldNode = oldNodeValue.next;
|
|
*parentNode = (short)oldNode;
|
|
parentNode = &game::gScrMemTreeGlob[inst].nodes[oldNode].next;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
oldNode = oldNodeValue.prev;
|
|
*parentNode = (short)oldNode;
|
|
parentNode = &game::gScrMemTreeGlob[inst].nodes[oldNode].prev;
|
|
}
|
|
}
|
|
assert(oldNode != 0);
|
|
|
|
tempNodeValue = oldNodeValue;
|
|
oldNodeValue = game::gScrMemTreeGlob[inst].nodes[oldNode];
|
|
game::gScrMemTreeGlob[inst].nodes[oldNode] = tempNodeValue;
|
|
}
|
|
}
|
|
|
|
// Decomp Status: Tested, Completed
|
|
void MT_Init(game::scriptInstance_t inst)
|
|
{
|
|
game::Sys_EnterCriticalSection(game::CRITSECT_MEMORY_TREE);
|
|
|
|
game::scrMemTreeGlob_t* memTreeBuffer = &game::gScrMemTreeGlob[inst];
|
|
game::gScrMemTreePub[inst].mt_buffer = memTreeBuffer;
|
|
|
|
game::MT_InitBits(inst);
|
|
|
|
for (int i = 0; i <= MT_NODE_BITS; ++i)
|
|
{
|
|
memTreeBuffer->head[i] = 0;
|
|
}
|
|
|
|
memTreeBuffer->nodes[0].next = 0;
|
|
memTreeBuffer->nodes[0].prev = 0;
|
|
|
|
for (int i = 0; i < MT_NODE_BITS; ++i)
|
|
{
|
|
game::MT_AddMemoryNode(inst, 1 << i, i);
|
|
}
|
|
|
|
game::Sys_LeaveCriticalSection(game::CRITSECT_MEMORY_TREE);
|
|
}
|
|
|
|
// Decomp Status: Tested, Completed
|
|
void MT_Error(game::scriptInstance_t inst, const char* funcName, int numBytes)
|
|
{
|
|
game::MT_DumpTree(inst);
|
|
game::Com_Printf(game::CON_CHANNEL_PARSERSCRIPT, "%s: failed memory allocation of %d bytes for script usage\n", funcName, numBytes);
|
|
game::Scr_DumpScriptThreads(inst);
|
|
game::gScrVmPub[inst].terminal_error = 1;
|
|
game::Scr_Error("failed memory allocation for script usage", inst, 0);
|
|
}
|
|
|
|
// Decomp Status: Tested, Completed
|
|
int MT_GetSize(int numBytes, game::scriptInstance_t inst)
|
|
{
|
|
int numBuckets;
|
|
int result;
|
|
|
|
assert(numBytes > 0);
|
|
|
|
if (numBytes >= MT_NODE_COUNT)
|
|
{
|
|
game::MT_Error(inst, "MT_GetSize: max allocation exceeded", numBytes);
|
|
result = 0;
|
|
}
|
|
else
|
|
{
|
|
numBuckets = (numBytes + MT_NODE_SIZE - 1) / MT_NODE_SIZE - 1;
|
|
if (numBuckets > MT_NUM_BUCKETS - 1)
|
|
{
|
|
result = game::gScrMemTreeGlob[inst].logBits[numBuckets >> 8] + 8;
|
|
}
|
|
else
|
|
{
|
|
result = game::gScrMemTreeGlob[inst].logBits[numBuckets];
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// Decomp Status: Tested, Completed
|
|
unsigned __int16 MT_AllocIndex(game::scriptInstance_t inst, int numBytes)
|
|
{
|
|
int nodeNum;
|
|
int size = game::MT_GetSize(numBytes, inst);
|
|
int newSize;
|
|
|
|
assert(size >= 0 && size <= MT_NODE_BITS);
|
|
|
|
game::Sys_EnterCriticalSection(game::CRITSECT_MEMORY_TREE);
|
|
|
|
for (newSize = size; ; ++newSize)
|
|
{
|
|
if (newSize > MT_NODE_BITS)
|
|
{
|
|
game::Sys_LeaveCriticalSection(game::CRITSECT_MEMORY_TREE);
|
|
game::MT_Error(inst, "MT_AllocIndex", numBytes);
|
|
return 0;
|
|
}
|
|
nodeNum = game::gScrMemTreeGlob[inst].head[newSize];
|
|
if (game::gScrMemTreeGlob[inst].head[newSize])
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
game::MT_RemoveHeadMemoryNode(inst, newSize);
|
|
|
|
while (newSize != size)
|
|
{
|
|
--newSize;
|
|
game::MT_AddMemoryNode(inst, nodeNum + (1 << newSize), newSize);
|
|
}
|
|
|
|
//assert(type);
|
|
|
|
//assert(!game::gScrMemTreeDebugGlob[inst].mt_usage[nodeNum]);
|
|
|
|
//assert(!game::gScrMemTreeDebugGlob[inst].mt_usage_size[nodeNum]);
|
|
|
|
game::Sys_LeaveCriticalSection(game::CRITSECT_MEMORY_TREE);
|
|
return (short)nodeNum;
|
|
}
|
|
|
|
// Decomp Status: Tested, Completed
|
|
void MT_FreeIndex(int numBytes, game::scriptInstance_t inst, int nodeNum)
|
|
{
|
|
int size = game::MT_GetSize(numBytes, inst);
|
|
|
|
assert(size >= 0 && size <= MT_NODE_BITS);
|
|
|
|
assert(nodeNum > 0 && nodeNum < MT_NODE_COUNT);
|
|
|
|
game::Sys_EnterCriticalSection(game::CRITSECT_MEMORY_TREE);
|
|
|
|
//assert(game::gScrMemTreeDebugGlob[inst].mt_usage[nodeNum]);
|
|
|
|
//assert(game::gScrMemTreeDebugGlob[inst].mt_usage_size[nodeNum] == size);
|
|
|
|
for (int i = 1 << size; size != MT_NODE_BITS; i = 1 << ++size)
|
|
{
|
|
assert(size <= MT_NODE_BITS);
|
|
|
|
assert(nodeNum == (nodeNum & ~((1 << size) - 1)));
|
|
|
|
if (!game::MT_RemoveMemoryNode(inst, nodeNum ^ i, size))
|
|
{
|
|
break;
|
|
}
|
|
nodeNum &= ~i;
|
|
}
|
|
game::MT_AddMemoryNode(inst, nodeNum, size);
|
|
|
|
game::Sys_LeaveCriticalSection(game::CRITSECT_MEMORY_TREE);
|
|
}
|
|
|
|
// Decomp Status: Tested, Completed
|
|
char* MT_Alloc(int numBytes, game::scriptInstance_t inst)
|
|
{
|
|
return (char*)(game::gScrMemTreeGlob[inst].nodes + game::MT_AllocIndex(inst, numBytes));
|
|
}
|
|
|
|
// Decomp Status: Tested, Completed
|
|
void MT_Free(void* p, int numBytes, game::scriptInstance_t inst)
|
|
{
|
|
assert((game::MemoryNode*)p - game::gScrMemTreeGlob[inst].nodes >= 0 && (game::MemoryNode*)p - game::gScrMemTreeGlob[inst].nodes < MT_NODE_COUNT);
|
|
|
|
game::MT_FreeIndex(numBytes, inst, (game::MemoryNode*)p - game::gScrMemTreeGlob[inst].nodes);
|
|
}
|
|
|
|
// Restored inlined function
|
|
char* MT_GetRefByIndex(game::scriptInstance_t inst, int index)
|
|
{
|
|
if (index > MT_NODE_COUNT)
|
|
{
|
|
game::MT_Error(inst, "MT_GetRefByIndex: out of bounds index", index);
|
|
return NULL;
|
|
}
|
|
return (char*)&game::gScrMemTreeGlob[inst].nodes[index];
|
|
}
|
|
} |