Skip to content

Commit

Permalink
Add __tostring meta to Unreal Lua objects for convenience
Browse files Browse the repository at this point in the history
* __tostring metamethod causes `tostring(object)` (e.g., from `print`)
  to provide some useful information about the object for debugging.

(cherry picked from commit b270792)
(cherry picked from commit 31db732)
  • Loading branch information
Lyrth committed Oct 11, 2024
1 parent 18a416c commit 4b7de0c
Show file tree
Hide file tree
Showing 20 changed files with 351 additions and 11 deletions.
41 changes: 41 additions & 0 deletions UE4SS/include/LuaType/LuaUObject.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,29 @@ namespace RC::LuaType
}
return 0;
});

base_object.get_metamethods().create(LuaMadeSimple::Lua::MetaMethod::ToString, []([[maybe_unused]] const LuaMadeSimple::Lua& lua) -> int {
if (!lua.is_userdata())
{
lua.throw_error(std::format("{} __tostring metamethod called but there was no userdata", ObjectName::ToString()));
}

std::string name;

const auto& lua_object = lua.get_userdata<SelfType>();
if (lua_object.get_remote_cpp_object())
{
name.append(to_string(lua_object.get_remote_cpp_object()->GetClassPrivate()->GetName()));
name.append(std::format(": {:016X}", reinterpret_cast<uintptr_t>(lua_object.get_remote_cpp_object())));
} else {
name.append(ObjectName::ToString());
name.append(": NULL");
}

lua.set_string(name);

return 1;
});
}

public:
Expand Down Expand Up @@ -732,6 +755,24 @@ No overload found for function 'UObject.ProcessConsoleExec'.
prepare_to_handle(Operation::Set, lua);
return 0;
});

base_object.get_metamethods().create(LuaMadeSimple::Lua::MetaMethod::ToString, []([[maybe_unused]] const LuaMadeSimple::Lua& lua) -> int {
if (!lua.is_userdata())
{
lua.throw_error("LocalUnrealParam __tostring metamethod called but there was no userdata");
}

std::string name;

const auto& lua_object = lua.get_userdata<LuaType::LocalUnrealParam<ParamType>>();
name.append("LocalUnrealParam<");
name.append(to_string(lua_object.m_property->GetClass().GetName()));
name.append(std::format(">: 0x{:012x}", reinterpret_cast<uintptr_t>(&lua_object)));

lua.set_string(name);

return 1;
});
}

auto static setup_member_functions(LuaMadeSimple::Lua::Table& table) -> void
Expand Down
17 changes: 17 additions & 0 deletions UE4SS/src/LuaType/LuaFName.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,23 @@ No overload found for function 'FName'.

return name_a.get_local_cpp_object() == name_b.get_local_cpp_object();
});

base_object.get_metamethods().create(LuaMadeSimple::Lua::MetaMethod::ToString, []([[maybe_unused]] const LuaMadeSimple::Lua& lua) -> int {
if (!lua.is_userdata())
{
lua.throw_error(std::format("{} __tostring metamethod called but there was no userdata", ClassName::ToString()));
}

std::string name;

auto& fname = lua.get_userdata<FName>().get_local_cpp_object();
name.append(ClassName::ToString());
name.append(std::format(" \"{}\": {:016X}", to_string(fname.ToString()), reinterpret_cast<uintptr_t>(&fname)));

lua.set_string(name);

return 1;
});
}

template <LuaMadeSimple::Type::IsFinal is_final>
Expand Down
17 changes: 16 additions & 1 deletion UE4SS/src/LuaType/LuaFOutputDevice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,22 @@ namespace RC::LuaType

auto FOutputDevice::setup_metamethods([[maybe_unused]] BaseObject& base_object) -> void
{
// FOutputDevice has no metamethods
base_object.get_metamethods().create(LuaMadeSimple::Lua::MetaMethod::ToString, []([[maybe_unused]] const LuaMadeSimple::Lua& lua) -> int {
if (!lua.is_userdata())
{
lua.throw_error(std::format("{} __tostring metamethod called but there was no userdata", ClassName::ToString()));
}

std::string name;

auto& lua_object = lua.get_userdata<FOutputDevice>();
name.append(ClassName::ToString());
name.append(std::format(": {:016X}", reinterpret_cast<uintptr_t>(lua_object.get_remote_cpp_object())));

lua.set_string(name);

return 1;
});
}

