Skip to content

Commit

Permalink
.NET: Unify TryGetMember code with GetDataBoxed
Browse files Browse the repository at this point in the history
  • Loading branch information
praydog committed May 13, 2024
1 parent 2aa2eed commit 96a8ea4
Show file tree
Hide file tree
Showing 5 changed files with 27 additions and 121 deletions.
2 changes: 1 addition & 1 deletion csharp-api/REFrameworkNET/Field.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ namespace REFrameworkNET {
return nullptr;
}

return Utility::BoxData((uintptr_t*)raw_data, this->Type, false);
return Utility::BoxData((uintptr_t*)raw_data, this->Type, false, this);
}

System::Object^ Field::GetDataBoxed(System::Type^ targetReturnType, uintptr_t obj, bool isValueType) {
Expand Down
111 changes: 1 addition & 110 deletions csharp-api/REFrameworkNET/UnifiedObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,116 +90,7 @@ namespace REFrameworkNET {

if (field != nullptr)
{
const auto field_type = field->GetType();

if (field_type == nullptr) {
return false;
}

const auto raw_ft = (reframework::API::TypeDefinition*)field_type;
const uintptr_t addr = field->IsStatic() ? 0 : this->GetAddress();
const auto vm_obj_type = field_type->GetVMObjType();

#define MAKE_TYPE_HANDLER(X, Y) \
case ##X##_fnv: \
result = gcnew Y(field->GetData<##Y##>(addr, field_type->IsValueType())); \
break;

switch (REFrameworkNET::hash(raw_ft->get_full_name())) {
MAKE_TYPE_HANDLER("System.Boolean", bool)
MAKE_TYPE_HANDLER("System.Byte", uint8_t)
MAKE_TYPE_HANDLER("System.SByte", int8_t)
MAKE_TYPE_HANDLER("System.Int16", int16_t)
MAKE_TYPE_HANDLER("System.UInt16", uint16_t)
MAKE_TYPE_HANDLER("System.Int32", int32_t)
MAKE_TYPE_HANDLER("System.UInt32", uint32_t)
MAKE_TYPE_HANDLER("System.Int64", int64_t)
MAKE_TYPE_HANDLER("System.UInt64", uint64_t)
MAKE_TYPE_HANDLER("System.Single", float)
MAKE_TYPE_HANDLER("System.Double", double)
MAKE_TYPE_HANDLER("System.Char", wchar_t)
MAKE_TYPE_HANDLER("System.IntPtr", intptr_t)
MAKE_TYPE_HANDLER("System.UIntPtr", uintptr_t)
case "System.String"_fnv:
{
if (field->IsLiteral()) {
result = gcnew System::String((const char*)field->GetInitDataPtr());
break;
}

// TODO: Check if this half of it works
auto strObject = field->GetData<reframework::API::ManagedObject*>(addr, field_type->IsValueType());

if (strObject == nullptr) {
result = nullptr;
break;
}

const auto firstCharField = field_type->GetField("_firstChar");
uint32_t offset = 0;

if (firstCharField != nullptr) {
offset = field_type->IsValueType() ? firstCharField->GetOffsetFromFieldPtr() : firstCharField->GetOffsetFromBase();
} else {
const auto fieldOffset = *(uint32_t*)(*(uintptr_t*)strObject - sizeof(void*));
offset = fieldOffset + 4;
}

wchar_t* chars = (wchar_t*)((uintptr_t)strObject + offset);
result = gcnew System::String(chars);
break;
}
default:
if (vm_obj_type > VMObjType::NULL_ && vm_obj_type < VMObjType::ValType) {
switch (vm_obj_type) {
case VMObjType::Array:
/*
Just return it as an managed object for now
*/
default: {
//const auto td = utility::re_managed_object::get_type_definition(*(::REManagedObject**)data);
auto& obj = field->GetData<reframework::API::ManagedObject*>(addr, field_type->IsValueType());

if (obj == nullptr) {
result = nullptr;
break;
}

auto td = TypeDefinition::GetInstance(obj->get_type_definition());

// another fallback incase the method returns an object which is an array
if (td != nullptr && td->GetVMObjType() == VMObjType::Array) {
/*
Just return it as an managed object for now
*/
}

result = ManagedObject::Get(obj);
break;
}
}
} else {
switch (field_type->GetSize()) {
case 8:
result = gcnew System::UInt64(field->GetData<uint64_t>(addr, field_type->IsValueType()));
break;
case 4:
result = gcnew System::UInt32(field->GetData<uint32_t>(addr, field_type->IsValueType()));
break;
case 2:
result = gcnew System::UInt16(field->GetData<uint16_t>(addr, field_type->IsValueType()));
break;
case 1:
result = gcnew System::Byte(field->GetData<uint8_t>(addr, field_type->IsValueType()));
break;
default:
result = nullptr;
break;
}

break;
}
};
result = field->GetDataBoxed(this->GetAddress(), !this->IsManaged() && this->GetTypeDefinition()->IsValueType());

return true;
}
Expand Down
11 changes: 9 additions & 2 deletions csharp-api/REFrameworkNET/Utility.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public interface class DummyInterface {

};

System::Object^ Utility::BoxData(uintptr_t* ptr, TypeDefinition^ t, bool fromInvoke) {
System::Object^ Utility::BoxData(uintptr_t* ptr, TypeDefinition^ t, bool fromInvoke, Field^ field) {
System::Object^ result = nullptr;

if (t == nullptr) {
Expand All @@ -35,6 +35,10 @@ System::Object^ Utility::BoxData(uintptr_t* ptr, TypeDefinition^ t, bool fromInv

// TODO: Clean this up
if (vm_object_type == VMObjType::String) {
if (field != nullptr && field->IsLiteral()) {
return gcnew System::String((const char*)field->GetInitDataPtr());
}

auto strObject = (reframework::API::ManagedObject*)*ptr;
auto strType = strObject->get_type_definition();
const auto firstCharField = strType->find_field("_firstChar");
Expand Down Expand Up @@ -76,20 +80,23 @@ System::Object^ Utility::BoxData(uintptr_t* ptr, TypeDefinition^ t, bool fromInv
switch (t->GetFNV64Hash()) {
MAKE_TYPE_HANDLER_2(System, Boolean, bool, byte)
MAKE_TYPE_HANDLER_2(System, Byte, uint8_t, byte)
MAKE_TYPE_HANDLER_2(System, Char, wchar_t, byte)
MAKE_TYPE_HANDLER_2(System, UInt16, uint16_t, word)
MAKE_TYPE_HANDLER_2(System, UInt32, uint32_t, dword)
MAKE_TYPE_HANDLER_2(System, UInt64, uint64_t, qword)
MAKE_TYPE_HANDLER_2(System, SByte, int8_t, byte)
MAKE_TYPE_HANDLER_2(System, Int16, int16_t, word)
MAKE_TYPE_HANDLER_2(System, Int32, int32_t, dword)
MAKE_TYPE_HANDLER_2(System, Int64, int64_t, qword)
MAKE_TYPE_HANDLER_2(System, IntPtr, intptr_t, qword)
MAKE_TYPE_HANDLER_2(System, UIntPtr, uintptr_t, qword)
MAKE_TYPE_HANDLER_2(System, Double, double, d)
// Because invoke wrappers returning a single actually return a double
// for consistency purposes
//MAKE_TYPE_HANDLER_2(System, Single, double, d)
case "System.Single"_fnv: {
if (fromInvoke) {
result = gcnew System::Double(*(double*)ptr);
result = gcnew System::Single((float)*(double*)ptr);
break;
}

Expand Down
8 changes: 7 additions & 1 deletion csharp-api/REFrameworkNET/Utility.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

namespace REFrameworkNET {
ref class TypeDefinition;
ref class Field;

static constexpr auto hash(std::string_view data) {
size_t result = 0xcbf29ce484222325;
Expand All @@ -23,7 +24,12 @@ namespace REFrameworkNET {

ref class Utility {
public:
static System::Object^ BoxData(uintptr_t* ptr, TypeDefinition^ t, bool fromInvoke);
// field can be null, just used for more information (particularly for static strings that can be literal)
static System::Object^ BoxData(uintptr_t* ptr, TypeDefinition^ t, bool fromInvoke) {
return BoxData(ptr, t, fromInvoke, nullptr);
}

static System::Object^ BoxData(uintptr_t* ptr, TypeDefinition^ t, bool fromInvoke, Field^ field);
static System::Object^ TranslateBoxedData(System::Type^ targetReturnType, System::Object^ boxedData);
};
}
16 changes: 9 additions & 7 deletions csharp-api/test/Test/Test.cs
Original file line number Diff line number Diff line change
Expand Up @@ -394,19 +394,21 @@ public static void MainImpl() {
REFrameworkNET.API.LogInfo("HasAnySave: " + hasAnySave.ToString());

dynamic guiManager = REFrameworkNET.API.GetManagedSingleton("app.GuiManager");

ulong guiManagerAddress = guiManager != null ? (guiManager as REFrameworkNET.ManagedObject).GetAddress() : 0;
dynamic fadeOwnerCmn = guiManager?.FadeOwnerCmn;
dynamic optionData = guiManager?.OptionData;
dynamic optionDataFromGet = guiManager?.getOptionData();
bool? isDispSubtitle = optionData?._IsDispSubtitle;

REFrameworkNET.API.LogInfo("GuiManager: " + guiManager.ToString() + " @ " + guiManagerAddress.ToString("X"));

dynamic fadeOwnerCmn = guiManager?.FadeOwnerCmn;
REFrameworkNET.API.LogInfo(" FadeOwnerCmn: " + fadeOwnerCmn.ToString());

dynamic optionData = guiManager?.OptionData;
REFrameworkNET.API.LogInfo(" OptionData: " + optionData.ToString() + ": " + optionData?.GetTypeDefinition()?.GetFullName()?.ToString());

dynamic optionDataFromGet = guiManager?.getOptionData();
REFrameworkNET.API.LogInfo(" OptionDataFromGet: " + optionDataFromGet.ToString() + ": " + optionDataFromGet?.GetTypeDefinition()?.GetFullName()?.ToString());
REFrameworkNET.API.LogInfo(" OptionDataFromGet same: " + (optionData?.Equals(optionDataFromGet)).ToString() + (" {0} vs {1}", optionData?.GetAddress().ToString("X"), optionDataFromGet?.GetAddress().ToString("X")));


bool? isDispSubtitle = optionData?._IsDispSubtitle;

REFrameworkNET.API.LogInfo(" IsDispSubtitle: " + isDispSubtitle.ToString());

if (optionData != null) {
Expand Down

0 comments on commit 96a8ea4

Please sign in to comment.