Skip to content

Commit

Permalink
Merge pull request #2624 from ivan-mogilko/362--pluginapi-createdynarray
Browse files Browse the repository at this point in the history
Engine Plugin API: add CreateDynamicArray()
  • Loading branch information
ivan-mogilko authored Dec 26, 2024
2 parents 6d7b756 + 0507a7b commit cccca58
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 19 deletions.
16 changes: 9 additions & 7 deletions Engine/ac/dynobj/cc_dynamicarray.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,16 +76,18 @@ void CCDynamicArray::Unserialize(int index, Stream *in, size_t data_sz)
ccRegisterUnserializedObject(index, &new_arr[MemHeaderSz], this);
}

/* static */ DynObjectRef CCDynamicArray::Create(int numElements, int elementSize, bool isManagedType)
/* static */ DynObjectRef CCDynamicArray::Create(uint32_t elem_count, uint32_t elem_size, bool is_managed)
{
assert(numElements >= 0);
if (numElements < 0)
assert(elem_count <= INT32_MAX);
assert(!is_managed || elem_size == sizeof(int32_t));
if (elem_count > INT32_MAX || (is_managed && elem_size != sizeof(int32_t)))
return {};
uint8_t *new_arr = new uint8_t[numElements * elementSize + MemHeaderSz];
memset(new_arr, 0, numElements * elementSize + MemHeaderSz);

uint8_t *new_arr = new uint8_t[elem_count * elem_size + MemHeaderSz];
memset(new_arr, 0, elem_count * elem_size + MemHeaderSz);
Header &hdr = reinterpret_cast<Header&>(*new_arr);
hdr.ElemCount = numElements | (ARRAY_MANAGED_TYPE_FLAG * isManagedType);
hdr.TotalSize = elementSize * numElements;
hdr.ElemCount = elem_count | (ARRAY_MANAGED_TYPE_FLAG * is_managed);
hdr.TotalSize = elem_size * elem_count;
void *obj_ptr = &new_arr[MemHeaderSz];
int32_t handle = ccRegisterManagedObject(obj_ptr, &globalDynamicArray);
if (handle == 0)
Expand Down
2 changes: 1 addition & 1 deletion Engine/ac/dynobj/cc_dynamicarray.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ struct CCDynamicArray final : AGSCCDynamicObject
}

// Create managed array object and return a pointer to the beginning of a buffer
static DynObjectRef Create(int numElements, int elementSize, bool isManagedType);
static DynObjectRef Create(uint32_t elem_count, uint32_t elem_size, bool is_managed);

// return the type name of the object
const char *GetType() override;
Expand Down
34 changes: 32 additions & 2 deletions Engine/plugin/agsplugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include "ac/sys_events.h"
#include "ac/view.h"
#include "ac/dynobj/dynobj_manager.h"
#include "ac/dynobj/cc_dynamicarray.h"
#include "ac/dynobj/scriptstring.h"
#include "ac/dynobj/scriptsystem.h"
#include "debug/debug_log.h"
Expand Down Expand Up @@ -98,7 +99,7 @@ extern RoomStatus *croom;
// **************** PLUGIN IMPLEMENTATION ****************


