AshitaXI / Ashita

Issue tracker and wiki for the Ashita project.
https://ashitaxi.com/
6 stars 1 forks source link

Expose Direct Object Pointers To AshitaCore and LogManager To Addons #53

Closed atom0s closed 10 months ago

atom0s commented 10 months ago

Feature Description

A feature request has been made to expose direct object pointers to the main IAshitaCore and ILogManager instances within Ashita to addons.

Reason

Lua offers a feature, through its require system, that allows users to directly load specifically designed DLL files and export additional functions into the Lua state. Along with this, LuaJIT also offers a greater dynamic system through its FFI library, allowing for directly loading and calling functions exported in [nearly] any DLL file.

Addon developers can greatly expand on what their addon can do by writing external modules their addon can then reference either by the traditional Lua C library manner or by using the more advanced FFI library provided with LuaJIT.

When writing these extensions, being able to directly access the raw object pointers of things such as IAshitaCore and ILogManager like a normal plugin would be greatly useful.

Proposed Implementation

The manner in which Lua treats pointers is not ideal for this situation. Pointers within Lua are normally converted to its userdata type which is not intended to be accessed within the Lua scripting side. It's instead intended to be passed back to the C side of the Lua implementation and recasted back to its assumed parent object type.

To work around this, passing pointers to Lua as a raw number allows it to be cased back as a pointer by the user elsewhere. While this is technically not proper and 'undefined behavior', it is the only solution here that works in this kind of setup. We consider this 'safe' as well as there is only ever one instance of each of these interfaces ever created during the lifespan of Ashita being installed in a process.

A proposed implementation would be:

local ashita_core_ptr = AshitaCore:GetPointer();
local log_manager_ptr = LogManager:GetPointer();

This does not break any existing functionality or require any changes to existing addons. This simply adds a custom method to each interface to expose a number return which is the address of the object.

Example Usage

An example of this being used could be something such as:

// Export this function from your module to be used with LuaJIT's FFI library..
extern "C" __declspec(dllexport) int32_t do_something(uint32_t ashita_core_ptr)
{
    const auto core = reinterpret_cast<IAshitaCore*>(ashita_core_ptr);
    if (core == nullptr) return 0;

    core->GetChatManager()->Write(0, false, "Hello world!");

    return 1;
}
require('common');
require('win32types');
local ffi = require('ffi');

ffi.cdef[[
    int32_t do_something(uint32_t);
]];

local mylib = ffi.load('mylib_name');

mylib.do_something(AshitaCore:GetPointer());
atom0s commented 10 months ago

This is now implemented and will be in the next release.

-- Pointers are returned as uint32_t values (number in Lua)..
local ashita_core_ptr = AshitaCore:GetPointer();
local log_manager_ptr = LogManager:GetPointer();
onimitch commented 9 months ago

I finally got round to using this today and wanted to say a big thanks, made my job of tracking down an issue in some DLL code so much easier.