Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Engine Plugin API: add CreateDynamicArray() #2624

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading