mirror of
https://github.com/rehlds/rehlds.git
synced 2025-01-14 23:58:10 +03:00
Enhanced API interface game message manager
Bump major API version Minor refactoring
This commit is contained in:
parent
c9f9bbfff9
commit
0f45ec09fa
@ -66,7 +66,21 @@ public:
|
|||||||
SPEC, // Sends to all spectator proxies
|
SPEC, // Sends to all spectator proxies
|
||||||
};
|
};
|
||||||
|
|
||||||
virtual ~IMessage() {};
|
/**
|
||||||
|
* @brief Data types for message data
|
||||||
|
*/
|
||||||
|
enum class DataType : uint8_t
|
||||||
|
{
|
||||||
|
Any, // Any part of the message
|
||||||
|
Dest, // Destination of the message
|
||||||
|
Index, // Index of the message
|
||||||
|
Origin, // Origin of the message
|
||||||
|
Edict, // Pointer to the edict of the recipient client
|
||||||
|
Param, // Parameter of the message
|
||||||
|
Max
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual ~IMessage() = default;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns the number of parameters in the message
|
* @brief Returns the number of parameters in the message
|
||||||
@ -137,10 +151,10 @@ public:
|
|||||||
virtual Dest getDest() const = 0;
|
virtual Dest getDest() const = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns the type of the message
|
* @brief Returns the index of the message
|
||||||
* @return The type of the message
|
* @return The index of the message
|
||||||
*/
|
*/
|
||||||
virtual int getType() const = 0;
|
virtual int getId() const = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns the origin of the message
|
* @brief Returns the origin of the message
|
||||||
@ -155,10 +169,110 @@ public:
|
|||||||
virtual struct edict_s* getEdict() const = 0;
|
virtual struct edict_s* getEdict() const = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns whether the message has been modified
|
* @brief Checks if the specified type of message data has been modified
|
||||||
* @return True if the message has been modified, false otherwise
|
*
|
||||||
|
* This function allows you to check if any part of the message data, such as its
|
||||||
|
* destination, type, origin, edict, or any specific parameter, has been modified
|
||||||
|
*
|
||||||
|
* @param type The type of the data to check for modification
|
||||||
|
* This can be one of the following:
|
||||||
|
* - DataType::Any: Check if any part of the message has been modified
|
||||||
|
* - DataType::Dest: Check if the destination has been modified
|
||||||
|
* - DataType::Index: Check if the message ID has been modified
|
||||||
|
* - DataType::Origin: Check if the origin has been modified
|
||||||
|
* - DataType::Edict: Check if the edict pointer has been modified
|
||||||
|
* - DataType::Param: Check if a specific parameter has been modified
|
||||||
|
*
|
||||||
|
* @param index The index of the parameter to check for modification (used only when type is DataType::Param)
|
||||||
|
* Default value is -1, which means the parameter index is not applicable
|
||||||
|
*
|
||||||
|
* @return True if the specified data type has been modified, false otherwise
|
||||||
*/
|
*/
|
||||||
virtual bool isModified() const = 0;
|
virtual bool isDataModified(DataType type = DataType::Any, size_t index = -1) const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Resets a specific type of message data to its original value
|
||||||
|
*
|
||||||
|
* @param type The type of data to reset to its original value
|
||||||
|
* This can be one of the following:
|
||||||
|
* - DataType::Any: Reset all modified message data to its original values
|
||||||
|
* - DataType::Dest: Reset the destination to its original value
|
||||||
|
* - DataType::Index: Reset the message ID to its original value
|
||||||
|
* - DataType::Origin: Reset the origin to its original value
|
||||||
|
* - DataType::Edict: Reset the edict pointer of the recipient client to its original value
|
||||||
|
* - DataType::Param: Reset a specific parameter to its original value
|
||||||
|
*
|
||||||
|
* @param index The index of the parameter to reset (used only when type is DataType::Param)
|
||||||
|
* Default value is -1, which means the parameter index is not applicable
|
||||||
|
*
|
||||||
|
* @return True if the modified data type was reset, false otherwise
|
||||||
|
*/
|
||||||
|
virtual bool resetModifiedData(DataType type = DataType::Any, size_t index = -1) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets the destination of the message
|
||||||
|
*/
|
||||||
|
virtual void setDest(Dest dest) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets the index of the message
|
||||||
|
*/
|
||||||
|
virtual void setId(int msg_id) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets the origin of the message
|
||||||
|
*/
|
||||||
|
virtual void setOrigin(const float *origin) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets the edict associated with the message
|
||||||
|
*/
|
||||||
|
virtual void setEdict(struct edict_s *pEdict) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns the original destination of the message before any modifications
|
||||||
|
* @return The original destination of the message
|
||||||
|
*/
|
||||||
|
virtual Dest getOriginalDest() const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns the original type of the message before any modifications
|
||||||
|
* @return The original type of the message
|
||||||
|
*/
|
||||||
|
virtual int getOriginalId() const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns the original origin of the message before any modifications
|
||||||
|
* @return The original origin of the message
|
||||||
|
*/
|
||||||
|
virtual const float* getOriginalOrigin() const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns the original edict associated with the message before any modifications
|
||||||
|
* @return The original edict associated with the message
|
||||||
|
*/
|
||||||
|
virtual struct edict_s* getOriginalEdict() const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns the original integer value of the parameter at the given index before any modifications
|
||||||
|
* @param index The index of the parameter
|
||||||
|
* @return The original integer value of the parameter
|
||||||
|
*/
|
||||||
|
virtual int getOriginalParamInt(size_t index) const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns the original float value of the parameter at the given index before any modifications
|
||||||
|
* @param index The index of the parameter
|
||||||
|
* @return The original float value of the parameter
|
||||||
|
*/
|
||||||
|
virtual float getOriginalParamFloat(size_t index) const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns the original string value of the parameter at the given index before any modifications
|
||||||
|
* @param index The index of the parameter
|
||||||
|
* @return The original string value of the parameter
|
||||||
|
*/
|
||||||
|
virtual const char* getOriginalParamString(size_t index) const = 0;
|
||||||
|
|
||||||
// This must be the last virtual function in class
|
// This must be the last virtual function in class
|
||||||
#ifdef REHLDS_SELF
|
#ifdef REHLDS_SELF
|
||||||
@ -167,7 +281,7 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
#define MESSAGEMNGR_VERSION_MAJOR 1
|
#define MESSAGEMNGR_VERSION_MAJOR 2
|
||||||
#define MESSAGEMNGR_VERSION_MINOR 0
|
#define MESSAGEMNGR_VERSION_MINOR 0
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -178,7 +292,7 @@ class IMessageManager
|
|||||||
public:
|
public:
|
||||||
using hookfunc_t = void (*)(IVoidHookChain<IMessage *> *chain, IMessage *msg);
|
using hookfunc_t = void (*)(IVoidHookChain<IMessage *> *chain, IMessage *msg);
|
||||||
|
|
||||||
virtual ~IMessageManager() {};
|
virtual ~IMessageManager() = default;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns the major version of the MessageManager
|
* @brief Returns the major version of the MessageManager
|
||||||
@ -194,30 +308,30 @@ public:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns the blocking behavior for the given message type
|
* @brief Returns the blocking behavior for the given message type
|
||||||
* @param msgType The message type
|
* @param msg_id The message type
|
||||||
* @return The blocking behavior for the given message type
|
* @return The blocking behavior for the given message type
|
||||||
*/
|
*/
|
||||||
virtual IMessage::BlockType getMessageBlock(int msgType) const = 0;
|
virtual IMessage::BlockType getMessageBlock(int msg_id) const = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Sets the blocking behavior for the given message type
|
* @brief Sets the blocking behavior for the given message type
|
||||||
* @param msgType The message type
|
* @param msg_id The message type
|
||||||
* @param blockType The blocking behavior to set
|
* @param blockType The blocking behavior to set
|
||||||
*/
|
*/
|
||||||
virtual void setMessageBlock(int msgType, IMessage::BlockType blockType) = 0;
|
virtual void setMessageBlock(int msg_id, IMessage::BlockType blockType) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Registers a hook function for the given message type
|
* @brief Registers a hook function for the given message type
|
||||||
* @param msgType The message type to register the hook for
|
* @param msg_id The message type to register the hook for
|
||||||
* @param handler The hook function to register
|
* @param handler The hook function to register
|
||||||
* @param priority The priority of the hook function (see enum HookChainPriority)
|
* @param priority The priority of the hook function (see enum HookChainPriority)
|
||||||
*/
|
*/
|
||||||
virtual void registerHook(int msgType, hookfunc_t handler, int priority = HC_PRIORITY_DEFAULT) = 0;
|
virtual void registerHook(int msg_id, hookfunc_t handler, int priority = HC_PRIORITY_DEFAULT) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Unregisters a hook function for the given message type
|
* @brief Unregisters a hook function for the given message type
|
||||||
* @param msgType The message type to unregister the hook for
|
* @param msg_id The message type to unregister the hook for
|
||||||
* @param handler The hook function to unregister
|
* @param handler The hook function to unregister
|
||||||
*/
|
*/
|
||||||
virtual void unregisterHook(int msgType, hookfunc_t handler) = 0;
|
virtual void unregisterHook(int msg_id, hookfunc_t handler) = 0;
|
||||||
};
|
};
|
||||||
|
@ -21,53 +21,60 @@
|
|||||||
// Constructs a Message object
|
// Constructs a Message object
|
||||||
MessageImpl::MessageImpl()
|
MessageImpl::MessageImpl()
|
||||||
{
|
{
|
||||||
m_buffer.buffername = "MessageManager/Begin/End";
|
|
||||||
m_buffer.data = m_bufferData;
|
|
||||||
m_buffer.flags = SIZEBUF_ALLOW_OVERFLOW;
|
|
||||||
m_buffer.cursize = 0;
|
|
||||||
m_buffer.maxsize = sizeof(m_bufferData);
|
|
||||||
|
|
||||||
m_paramCount = 0;
|
m_paramCount = 0;
|
||||||
|
m_modifiedDataBits = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sets the active state of the message with the given parameters
|
// Sets the active state of the message with the given parameters
|
||||||
void MessageImpl::setActive(int dest, int type, const float *origin, edict_t *edict)
|
void MessageImpl::setActive(int dest, int id, const float *origin, edict_t *edict)
|
||||||
{
|
{
|
||||||
m_dest = static_cast<Dest>(dest);
|
// Initialize storage buffers
|
||||||
m_type = type;
|
for (int i = 0; i < MAX_STORAGE; i++)
|
||||||
m_edict = edict;
|
{
|
||||||
|
Storage_t &storage = m_Storage[i];
|
||||||
// Reset buffer size
|
storage.buf.cursize = 0;
|
||||||
m_buffer.flags = SIZEBUF_ALLOW_OVERFLOW;
|
storage.dest = static_cast<Dest>(dest);
|
||||||
m_buffer.cursize = 0;
|
storage.msgid = id;
|
||||||
|
storage.edict = edict;
|
||||||
|
|
||||||
// Copy origin vector if provided
|
// Copy origin vector if provided
|
||||||
if (origin)
|
if (origin)
|
||||||
VectorCopy(origin, m_origin);
|
VectorCopy(origin, storage.origin);
|
||||||
else
|
else
|
||||||
VectorClear(m_origin);
|
VectorClear(storage.origin);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_paramCount = 0;
|
||||||
|
m_modifiedDataBits = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sets the buffer for the message
|
// Sets the buffer for the message
|
||||||
void MessageImpl::setBuffer(sizebuf_t *pbuf)
|
void MessageImpl::setBuffer(sizebuf_t *pbuf)
|
||||||
{
|
{
|
||||||
// Copy data from the provided buffer to the message buffer
|
// Copy data from the provided buffer to the message buffer
|
||||||
memcpy(m_buffer.data, pbuf->data, pbuf->cursize);
|
for (int i = 0; i < MAX_STORAGE; i++)
|
||||||
m_buffer.cursize = pbuf->cursize;
|
{
|
||||||
|
Storage_t &storage = m_Storage[i];
|
||||||
|
Q_memcpy(storage.buf.data, pbuf->data, pbuf->cursize);
|
||||||
|
storage.buf.cursize = pbuf->cursize;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sets the copyback buffer for the message
|
// Sets the copyback buffer for the message
|
||||||
void MessageImpl::setCopybackBuffer(sizebuf_t *pbuf)
|
void MessageImpl::setCopybackBuffer(sizebuf_t *pbuf)
|
||||||
{
|
{
|
||||||
|
const Storage_t &storage = m_Storage[BACK];
|
||||||
|
|
||||||
// Copy data from the message buffer back to the provided buffer
|
// Copy data from the message buffer back to the provided buffer
|
||||||
memcpy(pbuf->data, m_buffer.data, m_buffer.cursize);
|
Q_memcpy(pbuf->data, storage.buf.data, storage.buf.cursize);
|
||||||
pbuf->cursize = m_buffer.cursize;
|
pbuf->cursize = storage.buf.cursize;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clears the message parameters
|
// Clears the message parameters
|
||||||
void MessageImpl::clear()
|
void MessageImpl::clear()
|
||||||
{
|
{
|
||||||
m_paramCount = 0;
|
m_paramCount = 0;
|
||||||
|
m_modifiedDataBits = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// An array containing fixed sizes for various types of parameters
|
// An array containing fixed sizes for various types of parameters
|
||||||
@ -88,8 +95,8 @@ void MessageImpl::addParam(IMessage::ParamType type, size_t length)
|
|||||||
{
|
{
|
||||||
Param_t ¶m = m_params[m_paramCount++];
|
Param_t ¶m = m_params[m_paramCount++];
|
||||||
param.type = type;
|
param.type = type;
|
||||||
param.len = (length == -1) ? SIZEOF_PARAMTYPE[static_cast<size_t>(type)] : length;
|
param.newlen = param.oldlen = (length == -1) ? SIZEOF_PARAMTYPE[static_cast<size_t>(type)] : length;
|
||||||
param.pos = gMsgBuffer.cursize;
|
param.posBack = param.posFront = gMsgBuffer.cursize;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sets the value of a primitive parameter at the given index
|
// Sets the value of a primitive parameter at the given index
|
||||||
@ -97,12 +104,11 @@ template <typename T>
|
|||||||
void MessageImpl::setParamPrimitive(size_t index, T value)
|
void MessageImpl::setParamPrimitive(size_t index, T value)
|
||||||
{
|
{
|
||||||
// Ensure index is within bounds
|
// Ensure index is within bounds
|
||||||
if (index < 0 || index >= m_paramCount)
|
if (index >= m_paramCount)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const Param_t ¶m = m_params[index];
|
Param_t ¶m = m_params[index];
|
||||||
|
void *pbuf = m_Storage[BACK].buf.data + param.posBack;
|
||||||
void *pbuf = m_buffer.data + param.pos;
|
|
||||||
|
|
||||||
// Set value based on parameter type
|
// Set value based on parameter type
|
||||||
switch (param.type)
|
switch (param.type)
|
||||||
@ -118,7 +124,7 @@ void MessageImpl::setParamPrimitive(size_t index, T value)
|
|||||||
*(int16 *)pbuf = value;
|
*(int16 *)pbuf = value;
|
||||||
break;
|
break;
|
||||||
case IMessage::ParamType::Long:
|
case IMessage::ParamType::Long:
|
||||||
*(uint16 *)pbuf = value;
|
*(uint32 *)pbuf = value;
|
||||||
break;
|
break;
|
||||||
case IMessage::ParamType::Angle:
|
case IMessage::ParamType::Angle:
|
||||||
// Convert angle value to byte representation with loss of precision
|
// Convert angle value to byte representation with loss of precision
|
||||||
@ -133,7 +139,10 @@ void MessageImpl::setParamPrimitive(size_t index, T value)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Mark message as modified
|
// Mark message as modified
|
||||||
m_modified = true;
|
param.modified = true;
|
||||||
|
|
||||||
|
// Mark the overall status as changed
|
||||||
|
setModifiedDataBit(DataType::Param);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transforms the buffer after setting a string parameter at the given index
|
// Transforms the buffer after setting a string parameter at the given index
|
||||||
@ -143,8 +152,10 @@ void MessageImpl::setTxformBuffer(size_t index, size_t startPos, size_t oldLengt
|
|||||||
int32_t diffLength = newLength - oldLength;
|
int32_t diffLength = newLength - oldLength;
|
||||||
if (diffLength != 0)
|
if (diffLength != 0)
|
||||||
{
|
{
|
||||||
|
sizebuf_t &buf = m_Storage[BACK].buf;
|
||||||
|
|
||||||
// Check if the buffer size limit will be exceeded
|
// Check if the buffer size limit will be exceeded
|
||||||
if (m_buffer.cursize + diffLength > m_buffer.maxsize)
|
if (buf.cursize + diffLength > buf.maxsize)
|
||||||
{
|
{
|
||||||
Sys_Error(
|
Sys_Error(
|
||||||
"%s: Refusing to transform string with %i param of user message of %i bytes, "
|
"%s: Refusing to transform string with %i param of user message of %i bytes, "
|
||||||
@ -152,13 +163,18 @@ void MessageImpl::setTxformBuffer(size_t index, size_t startPos, size_t oldLengt
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Move the data in the buffer
|
// Move the data in the buffer
|
||||||
size_t moveLength = m_buffer.cursize - (startPos + oldLength);
|
size_t moveLength = buf.cursize - (startPos + oldLength);
|
||||||
Q_memmove(m_buffer.data + startPos + newLength, m_buffer.data + startPos + oldLength, moveLength);
|
if (moveLength > 0)
|
||||||
m_buffer.cursize += diffLength;
|
Q_memmove(buf.data + startPos + newLength, buf.data + startPos + oldLength, moveLength);
|
||||||
|
|
||||||
|
buf.cursize += diffLength;
|
||||||
|
|
||||||
|
if (newLength < oldLength)
|
||||||
|
Q_memset(buf.data + startPos + newLength + moveLength, 0, oldLength - newLength);
|
||||||
|
|
||||||
// Update the position of all subsequent parameters
|
// Update the position of all subsequent parameters
|
||||||
for (size_t i = index + 1; i < m_paramCount; i++)
|
for (size_t i = index + 1; i < m_paramCount; i++)
|
||||||
m_params[i].pos += diffLength;
|
m_params[i].posBack += diffLength;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -166,12 +182,13 @@ void MessageImpl::setTxformBuffer(size_t index, size_t startPos, size_t oldLengt
|
|||||||
int MessageImpl::getParamInt(size_t index) const
|
int MessageImpl::getParamInt(size_t index) const
|
||||||
{
|
{
|
||||||
// Ensure index is within bounds
|
// Ensure index is within bounds
|
||||||
if (index < 0 || index >= m_paramCount)
|
if (index >= m_paramCount)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
// Get the parameter value based on its type
|
// Get the parameter value based on its type
|
||||||
void *buf = m_buffer.data + m_params[index].pos;
|
const Param_t ¶m = m_params[index];
|
||||||
switch (m_params[index].type)
|
const void *buf = m_Storage[BACK].buf.data + param.posBack;
|
||||||
|
switch (param.type)
|
||||||
{
|
{
|
||||||
case IMessage::ParamType::Byte:
|
case IMessage::ParamType::Byte:
|
||||||
return *(uint8 *)buf;
|
return *(uint8 *)buf;
|
||||||
@ -181,7 +198,7 @@ int MessageImpl::getParamInt(size_t index) const
|
|||||||
case IMessage::ParamType::Entity:
|
case IMessage::ParamType::Entity:
|
||||||
return *(int16 *)buf;
|
return *(int16 *)buf;
|
||||||
case IMessage::ParamType::Long:
|
case IMessage::ParamType::Long:
|
||||||
return *(uint16 *)buf;
|
return *(uint32 *)buf;
|
||||||
default:
|
default:
|
||||||
return 0; // bad type
|
return 0; // bad type
|
||||||
}
|
}
|
||||||
@ -191,12 +208,12 @@ int MessageImpl::getParamInt(size_t index) const
|
|||||||
float MessageImpl::getParamFloat(size_t index) const
|
float MessageImpl::getParamFloat(size_t index) const
|
||||||
{
|
{
|
||||||
// Ensure index is within bounds
|
// Ensure index is within bounds
|
||||||
if (index < 0 || index >= m_paramCount)
|
if (index >= m_paramCount)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
// Get the parameter value based on its type
|
// Get the parameter value based on its type
|
||||||
const Param_t ¶m = m_params[index];
|
const Param_t ¶m = m_params[index];
|
||||||
void *buf = m_buffer.data + param.pos;
|
const void *buf = m_Storage[BACK].buf.data + param.posBack;
|
||||||
switch (param.type)
|
switch (param.type)
|
||||||
{
|
{
|
||||||
case IMessage::ParamType::Angle:
|
case IMessage::ParamType::Angle:
|
||||||
@ -214,13 +231,74 @@ float MessageImpl::getParamFloat(size_t index) const
|
|||||||
const char *MessageImpl::getParamString(size_t index) const
|
const char *MessageImpl::getParamString(size_t index) const
|
||||||
{
|
{
|
||||||
// Ensure index is within bounds
|
// Ensure index is within bounds
|
||||||
if (index < 0 || index >= m_paramCount)
|
if (index >= m_paramCount)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
// Get the parameter value if it is a string
|
// Get the parameter value if it is a string
|
||||||
const Param_t ¶m = m_params[index];
|
const Param_t ¶m = m_params[index];
|
||||||
if (param.type == IMessage::ParamType::String)
|
if (param.type == IMessage::ParamType::String)
|
||||||
return (const char *)m_buffer.data + param.pos;
|
return (const char *)m_Storage[BACK].buf.data + param.posBack;
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
int MessageImpl::getOriginalParamInt(size_t index) const
|
||||||
|
{
|
||||||
|
// Ensure index is within bounds
|
||||||
|
if (index >= m_paramCount)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Get the parameter value based on its type
|
||||||
|
const Param_t ¶m = m_params[index];
|
||||||
|
const void *buf = m_Storage[FRONT].buf.data + param.posFront;
|
||||||
|
switch (param.type)
|
||||||
|
{
|
||||||
|
case IMessage::ParamType::Byte:
|
||||||
|
return *(uint8 *)buf;
|
||||||
|
case IMessage::ParamType::Char:
|
||||||
|
return *(int8 *)buf;
|
||||||
|
case IMessage::ParamType::Short:
|
||||||
|
case IMessage::ParamType::Entity:
|
||||||
|
return *(int16 *)buf;
|
||||||
|
case IMessage::ParamType::Long:
|
||||||
|
return *(uint32 *)buf;
|
||||||
|
default:
|
||||||
|
return 0; // bad type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float MessageImpl::getOriginalParamFloat(size_t index) const
|
||||||
|
{
|
||||||
|
// Ensure index is within bounds
|
||||||
|
if (index >= m_paramCount)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Get the parameter value based on its type
|
||||||
|
const Param_t ¶m = m_params[index];
|
||||||
|
const void *buf = m_Storage[FRONT].buf.data + param.posFront;
|
||||||
|
switch (param.type)
|
||||||
|
{
|
||||||
|
case IMessage::ParamType::Angle:
|
||||||
|
return (float)(*(uint8 *)buf * (360.0 / 256.0));
|
||||||
|
case IMessage::ParamType::Coord:
|
||||||
|
return (float)(*(int16 *)buf * (1.0 / 8));
|
||||||
|
default:
|
||||||
|
break; // bad type
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *MessageImpl::getOriginalParamString(size_t index) const
|
||||||
|
{
|
||||||
|
// Ensure index is within bounds
|
||||||
|
if (index >= m_paramCount)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
// Get the parameter value if it is a string
|
||||||
|
const Param_t ¶m = m_params[index];
|
||||||
|
if (param.type == IMessage::ParamType::String)
|
||||||
|
return (const char *)m_Storage[FRONT].buf.data + param.posFront;
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -244,13 +322,13 @@ void MessageImpl::setParamVec(size_t index, const float *pos)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// Ensure index is within bounds
|
// Ensure index is within bounds
|
||||||
if (index < 0 || (index + 3) >= m_paramCount)
|
if ((index + 3) >= m_paramCount)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Get the parameter position in the buffer
|
// Get the parameter position in the buffer
|
||||||
const Param_t ¶m = m_params[index];
|
Param_t ¶m = m_params[index];
|
||||||
|
|
||||||
int16 *pbuf = (int16 *)m_buffer.data + param.pos;
|
int16 *pbuf = (int16 *)m_Storage[BACK].buf.data + param.posBack;
|
||||||
|
|
||||||
// Set each component of the vector parameter
|
// Set each component of the vector parameter
|
||||||
*(int16 *)pbuf++ = (int16)(pos[0] * 8.0);
|
*(int16 *)pbuf++ = (int16)(pos[0] * 8.0);
|
||||||
@ -258,7 +336,10 @@ void MessageImpl::setParamVec(size_t index, const float *pos)
|
|||||||
*(int16 *)pbuf++ = (int16)(pos[2] * 8.0);
|
*(int16 *)pbuf++ = (int16)(pos[2] * 8.0);
|
||||||
|
|
||||||
// Mark message as modified
|
// Mark message as modified
|
||||||
m_modified = true;
|
param.modified = true;
|
||||||
|
|
||||||
|
// Mark the overall status as modified
|
||||||
|
setModifiedDataBit(DataType::Param);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sets the string value of the parameter at the given index
|
// Sets the string value of the parameter at the given index
|
||||||
@ -268,77 +349,276 @@ void MessageImpl::setParamString(size_t index, const char *value)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// Ensure index is within bounds
|
// Ensure index is within bounds
|
||||||
if (index < 0 || index >= m_paramCount)
|
if (index >= m_paramCount)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Calculate the length of the string
|
// Calculate the length of the string
|
||||||
size_t length = Q_strlen(value) + 1;
|
Param_t ¶m = m_params[index];
|
||||||
const Param_t ¶m = m_params[index];
|
|
||||||
|
param.newlen = Q_strlen(value) + 1;
|
||||||
|
|
||||||
// Transform buffer to accommodate the new string length
|
// Transform buffer to accommodate the new string length
|
||||||
setTxformBuffer(index, param.pos, param.len, length);
|
setTxformBuffer(index, param.posBack, param.oldlen, param.newlen);
|
||||||
|
|
||||||
// Copy the string value to the buffer
|
// Copy the string value to the buffer
|
||||||
memcpy(m_buffer.data + param.pos, value, length);
|
Q_memcpy(m_Storage[BACK].buf.data + param.posBack, value, param.newlen);
|
||||||
|
|
||||||
// Mark message as modified
|
// Mark message as modified
|
||||||
m_modified = true;
|
param.modified = true;
|
||||||
|
|
||||||
|
// Mark the overall status as modified
|
||||||
|
setModifiedDataBit(DataType::Param);
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageManagerImpl::MessageManagerImpl()
|
// Sets the destination of the message
|
||||||
|
void MessageImpl::setDest(Dest dest)
|
||||||
|
{
|
||||||
|
m_Storage[BACK].dest = dest;
|
||||||
|
setModifiedDataBit(DataType::Dest);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sets the type of the message
|
||||||
|
void MessageImpl::setId(int msg_id)
|
||||||
|
{
|
||||||
|
m_Storage[BACK].msgid = msg_id;
|
||||||
|
setModifiedDataBit(DataType::Index);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sets the origin of the message
|
||||||
|
void MessageImpl::setOrigin(const float *origin)
|
||||||
|
{
|
||||||
|
// Copy origin vector if provided
|
||||||
|
if (origin)
|
||||||
|
VectorCopy(origin, m_Storage[BACK].origin);
|
||||||
|
else
|
||||||
|
VectorClear(m_Storage[BACK].origin);
|
||||||
|
|
||||||
|
setModifiedDataBit(DataType::Origin);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Sets the edict associated with the message
|
||||||
|
void MessageImpl::setEdict(edict_t *pEdict)
|
||||||
|
{
|
||||||
|
m_Storage[BACK].edict = pEdict;
|
||||||
|
setModifiedDataBit(DataType::Edict);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MessageImpl::isDataModified(DataType type, size_t index) const
|
||||||
|
{
|
||||||
|
if (!isDataTypeModified(type))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (type == DataType::Param && index != -1)
|
||||||
|
{
|
||||||
|
// Ensure index is within bounds
|
||||||
|
if (index >= m_paramCount)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const Param_t ¶m = m_params[index];
|
||||||
|
return param.modified;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MessageImpl::resetParam(size_t index)
|
||||||
|
{
|
||||||
|
Param_t ¶m = m_params[index];
|
||||||
|
|
||||||
|
void *pbackbuf = m_Storage[BACK].buf.data + param.posBack;
|
||||||
|
const void *pfrontbuf = m_Storage[FRONT].buf.data + param.posFront;
|
||||||
|
|
||||||
|
// Set value based on parameter type
|
||||||
|
switch (param.type)
|
||||||
|
{
|
||||||
|
case IMessage::ParamType::Byte:
|
||||||
|
*(uint8 *)pbackbuf = *(uint8 *)pfrontbuf;
|
||||||
|
break;
|
||||||
|
case IMessage::ParamType::Char:
|
||||||
|
*(int8 *)pbackbuf = *(int8 *)pfrontbuf;
|
||||||
|
break;
|
||||||
|
case IMessage::ParamType::Short:
|
||||||
|
case IMessage::ParamType::Entity:
|
||||||
|
*(int16 *)pbackbuf = *(int16 *)pfrontbuf;
|
||||||
|
break;
|
||||||
|
case IMessage::ParamType::Long:
|
||||||
|
*(uint32 *)pbackbuf = *(uint32 *)pfrontbuf;
|
||||||
|
break;
|
||||||
|
case IMessage::ParamType::Angle:
|
||||||
|
*(uint8 *)pbackbuf = *(uint8 *)pfrontbuf;
|
||||||
|
break;
|
||||||
|
case IMessage::ParamType::Coord:
|
||||||
|
*(int16 *)pbackbuf = *(int16 *)pfrontbuf;
|
||||||
|
break;
|
||||||
|
case IMessage::ParamType::String:
|
||||||
|
// Return the original string value from the front buffer
|
||||||
|
setTxformBuffer(index, param.posBack, param.newlen, param.oldlen);
|
||||||
|
Q_memcpy(pbackbuf, pfrontbuf, param.oldlen);
|
||||||
|
param.newlen = param.oldlen;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return; // bad type
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmark message as modified
|
||||||
|
param.modified = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resets a specific message parameter to its original value
|
||||||
|
bool MessageImpl::resetModifiedData(DataType type, size_t index)
|
||||||
|
{
|
||||||
|
Storage_t &storageBack = m_Storage[BACK];
|
||||||
|
const Storage_t &storageFront = m_Storage[FRONT];
|
||||||
|
|
||||||
|
unsetModifiedDataBit(type);
|
||||||
|
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
// Resets all message parameters and storage data to their original values
|
||||||
|
case DataType::Any:
|
||||||
|
{
|
||||||
|
// Update the position of all subsequent parameters
|
||||||
|
for (size_t i = 0; i < m_paramCount; i++)
|
||||||
|
{
|
||||||
|
Param_t ¶m = m_params[i];
|
||||||
|
param.posBack = param.posFront;
|
||||||
|
param.newlen = param.oldlen;
|
||||||
|
param.modified = false; // Unmark message as modified
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy front storage data to back buffer data
|
||||||
|
Q_memcpy(storageBack.buf.data, storageFront.buf.data, storageFront.buf.maxsize);
|
||||||
|
|
||||||
|
storageBack.dest = storageFront.dest;
|
||||||
|
storageBack.msgid = storageFront.msgid;
|
||||||
|
storageBack.edict = storageFront.edict;
|
||||||
|
|
||||||
|
VectorCopy(storageFront.origin, storageBack.origin);
|
||||||
|
|
||||||
|
m_modifiedDataBits = 0;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DataType::Dest:
|
||||||
|
storageBack.dest = storageFront.dest;
|
||||||
|
break;
|
||||||
|
case DataType::Index:
|
||||||
|
storageBack.msgid = storageFront.msgid;
|
||||||
|
break;
|
||||||
|
case DataType::Origin:
|
||||||
|
VectorCopy(storageFront.origin, storageBack.origin);
|
||||||
|
break;
|
||||||
|
case DataType::Edict:
|
||||||
|
storageBack.edict = storageFront.edict;
|
||||||
|
break;
|
||||||
|
case DataType::Param:
|
||||||
|
{
|
||||||
|
// Reset a specific parameter
|
||||||
|
if (index != -1)
|
||||||
|
{
|
||||||
|
// Ensure index is within bounds
|
||||||
|
if (index < m_paramCount)
|
||||||
|
resetParam(index);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < m_paramCount; i++)
|
||||||
|
resetParam(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recalc modified data bits
|
||||||
|
for (size_t i = 0; i < m_paramCount; i++)
|
||||||
|
{
|
||||||
|
const Param_t ¶m = m_params[i];
|
||||||
|
if (param.modified)
|
||||||
|
{
|
||||||
|
setModifiedDataBit(DataType::Param);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there was any other modified data, mark Any as overall modified data
|
||||||
|
if (m_modifiedDataBits != 0)
|
||||||
|
setModifiedDataBit(DataType::Any);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageManagerImpl::MessageManagerImpl() : m_stack(m_pool)
|
||||||
{
|
{
|
||||||
m_inblock = false;
|
m_inblock = false;
|
||||||
m_inhook = false;
|
m_inhook = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register hook function for the game message type
|
// Register hook function for the game message type
|
||||||
void MessageManagerImpl::registerHook(int msgType, hookfunc_t handler, int priority)
|
void MessageManagerImpl::registerHook(int msg_id, hookfunc_t handler, int priority)
|
||||||
{
|
{
|
||||||
m_hooks[msgType].registerHook(handler, priority);
|
if (!m_hooks[msg_id])
|
||||||
|
m_hooks[msg_id] = new HookRegistry_t;
|
||||||
|
|
||||||
|
if (m_hooks[msg_id]->findHook(handler))
|
||||||
|
return; // already registered
|
||||||
|
|
||||||
|
m_hooks[msg_id]->registerHook(handler, priority);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unregister hook function for the game message type
|
// Unregister hook function for the game message type
|
||||||
void MessageManagerImpl::unregisterHook(int msgType, hookfunc_t handler)
|
void MessageManagerImpl::unregisterHook(int msg_id, hookfunc_t handler)
|
||||||
{
|
{
|
||||||
m_hooks[msgType].unregisterHook(handler);
|
if (!m_hooks[msg_id])
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_hooks[msg_id]->unregisterHook(handler);
|
||||||
|
|
||||||
|
if (m_hooks[msg_id]->getCount() == 0)
|
||||||
|
{
|
||||||
|
delete m_hooks[msg_id];
|
||||||
|
m_hooks[msg_id] = nullptr;
|
||||||
|
m_pool.clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the block type for the game message type
|
// Get the block type for the game message type
|
||||||
IMessage::BlockType MessageManagerImpl::getMessageBlock(int msgType) const
|
IMessage::BlockType MessageManagerImpl::getMessageBlock(int msg_id) const
|
||||||
{
|
{
|
||||||
return m_blocks[msgType];
|
return m_blocks[msg_id];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the block type for the game message type
|
// Set the block type for the game message type
|
||||||
void MessageManagerImpl::setMessageBlock(int msgType, IMessage::BlockType blockType)
|
void MessageManagerImpl::setMessageBlock(int msg_id, IMessage::BlockType blockType)
|
||||||
{
|
{
|
||||||
m_blocks[msgType] = blockType;
|
m_blocks[msg_id] = blockType;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MessageManagerImpl::MessageBegin(int msg_dest, int msg_type, const float *pOrigin, edict_t *ed)
|
bool MessageManagerImpl::MessageBegin(int msg_dest, int msg_id, const float *pOrigin, edict_t *ed)
|
||||||
{
|
{
|
||||||
// Check if the message type is blocked
|
// Check if the message type is blocked
|
||||||
if (m_blocks[msg_type] != IMessage::BlockType::Not)
|
if (m_blocks[msg_id] != IMessage::BlockType::Not)
|
||||||
{
|
{
|
||||||
m_inblock = true;
|
m_inblock = true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if there are hooks registered for the message type
|
// Check if there are hooks registered for the message type
|
||||||
m_inhook = m_hooks[msg_type].getCount() > 0;
|
m_inhook = (m_hooks[msg_id] && m_hooks[msg_id]->getCount() > 0);
|
||||||
|
|
||||||
if (m_inhook)
|
if (m_inhook)
|
||||||
{
|
{
|
||||||
// Check for stack overflow
|
// Check for stack overflow
|
||||||
if (m_stack.size() >= m_stack.max_size() - 1)
|
if (m_stack.size() >= m_stack.max_size() - 1)
|
||||||
Sys_Error("%s: stack overflow in #%i user message.\nIndicate potential recursive calls...\n", __func__, msg_type);
|
Sys_Error("%s: stack overflow in #%i user message.\nIndicate potential recursive calls...\n", __func__, msg_id);
|
||||||
|
|
||||||
// Push a new game message onto the stack
|
// Push a new game message onto the stack
|
||||||
m_stack.push();
|
MessageImpl &msg = m_stack.push();
|
||||||
|
|
||||||
// Initialize the message
|
// Initialize the message
|
||||||
MessageImpl &msg = m_stack.back();
|
msg.setActive(msg_dest, msg_id, pOrigin, ed);
|
||||||
msg.setActive(msg_dest, msg_type, pOrigin, ed);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -347,7 +627,7 @@ bool MessageManagerImpl::MessageBegin(int msg_dest, int msg_type, const float *p
|
|||||||
static void EXT_FUNC SendUserMessageData(IMessage *msg)
|
static void EXT_FUNC SendUserMessageData(IMessage *msg)
|
||||||
{
|
{
|
||||||
// Set global variables with message data
|
// Set global variables with message data
|
||||||
gMsgType = msg->getType();
|
gMsgType = msg->getId();
|
||||||
gMsgEntity = msg->getEdict();
|
gMsgEntity = msg->getEdict();
|
||||||
gMsgDest = static_cast<int>(msg->getDest());
|
gMsgDest = static_cast<int>(msg->getDest());
|
||||||
|
|
||||||
@ -383,11 +663,11 @@ bool MessageManagerImpl::MessageEnd()
|
|||||||
gMsgStarted = FALSE;
|
gMsgStarted = FALSE;
|
||||||
|
|
||||||
// Get the message from the top of the stack
|
// Get the message from the top of the stack
|
||||||
MessageImpl &msg = m_stack.back();
|
MessageImpl &msg = m_stack.top();
|
||||||
|
|
||||||
// Set buffer from global buffer and call hookchain
|
// Set buffer from global buffer and call hookchain
|
||||||
msg.setBuffer(&gMsgBuffer);
|
msg.setBuffer(&gMsgBuffer);
|
||||||
m_hooks[msg.getType()].callChain(SendUserMessageData, &msg);
|
m_hooks[msg.getId()]->callChain(SendUserMessageData, &msg);
|
||||||
m_inhook = false;
|
m_inhook = false;
|
||||||
|
|
||||||
// Clear the message and pop from the stack
|
// Clear the message and pop from the stack
|
||||||
@ -407,7 +687,7 @@ bool MessageManagerImpl::WriteParam(IMessage::ParamType type, size_t length)
|
|||||||
if (m_inhook)
|
if (m_inhook)
|
||||||
{
|
{
|
||||||
// Add parameter to top stack message
|
// Add parameter to top stack message
|
||||||
MessageImpl &msg = m_stack.back();
|
MessageImpl &msg = m_stack.top();
|
||||||
msg.addParam(type, length);
|
msg.addParam(type, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -418,14 +698,14 @@ bool MessageManagerImpl::WriteParam(IMessage::ParamType type, size_t length)
|
|||||||
// Functions intercept to handle messages
|
// Functions intercept to handle messages
|
||||||
//
|
//
|
||||||
|
|
||||||
void EXT_FUNC PF_MessageBegin_Intercept(int msg_dest, int msg_type, const float *pOrigin, edict_t *ed)
|
void EXT_FUNC PF_MessageBegin_Intercept(int msg_dest, int msg_id, const float *pOrigin, edict_t *ed)
|
||||||
{
|
{
|
||||||
// Set global message type
|
// Set global message type
|
||||||
gMsgType = msg_type;
|
gMsgType = msg_id;
|
||||||
|
|
||||||
// Begin message manager
|
// Begin message manager
|
||||||
if (MessageManager().MessageBegin(msg_dest, msg_type, pOrigin, ed))
|
if (MessageManager().MessageBegin(msg_dest, msg_id, pOrigin, ed))
|
||||||
PF_MessageBegin_I(msg_dest, msg_type, pOrigin, ed);
|
PF_MessageBegin_I(msg_dest, msg_id, pOrigin, ed);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EXT_FUNC PF_MessageEnd_Intercept(void)
|
void EXT_FUNC PF_MessageEnd_Intercept(void)
|
||||||
|
@ -21,6 +21,9 @@
|
|||||||
#include "IMessageManager.h"
|
#include "IMessageManager.h"
|
||||||
#include "hookchains.h"
|
#include "hookchains.h"
|
||||||
|
|
||||||
|
#include <memory> // std::unique_ptr
|
||||||
|
#include <algorithm> // std::move
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Implementation interface for defining message parameters and behavior for a game message object
|
* @brief Implementation interface for defining message parameters and behavior for a game message object
|
||||||
*/
|
*/
|
||||||
@ -71,6 +74,27 @@ public:
|
|||||||
*/
|
*/
|
||||||
void setParamInt(size_t index, int value);
|
void setParamInt(size_t index, int value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns the original integer value of the parameter at the given index before any modifications
|
||||||
|
* @param index The index of the parameter
|
||||||
|
* @return The original integer value of the parameter
|
||||||
|
*/
|
||||||
|
int getOriginalParamInt(size_t index) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns the original float value of the parameter at the given index before any modifications
|
||||||
|
* @param index The index of the parameter
|
||||||
|
* @return The original float value of the parameter
|
||||||
|
*/
|
||||||
|
float getOriginalParamFloat(size_t index) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns the original string value of the parameter at the given index before any modifications
|
||||||
|
* @param index The index of the parameter
|
||||||
|
* @return The original string value of the parameter
|
||||||
|
*/
|
||||||
|
const char* getOriginalParamString(size_t index) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Sets the float value of the parameter at the given index
|
* @brief Sets the float value of the parameter at the given index
|
||||||
* @param index The index of the parameter
|
* @param index The index of the parameter
|
||||||
@ -92,42 +116,101 @@ public:
|
|||||||
*/
|
*/
|
||||||
void setParamString(size_t index, const char *string);
|
void setParamString(size_t index, const char *string);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets the destination of the message
|
||||||
|
*/
|
||||||
|
void setDest(Dest dest);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns the destination of the message
|
* @brief Returns the destination of the message
|
||||||
* @return The destination of the message
|
* @return The destination of the message
|
||||||
*/
|
*/
|
||||||
Dest getDest() const { return m_dest; }
|
Dest getDest() const { return m_Storage[BACK].dest; }
|
||||||
|
Dest getOriginalDest() const { return m_Storage[FRONT].dest; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns the type of the message
|
* @brief Sets the index of the message
|
||||||
* @return The type of the message
|
|
||||||
*/
|
*/
|
||||||
int getType() const { return m_type; }
|
void setId(int msg_id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns the index of the message
|
||||||
|
* @return The index of the message
|
||||||
|
*/
|
||||||
|
int getId() const { return m_Storage[BACK].msgid; }
|
||||||
|
int getOriginalId() const { return m_Storage[FRONT].msgid; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets the origin of the message
|
||||||
|
*/
|
||||||
|
void setOrigin(const float *origin);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns the origin of the message
|
* @brief Returns the origin of the message
|
||||||
* @return The origin of the message
|
* @return The origin of the message
|
||||||
*/
|
*/
|
||||||
const float *getOrigin() const { return m_origin; }
|
const float *getOrigin() const { return m_Storage[BACK].origin; }
|
||||||
|
const float *getOriginalOrigin() const { return m_Storage[FRONT].origin; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets the edict associated with the message
|
||||||
|
*/
|
||||||
|
void setEdict(edict_t *pEdict);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns the edict associated with the message
|
* @brief Returns the edict associated with the message
|
||||||
* @return The edict associated with the message
|
* @return The edict associated with the message
|
||||||
*/
|
*/
|
||||||
edict_t *getEdict() const { return m_edict; }
|
edict_t *getEdict() const { return m_Storage[BACK].edict; }
|
||||||
|
edict_t *getOriginalEdict() const { return m_Storage[FRONT].edict; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns whether the message has been modified
|
* @brief Checks if the specified type of message data has been modified
|
||||||
* @return True if the message has been modified, false otherwise
|
*
|
||||||
|
* This function allows you to check if any part of the message data, such as its
|
||||||
|
* destination, type, origin, edict, or any specific parameter, has been modified
|
||||||
|
*
|
||||||
|
* @param type The type of the data to check for modification
|
||||||
|
* This can be one of the following:
|
||||||
|
* - DataType::Any: Check if any part of the message has been modified
|
||||||
|
* - DataType::Dest: Check if the destination has been modified
|
||||||
|
* - DataType::Index: Check if the message ID has been modified
|
||||||
|
* - DataType::Origin: Check if the origin has been modified
|
||||||
|
* - DataType::Edict: Check if the edict pointer has been modified
|
||||||
|
* - DataType::Param: Check if a specific parameter has been modified
|
||||||
|
*
|
||||||
|
* @param index The index of the parameter to check for modification (used only when type is DataType::Param)
|
||||||
|
* Default value is -1, which means the parameter index is not applicable
|
||||||
|
*
|
||||||
|
* @return True if the specified data type has been modified, false otherwise
|
||||||
*/
|
*/
|
||||||
bool isModified() const { return m_modified; }
|
bool isDataModified(DataType type, size_t index) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Resets a specific type of message data to its original value
|
||||||
|
*
|
||||||
|
* @param type The type of data to reset to its original value
|
||||||
|
* This can be one of the following:
|
||||||
|
* - DataType::Any: Reset all modified message data to its original values
|
||||||
|
* - DataType::Dest: Reset the destination to its original value
|
||||||
|
* - DataType::Index: Reset the message ID to its original value
|
||||||
|
* - DataType::Origin: Reset the origin to its original value
|
||||||
|
* - DataType::Edict: Reset the edict pointer of the recipient client to its original value
|
||||||
|
* - DataType::Param: Reset a specific parameter to its original value
|
||||||
|
*
|
||||||
|
* @param index The index of the parameter to reset (used only when type is DataType::Param)
|
||||||
|
* Default value is -1, which means the parameter index is not applicable
|
||||||
|
*
|
||||||
|
* @return True if the modified data type was reset, false otherwise
|
||||||
|
*/
|
||||||
|
bool resetModifiedData(DataType type, size_t index = -1);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
friend class MessageManagerImpl;
|
friend class MessageManagerImpl;
|
||||||
|
|
||||||
// Sets the active state of the message with the given parameters
|
// Sets the active state of the message with the given parameters
|
||||||
void setActive(int dest, int type, const float *origin, edict_t *edict);
|
void setActive(int dest, int id, const float *origin, edict_t *edict);
|
||||||
|
|
||||||
// Sets the buffer for the message
|
// Sets the buffer for the message
|
||||||
void setBuffer(sizebuf_t *pbuf);
|
void setBuffer(sizebuf_t *pbuf);
|
||||||
@ -147,27 +230,78 @@ private:
|
|||||||
// Transforms buffer after sets string for a parameter at the given index
|
// Transforms buffer after sets string for a parameter at the given index
|
||||||
void setTxformBuffer(size_t index, size_t startPos, size_t oldLength, size_t newLength);
|
void setTxformBuffer(size_t index, size_t startPos, size_t oldLength, size_t newLength);
|
||||||
|
|
||||||
bool m_modified; // Flag indicating whether the message has been modified
|
enum
|
||||||
Dest m_dest; // The destination of the message
|
{
|
||||||
int m_type; // The type of the message
|
FRONT, // Original buffer storage data
|
||||||
float m_origin[3]; // The origin of the message
|
BACK, // Current modifiable buffer storage data
|
||||||
edict_t* m_edict; // The edict associated with the message
|
MAX_STORAGE
|
||||||
|
};
|
||||||
|
|
||||||
uint8 m_bufferData[512]; // The buffer data for the message 'm_buffer'
|
struct Storage_t
|
||||||
sizebuf_t m_buffer; // The buffer for the message
|
{
|
||||||
|
// The buffer storage data for the message 'm_buffer' (variable-length message limited to one byte is 256)
|
||||||
|
uint8_t bufData[256]{};
|
||||||
|
|
||||||
|
// The buffer for the message
|
||||||
|
sizebuf_t buf = { "MsgMngr/Begin/End", SIZEBUF_ALLOW_OVERFLOW, bufData, sizeof(bufData), 0 };
|
||||||
|
|
||||||
|
// The destination of the message
|
||||||
|
Dest dest{};
|
||||||
|
|
||||||
|
// The index of the message
|
||||||
|
int msgid{0};
|
||||||
|
|
||||||
|
// The origin of the message
|
||||||
|
float origin[3]{0,0,0};
|
||||||
|
|
||||||
|
// The edict associated with the message
|
||||||
|
edict_t *edict{nullptr};
|
||||||
|
};
|
||||||
|
|
||||||
|
Storage_t m_Storage[MAX_STORAGE];
|
||||||
|
|
||||||
|
#pragma pack(push, 1)
|
||||||
struct Param_t
|
struct Param_t
|
||||||
{
|
{
|
||||||
ParamType type; // The type of the parameter
|
bool modified : 1; // Flag indicating whether the message param has been modified
|
||||||
size_t pos; // The position of the parameter in the buffer
|
ParamType type : 3; // The type of the parameter
|
||||||
size_t len; // The length of the parameter in the buffer
|
size_t posBack : 9; // The current position of the parameter in the buffer
|
||||||
|
size_t posFront : 9; // The stock position of the parameter in the buffer
|
||||||
|
size_t oldlen : 9; // The length of the parameter in the buffer
|
||||||
|
size_t newlen : 9; // The length of the parameter in the buffer
|
||||||
};
|
};
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
static const size_t MAX_PARAMS = 16; // The maximum number of parameters allowed in the message
|
static const size_t MAX_PARAMS = 16; // The maximum number of parameters allowed in the message
|
||||||
Param_t m_params[MAX_PARAMS]; // The array of parameters in the message
|
Param_t m_params[MAX_PARAMS]{}; // The array of parameters in the message
|
||||||
size_t m_paramCount; // The number of parameters in the message
|
size_t m_paramCount : 4; // The number of parameters in the message
|
||||||
|
|
||||||
|
void resetParam(size_t index);
|
||||||
|
|
||||||
|
void setModifiedDataBit(DataType type);
|
||||||
|
void unsetModifiedDataBit(DataType type);
|
||||||
|
bool isDataTypeModified(DataType type) const;
|
||||||
|
uint8 m_modifiedDataBits : DataType::Max;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inline methods
|
||||||
|
*/
|
||||||
|
inline void MessageImpl::setModifiedDataBit(DataType type)
|
||||||
|
{
|
||||||
|
m_modifiedDataBits |= ((1 << static_cast<int>(DataType::Any)) | (1 << static_cast<int>(type)));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void MessageImpl::unsetModifiedDataBit(DataType type)
|
||||||
|
{
|
||||||
|
m_modifiedDataBits &= ~((1 << static_cast<int>(DataType::Any)) | (1 << static_cast<int>(type)));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool MessageImpl::isDataTypeModified(DataType type) const
|
||||||
|
{
|
||||||
|
return (m_modifiedDataBits & (1 << static_cast<int>(type))) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Implementation interface manages hooks and blocking behavior game messages
|
* @brief Implementation interface manages hooks and blocking behavior game messages
|
||||||
*/
|
*/
|
||||||
@ -194,35 +328,35 @@ public:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns the blocking behavior for the given message type
|
* @brief Returns the blocking behavior for the given message type
|
||||||
* @param msgType The message type
|
* @param msg_id The message type
|
||||||
* @return The blocking behavior for the given message type
|
* @return The blocking behavior for the given message type
|
||||||
*/
|
*/
|
||||||
IMessage::BlockType getMessageBlock(int msgType) const;
|
IMessage::BlockType getMessageBlock(int msg_id) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Sets the blocking behavior for the given message type
|
* @brief Sets the blocking behavior for the given message type
|
||||||
* @param msgType The message type
|
* @param msg_id The message type
|
||||||
* @param blockType The blocking behavior to set
|
* @param blockType The blocking behavior to set
|
||||||
*/
|
*/
|
||||||
void setMessageBlock(int msgType, IMessage::BlockType blockType);
|
void setMessageBlock(int msg_id, IMessage::BlockType blockType);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Registers a hook function for the given message type
|
* @brief Registers a hook function for the given message type
|
||||||
* @param msgType The message type to register the hook for
|
* @param msg_id The message type to register the hook for
|
||||||
* @param handler The hook function to register
|
* @param handler The hook function to register
|
||||||
* @param priority The priority of the hook function (see enum HookChainPriority)
|
* @param priority The priority of the hook function (see enum HookChainPriority)
|
||||||
*/
|
*/
|
||||||
void registerHook(int msgType, hookfunc_t handler, int priority = HC_PRIORITY_DEFAULT);
|
void registerHook(int msg_id, hookfunc_t handler, int priority = HC_PRIORITY_DEFAULT);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Unregisters a hook function for the given message type
|
* @brief Unregisters a hook function for the given message type
|
||||||
* @param msgType The message type to unregister the hook for
|
* @param msg_id The message type to unregister the hook for
|
||||||
* @param handler The hook function to unregister
|
* @param handler The hook function to unregister
|
||||||
*/
|
*/
|
||||||
void unregisterHook(int msgType, hookfunc_t handler);
|
void unregisterHook(int msg_id, hookfunc_t handler);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend void PF_MessageBegin_Intercept(int msg_dest, int msg_type, const float *pOrigin, edict_t *ed);
|
friend void PF_MessageBegin_Intercept(int msg_dest, int msg_id, const float *pOrigin, edict_t *ed);
|
||||||
friend void PF_MessageEnd_Intercept();
|
friend void PF_MessageEnd_Intercept();
|
||||||
friend void PF_WriteByte_Intercept(int iValue);
|
friend void PF_WriteByte_Intercept(int iValue);
|
||||||
friend void PF_WriteChar_Intercept(int iValue);
|
friend void PF_WriteChar_Intercept(int iValue);
|
||||||
@ -233,7 +367,7 @@ private:
|
|||||||
friend void PF_WriteString_Intercept(const char *sz);
|
friend void PF_WriteString_Intercept(const char *sz);
|
||||||
friend void PF_WriteEntity_Intercept(int iValue);
|
friend void PF_WriteEntity_Intercept(int iValue);
|
||||||
|
|
||||||
bool MessageBegin(int msg_dest, int msg_type, const float *pOrigin, edict_t *ed);
|
bool MessageBegin(int msg_dest, int msg_id, const float *pOrigin, edict_t *ed);
|
||||||
bool MessageEnd();
|
bool MessageEnd();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -243,31 +377,81 @@ private:
|
|||||||
bool m_inhook; // Flag indicating whether a message hook is currently active
|
bool m_inhook; // Flag indicating whether a message hook is currently active
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Helper a templated Stack class to manage a stack of Message objects
|
* @brief The fixed-size memory pool holds a list of free objects
|
||||||
* @tparam T The type of objects stored in the stack
|
* @tparam T The type of objects stored in the stack
|
||||||
* @tparam MAX The maximum size of the stack
|
* @tparam MAX The maximum size of the stack
|
||||||
*/
|
*/
|
||||||
template <typename T, size_t MAX>
|
template <typename T, size_t MAX>
|
||||||
class Stack
|
class MessagePool
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void push() { _size++; }
|
std::unique_ptr<T> acquire()
|
||||||
void pop () { _size--; }
|
{
|
||||||
|
if (_size > 0)
|
||||||
|
return std::move(_freeObjects[--_size]); // reusing
|
||||||
|
return std::make_unique<T>(); // initialize constructor for new element
|
||||||
|
}
|
||||||
|
|
||||||
|
void release(std::unique_ptr<T> obj)
|
||||||
|
{
|
||||||
|
if (_size < MAX)
|
||||||
|
_freeObjects[_size++] = std::move(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
while (_size > 0)
|
||||||
|
_freeObjects[--_size].reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
size_t _size{0u};
|
||||||
|
std::unique_ptr<T> _freeObjects[MAX]{};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Helper a templated MessageStack class to manage a stack of Message objects with fixed size
|
||||||
|
* @tparam T The type of objects stored in the stack
|
||||||
|
* @tparam MAX The maximum size of the stack
|
||||||
|
*/
|
||||||
|
template <typename T, size_t MAX>
|
||||||
|
class MessageStack
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MessageStack(MessagePool<T, MAX> &pool) : _pool(pool) {}
|
||||||
|
|
||||||
|
T &push()
|
||||||
|
{
|
||||||
|
std::unique_ptr<T> msg = _pool.acquire();
|
||||||
|
_activeObjects[_size++] = std::move(msg);
|
||||||
|
return *_activeObjects[_size - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
void pop()
|
||||||
|
{
|
||||||
|
if (_size > 0)
|
||||||
|
_pool.release(std::move(_activeObjects[--_size]));
|
||||||
|
}
|
||||||
|
|
||||||
size_t size() const { return _size; }
|
size_t size() const { return _size; }
|
||||||
size_t max_size() const { return MAX; }
|
size_t max_size() const { return MAX; }
|
||||||
|
|
||||||
const T &back() const { return _data[_size - 1]; }
|
const T &top() const { return *_activeObjects[_size - 1]; }
|
||||||
T &back() { return _data[_size - 1]; }
|
T &top() { return *_activeObjects[_size - 1]; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
size_t _size = 0u;
|
size_t _size{0u};
|
||||||
T _data[MAX]{};
|
std::unique_ptr<T> _activeObjects[MAX]{};
|
||||||
|
MessagePool<T, MAX> &_pool;
|
||||||
};
|
};
|
||||||
|
|
||||||
static const size_t MAX_MSGSTACK = 16; // The maximum size of the message stack, 16 it should be enough
|
static const size_t MAX_MSGSTACK = 16; // The maximum size of the message stack, 16 it should be enough
|
||||||
Stack<MessageImpl, MAX_MSGSTACK> m_stack;
|
MessagePool<MessageImpl, MAX_MSGSTACK> m_pool; // A fixed-size memory pool stack for reusable
|
||||||
|
MessageStack<MessageImpl, MAX_MSGSTACK> m_stack;
|
||||||
|
|
||||||
|
using HookRegistry_t = IVoidHookChainRegistryImpl<IMessage *>;
|
||||||
|
HookRegistry_t *m_hooks[MAX_USERMESSAGES]{};
|
||||||
|
|
||||||
IVoidHookChainRegistryImpl<IMessage *> m_hooks [MAX_USERMESSAGES]{}; // The array of hook chain registries for each message type
|
|
||||||
IMessage::BlockType m_blocks[MAX_USERMESSAGES]{}; // The array of blocking behaviors for each message type
|
IMessage::BlockType m_blocks[MAX_USERMESSAGES]{}; // The array of blocking behaviors for each message type
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user