Closed gustavomassa closed 3 years ago
Thanks for taking the time to check out this plugin @gustavomassa :)
The compiler error reads "You cannot use a TSharedPtr of one mode with a type which inherits TSharedFromThis of another mode."
This leads me to believe the issue you are having is because you are trying to create the shared pointer with the wrong ESPMode
. TExpectedPromise
extends from TSharedFromThis
with ESPMode::ThreadSafe
, however the default ESPMode
for TSHaredPtr
is ESPMode::NotThreadSafe
. ESPMode is specified as the second template argument to TSharedPtr
.
Changing the line in question to
TSharedPtr<SD::TExpectedPromise<TArray<FOnlineSessionSearchResult>>, ESPMode::ThreadSafe> Promise = MakeShared<SD::TExpectedPromise<TArray<FOnlineSessionSearchResult>>>();
or
auto Promise = MakeShared<SD::TExpectedPromise<TArray<FOnlineSessionSearchResult>>>();
should fix the problem.
Hey @ragnarula thank you for the help!
Using ThreadSafe worked perfectly!
auto Promise = MakeShared<SD::TExpectedPromise<bool>, ESPMode::ThreadSafe>();
Sorry to bother you again, I just have 2 more questions:
I'm trying to use the Get() for sync blocking, but it never returns, it blocks the entire thread, the idea is to use something like the Await, waiting for the promise to resolve on a sync way, any ideas?
I'm returning the SD::Error from the promise, it works perfectly, but I'm not able to print the ErrorInfo correctly, it prints the address memory instead of the value.
if (SessionService)
{
SessionService->CreateSession(TEXT("Survival Server"), false, 10, false, false, false, false).Then([this](SD::TExpected<bool> bSuccess) {
if (bSuccess.IsCompleted() && bSuccess.GetValue() == true)
{
UE_LOG(LogTemp, Error, TEXT("Server Running with name: Survival Server"));
}
else if (bSuccess.IsError())
{
UE_LOG(LogTemp, Error, TEXT("Failed to Create Server Session: %s"), bSuccess.GetError().Get().GetErrorInfo().Get());
}
});
}
I'm returning the error like this:
auto Promise = MakeShared<SD::TExpectedPromise<bool>, ESPMode::ThreadSafe>();
if (!SessionInterface.IsValid())
{
Promise->SetValue(SD::Error(-1, TEXT("Session invalid!")));
return Promise->GetFuture();
}
Thank you!
Glad I could help :)
Rather than calling Get()
which you rightly pointed out will block until it completes, use Then()
to schedule a continuation. Within this continuation you can do any work you would otherwise have done after getting the result of Get()
. Be mindful of how you capture references within the lambda passed to Then()
, making sure to use TWeakPtr
/TWeakObjectPtr
where appropriate.
GetErrorInfo()
returns a TSharedPtr<FString>
. Calling Get()
will give you a FString*
which is a pointer, this is probably the memory address it's printing. I think you would need to dereference this once to get the FString
, then dereference it again to get the TCHAR*
(or adding GetErrorInfo()->GetData()
should also work I think).
Thank you again!
Be mindful of how you capture references within the lambda passed to Then(), making sure to use TWeakPtr/TWeakObjectPtr where appropriate.
As you mentioned about references passed to lambdas, the rule if the same when passing this? Should I also use TWeakPtr/TWeakObjectPtr when passing "this"? Also, if I'm passing "this", is safe to use engine functions like the GetFirstLocalPlayerController inside the lambda context?
GetErrorInfo() returns a TSharedPtr
. Calling Get() will give you a FString which is a pointer, this is probably the memory address it's printing. I think you would need to dereference this once to get the FString, then dereference it again to get the TCHAR (or adding GetErrorInfo()->GetData() should also work I think).
GetErrorInfo()->GetData() does not work :(, here is how I'm getting the error message:
else if (Result.IsError())
{
FString *ErrorMessage = Result.GetError().Get().GetErrorInfo().Get();
if (ErrorMessage != nullptr)
{
UE_LOG(LogTemp, Error, TEXT("Failed to InitServer: %s"), ErrorMessage->GetCharArray().GetData());
}
}
Same for Completed Future Expected values, I have to call GetValue twice because of the TOptional:
if (Result.IsCompleted() && Result.GetValue().IsSet())
{
// Get results and save it
OnlineSessionSearchResult = Result.GetValue().GetValue();
}
Sorry about all the questions, but I'm new to UE4, being studying it for about 2 months.
Hello, thank you for this amazing extension, UE4 lacks a good async API.
Engine Version: 4.25.1 (Not compiled from source)
I'm having issues trying to use the extension, I've installed the Plugin on the projects folder, re-generated the project files (VSCode), but when I try to include the #include "FutureExtensions.h" header the compiles does not find it. If I don't include this header file I get a lot of errors regarding the SD namespace. I've also updated the .uproject and added and enabled both Automatron and SDFutureExtensions plugins.
To get rid of these issues I include the extension directly on the source folder as a module. I've also updated the project.build.cs file:
I was able to use the extension as a module, but now I'm facing sharedPtr errors regarding the Wrapping UE4 delegates example. The code I'm trying to use inside a UObject class SSessionService.cpp:
Compile errors:
What I'm doing wrong/missing? I'm able to declare the promise as a raw pointer:
auto Promise = new SD::TExpectedPromise<TArray<FOnlineSessionSearchResult>>();
So, when to delete the promise pointer?Here is my implementation so far, missing the Create/Join Session Delegates:
I'm using class member variable pointers to control the memory allocation, I changed the logic on the CreateSession to create the pointer on the function scope.