#pragma once
#include "BaseGameType.h"
#include <vector>
#include "Log/Log.h"
#include "Serialize/Stream.h"
#include "GameDefine.h"
#pragma pack(push,1)
template <typename T, TUint32 N>
struct StaticVector
{
public:
StaticVector()
{
m_vecLen = 0;
}
~StaticVector(){}
Tint32 GetSize() const //获取容器的总容量
{
return N;
}
Tint32 GetLen() const //获取数据的长度
{
return m_vecLen;
}
void Add(T &Data)
{
if(m_vecLen >= N)
{
Log::Instance()->WriteLog(enLogType_Error,"StaticVector::Add错误");
return ;
}
m_vecData[m_vecLen++] = Data;
}
T* GetDataHead() //获取首地址
{
return m_vecData;
}
T& GetData(TUint32 nIndex) //获取指定位置数据
{
if(nIndex < 0 || nIndex >= m_vecLen)
{
Log::Instance()->WriteLog(enLogType_Error,"StaticVector::GetData错误");
return (T&)m_vecData[0];
}
return (T&)m_vecData[nIndex];
}
void SetData(TUint32 nIndex, T& Data)
{
if(nIndex < 0 || nIndex >= m_vecLen)
{
Log::Instance()->WriteLog(enLogType_Error,"StaticVector::SetData错误");
return ;
}
m_vecData[nIndex] = Data;
}
T& operator [] (TUint32 nIndex) const
{
if(nIndex < 0 || nIndex >= m_vecLen)
{
Log::Instance()->WriteLog(enLogType_Error,"StaticVector::[]错误");
return (T&)m_vecData[0];
}
return (T&)m_vecData[nIndex];
}
void clear()
{
m_vecLen = 0;
}
void Serialize( Stream& stream )
{
TUint16 nLen = GetLen();
stream.Write(nLen);
for (int i=0; i < nLen; i++)
{
stream.Write(GetData(i));
}
}
bool DeSerialize( Stream& stream )
{
TUint16 nLen = 0;
if (!stream.Read(nLen))
return false;
for (TUint16 i=0; i < nLen; i++)
{
if(GetSize() - GetLen() <=0 )
return false;
T data;
if (!stream.Read(data))
return false;
Add(data);
}
return true;
}
protected:
T m_vecData[N];
TUint32 m_vecLen;
};
#pragma pack(pop)
至于为什么要用静态容器,是因为游戏开发玩家数据需要用到很多容器,而如果要用内存池,就必须提前知道玩家的最大内存消耗申请内存。
void Log::WriteCriticalError(const char *pszParam, ...)
{
if(pszParam == NULL)
return;
AutoLock locker(logLocker);
va_list va;
va_start(va, pszParam);
int nLen = 0;
char szResult[LOG_BUFFER_SIZE];
time_t t = time(0);
tm* Tm = localtime(&t);
nLen = strftime(szResult, LOG_BUFFER_SIZE, "%Y-%m-%d %H:%M:%S ", Tm);
#ifdef WIN32
nLen += vsnprintf_s(szResult + nLen, LOG_BUFFER_SIZE - nLen, _TRUNCATE, pszParam, va);
#else
nLen += vsprintf(szResult + nLen, pszParam, va );
#endif
nLen += sprintf(szResult + nLen, "\r\n");
printf(szResult);
#ifdef WIN32
MessageBoxA(NULL,szResult,"严重错误!",MB_OK);
#else
WriteLog(enLogType_Error,szResult);
#endif
}
void Log::PrintConsole(const char *pszParam, ...)
{
int length = strlen(pszParam);
if(pszParam == NULL || LOG_BUFFER_SIZE <= length)
return;
AutoLock locker(logLocker);
char szResult[LOG_BUFFER_SIZE];
int resultLen = 0;
va_list va;
va_start(va, pszParam);
resultLen = FormatWrite(enLogType_Msg,szResult,sizeof(szResult),pszParam, va);
va_end(va);
printf(szResult);
}
void Log::WriteLog(enLogType LogType, const char *pszParam, ...)
{
int length = strlen(pszParam);
if(pszParam == NULL || enLogType_Max <= LogType || LOG_BUFFER_SIZE <= length)
return;
if(CanWrite[LogType] == false)
return;
char szResult[LOG_BUFFER_SIZE];
int resultLen = 0;
va_list va;
va_start(va, pszParam);
resultLen = FormatWrite(LogType,szResult,sizeof(szResult),pszParam, va);
va_end(va);
LogSaveData data;
data.m_type = LogType;
data.bIsUTF8 = false;
data.m_count = resultLen;
data.m_data = szResult;
{
AutoLock locker(logLocker);
m_lstLogData.push_back(data);
}
m_WaitEvent.SetEvent();
}
比如,我们要封装一个自己的写log函数,就需要动态参数。
参考资料
C++ 模板 https://www.runoob.com/cplusplus/cpp-templates.html
C++学习之可变参数的函数与模板 https://songlee24.github.io/2014/07/22/cpp-changeable-parameter/