diff --git a/core/logic/CDataPack.cpp b/core/logic/CDataPack.cpp index d794e379..af53c52d 100644 --- a/core/logic/CDataPack.cpp +++ b/core/logic/CDataPack.cpp @@ -123,6 +123,28 @@ void CDataPack::PackString(const char *string) elements.insert(position++, val); } +void CDataPack::PackCellArray(cell_t const *vals, cell_t count) +{ + InternalPack val; + val.type = CDataPackType::CellArray; + + val.pData.aval = new cell_t [count + 1]; + memcpy(&val.pData.aval[1], vals, sizeof(cell_t) * (count + 1)); + val.pData.aval[0] = count; + elements.insert(position++, val); +} + +void CDataPack::PackFloatArray(cell_t const *vals, cell_t count) +{ + InternalPack val; + val.type = CDataPackType::FloatArray; + + val.pData.aval = new cell_t [count + 1]; + memcpy(&val.pData.aval[1], vals, sizeof(cell_t) * (count + 1)); + val.pData.aval[0] = count; + elements.insert(position++, val); +} + void CDataPack::Reset() const { position = 0; @@ -188,6 +210,46 @@ const char *CDataPack::ReadString(size_t *len) const return val.chars(); } +cell_t *CDataPack::ReadCellArray(cell_t *size) const +{ + if (!IsReadable() || elements[position].type != CDataPackType::CellArray) + { + if(size) + *size = 0; + + return nullptr; + } + + cell_t *val = elements[position].pData.aval; + cell_t *ptr = &(val[1]); + ++position; + + if (size) + *size = val[0]; + + return ptr; +} + +cell_t *CDataPack::ReadFloatArray(cell_t *size) const +{ + if (!IsReadable() || elements[position].type != CDataPackType::FloatArray) + { + if(size) + *size = 0; + + return nullptr; + } + + cell_t *val = elements[position].pData.aval; + cell_t *ptr = &(val[1]); + ++position; + + if (size) + *size = val[0]; + + return ptr; +} + void *CDataPack::ReadMemory(size_t *size) const { void *ptr = nullptr; @@ -239,6 +301,13 @@ bool CDataPack::RemoveItem(size_t pos) delete elements[pos].pData.sval; break; } + + case CDataPackType::CellArray: + case CDataPackType::FloatArray: + { + delete elements[pos].pData.aval; + break; + } } elements.remove(pos); diff --git a/core/logic/CDataPack.h b/core/logic/CDataPack.h index 2ce846f2..6e46bd89 100644 --- a/core/logic/CDataPack.h +++ b/core/logic/CDataPack.h @@ -43,7 +43,9 @@ enum CDataPackType { Cell, Float, String, - Function + Function, + CellArray, + FloatArray, }; class CDataPack @@ -90,6 +92,21 @@ public: // Originally IDataReader */ float ReadFloat() const; + /** + * @brief Reads an array of values from the data stream. + * + * @param len The size of the array stored at this position to return. + * @return A cell array read from the current position. + */ + cell_t *ReadCellArray(cell_t *len) const; + /** + * @brief Reads an array of values from the data stream. + * + * @param len The size of the array stored at this position to return. + * @return A cell array read from the current position. + */ + cell_t *ReadFloatArray(cell_t *len) const; + /** * @brief Returns whether or not a specified number of bytes from the current stream * position to the end can be read. @@ -150,6 +167,21 @@ public: // Originally IDataPack */ void PackString(const char *string); + /** + * @brief Packs an array of cells into the data stream. + * + * @param vals Cells to write. + * @param count Number of cells. + */ + void PackCellArray(cell_t const *vals, cell_t count); + /** + * @brief Packs an array of cells into the data stream. + * + * @param vals Cells to write. + * @param count Number of cells. + */ + void PackFloatArray(cell_t const *vals, cell_t count); + /** * @brief Creates a generic block of memory in the stream. * @@ -182,6 +214,7 @@ private: float fval; uint8_t *vval; ke::AString *sval; + cell_t *aval; } InternalPackValue; typedef struct { diff --git a/core/logic/smn_datapacks.cpp b/core/logic/smn_datapacks.cpp index 529eea25..18dfdc5d 100644 --- a/core/logic/smn_datapacks.cpp +++ b/core/logic/smn_datapacks.cpp @@ -166,6 +166,62 @@ static cell_t smn_WritePackString(IPluginContext *pContext, const cell_t *params return 1; } +static cell_t smn_WritePackCellArray(IPluginContext *pContext, const cell_t *params) +{ + HandleError herr; + HandleSecurity sec; + sec.pOwner = pContext->GetIdentity(); + sec.pIdentity = g_pCoreIdent; + + Handle_t hndl = static_cast(params[1]); + CDataPack *pDataPack = nullptr; + if ((herr = handlesys->ReadHandle(hndl, g_DataPackType, &sec, (void **)&pDataPack)) + != HandleError_None) + { + pContext->ReportError("Invalid data pack handle %x (error %d).", hndl, herr); + return 0; + } + + if (!params[4]) + { + pDataPack->RemoveItem(); + } + + cell_t *pArray; + pContext->LocalToPhysAddr(params[2], &pArray); + pDataPack->PackCellArray(pArray, params[3]); + + return 1; +} + +static cell_t smn_WritePackFloatArray(IPluginContext *pContext, const cell_t *params) +{ + HandleError herr; + HandleSecurity sec; + sec.pOwner = pContext->GetIdentity(); + sec.pIdentity = g_pCoreIdent; + + Handle_t hndl = static_cast(params[1]); + CDataPack *pDataPack = nullptr; + if ((herr = handlesys->ReadHandle(hndl, g_DataPackType, &sec, (void **)&pDataPack)) + != HandleError_None) + { + pContext->ReportError("Invalid data pack handle %x (error %d).", hndl, herr); + return 0; + } + + if (!params[4]) + { + pDataPack->RemoveItem(); + } + + cell_t *pArray; + pContext->LocalToPhysAddr(params[2], &pArray); + pDataPack->PackFloatArray(pArray, params[3]); + + return 1; +} + static cell_t smn_WritePackFunction(IPluginContext *pContext, const cell_t *params) { Handle_t hndl = static_cast(params[1]); @@ -312,6 +368,108 @@ static cell_t smn_ReadPackFunction(IPluginContext *pContext, const cell_t *param return pDataPack->ReadFunction(); } +static cell_t smn_ReadPackCellArray(IPluginContext *pContext, const cell_t *params) +{ + HandleError herr; + HandleSecurity sec; + sec.pOwner = pContext->GetIdentity(); + sec.pIdentity = g_pCoreIdent; + + Handle_t hndl = static_cast(params[1]); + CDataPack *pDataPack = nullptr; + if ((herr = handlesys->ReadHandle(hndl, g_DataPackType, &sec, (void **)&pDataPack)) + != HandleError_None) + { + pContext->ReportError("Invalid data pack handle %x (error %d).", hndl, herr); + return 0; + } + + if (!pDataPack->IsReadable()) + { + pContext->ReportError("Data pack operation is out of bounds."); + return 0; + } + + if (pDataPack->GetCurrentType() != CDataPackType::CellArray) + { + pContext->ReportError("Invalid data pack type (got %d / expected %d).", pDataPack->GetCurrentType(), CDataPackType::CellArray); + return 0; + } + + cell_t packCount = 0; + cell_t *pData = pDataPack->ReadCellArray(&packCount); + if(pData == nullptr || packCount == 0) + { + pContext->ReportError("Invalid data pack operation: current position isn't an array!"); + return 0; + } + + cell_t count = params[3]; + if(packCount > count) + { + pContext->ReportError("Input buffer too small (needed %d, got %d).", packCount, count); + return 0; + } + + cell_t *pArray; + pContext->LocalToPhysAddr(params[2], &pArray); + + memcpy(pArray, pData, sizeof(cell_t) * count); + + return 1; +} + +static cell_t smn_ReadPackFloatArray(IPluginContext *pContext, const cell_t *params) +{ + HandleError herr; + HandleSecurity sec; + sec.pOwner = pContext->GetIdentity(); + sec.pIdentity = g_pCoreIdent; + + Handle_t hndl = static_cast(params[1]); + CDataPack *pDataPack = nullptr; + if ((herr = handlesys->ReadHandle(hndl, g_DataPackType, &sec, (void **)&pDataPack)) + != HandleError_None) + { + pContext->ReportError("Invalid data pack handle %x (error %d).", hndl, herr); + return 0; + } + + if (!pDataPack->IsReadable()) + { + pContext->ReportError("Data pack operation is out of bounds."); + return 0; + } + + if (pDataPack->GetCurrentType() != CDataPackType::FloatArray) + { + pContext->ReportError("Invalid data pack type (got %d / expected %d).", pDataPack->GetCurrentType(), CDataPackType::FloatArray); + return 0; + } + + cell_t packCount = 0; + cell_t *pData = pDataPack->ReadFloatArray(&packCount); + if(pData == nullptr || packCount == 0) + { + pContext->ReportError("Invalid data pack operation: current position isn't an array!"); + return 0; + } + + cell_t count = params[3]; + if(packCount > count) + { + pContext->ReportError("Input buffer too small (needed %d, got %d).", packCount, count); + return 0; + } + + cell_t *pArray; + pContext->LocalToPhysAddr(params[2], &pArray); + + memcpy(pArray, pData, sizeof(cell_t) * count); + + return 1; +} + static cell_t smn_ResetPack(IPluginContext *pContext, const cell_t *params) { Handle_t hndl = static_cast(params[1]); @@ -426,10 +584,14 @@ REGISTER_NATIVES(datapacknatives) {"DataPack.WriteFloat", smn_WritePackFloat}, {"DataPack.WriteString", smn_WritePackString}, {"DataPack.WriteFunction", smn_WritePackFunction}, + {"DataPack.WriteCellArray", smn_WritePackCellArray}, + {"DataPack.WriteFloatArray", smn_WritePackFloatArray}, {"DataPack.ReadCell", smn_ReadPackCell}, {"DataPack.ReadFloat", smn_ReadPackFloat}, {"DataPack.ReadString", smn_ReadPackString}, {"DataPack.ReadFunction", smn_ReadPackFunction}, + {"DataPack.ReadCellArray", smn_ReadPackCellArray}, + {"DataPack.ReadFloatArray", smn_ReadPackFloatArray}, {"DataPack.Reset", smn_ResetPack}, {"DataPack.Position.get", smn_GetPackPosition}, {"DataPack.Position.set", smn_SetPackPosition}, diff --git a/plugins/include/datapack.inc b/plugins/include/datapack.inc index 7e88919a..ed2f9ace 100644 --- a/plugins/include/datapack.inc +++ b/plugins/include/datapack.inc @@ -71,6 +71,20 @@ methodmap DataPack < Handle // @param insert Determines whether mid-pack writes will insert instead of overwrite. public native void WriteFunction(Function fktptr, bool insert = false); + // Packs an array of cells into a data pack. + // + // @param array Array to add. + // @param count Number of elements + // @param insert Determines whether mid-pack writes will insert instead of overwrite. + public native void WriteCellArray(const any[] array, int count, bool insert = false); + + // Packs an array of floats into a data pack. + // + // @param array Array to add. + // @param count Number of elements + // @param insert Determines whether mid-pack writes will insert instead of overwrite. + public native void WriteFloatArray(const float[] array, int count, bool insert = false); + // Reads a cell from a data pack. // // @return A cell at this position @@ -92,6 +106,18 @@ methodmap DataPack < Handle // @return Function pointer. public native Function ReadFunction(); + // Reads an array of cells a data pack. + // + // @param buffer Destination buffer. + // @param count Maximum length of output buffer. + public native void ReadCellArray(any[] buffer, int count); + + // Reads an array of floats from a data pack. + // + // @param buffer Destination buffer. + // @param count Maximum length of output buffer. + public native void ReadFloatArray(float[] buffer, int count); + // Resets the position in a data pack. // // @param clear If true, clears the contained data.