const int PLUGIN_API_VERSION = 29;
const int PLUGIN_API_VERSION = 30;
struct EnginePlugin
{
EnginePlugin() {
Expand Down Expand Up @@ -717,7 +718,7 @@ void* IAGSEngine::GetManagedObjectAddressByKey(int key) {

const char* IAGSEngine::CreateScriptString(const char *fromText) {
const char *string = CreateNewScriptString(fromText);
// Should be still standard dynamic object, because not managed by plugin
// Should be standard dynamic object, because not managed by plugin
ccInstance::SetPluginReturnValue(RuntimeScriptValue().SetScriptObject((void*)string, &myScriptStringImpl));
return string;
}
Expand Down Expand Up @@ -848,6 +849,35 @@ void IAGSEngine::Log(int level, const char *fmt, ...)
va_end(argptr);
}

void *IAGSEngine::CreateDynamicArray(size_t elem_count, size_t elem_size, bool is_managed_type)
{
if (elem_count > INT32_MAX || elem_size > INT32_MAX || (static_cast<uint64_t>(elem_count) * elem_size) > UINT32_MAX)
{
debug_script_warn("IAGSEngine::CreateDynamicArray: requested array size exceeds the supported limit");
return nullptr;
}
if (is_managed_type && elem_size != sizeof(int32_t))
{
debug_script_warn("IAGSEngine::CreateDynamicArray: managed handles must have elem_size = 4, requested %zu instead", elem_size);
return nullptr;
}

auto obj_ref = CCDynamicArray::Create(static_cast<uint32_t>(elem_count), static_cast<uint32_t>(elem_size), is_managed_type);
// Should be standard dynamic object, because not managed by plugin
ccInstance::SetPluginReturnValue(RuntimeScriptValue().SetScriptObject(obj_ref.Obj, &globalDynamicArray));
return obj_ref.Obj;
}

size_t IAGSEngine::GetDynamicArrayLength(const void *arr)
{
return arr ? CCDynamicArray::GetHeader(arr).ElemCount : 0u;
}

size_t IAGSEngine::GetDynamicArraySize(const void *arr)
{
return arr ? CCDynamicArray::GetHeader(arr).TotalSize : 0u;
}

// *********** General plugin implementation **********

void pl_stop_plugins() {
Expand Down
21 changes: 21 additions & 0 deletions Engine/plugin/agsplugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -665,6 +665,27 @@ class IAGSEngine {
// *** BELOW ARE INTERFACE VERSION 29 AND ABOVE ONLY
// Print message to the engine's log, under one of the log levels AGSLOG_LEVEL_*.
AGSIFUNC(void) Log(int level, const char *fmt, ...);

// *** BELOW ARE INTERFACE VERSION 30 AND ABOVE ONLY
// Create a new dynamic array, allocating space for the given number of elements
// of the given size. Optionally instructs to create an array for managed handles,
// in which case the element size must be sizeof(int32).
// IMPORTANT: you MUST correctly tell if this is going to be an array of handles, because
// otherwise engine won't know to release their references, which may lead to memory leaks.
// IMPORTANT: when writing handles into this array, you MUST inc ref count for each one
// of them (see IncrementManagedObjectRefCount), otherwise these objects may get disposed
// before the array itself, making these handles invalid!
// Dynamic arrays have their meta data allocated prior to array of elements;
// this function returns a pointer to the element array, which you may write to.
// You may return this pointer from the registered plugin's function just like any other
// managed object pointer.
AGSIFUNC(void*) CreateDynamicArray(size_t elem_count, size_t elem_size, bool is_managed_type);
// Retrieves dynamic array's length (number of elements).
// You should pass a dynamic array object either received from the engine in your registered
// script function, or created by you with CreateDynamicArray().
AGSIFUNC(size_t) GetDynamicArrayLength(const void *arr);
// Retrieves dynamic array's size (total capacity in bytes).
AGSIFUNC(size_t) GetDynamicArraySize(const void *arr);
};


Expand Down
18 changes: 9 additions & 9 deletions Engine/script/cc_instance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1432,25 +1432,25 @@ ccInstError ccInstance::Run(int32_t curpc)
case SCMD_NEWARRAY:
{
auto &reg1 = _registers[codeOp.Arg1i()];
const auto arg_elsize = codeOp.Arg2i();
const auto arg_managed = codeOp.Arg3().GetAsBool();
int numElements = reg1.IValue;
if (numElements < 0)
const int arg_elnum = reg1.IValue;
const uint32_t arg_elsize = static_cast<uint32_t>(codeOp.Arg2i());
const bool arg_managed = codeOp.Arg3().GetAsBool();
if (arg_elnum < 0)
{
cc_error("Invalid size for dynamic array; requested: %d, range: 0..%d", numElements, INT32_MAX);
cc_error("Invalid size for dynamic array; requested: %d, range: 0..%d", arg_elnum, INT32_MAX);
return kInstErr_Generic;
}
DynObjectRef ref = CCDynamicArray::Create(numElements, arg_elsize, arg_managed);
DynObjectRef ref = CCDynamicArray::Create(static_cast<uint32_t>(arg_elnum), arg_elsize, arg_managed);
reg1.SetScriptObject(ref.Obj, &globalDynamicArray);
break;
}
case SCMD_NEWUSEROBJECT:
{
auto &reg1 = _registers[codeOp.Arg1i()];
const auto arg_size = codeOp.Arg2i();
if (arg_size < 0)
const uint32_t arg_size = static_cast<uint32_t>(codeOp.Arg2i());
if (arg_size > INT32_MAX)
{
cc_error("Invalid size for user object; requested: %d (or %d), range: 0..%d", arg_size, arg_size, INT_MAX);
cc_error("Invalid size for user object; requested: %u, range: 0..%d", arg_size, INT32_MAX);
return kInstErr_Generic;
}
DynObjectRef ref = ScriptUserObject::Create(arg_size);
Expand Down

0 comments on commit cccca58

Please sign in to comment.