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

Conversation

ivan-mogilko
Copy link
Contributor

@ivan-mogilko ivan-mogilko commented Dec 20, 2024

Resolve #2313

This adds IAGSEngine::CreateDynamicArray, GetDynamicArrayLength and GetDynamicArraySize:

  // 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);

This lets plugins to create and return dynamic arrays in their own functions. So you can have plugin functions that return dynamic array to user script.

To be honest, this method is not trivial, plugin authors have to take care to properly init array.
Specifically, when writing array of managed handles, they must not forget to add 1 extra reference to each of the objects they put there, this reference is "owned" by array. If you don't do that, the object may in theory get disposed before array gets disposed.

Following are example of using this method, which I used to test in a dummy plugin:

void* MyPlugin_TestArray(int length)
{
    void *arr = GetAGS()->CreateDynamicArray(length, sizeof(int32_t), false);
    int32_t *arr_int = static_cast<int32_t*>(arr);
    for (int i = 0; i < length; ++i)
    {
        arr_int[i] = i;
    }
    return arr;
}

void* MyPlugin_TestManagedArray(int length)
{
    std::vector<int32_t> string_handles;
    for (int i = 0; i < length; ++i)
    {
        const char *script_string =
            GetAGS()->CreateScriptString((std::string("some text {") + std::to_string(i) + std::string("}")).c_str());
        GetAGS()->IncrementManagedObjectRefCount((void*)script_string);
        string_handles.push_back(GetAGS()->GetManagedObjectKeyByAddress((void*)script_string));
    }
    
    void *arr = GetAGS()->CreateDynamicArray(length, sizeof(int32_t), true);
    int32_t *arr_handles = static_cast<int32_t*>(arr);
    for (int i = 0; i < length; ++i)
    {
        arr_handles[i] = string_handles[i];
    }
    return arr;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Plugin API: add a CreateScriptArray method
1 participant