diff --git a/UE4SS/include/LuaType/LuaUObject.hpp b/UE4SS/include/LuaType/LuaUObject.hpp index ea81196a3..031e177b7 100644 --- a/UE4SS/include/LuaType/LuaUObject.hpp +++ b/UE4SS/include/LuaType/LuaUObject.hpp @@ -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(); + 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(lua_object.get_remote_cpp_object()))); + } else { + name.append(ObjectName::ToString()); + name.append(": NULL"); + } + + lua.set_string(name); + + return 1; + }); } public: @@ -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>(); + name.append("LocalUnrealParam<"); + name.append(to_string(lua_object.m_property->GetClass().GetName())); + name.append(std::format(">: 0x{:012x}", reinterpret_cast(&lua_object))); + + lua.set_string(name); + + return 1; + }); } auto static setup_member_functions(LuaMadeSimple::Lua::Table& table) -> void diff --git a/UE4SS/src/LuaType/LuaFName.cpp b/UE4SS/src/LuaType/LuaFName.cpp index 207ecc3e8..a20afdeeb 100644 --- a/UE4SS/src/LuaType/LuaFName.cpp +++ b/UE4SS/src/LuaType/LuaFName.cpp @@ -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().get_local_cpp_object(); + name.append(ClassName::ToString()); + name.append(std::format(" \"{}\": {:016X}", to_string(fname.ToString()), reinterpret_cast(&fname))); + + lua.set_string(name); + + return 1; + }); } template diff --git a/UE4SS/src/LuaType/LuaFOutputDevice.cpp b/UE4SS/src/LuaType/LuaFOutputDevice.cpp index 105c59ce2..2ce92f7a5 100644 --- a/UE4SS/src/LuaType/LuaFOutputDevice.cpp +++ b/UE4SS/src/LuaType/LuaFOutputDevice.cpp @@ -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(); + name.append(ClassName::ToString()); + name.append(std::format(": {:016X}", reinterpret_cast(lua_object.get_remote_cpp_object()))); + + lua.set_string(name); + + return 1; + }); } template diff --git a/UE4SS/src/LuaType/LuaFSoftObjectPath.cpp b/UE4SS/src/LuaType/LuaFSoftObjectPath.cpp index 0622f0ad4..2ae06b538 100644 --- a/UE4SS/src/LuaType/LuaFSoftObjectPath.cpp +++ b/UE4SS/src/LuaType/LuaFSoftObjectPath.cpp @@ -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(); + name.append(ClassName::ToString()); + name.append(std::format(": {:016X}", reinterpret_cast(&lua_object.get_local_cpp_object()))); + + lua.set_string(name); + + return 1; + }); } template diff --git a/UE4SS/src/LuaType/LuaFString.cpp b/UE4SS/src/LuaType/LuaFString.cpp index 455e0be76..8d325d81f 100644 --- a/UE4SS/src/LuaType/LuaFString.cpp +++ b/UE4SS/src/LuaType/LuaFString.cpp @@ -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().get_remote_cpp_object(); + name.append(ClassName::ToString()); + name.append(std::format(" \"{}\": {:016X}", to_string(fstring->GetCharArray()), reinterpret_cast(fstring))); + + lua.set_string(name); + + return 1; + }); } template diff --git a/UE4SS/src/LuaType/LuaFText.cpp b/UE4SS/src/LuaType/LuaFText.cpp index d28a91ef6..1023191a7 100644 --- a/UE4SS/src/LuaType/LuaFText.cpp +++ b/UE4SS/src/LuaType/LuaFText.cpp @@ -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().get_local_cpp_object(); + name.append(ClassName::ToString()); + name.append(std::format(" \"{}\": {:016X}", to_string(ftext.ToString()), reinterpret_cast(&ftext))); + + lua.set_string(name); + + return 1; + }); } template diff --git a/UE4SS/src/LuaType/LuaFWeakObjectPtr.cpp b/UE4SS/src/LuaType/LuaFWeakObjectPtr.cpp index 71e1b71bb..e33e8027d 100644 --- a/UE4SS/src/LuaType/LuaFWeakObjectPtr.cpp +++ b/UE4SS/src/LuaType/LuaFWeakObjectPtr.cpp @@ -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().get_local_cpp_object(); + name.append(ClassName::ToString()); + if (fptr.Get()) + { + name.append(std::format(" -> {:016X}: {:016X}", reinterpret_cast(fptr.Get()), reinterpret_cast(&fptr))); + } + else + { + name.append(std::format(" -> NULL: {:016X}", reinterpret_cast(fptr.Get()), reinterpret_cast(&fptr))); + } + + lua.set_string(name); + + return 1; + }); } template diff --git a/UE4SS/src/LuaType/LuaModRef.cpp b/UE4SS/src/LuaType/LuaModRef.cpp index ee9fa4b15..db26278fd 100644 --- a/UE4SS/src/LuaType/LuaModRef.cpp +++ b/UE4SS/src/LuaType/LuaModRef.cpp @@ -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(); + name.append(ClassName::ToString()); + name.append(std::format(": 0x{:012x}", reinterpret_cast(&lua_object))); + + lua.set_string(name); + + return 1; + }); } template diff --git a/UE4SS/src/LuaType/LuaTArray.cpp b/UE4SS/src/LuaType/LuaTArray.cpp index ebeb58f35..3774f23d8 100644 --- a/UE4SS/src/LuaType/LuaTArray.cpp +++ b/UE4SS/src/LuaType/LuaTArray.cpp @@ -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().get_remote_cpp_object(); + name.append(ClassName::ToString()); + if (tarray) + { + name.append(std::format("[{}]: {:016X}", tarray->Num(), reinterpret_cast(tarray))); + } + else + { + name.append(std::format(": NULL")); + } + + lua.set_string(name); + + return 1; + }); } template diff --git a/UE4SS/src/LuaType/LuaTSoftClassPtr.cpp b/UE4SS/src/LuaType/LuaTSoftClassPtr.cpp index a1907574b..6effea315 100644 --- a/UE4SS/src/LuaType/LuaTSoftClassPtr.cpp +++ b/UE4SS/src/LuaType/LuaTSoftClassPtr.cpp @@ -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(); + name.append(ClassName::ToString()); + name.append(std::format(": {:016X}", reinterpret_cast(&lua_object.get_local_cpp_object()))); + + lua.set_string(name); + + return 1; + }); } template diff --git a/UE4SS/src/LuaType/LuaUClass.cpp b/UE4SS/src/LuaType/LuaUClass.cpp index 21ece9996..e7a2b0915 100644 --- a/UE4SS/src/LuaType/LuaUClass.cpp +++ b/UE4SS/src/LuaType/LuaUClass.cpp @@ -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().get_remote_cpp_object(); + name.append(ClassName::ToString()); + name.append(std::format("<{}>: {:016X}", to_string(uclass->GetName()), reinterpret_cast(uclass))); + + lua.set_string(name); + + return 1; + }); } template diff --git a/UE4SS/src/LuaType/LuaUEnum.cpp b/UE4SS/src/LuaType/LuaUEnum.cpp index f25a8a15d..76235f445 100644 --- a/UE4SS/src/LuaType/LuaUEnum.cpp +++ b/UE4SS/src/LuaType/LuaUEnum.cpp @@ -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().get_remote_cpp_object(); + name.append(ClassName::ToString()); + name.append(std::format("<{}>: {:016X}", to_string(uenum->GetName()), reinterpret_cast(uenum))); + + lua.set_string(name); + + return 1; + }); } template diff --git a/UE4SS/src/LuaType/LuaUFunction.cpp b/UE4SS/src/LuaType/LuaUFunction.cpp index 76118829a..d34916fc1 100644 --- a/UE4SS/src/LuaType/LuaUFunction.cpp +++ b/UE4SS/src/LuaType/LuaUFunction.cpp @@ -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().get_remote_cpp_object(); + name.append(ClassName::ToString()); + name.append(std::format("<{}:{}>: {:016X}", to_string(ufunction->GetOuterPrivate()->GetName()), to_string(ufunction->GetName()), reinterpret_cast(ufunction))); + + lua.set_string(name); + + return 1; + }); } template diff --git a/UE4SS/src/LuaType/LuaUInterface.cpp b/UE4SS/src/LuaType/LuaUInterface.cpp index eb7694f95..bb6754f8a 100644 --- a/UE4SS/src/LuaType/LuaUInterface.cpp +++ b/UE4SS/src/LuaType/LuaUInterface.cpp @@ -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().get_remote_cpp_object(); + name.append(ClassName::ToString()); + name.append(std::format("<{}>: {:016X}", to_string(uinterface->GetName()), reinterpret_cast(uinterface))); + + lua.set_string(name); + + return 1; + }); } template diff --git a/UE4SS/src/LuaType/LuaUObject.cpp b/UE4SS/src/LuaType/LuaUObject.cpp index 015a544ec..160e1c631 100644 --- a/UE4SS/src/LuaType/LuaUObject.cpp +++ b/UE4SS/src/LuaType/LuaUObject.cpp @@ -1377,6 +1377,24 @@ No overload found for function 'IsA'. 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("RemoteUnrealParam __tostring metamethod called but there was no userdata"); + } + + std::string name; + + const auto& lua_object = lua.get_userdata(); + name.append("RemoteUnrealParam<"); + name.append(to_string(lua_object.m_type.ToString())); + name.append(std::format(">: 0x{:012x}", reinterpret_cast(&lua_object))); + + lua.set_string(name); + + return 1; + }); } auto RemoteUnrealParam::setup_member_functions(LuaMadeSimple::Lua::Table& table) -> void diff --git a/UE4SS/src/LuaType/LuaUScriptStruct.cpp b/UE4SS/src/LuaType/LuaUScriptStruct.cpp index af01c8802..4003c820e 100644 --- a/UE4SS/src/LuaType/LuaUScriptStruct.cpp +++ b/UE4SS/src/LuaType/LuaUScriptStruct.cpp @@ -65,6 +65,30 @@ namespace RC::LuaType prepare_to_handle(LuaMadeSimple::Type::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(std::format("{} __tostring metamethod called but there was no userdata", ClassName::ToString())); + } + + std::string name; + + auto& scriptstruct = lua.get_userdata().get_local_cpp_object(); + name.append(ClassName::ToString()); + if (scriptstruct.script_struct) + { + name.append(std::format("<{}>: {:016X}", to_string(scriptstruct.script_struct->GetName()), reinterpret_cast(&scriptstruct))); + } + else + { + name.append(std::format(": {:016X}", reinterpret_cast(&scriptstruct))); + } + + lua.set_string(name); + + return 1; + }); } template diff --git a/UE4SS/src/LuaType/LuaUStruct.cpp b/UE4SS/src/LuaType/LuaUStruct.cpp index 3e3b766c8..eb74000f0 100644 --- a/UE4SS/src/LuaType/LuaUStruct.cpp +++ b/UE4SS/src/LuaType/LuaUStruct.cpp @@ -49,7 +49,22 @@ namespace RC::LuaType auto UStruct::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* ustruct = lua.get_userdata().get_remote_cpp_object(); + name.append(ClassName::ToString()); + name.append(std::format("<{}>: {:016X}", to_string(ustruct->GetName()), reinterpret_cast(ustruct))); + + lua.set_string(name); + + return 1; + }); } template diff --git a/UE4SS/src/LuaType/LuaUWorld.cpp b/UE4SS/src/LuaType/LuaUWorld.cpp index 887db969b..2a1a48df9 100644 --- a/UE4SS/src/LuaType/LuaUWorld.cpp +++ b/UE4SS/src/LuaType/LuaUWorld.cpp @@ -53,7 +53,22 @@ namespace RC::LuaType auto UWorld::setup_metamethods([[maybe_unused]] BaseObject& base_object) -> void { - // UWorld 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(); + name.append(ClassName::ToString()); + name.append(std::format(": {:016X}", reinterpret_cast(lua_object.get_remote_cpp_object()))); + + lua.set_string(name); + + return 1; + }); } template diff --git a/deps/first/LuaMadeSimple/include/LuaMadeSimple/LuaMadeSimple.hpp b/deps/first/LuaMadeSimple/include/LuaMadeSimple/LuaMadeSimple.hpp index a4ca10f2f..0384837cd 100644 --- a/deps/first/LuaMadeSimple/include/LuaMadeSimple/LuaMadeSimple.hpp +++ b/deps/first/LuaMadeSimple/include/LuaMadeSimple/LuaMadeSimple.hpp @@ -156,6 +156,7 @@ namespace RC::LuaMadeSimple Call, Equal, Length, + ToString, }; /** @@ -169,6 +170,7 @@ namespace RC::LuaMadeSimple std::optional call = std::nullopt; std::optional equal = std::nullopt; std::optional length = std::nullopt; + std::optional tostring = std::nullopt; template auto create(MetaMethod metamethod, LuaCallable lua_callable) -> void @@ -192,6 +194,10 @@ namespace RC::LuaMadeSimple return; case MetaMethod::Length: length = lua_callable; + return; + case MetaMethod::ToString: + tostring = lua_callable; + return; } // TODO: use throw_error() here diff --git a/deps/first/LuaMadeSimple/src/LuaMadeSimple.cpp b/deps/first/LuaMadeSimple/src/LuaMadeSimple.cpp index 411ddfe7d..97cbee99f 100644 --- a/deps/first/LuaMadeSimple/src/LuaMadeSimple.cpp +++ b/deps/first/LuaMadeSimple/src/LuaMadeSimple.cpp @@ -412,6 +412,7 @@ namespace RC::LuaMadeSimple create("__call", metamethods.call); create("__eq", metamethods.equal); create("__len", metamethods.length); + create("__tostring", metamethods.tostring); return custom_gc_method; }; @@ -773,6 +774,7 @@ namespace RC::LuaMadeSimple metamethods->call, metamethods->equal, metamethods->length, + metamethods->tostring, }; new_metatable(metatable_name, std::nullopt); transfer_stack_object(std::move(c), metatable_name, std::nullopt, true);