template <LuaMadeSimple::Type::IsFinal is_final>
Expand Down
16 changes: 16 additions & 0 deletions UE4SS/src/LuaType/LuaFSoftObjectPath.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,22 @@ namespace RC::LuaType

auto FSoftObjectPath::setup_metamethods(BaseObject& base_object) -> void
{
base_object.get_metamethods().create(LuaMadeSimple::Lua::MetaMethod::ToString, []([[maybe_unused]] const LuaMadeSimple::Lua& lua) -> int {
if (!lua.is_userdata())
{
lua.throw_error(std::format("{} __tostring metamethod called but there was no userdata", ClassName::ToString()));
}

std::string name;

auto& lua_object = lua.get_userdata<FSoftObjectPath>();
name.append(ClassName::ToString());
name.append(std::format(": {:016X}", reinterpret_cast<uintptr_t>(&lua_object.get_local_cpp_object())));

lua.set_string(name);

return 1;
});
}

template <LuaMadeSimple::Type::IsFinal is_final>
Expand Down
17 changes: 16 additions & 1 deletion UE4SS/src/LuaType/LuaFString.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,22 @@ namespace RC::LuaType

auto FString::setup_metamethods([[maybe_unused]] BaseObject& base_object) -> void
{
// FString has no metamethods
base_object.get_metamethods().create(LuaMadeSimple::Lua::MetaMethod::ToString, []([[maybe_unused]] const LuaMadeSimple::Lua& lua) -> int {
if (!lua.is_userdata())
{
lua.throw_error(std::format("{} __tostring metamethod called but there was no userdata", ClassName::ToString()));
}

std::string name;

auto* fstring = lua.get_userdata<LuaType::FString>().get_remote_cpp_object();
name.append(ClassName::ToString());
name.append(std::format(" \"{}\": {:016X}", to_string(fstring->GetCharArray()), reinterpret_cast<uintptr_t>(fstring)));

lua.set_string(name);

return 1;
});
}

template <LuaMadeSimple::Type::IsFinal is_final>
Expand Down
17 changes: 17 additions & 0 deletions UE4SS/src/LuaType/LuaFText.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,23 @@ No overload found for function 'FText'.
// FText objects are equal if their string representations are equal
return text_a.get_local_cpp_object().ToString() == text_b.get_local_cpp_object().ToString();
});

base_object.get_metamethods().create(LuaMadeSimple::Lua::MetaMethod::ToString, []([[maybe_unused]] const LuaMadeSimple::Lua& lua) -> int {
if (!lua.is_userdata())
{
lua.throw_error(std::format("{} __tostring metamethod called but there was no userdata", ClassName::ToString()));
}

std::string name;

auto& ftext = lua.get_userdata<FText>().get_local_cpp_object();
name.append(ClassName::ToString());
name.append(std::format(" \"{}\": {:016X}", to_string(ftext.ToString()), reinterpret_cast<uintptr_t>(&ftext)));

lua.set_string(name);

return 1;
});
}

template <LuaMadeSimple::Type::IsFinal is_final>
Expand Down
24 changes: 23 additions & 1 deletion UE4SS/src/LuaType/LuaFWeakObjectPtr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,29 @@ namespace RC::LuaType

