Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

better handle version error exceptions, define ftext in ue3 #26

Merged
merged 2 commits into from
Oct 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions src/unrealsdk/unreal/cast.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,6 @@ namespace unrealsdk::unreal {
* @note Intended for to be used to iterate over all types using recursive templates.
*/
using all_unreal_classes = std::tuple< //
#ifdef UE4
UTextProperty,
#endif
UArrayProperty,
UBlueprintGeneratedClass,
UBoolProperty,
Expand All @@ -64,6 +61,7 @@ using all_unreal_classes = std::tuple< //
UStrProperty,
UStruct,
UStructProperty,
UTextProperty,
UUInt16Property,
UUInt32Property,
UUInt64Property,
Expand Down
4 changes: 0 additions & 4 deletions src/unrealsdk/unreal/classes/properties/utextproperty.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@
#include "unrealsdk/unreal/wrappers/unreal_pointer.h"
#include "unrealsdk/unrealsdk.h"

#ifdef UE4

namespace unrealsdk::unreal {

PropTraits<UTextProperty>::Value PropTraits<UTextProperty>::get(
Expand All @@ -31,5 +29,3 @@ void PropTraits<UTextProperty>::destroy(const UTextProperty* /*prop*/, uintptr_t
}

} // namespace unrealsdk::unreal

#endif
6 changes: 0 additions & 6 deletions src/unrealsdk/unreal/classes/properties/utextproperty.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,6 @@
#include "unrealsdk/unreal/prop_traits.h"
#include "unrealsdk/unreal/wrappers/unreal_pointer.h"

// Unlike other properties, which we can define on engine versions which don't support them, text
// properties call into a game-specific hook, which means we can only define them in UE4
#if defined(UE4)

namespace unrealsdk::unreal {

#if defined(_MSC_VER) && defined(ARCH_X86)
Expand Down Expand Up @@ -48,6 +44,4 @@ struct ClassTraits<UTextProperty> {

} // namespace unrealsdk::unreal

#endif

#endif /* UNREALSDK_UNREAL_CLASSES_PROPERTIES_UTEXTPROPERTY_H */
48 changes: 43 additions & 5 deletions src/unrealsdk/unreal/structs/ftext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,21 @@
#include "unrealsdk/unreal/structs/ftext.h"
#include "unrealsdk/unrealsdk.h"
#include "unrealsdk/utils.h"

#ifdef UE4
#include "unrealsdk/version_error.h"

namespace unrealsdk::unreal {

#ifdef UE4

FText::FText(const std::string& str) : FText(utils::widen(str)) {}
FText::FText(const std::wstring& str) : data(), flags() {
unrealsdk::ftext_as_culture_invariant(this, str);
}

FText& FText::operator=(const std::string& str) noexcept {
FText& FText::operator=(const std::string& str) {
return *this = utils::widen(str);
}
FText& FText::operator=(const std::wstring& str) noexcept {
FText& FText::operator=(const std::wstring& str) {
// Modifying in place is a pain, instead create a new FText and swap it in
FText local_text{str};
std::swap(this->data, local_text.data);
Expand Down Expand Up @@ -50,6 +51,43 @@ FText::~FText() {
}
}

} // namespace unrealsdk::unreal
#else

FText::FText(const std::string& /* str */) : data(), flags() {
(void)this;
(void)this->data;
(void)this->flags;
throw_version_error("FTexts are not implemented in UE3");
}
FText::FText(const std::wstring& /* str */) : data(), flags() {
(void)this;
throw_version_error("FTexts are not implemented in UE3");
}
FText& FText::operator=(const std::string& /* str */) {
(void)this;
throw_version_error("FTexts are not implemented in UE3");
return *this;
}
FText& FText::operator=(const std::wstring& /* str */) {
(void)this;
throw_version_error("FTexts are not implemented in UE3");
return *this;
}
FText::operator std::string() const {
(void)this;
throw_version_error("FTexts are not implemented in UE3");
return {};
}
FText::operator std::wstring() const {
(void)this;
throw_version_error("FTexts are not implemented in UE3");
return {};
}
// Rather not throw from a destructor, since it will crash the whole game
FText::~FText() {
(void)this;
}

#endif

} // namespace unrealsdk::unreal
4 changes: 2 additions & 2 deletions src/unrealsdk/unreal/structs/ftext.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ struct FText {
* @param str The string to assign.
* @return A reference to this FText.
*/
FText& operator=(const std::string& str) noexcept;
FText& operator=(const std::wstring& str) noexcept;
FText& operator=(const std::string& str);
FText& operator=(const std::wstring& str);

/**
* @brief Convert the FText to it's string representation.
Expand Down
6 changes: 4 additions & 2 deletions src/unrealsdk/unreal/wrappers/gobjects.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "unrealsdk/unreal/structs/gobjects.h"
#else
#include "unrealsdk/unreal/structs/tarray.h"
#include "unrealsdk/version_error.h"
#endif

namespace unrealsdk::unreal {
Expand Down Expand Up @@ -133,12 +134,13 @@ UObject* GObjects::obj_at(size_t idx) const {

UObject* GObjects::get_weak_object(const FWeakObjectPtr* /* ptr */) const {
(void)this;
throw std::runtime_error("Weak object pointers are not implemented in UE3");
throw_version_error("Weak object pointers are not implemented in UE3");
return nullptr;
}

void GObjects::set_weak_object(FWeakObjectPtr* /* ptr */, const UObject* /* obj */) const {
(void)this;
throw std::runtime_error("Weak object pointers are not implemented in UE3");
throw_version_error("Weak object pointers are not implemented in UE3");
}

#else
Expand Down
18 changes: 18 additions & 0 deletions src/unrealsdk/version_error.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#include "unrealsdk/pch.h"

namespace unrealsdk {

// Just noinline isn't enough for MSVC, also need to turn all optimizations off :/
#if defined(_MSC_VER) && !defined(__clang__) && !defined(__MINGW32__)
#pragma optimize("", off)
#endif

void throw_version_error(const char* msg) {
throw std::runtime_error(msg);
}

#if defined(_MSC_VER) && !defined(__clang__) && !defined(__MINGW32__)
#pragma optimize("", on)
#endif

} // namespace unrealsdk
44 changes: 44 additions & 0 deletions src/unrealsdk/version_error.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#ifndef UNREALSDK_VERSION_ERROR_H
#define UNREALSDK_VERSION_ERROR_H

#include "pch.h"

/*
When attempting to use a feature which is not currently available to the sdk, it may throw a version
error. At this point, these should be caught using simply `std::exception`. A more detailed
exception may be exposed at a later date.
*/

namespace unrealsdk {

/*
Since we sometimes expect version errors to be gated behind ifdefs, previously innocent user code
may sometimes unconditionally throw an error. If the exception gets inlined (including during LTO),
this may cause an unreachable code warning. While we want an unconditional exception, we don't want
the warning, there's nothing wrong with the user's code.

To avoid this, hide throwing behind a noinline helper.
*/

#if defined(__clang__) || defined(__MINGW32__)
#define NOINLINE [[gnu::noinline]]
#elif defined(_MSC_VER)
#define NOINLINE [[msvc::noinline]]
#else
#error Unknown noinline attribute
#endif

/**
* @brief Helper function to throw a version error.
* @note This function is (deliberately) not considered noreturn - you may still need to return a
* dummy value after calling it.
*
* @param msg The exception's message.
*/
NOINLINE void throw_version_error(const char* msg);

#undef NOINLINE

} // namespace unrealsdk

#endif /* UNREALSDK_VERSION_ERROR_H */
Loading