@@ -370,15 +370,15 @@ struct ValueType {
370370 : type(t)
371371 {
372372 if (type != nullptr ) {
373- data.resize (type->get_size ());
373+ data.resize (type->get_valuetype_size ());
374374 }
375375 }
376376
377377 ValueType (::sdk::RETypeDefinition* t, void * addr): type(t) {
378378 if (t != nullptr && addr != nullptr ) {
379379 uint8_t * raw_data = reinterpret_cast <uint8_t *>(addr);
380- data.reserve (t->get_size ());
381- data.insert (data.begin (), raw_data, raw_data + t->get_size ());
380+ data.reserve (t->get_valuetype_size ());
381+ data.insert (data.begin (), raw_data, raw_data + t->get_valuetype_size ());
382382 }
383383 }
384384
@@ -425,16 +425,33 @@ struct ValueType {
425425 return sol::make_object (l, sol::nil);
426426 }
427427
428- auto real_obj = (void *)address ();
429428 auto def = type->get_method (name);
430429
431430 if (def == nullptr ) {
432431 return sol::make_object (l, sol::nil);
433432 }
434433
434+ // For instance methods on value types, we need to construct a fake boxed object.
435+ // The native invoke() expects a ManagedObject* with a 0x10 byte header:
436+ // 0x00: REObjectInfo* (type info / vtable pointer)
437+ // 0x08: uint32_t refcount + padding
438+ // 0x10: actual value type data starts here
439+ std::vector<uint8_t > fake_boxed_storage (0x10 + type->get_valuetype_size (), 0 );
440+ // REObject header: REObjectInfo* at offset 0x00
441+ *(void **)&fake_boxed_storage[0x00 ] = (void *)type;
442+ // REManagedObject: reference count at offset 0x08 (set high to prevent GC interference)
443+ *(uint32_t *)&fake_boxed_storage[0x08 ] = 9999 ;
444+ // Copy value type data at offset 0x10
445+ memcpy (&fake_boxed_storage[0x10 ], data.data (), type->get_valuetype_size ());
446+
447+ auto real_obj = (void *)fake_boxed_storage.data ();
448+
435449 auto vec_args = ::api::sdk::build_args (va);
436450 auto ret_val = def->invoke (real_obj, std::span (vec_args));
437451
452+ // copy back any changes to the value type from the fake boxed storage
453+ memcpy (data.data (), &fake_boxed_storage[0x10 ], type->get_valuetype_size ());
454+
438455 if (ret_val.exception_thrown ) {
439456 throw sol::error (" Invoke threw an exception" );
440457 }
0 commit comments