auto FWeakObjectPtr::setup_metamethods([[maybe_unused]] BaseObject& base_object) -> void
{
// FWeakObjectPtr has no metamethods
base_object.get_metamethods().create(LuaMadeSimple::Lua::MetaMethod::ToString, []([[maybe_unused]] const LuaMadeSimple::Lua& lua) -> int {
if (!lua.is_userdata())
{
lua.throw_error(std::format("{} __tostring metamethod called but there was no userdata", ClassName::ToString()));
}

std::string name;

auto& fptr = lua.get_userdata<FWeakObjectPtr>().get_local_cpp_object();
name.append(ClassName::ToString());
if (fptr.Get())
{
name.append(std::format(" -> {:016X}: {:016X}", reinterpret_cast<uintptr_t>(fptr.Get()), reinterpret_cast<uintptr_t>(&fptr)));
}
else
{
name.append(std::format(" -> NULL: {:016X}", reinterpret_cast<uintptr_t>(fptr.Get()), reinterpret_cast<uintptr_t>(&fptr)));
}

lua.set_string(name);

return 1;
});
}

template <LuaMadeSimple::Type::IsFinal is_final>
Expand Down
19 changes: 17 additions & 2 deletions UE4SS/src/LuaType/LuaModRef.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,24 @@ namespace RC::LuaType
return table;
}

auto LuaModRef::setup_metamethods(BaseObject&) -> void
auto LuaModRef::setup_metamethods(BaseObject& base_object) -> void
{
// Mod has no metamethods
base_object.get_metamethods().create(LuaMadeSimple::Lua::MetaMethod::ToString, []([[maybe_unused]] const LuaMadeSimple::Lua& lua) -> int {
if (!lua.is_userdata())
{
lua.throw_error(std::format("{} __tostring metamethod called but there was no userdata", ClassName::ToString()));
}

std::string name;

auto& lua_object = lua.get_userdata<LuaModRef>();
name.append(ClassName::ToString());
name.append(std::format(": 0x{:012x}", reinterpret_cast<uintptr_t>(&lua_object)));

lua.set_string(name);

return 1;
});
}

template <LuaMadeSimple::Type::IsFinal is_final>
Expand Down
24 changes: 24 additions & 0 deletions UE4SS/src/LuaType/LuaTArray.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,30 @@ namespace RC::LuaType
lua.set_integer(lua_object.get_remote_cpp_object()->Num());
return 1;
});

base_object.get_metamethods().create(LuaMadeSimple::Lua::MetaMethod::ToString, []([[maybe_unused]] const LuaMadeSimple::Lua& lua) -> int {
if (!lua.is_userdata())
{
lua.throw_error(std::format("{} __tostring metamethod called but there was no userdata", ClassName::ToString()));
}

std::string name;

auto* tarray = lua.get_userdata<TArray>().get_remote_cpp_object();
name.append(ClassName::ToString());
if (tarray)
{
name.append(std::format("[{}]: {:016X}", tarray->Num(), reinterpret_cast<uintptr_t>(tarray)));
}
else
{
name.append(std::format(": NULL"));
}

lua.set_string(name);

return 1;
});
}

template <LuaMadeSimple::Type::IsFinal is_final>
Expand Down
16 changes: 16 additions & 0 deletions UE4SS/src/LuaType/LuaTSoftClassPtr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,22 @@ namespace RC::LuaType

auto TSoftClassPtr::setup_metamethods(BaseObject& base_object) -> void
{
base_object.get_metamethods().create(LuaMadeSimple::Lua::MetaMethod::ToString, []([[maybe_unused]] const LuaMadeSimple::Lua& lua) -> int {
if (!lua.is_userdata())
{
lua.throw_error(std::format("{} __tostring metamethod called but there was no userdata", ClassName::ToString()));
}

std::string name;

auto& lua_object = lua.get_userdata<TSoftClassPtr>();
name.append(ClassName::ToString());
name.append(std::format(": {:016X}", reinterpret_cast<uintptr_t>(&lua_object.get_local_cpp_object())));

lua.set_string(name);

return 1;
});
}

template <LuaMadeSimple::Type::IsFinal is_final>
Expand Down
17 changes: 16 additions & 1 deletion UE4SS/src/LuaType/LuaUClass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,22 @@ namespace RC::LuaType

auto UClass::setup_metamethods([[maybe_unused]] BaseObject& base_object) -> void
{
// UClass has no metamethods
base_object.get_metamethods().create(LuaMadeSimple::Lua::MetaMethod::ToString, []([[maybe_unused]] const LuaMadeSimple::Lua& lua) -> int {
if (!lua.is_userdata())
{
lua.throw_error(std::format("{} __tostring metamethod called but there was no userdata", ClassName::ToString()));
}

std::string name;

auto* uclass = lua.get_userdata<UClass>().get_remote_cpp_object();
name.append(ClassName::ToString());
name.append(std::format("<{}>: {:016X}", to_string(uclass->GetName()), reinterpret_cast<uintptr_t>(uclass)));

lua.set_string(name);

return 1;
});
}

template <LuaMadeSimple::Type::IsFinal is_final>
Expand Down
19 changes: 17 additions & 2 deletions UE4SS/src/LuaType/LuaUEnum.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,24 @@ namespace RC::LuaType
return table;
}

auto UEnum::setup_metamethods(BaseObject&) -> void
auto UEnum::setup_metamethods(BaseObject& base_object) -> void
{
// UEnum has no metamethods
base_object.get_metamethods().create(LuaMadeSimple::Lua::MetaMethod::ToString, []([[maybe_unused]] const LuaMadeSimple::Lua& lua) -> int {
if (!lua.is_userdata())
{
lua.throw_error(std::format("{} __tostring metamethod called but there was no userdata", ClassName::ToString()));
}

std::string name;

auto* uenum = lua.get_userdata<UEnum>().get_remote_cpp_object();
name.append(ClassName::ToString());
name.append(std::format("<{}>: {:016X}", to_string(uenum->GetName()), reinterpret_cast<uintptr_t>(uenum)));

lua.set_string(name);

return 1;
});
}

template <LuaMadeSimple::Type::IsFinal is_final>
Expand Down
17 changes: 17 additions & 0 deletions UE4SS/src/LuaType/LuaUFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,23 @@ namespace RC::LuaType
base_object.get_metamethods().create(LuaMadeSimple::Lua::MetaMethod::Call, [](const LuaMadeSimple::Lua& lua) -> int {
return call_ufunction_from_lua(lua);
});

base_object.get_metamethods().create(LuaMadeSimple::Lua::MetaMethod::ToString, []([[maybe_unused]] const LuaMadeSimple::Lua& lua) -> int {
if (!lua.is_userdata())
{
lua.throw_error(std::format("{} __tostring metamethod called but there was no userdata", ClassName::ToString()));
}

std::string name;

auto* ufunction = lua.get_userdata<LuaType::UFunction>().get_remote_cpp_object();
name.append(ClassName::ToString());
name.append(std::format("<{}:{}>: {:016X}", to_string(ufunction->GetOuterPrivate()->GetName()), to_string(ufunction->GetName()), reinterpret_cast<uintptr_t>(ufunction)));

lua.set_string(name);

return 1;
});
}

template <LuaMadeSimple::Type::IsFinal is_final>
Expand Down
17 changes: 16 additions & 1 deletion UE4SS/src/LuaType/LuaUInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,22 @@ namespace RC::LuaType

auto UInterface::setup_metamethods([[maybe_unused]] BaseObject& base_object) -> void
{
// UInterface has no metamethods
base_object.get_metamethods().create(LuaMadeSimple::Lua::MetaMethod::ToString, []([[maybe_unused]] const LuaMadeSimple::Lua& lua) -> int {
if (!lua.is_userdata())
{
lua.throw_error(std::format("{} __tostring metamethod called but there was no userdata", ClassName::ToString()));
}

std::string name;

auto* uinterface = lua.get_userdata<UInterface>().get_remote_cpp_object();
name.append(ClassName::ToString());
name.append(std::format("<{}>: {:016X}", to_string(uinterface->GetName()), reinterpret_cast<uintptr_t>(uinterface)));

lua.set_string(name);

return 1;
});
}

template <LuaMadeSimple::Type::IsFinal is_final>
Expand Down
Loading

0 comments on commit 4b7de0c

Please sign in to comment.