16 Commits

Author SHA1 Message Date
JR-Morgan 205c8dbf5a Experimentation adding box conversion 2022-06-07 21:37:28 +01:00
JR-Morgan 8159860223 - Removed branch/stream/etc/ fetching from transports.
- Aligned names with .NET core.
- Added DP checks for error/edge cases.
- Tried to cleanup/reduce duplicated code.
2022-06-07 16:12:07 +01:00
Dimitrios Ververidis 2431b33726 Fetch also collaborators with ReceiveStreamOperation 2022-05-24 16:03:03 +03:00
Dimitrios Ververidis 8b70cbba64 Receive Globals Operation : Done 2022-05-24 09:06:45 +03:00
Dimitrios Ververidis db2ba86e6d Receive My User Data also working 2022-05-23 16:16:36 +03:00
Dimitrios Ververidis 618d480acf Receive List of Commits done! 2022-05-23 12:42:16 +03:00
Dimitrios Ververidis 26d5afc2c0 Fetch Branches : Done ! 2022-05-20 14:47:38 +03:00
Dimitrios Ververidis dc0495dd24 Merge branch 'specklesystems:main' into main 2022-05-20 13:53:40 +03:00
Dimitrios Ververidis a75fb3a0c7 First Working version that receives all Streams 2022-05-20 09:52:35 +03:00
Dimitrios Ververidis 434c9a7b96 Managed to run my own ReceiveOperation for Streams 2022-05-19 18:25:52 +03:00
Dimitrios Ververidis aa400d19ee Try 3 Delegate 2022-05-19 17:54:04 +03:00
Dimitrios Ververidis 5f9eb61228 Minor 2022-05-18 13:58:37 +03:00
Dimitrios Ververidis 63bba7063c Try 1 List of Streams 2022-05-18 13:46:33 +03:00
Dimitrios Ververidis da962e28f0 JSON list of Streams has been fetched 2022-05-17 15:42:57 +03:00
Dimitrios Ververidis 41a0d79229 Minor comments and line changes for easy reading 2022-05-17 09:27:19 +03:00
Dimitrios Ververidis 980fe124b2 Added some comments 2022-05-16 14:48:29 +03:00
74 changed files with 2161 additions and 775 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,364 @@
#include "API/ClientAPI.h"
#include "HttpModule.h"
#include "Interfaces/IHttpResponse.h"
#include "LogSpeckle.h"
#include "Mixpanel.h"
#include "Objects/HighLevel/SpeckleBranch.h"
#include "Objects/HighLevel/SpeckleCommit.h"
#include "Objects/HighLevel/SpeckleGlobals.h"
#include "Objects/HighLevel/SpeckleUser.h"
#include "Transports/Transport.h"
void FClientAPI::StreamsGet(const FString& ServerUrl, const FString& AuthToken,
const int Limit,
const FFetchStreamDelegate OnCompleteAction, const FErrorDelegate OnErrorAction)
{
const FString RequestLogName = FString(__FUNCTION__);
const FString PostPayload =
"{\"query\": \"query{user {streams(limit:" + FString::FromInt(Limit) + ") {totalCount items {id name description updatedAt createdAt isPublic role collaborators{id name role company avatar}}}}}\"}";
auto OnError = [=](const FString& Message) mutable
{
ensureAlwaysMsgf(OnErrorAction.ExecuteIfBound(Message), TEXT("%s: Unhandled error - %s"), *RequestLogName , *Message);
};
auto ResponseHandler = [=](FHttpRequestPtr, FHttpResponsePtr Response, bool bWasSuccessful) mutable
{
if(CheckRequestFailed(bWasSuccessful, Response, RequestLogName, OnError)) return;
TSharedPtr<FJsonObject> Obj;
if(!GetResponseAsJSON(Response, RequestLogName, Obj, OnError)) return;
TArray<TSharedPtr<FJsonValue>> StreamsArrJSON = Obj->GetObjectField(TEXT("data"))
->GetObjectField(TEXT("user"))
->GetObjectField(TEXT("streams"))
->GetArrayField(TEXT("items"));
TArray<FSpeckleStream> Streams;
Streams.Reserve(StreamsArrJSON.Num());
for (const TSharedPtr<FJsonValue> v : StreamsArrJSON)
{
FSpeckleStream Stream = FSpeckleStream(v);
Streams.Add(Stream);
}
UE_LOG(LogSpeckle, Log, TEXT("Operation %s completed successfully. Fetched %d items"), *RequestLogName, Streams.Num());
ensureAlwaysMsgf(OnCompleteAction.ExecuteIfBound(Streams), TEXT("%s: Complete handler was not bound properly"), *RequestLogName);
};
const FHttpRequestRef Request = CreateGraphQLRequest(ServerUrl, AuthToken, PostPayload);
Request->OnProcessRequestComplete().BindLambda(ResponseHandler);
SendGraphQLRequest(Request, RequestLogName, OnError);
}
void FClientAPI::StreamGetBranches(
const FString& ServerUrl, const FString& AuthToken,
const FString& StreamId, const int32 Limit,
const FFetchBranchDelegate OnCompleteAction, const FErrorDelegate OnErrorAction)
{
const FString RequestLogName = FString(__FUNCTION__);
//TODO limit
FString PostPayload = "{\"query\": \"query{ stream (id: \\\"" +
StreamId + "\\\"){id name branches(limit : " + FString::FromInt(Limit) + ") {totalCount cursor items{ id name description}}}}\"}";
// The above can be extended with author information
//query{stream(id:"a18f8c8569"){id name branches{totalCount items{id name description author{id, name, email, commits{cursor}}}}}}
auto OnError = [=](const FString& Message) mutable
{
ensureAlwaysMsgf(OnErrorAction.ExecuteIfBound(Message), TEXT("%s: Unhandled error - %s"), *RequestLogName , *Message);
};
auto ResponseHandler = [=](FHttpRequestPtr, FHttpResponsePtr Response, bool bWasSuccessful) mutable
{
if(CheckRequestFailed(bWasSuccessful, Response, RequestLogName, OnError)) return;
TSharedPtr<FJsonObject> Obj;
if(!GetResponseAsJSON(Response, RequestLogName, Obj, OnError)) return;
TArray<TSharedPtr<FJsonValue>> BranchesArrJSON = Obj->GetObjectField(TEXT("data"))
->GetObjectField(TEXT("stream"))
->GetObjectField(TEXT("branches"))
->GetArrayField(TEXT("items"));
TArray<FSpeckleBranch> Branches;
Branches.Reserve(BranchesArrJSON.Num());
for (const TSharedPtr<FJsonValue>& v : BranchesArrJSON)
{
const TSharedPtr<FJsonObject>* BranchObj;
if(ensureAlways(v->TryGetObject(BranchObj)))
{
FSpeckleBranch Branch = FSpeckleBranch(*BranchObj);
Branches.Add(Branch);
}
}
UE_LOG(LogSpeckle, Log, TEXT("Operation %s completed successfully. Fetched %d items"), *RequestLogName, Branches.Num());
ensureAlwaysMsgf(OnCompleteAction.ExecuteIfBound(Branches), TEXT("%s: Complete handler was not bound properly"), *RequestLogName);
};
const FHttpRequestRef Request = CreateGraphQLRequest(ServerUrl, AuthToken, PostPayload);
Request->OnProcessRequestComplete().BindLambda(ResponseHandler);
SendGraphQLRequest(Request, RequestLogName, OnError);
}
void FClientAPI::StreamGetCommits(const FString& ServerUrl, const FString& AuthToken,
const FString& StreamId, const FString& BranchName, const int32 Limit,
const FFetchCommitDelegate OnCompleteAction, const FErrorDelegate OnErrorAction)
{
const FString RequestLogName = FString(__FUNCTION__);
FString PostPayload = "{\"query\": \"query{stream (id: \\\"" + StreamId +
"\\\"){id name createdAt updatedAt "
+ "branch(name: \\\"" + BranchName + "\\\" ){id name description author{name id email} " +
"commits(limit: " + FString::FromInt(Limit) + "){totalCount items {id referencedObject sourceApplication totalChildrenCount " +
"branchName parents authorName authorId message createdAt commentCount}}}}}\"}"; // authorAvatar
auto OnError = [=](const FString& Message) mutable
{
ensureAlwaysMsgf(OnErrorAction.ExecuteIfBound(Message), TEXT("%s: Unhandled error - %s"), *RequestLogName , *Message);
};
auto ResponseHandler = [=](FHttpRequestPtr, FHttpResponsePtr Response, bool bWasSuccessful) mutable
{
if(CheckRequestFailed(bWasSuccessful, Response, RequestLogName, OnError)) return;
TSharedPtr<FJsonObject> Obj;
if(!GetResponseAsJSON(Response, RequestLogName, Obj, OnError)) return;
TArray<TSharedPtr<FJsonValue>> CommitsArrJSON = Obj->GetObjectField(TEXT("data"))
->GetObjectField(TEXT("stream"))
->GetObjectField(TEXT("branch"))
->GetObjectField(TEXT("commits"))
->GetArrayField(TEXT("items"));
TArray<FSpeckleCommit> ArrayOfCommits;
ArrayOfCommits.Reserve(CommitsArrJSON.Num());
for (const TSharedPtr<FJsonValue> v : CommitsArrJSON)
{
FSpeckleCommit Commit = FSpeckleCommit(v);
ArrayOfCommits.Add( Commit );
}
UE_LOG(LogSpeckle, Log, TEXT("Operation %s completed successfully. Fetched %d items"), *RequestLogName, ArrayOfCommits.Num());
ensureAlwaysMsgf(OnCompleteAction.ExecuteIfBound(ArrayOfCommits), TEXT("%s: Complete handler was not bound properly"), *RequestLogName);
};
const FHttpRequestRef Request = CreateGraphQLRequest(ServerUrl, AuthToken, PostPayload);
Request->OnProcessRequestComplete().BindLambda(ResponseHandler);
SendGraphQLRequest(Request, RequestLogName, OnError);
}
void FClientAPI::FetchGlobals(const FString& ServerUrl, const FString& AuthToken,
const FString& StreamId, const FString& ReferencedObjectId,
const FFetchGlobalsDelegate OnCompleteAction, const FErrorDelegate OnErrorAction)
{
const FString RequestLogName = FString(__FUNCTION__);
FString PostPayload = "{\"query\": \"query{stream (id:\\\"" + StreamId +
"\\\"){id name description updatedAt createdAt role isPublic object(id:\\\"" +
ReferencedObjectId +
"\\\"){id data}}}\"}";
auto OnError = [=](const FString& Message) mutable
{
ensureAlwaysMsgf(OnErrorAction.ExecuteIfBound(Message), TEXT("%s: Unhandled error - %s"), *RequestLogName , *Message);
};
auto ResponseHandler = [=](FHttpRequestPtr, FHttpResponsePtr Response, bool bWasSuccessful) mutable
{
if(CheckRequestFailed(bWasSuccessful, Response, RequestLogName, OnError)) return;
TSharedPtr<FJsonObject> Obj;
if(!GetResponseAsJSON(Response, RequestLogName, Obj, OnError)) return;
TSharedPtr<FJsonObject> GlobalsJSONObject = Obj->GetObjectField(TEXT("data"))
->GetObjectField(TEXT("stream"))
->GetObjectField(TEXT("object"))
->GetObjectField(TEXT("data"));
FSpeckleGlobals Globals = FSpeckleGlobals(GlobalsJSONObject);
UE_LOG(LogSpeckle, Log, TEXT("Operation %s completed successfully"), *RequestLogName);
ensureAlwaysMsgf(OnCompleteAction.ExecuteIfBound(Globals), TEXT("%s: Complete handler was not bound properly"), *RequestLogName);
};
const FHttpRequestRef Request = CreateGraphQLRequest(ServerUrl, AuthToken, PostPayload);
Request->OnProcessRequestComplete().BindLambda(ResponseHandler);
SendGraphQLRequest(Request, RequestLogName, OnError);
}
void FClientAPI::FetchUserData(const FString& ServerUrl, const FString& AuthToken,
const FFetchUserDelegate OnCompleteAction, const FErrorDelegate OnErrorAction)
{
const FString RequestLogName = FString(__FUNCTION__);
const FString PostPayload =
"{\"query\": \"query{user{id name email company role suuid bio profiles avatar}}\"}";
auto OnError = [=](const FString& Message) mutable
{
UE_LOG(LogSpeckle, Warning, TEXT("%s: failed - %s"), *RequestLogName , *Message);
ensureAlwaysMsgf(OnErrorAction.ExecuteIfBound(Message), TEXT("%s: Unhandled error - %s"), *RequestLogName , *Message);
};
auto ResponseHandler = [=](FHttpRequestPtr, FHttpResponsePtr Response, bool bWasSuccessful) mutable
{
if(CheckRequestFailed(bWasSuccessful, Response, RequestLogName, OnError)) return;
TSharedPtr<FJsonObject> Obj;
if(!GetResponseAsJSON(Response, RequestLogName, Obj, OnError)) return;
TSharedPtr<FJsonObject> UserJSONObject = Obj->GetObjectField(TEXT("data"))
->GetObjectField(TEXT("user"));
FSpeckleUser MyUserData = FSpeckleUser( UserJSONObject );
UE_LOG(LogSpeckle, Log, TEXT("Operation %s completed successfully"), *RequestLogName);
ensureAlwaysMsgf(OnCompleteAction.ExecuteIfBound(MyUserData), TEXT("%s: Complete handler was not bound properly"), *RequestLogName);
};
const FHttpRequestRef Request = CreateGraphQLRequest(ServerUrl, AuthToken, PostPayload);
Request->OnProcessRequestComplete().BindLambda(ResponseHandler);
SendGraphQLRequest(Request, RequestLogName, OnError);
}
bool FClientAPI::GetResponseAsJSON(const FHttpResponsePtr Response, const FString& RequestLogName, TSharedPtr<FJsonObject>& OutObject, const TFunctionRef<void(const FString& Message)> OnErrorAction)
{
const FString JsonResponse = Response->GetContentAsString();
TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(JsonResponse);
if(!FJsonSerializer::Deserialize(Reader, OutObject))
{
const FString Message = FString::Printf(
TEXT("Recieved a response from \"%s\" for \"%s\" request, but the response failed to deserialize: %s"),
*Response->GetURL(), *RequestLogName, *JsonResponse);
OnErrorAction(Message);
return false;
}
FString Error;
if(CheckForOperationErrors(OutObject, Error))
{
OnErrorAction(Error);
return false;
}
return true;
}
FHttpRequestRef FClientAPI::CreateGraphQLRequest(const FString& ServerUrl, const FString AuthToken, const FString& PostPayload, const FString& Encoding)
{
FHttpRequestRef Request = FHttpModule::Get().CreateRequest();
Request->SetURL(ServerUrl + "/graphql");
Request->SetVerb(TEXT("POST"));
Request->SetHeader("Accept-Encoding", Encoding);
Request->SetHeader("Content-Type", TEXT("application/json"));
Request->SetHeader("Authorization", "Bearer " + AuthToken);
Request->SetContentAsString(PostPayload);
return Request;
}
bool FClientAPI::SendGraphQLRequest(const FHttpRequestRef Request, const FString& RequestName,
const TFunctionRef<void(const FString& Message)> OnErrorAction)
{
const bool RequestSent = Request->ProcessRequest();
if(!RequestSent)
{
const FString Message = FString::Printf(TEXT("Request \"%s\" at \"%s\" failed: \nHTTP request failed to start"),
*RequestName, *Request->GetURL());
OnErrorAction(Message);
}
else
{
UE_LOG(LogSpeckle, Log, TEXT("POST Request %s to %s was sent, awaiting response"), *RequestName, *Request->GetURL() );
FAnalytics::TrackEvent("unknown", Request->GetURL(), "NodeRun", TMap<FString, FString> { {"name", RequestName }});
}
return RequestSent;
}
bool FClientAPI::CheckRequestFailed(bool bWasSuccessful, FHttpResponsePtr Response, const FString& RequestLogName, const TFunctionRef<void(const FString& Message)> OnErrorAction)
{
//Check the request was sent
if(!bWasSuccessful)
{
FString Message = FString::Printf(TEXT("Request \"%s\" to \"%s\" was unsuccessful: %s"),
*RequestLogName, *Response->GetURL(), *Response->GetContentAsString());
OnErrorAction(Message);
return true;
}
//Check Response code
const int32 ResponseCode = Response->GetResponseCode();
if (ResponseCode != 200)
{
FString Message = FString::Printf(TEXT("Request \"%s\" to \"%s\" failed with HTTP response %d"),
*RequestLogName, *Response->GetURL(), ResponseCode);
OnErrorAction(Message);
return true;
}
UE_LOG(LogSpeckle, Log, TEXT("Operation %s recieved a response from %s"), *RequestLogName, *Response->GetURL());
return false;
}
bool FClientAPI::CheckForOperationErrors(const TSharedPtr<FJsonObject> GraphQLResponse, FString& OutErrorMessage)
{
check(GraphQLResponse != nullptr);
bool WasError = false;
const TArray<TSharedPtr<FJsonValue>>* Errors;
if(GraphQLResponse->TryGetArrayField(TEXT("Errors"), Errors))
{
for(const TSharedPtr<FJsonValue>& e : *Errors)
{
FString Message;
const TSharedPtr<FJsonObject>* ErrorObject;
bool HadMessage = e->TryGetObject(ErrorObject)
&& (*ErrorObject)->TryGetStringField("message", Message);
if(!HadMessage)
{
Message = "An operation error occured but had no message!\n";
UE_LOG(LogSpeckle, Warning, TEXT("%s"), *Message);
}
OutErrorMessage.Append(Message + "\n");
WasError = true;
}
}
return WasError;
}
@@ -0,0 +1,73 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "API/Operations/ReceiveBranchesOperation.h"
#include "Mixpanel.h"
#include "LogSpeckle.h"
#include "API/ClientAPI.h"
UReceiveBranchesOperation* UReceiveBranchesOperation::ReceiveBranchesOperation(UObject* WorldContextObject,
const FString& ServerUrl, const FString& AuthToken,
const FString& StreamId, int32 Limit)
{
FString ObjectId = "Streams";
UReceiveBranchesOperation* Node = NewObject<UReceiveBranchesOperation>();
Node->StreamId = StreamId.TrimEnd();
Node->ServerUrl = ServerUrl.TrimEnd();
while(Node->ServerUrl.RemoveFromEnd("/")) { }
Node->AuthToken = AuthToken.TrimEnd();
Node->Limit = Limit;
Node->RegisterWithGameInstance(WorldContextObject);
return Node;
}
void UReceiveBranchesOperation::Activate()
{
FAnalytics::TrackEvent("unknown",
ServerUrl, "NodeRun", TMap<FString, FString> { {"name", StaticClass()->GetName() }});
Request();
}
void UReceiveBranchesOperation::Request()
{
ensureAlways(Limit > 0);
FFetchBranchDelegate CompleteDelegate;
CompleteDelegate.BindUObject(this, &UReceiveBranchesOperation::HandleReceive);
FErrorDelegate ErrorDelegate;
ErrorDelegate.BindUObject(this, &UReceiveBranchesOperation::HandleError);
FClientAPI::StreamGetBranches(ServerUrl, AuthToken, StreamId, Limit, CompleteDelegate, ErrorDelegate);
}
void UReceiveBranchesOperation::HandleReceive(const TArray<FSpeckleBranch>& Branches)
{
check(IsInGameThread());
UE_LOG(LogSpeckle, Log, TEXT("%s to %s Succeeded"), *StaticClass()->GetName(), *ServerUrl);
FEditorScriptExecutionGuard ScriptGuard;
OnReceiveSuccessfully.Broadcast(Branches, "");
SetReadyToDestroy();
}
void UReceiveBranchesOperation::HandleError(const FString& Message)
{
check(IsInGameThread());
UE_LOG(LogSpeckle, Warning, TEXT("%s failed - %s"), *StaticClass()->GetName(), *Message);
FEditorScriptExecutionGuard ScriptGuard;
const TArray<FSpeckleBranch> EmptyList;
OnError.Broadcast(EmptyList, Message);
SetReadyToDestroy();
}
@@ -0,0 +1,72 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "API/Operations/ReceiveCommitsOperation.h"
#include "Mixpanel.h"
#include "LogSpeckle.h"
#include "API/ClientAPI.h"
// ReceiveOperation
UReceiveCommitsOperation* UReceiveCommitsOperation::ReceiveCommitsOperation(UObject* WorldContextObject,
const FString& ServerUrl, const FString& AuthToken,
const FString& StreamId, const FString& BranchName, const int32 Limit)
{
UReceiveCommitsOperation* Node = NewObject<UReceiveCommitsOperation>();
Node->ServerUrl = ServerUrl.TrimEnd();
while(Node->ServerUrl.RemoveFromEnd("/")) { }
Node->AuthToken = AuthToken.TrimEnd();
Node->StreamId = StreamId.TrimEnd();
Node->BranchName = BranchName;
Node->Limit = Limit;
Node->RegisterWithGameInstance(WorldContextObject);
return Node;
}
// Activate
void UReceiveCommitsOperation::Activate()
{
FAnalytics::TrackEvent("unknown", ServerUrl,
"NodeRun", TMap<FString, FString> { {"name", StaticClass()->GetName() }});
Request();
}
void UReceiveCommitsOperation::Request()
{
ensureAlways(Limit > 0);
FFetchCommitDelegate CompleteDelegate;
CompleteDelegate.BindUObject(this, &UReceiveCommitsOperation::HandleReceive);
FErrorDelegate ErrorDelegate;
ErrorDelegate.BindUObject(this, &UReceiveCommitsOperation::HandleError);
FClientAPI::StreamGetCommits(ServerUrl, AuthToken, StreamId, BranchName, Limit, CompleteDelegate, ErrorDelegate);
}
void UReceiveCommitsOperation::HandleReceive(const TArray<FSpeckleCommit>& Commits)
{
check(IsInGameThread());
UE_LOG(LogSpeckle, Log, TEXT("%s to %s Succeeded"), *StaticClass()->GetName(), *ServerUrl);
FEditorScriptExecutionGuard ScriptGuard;
OnReceiveSuccessfully.Broadcast(Commits, "");
SetReadyToDestroy();
}
void UReceiveCommitsOperation::HandleError(const FString& Message)
{
check(IsInGameThread());
UE_LOG(LogSpeckle, Warning, TEXT("%s failed - %s"), *StaticClass()->GetName(), *Message);
FEditorScriptExecutionGuard ScriptGuard;
const TArray<FSpeckleCommit> EmptyList;
OnError.Broadcast(EmptyList, Message);
SetReadyToDestroy();
}
@@ -0,0 +1,66 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "API/Operations/ReceiveGlobalsOperation.h"
#include "Mixpanel.h"
#include "LogSpeckle.h"
#include "API/ClientAPI.h"
UReceiveGlobalsOperation* UReceiveGlobalsOperation::ReceiveGlobalsOperation(UObject* WorldContextObject,
const FString& ServerUrl, const FString& AuthToken,
const FString& StreamId, const FString& ReferencedObjectId)
{
UReceiveGlobalsOperation* Node = NewObject<UReceiveGlobalsOperation>();
Node->ServerUrl = ServerUrl.TrimEnd();
while(Node->ServerUrl.RemoveFromEnd("/")) { }
Node->AuthToken = AuthToken.TrimEnd();;
Node->StreamId = StreamId.TrimEnd();;
Node->ReferencedObjectId = ReferencedObjectId;
Node->RegisterWithGameInstance(WorldContextObject);
return Node;
}
void UReceiveGlobalsOperation::Activate()
{
FAnalytics::TrackEvent("unknown",
ServerUrl, "NodeRun", TMap<FString, FString> { {"name", StaticClass()->GetName() }});
Request();
}
void UReceiveGlobalsOperation::Request()
{
FFetchGlobalsDelegate CompleteDelegate;
CompleteDelegate.BindUObject(this, &UReceiveGlobalsOperation::HandleReceive);
FErrorDelegate ErrorDelegate;
ErrorDelegate.BindUObject(this, &UReceiveGlobalsOperation::HandleError);
FClientAPI::FetchGlobals(ServerUrl, AuthToken, StreamId, ReferencedObjectId, CompleteDelegate, ErrorDelegate);
}
void UReceiveGlobalsOperation::HandleReceive(const FSpeckleGlobals& Object)
{
check(IsInGameThread());
UE_LOG(LogSpeckle, Log, TEXT("%s to %s Succeeded"), *StaticClass()->GetName(), *ServerUrl);
FEditorScriptExecutionGuard ScriptGuard;
OnReceiveSuccessfully.Broadcast(Object, "");
SetReadyToDestroy();
}
void UReceiveGlobalsOperation::HandleError(const FString& Message)
{
check(IsInGameThread());
UE_LOG(LogSpeckle, Warning, TEXT("%s failed - %s"), *StaticClass()->GetName(), *Message);
FEditorScriptExecutionGuard ScriptGuard;
const FSpeckleGlobals BlankGlobals;
OnError.Broadcast(BlankGlobals, Message);
SetReadyToDestroy();
}
@@ -0,0 +1,64 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "API/Operations/ReceiveMyUserDataOperation.h"
#include "Mixpanel.h"
#include "LogSpeckle.h"
#include "API/ClientAPI.h"
UReceiveMyUserDataOperation* UReceiveMyUserDataOperation::ReceiveMyUserDataOperation(
UObject* WorldContextObject, const FString& ServerUrl, const FString& AuthToken)
{
UReceiveMyUserDataOperation* Node = NewObject<UReceiveMyUserDataOperation>();
Node->ServerUrl = ServerUrl.TrimEnd();;
while(Node->ServerUrl.RemoveFromEnd("/")) { }
Node->AuthToken = AuthToken.TrimEnd();;
Node->RegisterWithGameInstance(WorldContextObject);
return Node;
}
void UReceiveMyUserDataOperation::Activate()
{
FAnalytics::TrackEvent("unknown",
ServerUrl, "NodeRun", TMap<FString, FString> { {"name", StaticClass()->GetName() }});
Request();
}
void UReceiveMyUserDataOperation::Request()
{
FFetchUserDelegate CompleteDelegate;
CompleteDelegate.BindUObject(this, &UReceiveMyUserDataOperation::HandleReceive);
FErrorDelegate ErrorDelegate;
ErrorDelegate.BindUObject(this, &UReceiveMyUserDataOperation::HandleError);
FClientAPI::FetchUserData(ServerUrl, AuthToken, CompleteDelegate, ErrorDelegate);
}
void UReceiveMyUserDataOperation::HandleReceive(const FSpeckleUser& Object)
{
check(IsInGameThread());
UE_LOG(LogSpeckle, Log, TEXT("%s to %s Succeeded"), *StaticClass()->GetName(), *ServerUrl);
FEditorScriptExecutionGuard ScriptGuard;
OnReceiveSuccessfully.Broadcast(Object, "");
SetReadyToDestroy();
}
void UReceiveMyUserDataOperation::HandleError(const FString& Message)
{
check(IsInGameThread());
UE_LOG(LogSpeckle, Warning, TEXT("%s failed - %s"), *StaticClass()->GetName(), *Message);
FEditorScriptExecutionGuard ScriptGuard;
const FSpeckleUser BlankUser;
OnError.Broadcast(BlankUser, Message);
SetReadyToDestroy();
}
@@ -10,7 +10,11 @@
#include "Mixpanel.h"
UReceiveOperation* UReceiveOperation::ReceiveOperation(UObject* WorldContextObject, const FString& ObjectId, TScriptInterface<ITransport> RemoteTransport, TScriptInterface<ITransport> LocalTransport)
// ReceiveOperation
UReceiveOperation* UReceiveOperation::ReceiveOperation(UObject* WorldContextObject,
const FString& ObjectId,
TScriptInterface<ITransport> RemoteTransport,
TScriptInterface<ITransport> LocalTransport)
{
UReceiveOperation* Node = NewObject<UReceiveOperation>();
Node->ObjectId = ObjectId;
@@ -21,10 +25,11 @@ UReceiveOperation* UReceiveOperation::ReceiveOperation(UObject* WorldContextObje
return Node;
}
// Activate
void UReceiveOperation::Activate()
{
FAnalytics::TrackEvent("unknown", "unknown", "NodeRun", TMap<FString, FString> { {"name", StaticClass()->GetName() }});
FAnalytics::TrackEvent("unknown",
"unknown", "NodeRun", TMap<FString, FString> { {"name", StaticClass()->GetName() }});
//Async(EAsyncExecution::Thread, [this]{Receive();});
Receive();
@@ -46,13 +51,16 @@ void UReceiveOperation::Receive()
// 2. Try and get object from remote transport
if(RemoteTransport == nullptr)
{
FString ErrorMessage = TEXT("Could not find specified object using the local transport, and you didn't provide a fallback remote from which to pull it.");
FString ErrorMessage = TEXT(
"Could not find specified object using the local transport, and you didn't provide a fallback remote from which to pull it.");
HandleError(ErrorMessage);
return;
}
FTransportCopyObjectCompleteDelegate CompleteDelegate;
CompleteDelegate.BindUObject(this, &UReceiveOperation::HandleReceive);
FTransportErrorDelegate ErrorDelegate;
ErrorDelegate.BindUObject(this, &UReceiveOperation::HandleError);
@@ -86,5 +94,4 @@ void UReceiveOperation::HandleError(FString& Message)
FEditorScriptExecutionGuard ScriptGuard;
OnError.Broadcast(nullptr, Message);
SetReadyToDestroy();
}
}
@@ -0,0 +1,69 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "API/Operations/ReceiveStreamsOperation.h"
#include "Mixpanel.h"
#include "LogSpeckle.h"
#include "API/ClientAPI.h"
UReceiveStreamsOperation* UReceiveStreamsOperation::ReceiveStreamsOperation(UObject* WorldContextObject,
const FString& ServerUrl,
const FString& AuthToken,
const int32 Limit)
{
FString ObjectId = "Streams";
UReceiveStreamsOperation* Node = NewObject<UReceiveStreamsOperation>();
Node->ServerUrl = ServerUrl.TrimEnd();;
Node->AuthToken = AuthToken.TrimEnd();;
Node->Limit = Limit;
Node->RegisterWithGameInstance(WorldContextObject);
return Node;
}
void UReceiveStreamsOperation::Activate()
{
FAnalytics::TrackEvent("unknown",
ServerUrl, "NodeRun", TMap<FString, FString> { {"name", StaticClass()->GetName() }});
Request();
}
void UReceiveStreamsOperation::Request()
{
FFetchStreamDelegate CompleteDelegate;
CompleteDelegate.BindUObject(this, &UReceiveStreamsOperation::HandleReceive);
FErrorDelegate ErrorDelegate;
ErrorDelegate.BindUObject(this, &UReceiveStreamsOperation::HandleError);
FClientAPI::StreamsGet(ServerUrl, AuthToken, Limit, CompleteDelegate, ErrorDelegate);
}
void UReceiveStreamsOperation::HandleReceive(const TArray<FSpeckleStream>& Streams)
{
check(IsInGameThread());
UE_LOG(LogSpeckle, Log, TEXT("%s to %s Succeeded"), *StaticClass()->GetName(), *ServerUrl);
FEditorScriptExecutionGuard ScriptGuard;
OnReceiveSuccessfully.Broadcast(Streams, "");
SetReadyToDestroy();
}
void UReceiveStreamsOperation::HandleError(const FString& Message)
{
check(IsInGameThread());
UE_LOG(LogSpeckle, Warning, TEXT("%s failed - %s"), *StaticClass()->GetName(), *Message);
FEditorScriptExecutionGuard ScriptGuard;
const TArray<FSpeckleStream> EmptyList;
OnError.Broadcast(EmptyList, Message);
SetReadyToDestroy();
}
@@ -1,33 +1,22 @@
#include "API/Operations/SendOperation.h"
#include "Mixpanel.h"
#include "Transports/Transport.h"
USendOperation* USendOperation::SendOperation(UObject* WorldContextObject, UBase* Base, TArray<TScriptInterface<ITransport>> Transports)
{
USendOperation* Node = NewObject<USendOperation>();
Node->Base = Base;
Node->Transports = Transports;
Node->RegisterWithGameInstance(WorldContextObject);
return Node;
}
void USendOperation::Activate()
{
FAnalytics::TrackEvent("unknown", "unknown", "NodeRun", TMap<FString, FString> { {"name", StaticClass()->GetName() }});
Send();
}
void USendOperation::Send()
{
check(Transports.Num() > 0);
for (const auto t : Transports)
{
//TODO
//ITransport::
}
}
// USendOperation* USendOperation::SendOperation(UObject* WorldContextObject, UBase* Base, TScriptArray<TScriptInterface<ITransport>> Transports)
// {
// USendOperation* Node = NewObject<USendOperation>();
// Node->Base = Base;
// Node->Transports = Transports;
//
// Node->RegisterWithGameInstance(WorldContextObject);
// return Node;
// }
//
// void USendOperation::Activate()
// {
// check(Transports.Num() > 0);
//
// //TODO implement
// unimplemented();
//
// }
@@ -9,18 +9,19 @@
#include "UObject/Package.h"
UBase* USpeckleSerializer::DeserializeBase(const TSharedPtr<FJsonObject> Obj, const TScriptInterface<ITransport> ReadTransport)
// Create the Deserialization Base
UBase* USpeckleSerializer::DeserializeBase(const TSharedPtr<FJsonObject> Obj,
const TScriptInterface<ITransport> ReadTransport)
{
if(Obj == nullptr) return nullptr;
{ // Handle Detached Objects
TSharedPtr<FJsonObject> DetachedObject;
if(USpeckleObjectUtils::ResolveReference(Obj, ReadTransport, DetachedObject))
{
// Handle Detached Objects
TSharedPtr<FJsonObject> DetachedObject;
if(USpeckleObjectUtils::ResolveReference(Obj, ReadTransport, DetachedObject))
{
return DeserializeBase(DetachedObject, ReadTransport);
}
}
FString SpeckleType;
if (!Obj->TryGetStringField("speckle_type", SpeckleType)) return nullptr;
FString ObjectId = "";
@@ -59,23 +60,8 @@ UBase* USpeckleSerializer::DeserializeBase(const TSharedPtr<FJsonObject> Obj, co
}
UBase* USpeckleSerializer::DeserializeBaseById(const FString& ObjectId,
const TScriptInterface<ITransport> ReadTransport)
const TScriptInterface<ITransport> ReadTransport)
{
auto Obj = ReadTransport->GetSpeckleObject(ObjectId);
return DeserializeBase(Obj, ReadTransport);
}
UBase* TrySetProperties(const TSubclassOf<UBase> BaseType, const FString& SerialisedObject, TScriptInterface<ITransport> Transport)
{
UBase* Base = NewObject<UBase>(GetTransientPackage(), BaseType);
TSharedRef<FJsonStringReader> Reader = FJsonStringReader::Create(SerialisedObject);
for(auto foo : Reader.)
{
}
return Base;
}
@@ -34,10 +34,11 @@ void UAggregateConverter::PostEditChangeProperty(FPropertyChangedEvent& Property
}
#endif
void UAggregateConverter::ConvertToSpeckle_Implementation(const UObject* Object, UBase* SpeckleObject)
UBase* UAggregateConverter::ConvertToSpeckle_Implementation(const UObject* Object)
{
//TODO implement ToSpeckle
unimplemented();
return nullptr;
}
@@ -56,6 +57,13 @@ UObject* UAggregateConverter::ConvertToNativeInternal(const UBase* Object, UWorl
UObject* Converter = GetConverter(Type).GetObject();
if(!IsValid(Converter))
{
//TODO convert displayValues then halt traversal
if(Type != UBase::StaticClass())
{
UE_LOG(LogSpeckle, Warning, TEXT("Skipping Object %s: No conversion functions exist for %s"), *Object->Id, *Type->GetName());
@@ -79,7 +87,6 @@ bool UAggregateConverter::CanConvertToNative_Implementation(TSubclassOf<UBase> B
return GetConverter(BaseType).GetInterface() != nullptr;
}
TScriptInterface<ISpeckleConverter> UAggregateConverter::GetConverter(const TSubclassOf<UBase> BaseType)
{
// Check if this SpeckleType has a known converter.
@@ -10,6 +10,7 @@
#include "Objects/Other/RenderMaterial.h"
#include "Objects/Utils/SpeckleObjectUtils.h"
// Setup some basics
UProceduralMeshConverter::UProceduralMeshConverter()
{
SpeckleTypes.Add(UMesh::StaticClass());
@@ -19,7 +20,9 @@ UProceduralMeshConverter::UProceduralMeshConverter()
ActorMobility = EComponentMobility::Static;
}
UObject* UProceduralMeshConverter::ConvertToNative_Implementation(const UBase* SpeckleBase, UWorld* World, TScriptInterface<ISpeckleConverter>& AvailableConverters )
// Blueprint for converting data to 3D model
UObject* UProceduralMeshConverter::ConvertToNative_Implementation(const UBase* SpeckleBase, UWorld* World,
TScriptInterface<ISpeckleConverter>& AvailableConverters )
{
const UMesh* m = Cast<UMesh>(SpeckleBase);
if(m != nullptr)
@@ -47,7 +50,9 @@ UObject* UProceduralMeshConverter::ConvertToNative_Implementation(const UBase* S
return nullptr;
}
AActor* UProceduralMeshConverter::MeshToNative(const UMesh* SpeckleMesh, UWorld* World, TScriptInterface<ISpeckleConverter>& MaterialConverter)
AActor* UProceduralMeshConverter::MeshToNative(const UMesh* SpeckleMesh,
UWorld* World,
TScriptInterface<ISpeckleConverter>& MaterialConverter)
{
AActor* MeshActor = CreateEmptyActor(World, USpeckleObjectUtils::CreateTransform(SpeckleMesh->Transform));
UProceduralMeshComponent* MeshComponent = NewObject<UProceduralMeshComponent>(MeshActor, FName("SpeckleMeshComponent"));
@@ -14,15 +14,25 @@
#include "Conversion/Converters/MaterialConverter.h"
#include "Misc/ScopedSlowTask.h"
#include "Objects/DisplayValueElement.h"
#include "Objects/Geometry/Box.h"
#include "Objects/Other/RenderMaterial.h"
#include "Objects/Utils/SpeckleObjectUtils.h"
#define LOCTEXT_NAMESPACE "FSpeckleUnrealModule"
bool UStaticMeshConverter::CanConvertToNative_Implementation(TSubclassOf<UBase> BaseType)
{
if(EnabledTypes.Contains(BaseType))
return EnabledTypes[BaseType];
return false;
}
UStaticMeshConverter::UStaticMeshConverter()
{
SpeckleTypes.Add(UMesh::StaticClass());
SpeckleTypes.Add(UDisplayValueElement::StaticClass());
EnabledTypes.Add(UMesh::StaticClass(), true);
EnabledTypes.Add(UDisplayValueElement::StaticClass(), true);
EnabledTypes.Add(UBoxx::StaticClass(), true);
#if WITH_EDITORONLY_DATA
UseFullBuild = true;
@@ -58,6 +68,15 @@ UObject* UStaticMeshConverter::ConvertToNative_Implementation(const UBase* Speck
return MeshToNativeActor(m, World, AvailableConverters);
}
const UBoxx* b = Cast<UBoxx>(SpeckleBase);
if(b != nullptr)
{
//Handle Element with Display Values
const UMesh* m = b->ToMesh();
return MeshToNativeActor(m, World, AvailableConverters);
}
const UDisplayValueElement* d = Cast<UDisplayValueElement>(SpeckleBase);
if(d != nullptr)
{
@@ -366,7 +385,7 @@ void UStaticMeshConverter::GenerateMeshParams(UStaticMesh::FBuildMeshDescription
}
void UStaticMeshConverter::ConvertToSpeckle_Implementation(const UObject* Object, UBase* SpeckleObject)
UBase* UStaticMeshConverter::ConvertToSpeckle_Implementation(const UObject* Object)
{
const UStaticMeshComponent* M = Cast<UStaticMeshComponent>(Object);
@@ -378,68 +397,15 @@ void UStaticMeshConverter::ConvertToSpeckle_Implementation(const UObject* Object
M = A->FindComponentByClass<UStaticMeshComponent>();
}
}
if(M == nullptr) return;
//SpeckleObject->DynamicProperties.Add(TEXT("@displayValue"), MeshToSpeckle(M));
if(M == nullptr) return nullptr;
return MeshToSpeckle(M);
}
TArray<UMesh*> UStaticMeshConverter::MeshToSpeckle(const UStaticMeshComponent* MeshComponent)
UBase* UStaticMeshConverter::MeshToSpeckle(const UStaticMeshComponent* Object)
{
UStaticMeshDescription* StaticMeshDescription = NewObject<UStaticMeshDescription>(GetTransientPackage(), NAME_None, RF_Transient);
const FMeshDescription* MeshDescription = MeshComponent->GetStaticMesh()->GetMeshDescription(0);;
StaticMeshDescription->SetMeshDescription(*MeshDescription);
StaticMeshDescription->RegisterAttributes();
const FVertexArray& nVertices = StaticMeshDescription->Vertices();
TArray<FVector> sVertices;
sVertices.Reserve(nVertices.Num()); // * 3));
TMap<FVertexID, int32> VertexIdToIndex;
VertexIdToIndex.Reserve(nVertices.Num() * 3);
int32 i = 0;
for (const FVertexID& VertexId : nVertices.GetElementIDs())
{
const FVector Vert = StaticMeshDescription->GetVertexPosition(VertexId);
sVertices.Add(Vert);
VertexIdToIndex.Add(VertexId, i);
i++;
}
FTriangleArray& nTriangles = StaticMeshDescription->Triangles();
TArray<int32> sFaces;
sFaces.Reserve(nTriangles.Num());
for (const FTriangleID& TriangleId : nTriangles.GetElementIDs())
{
TArray<FVertexID> Tri;
StaticMeshDescription->GetTriangleVertices(TriangleId, Tri);
sFaces.Add(3);
sFaces.Add(VertexIdToIndex[Tri[0]]);
sFaces.Add(VertexIdToIndex[Tri[1]]);
sFaces.Add(VertexIdToIndex[Tri[2]]);
}
//TODO colors
//TODO tex-coords
//TODO split mesh by material
UMesh* Mesh = NewObject<UMesh>(GetTransientPackage(), NAME_None, RF_Transient);
Mesh->Vertices = sVertices;
Mesh->Faces = sFaces;
//Mesh->Colors = sColors;
//Mesh->TextureCoordinates = sTexCoords;
Mesh->Units = "cm";
return TArray<UMesh*>{Mesh};
return nullptr; //TODO implement ToSpeckle function
}
@@ -1,60 +0,0 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "Conversion/SpeckleConverter.h"
#include "Conversion/SpeckleConverterComponent.h"
#include "Conversion/Converters/AggregateConverter.h"
#define LOCTEXT_NAMESPACE "FSpeckleUnrealModule"
UBase* USpeckleConverterComponent::RecursivelyConvertToSpeckle(const TArray<AActor*>& RootActors, FActorPredicate& Predicate)
{
TArray<UBase*> ConvertedRootActors;
for(const AActor* RootActor : RootActors)
{
RecurseTreeToSpeckle(RootActor, Predicate, ConvertedRootActors);
}
UBase* Wrapper = NewObject<UBase>(GetTransientPackage(), NAME_None, RF_Transient);
//Converted->DynamicProperties["objects"] = ConvertedRootActors; //TODO set children
return Wrapper;
}
void USpeckleConverterComponent::RecurseTreeToSpeckle(const AActor* RootActor, FActorPredicate& Predicate, TArray<UBase*>& OutConverted)
{
// Convert children first
TArray<UBase*> ConvertedChildren;
ConvertedChildren.Reserve(RootActor->Children.Num());
for (const AActor* Child : RootActor->Children)
{
RecurseTreeToSpeckle(Child, Predicate, ConvertedChildren);
}
bool ShouldConvert;
Predicate.Execute(RootActor, ShouldConvert);
if(ISpeckleConverter::Execute_CanConvertToSpeckle(SpeckleConverter, RootActor) && ShouldConvert)
{
// Convert and output
UBase* Converted = NewObject<UBase>(GetTransientPackage(), NAME_None, RF_Transient);
//Converted->DynamicProperties["name"] = RootActor->GetName(),
//["transform"] = TransformToSpeckle(go.Transform), //TODO set common props
//Converted->DynamicProperties["tag"] = go.tag,
//Converted->DynamicProperties["layer"] = go.layer,
//Converted->DynamicProperties["isStatic"] = go.isStatic,
ISpeckleConverter::Execute_ConvertToSpeckle(SpeckleConverter, RootActor, Converted);
//Converted->DynamicProperties["objects"] = ConvertedChildren; //TODO set children
OutConverted.Add(Converted);
}
else
{
// Skip this object, and output any children
OutConverted.Append(ConvertedChildren);
}
}
#undef LOCTEXT_NAMESPACE
@@ -11,7 +11,9 @@
#include "Conversion/Converters/StaticMeshConverter.h"
#include "Conversion/Converters/MaterialConverter.h"
#include "Misc/ScopedSlowTask.h"
#include "Transports/Transport.h"
#include "UObject/ConstructorHelpers.h"
#include "LogSpeckle.h"
#define LOCTEXT_NAMESPACE "FSpeckleUnrealModule"
@@ -43,7 +45,11 @@ AActor* USpeckleConverterComponent::RecursivelyConvertToNative(AActor* AOwner, c
{
float ObjectsToConvert{};
Base->TryGetDynamicNumber("totalChildrenCount", ObjectsToConvert);
FScopedSlowTask Progress(ObjectsToConvert + 2, LOCTEXT("SpeckleConvertoNative","Converting Speckle Objects to Native"), DisplayProgressBar);
// Progress bar
FScopedSlowTask Progress(ObjectsToConvert + 2,
LOCTEXT("SpeckleConvertoNative","Converting Speckle Objects to Native"), DisplayProgressBar);
#if WITH_EDITOR
Progress.MakeDialog(true, false);
#endif
@@ -54,6 +60,21 @@ AActor* USpeckleConverterComponent::RecursivelyConvertToNative(AActor* AOwner, c
return RootActor;
}
// We should convert JSON to Speckle Object Streams
TArray<FSpeckleStream> USpeckleConverterComponent::ConvertStreamsToNative(AActor* AOwner, const UBase* Base,
const TScriptInterface<ITransport>& LocalTransport, bool DisplayProgressBar, TArray<AActor*>& OutActors)
{
return ArrayOfStreams;
}
AActor* USpeckleConverterComponent::RecursivelyConvertToNative_Internal(AActor* AOwner, const UBase* Base,
const TScriptInterface<ITransport>& LocalTransport,
FSlowTask* Task,
@@ -107,7 +128,7 @@ void USpeckleConverterComponent::ConvertChild(const TSharedPtr<FJsonValue> Objec
const TArray<TSharedPtr<FJsonValue>>* ChildArr;
if (Object->TryGetArray(ChildArr))
{
for (const auto& v : *ChildArr)
for (const auto v : *ChildArr)
{
ConvertChild(v, AOwner, LocalTransport, Task, OutActors);
}
@@ -176,4 +197,4 @@ void USpeckleConverterComponent::FinishConversion()
SpeckleConverter->FinishConversion_Internal();
}
#undef LOCTEXT_NAMESPACE
#undef LOCTEXT_NAMESPACE
@@ -1,80 +0,0 @@
// Copyright AEC Systems Ltd
#include "Objects/DynamicBase.h"
#include "Misc/Variant.h"
template <typename T>
bool UDynamicBase::TryGetDynamicProperty(const FString& Key, T& OutValue) const
{
const auto Wrapper = DynamicProperties.FindRef(Key);
if(Wrapper.IsValid()) return false;
if(Wrapper->GetType() != TVariantTraits<T>::GetType()) return false;
OutValue = Wrapper->GetValue<T>();
return true;
}
template <typename T>
void UDynamicBase::SetDynamicProperty(const FString& Key, T Value)
{
DynamicProperties.Add(Key, MakeShareable(new FVariant(Value)));
}
int32 UDynamicBase::RemoveDynamicProperty(const FString& Key)
{
return DynamicProperties.Remove(Key);
}
//-------------------
bool UDynamicBase::TryGetDynamicStringProperty(const FString& Key, FString& OutValue) const
{
return TryGetDynamicProperty(Key, OutValue);
}
bool UDynamicBase::TryGetDynamicIntProperty(const FString& Key, int32& OutValue) const
{
return TryGetDynamicProperty(Key, OutValue);
}
bool UDynamicBase::TryGetDynamicFloatProperty(const FString& Key, float& OutValue) const
{
return TryGetDynamicProperty(Key, OutValue);
}
bool UDynamicBase::TryGetDynamicBoolProperty(const FString& Key, bool& OutValue) const
{
return TryGetDynamicProperty(Key, OutValue);
}
bool UDynamicBase::TryGetDynamicBaseProperty(const FString& Key, UBase*& OutValue) const
{
return TryGetDynamicProperty(Key, OutValue);
}
void UDynamicBase::SetDynamicStringProperty(const FString& Key, FString& OutValue)
{
SetDynamicProperty(Key, OutValue);
}
void UDynamicBase::SetDynamicIntProperty(const FString& Key, int32& OutValue)
{
SetDynamicProperty(Key, OutValue);
}
void UDynamicBase::SetDynamicFloatProperty(const FString& Key, float& OutValue)
{
SetDynamicProperty(Key, OutValue);
}
void UDynamicBase::SetDynamicBoolProperty(const FString& Key, bool& OutValue)
{
SetDynamicProperty(Key, OutValue);
}
void UDynamicBase::SetDynamicBaseProperty(const FString& Key, UBase*& OutValue)
{
SetDynamicProperty(Key, OutValue);
}
@@ -0,0 +1,55 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "Objects/Geometry/Box.h"
#include "Objects/Geometry/Plane.h"
#include "Objects/Utils/SpeckleObjectUtils.h"
bool UBoxx::Parse(const TSharedPtr<FJsonObject> Obj, const TScriptInterface<ITransport> ReadTransport)
{
if(!Super::Parse(Obj, ReadTransport)) return false;
const float ScaleFactor = USpeckleObjectUtils::ParseScaleFactor(Units);
const FString BasePlanePropertyName = TEXT("basePlane");
if (Obj->HasField(BasePlanePropertyName))
{
BasePlane = NewObject<UPlane>();
if(!BasePlane->Parse(Obj->GetObjectField(BasePlanePropertyName), ReadTransport)) return false;
DynamicProperties.Remove(BasePlanePropertyName);
}
if(!USpeckleObjectUtils::ParseVectorProperty(Obj, "xSize", ReadTransport, XSize)) return false;
XSize *= ScaleFactor;
DynamicProperties.Remove("xSize");
if(!USpeckleObjectUtils::ParseVectorProperty(Obj, "ySize", ReadTransport, YSize)) return false;
YSize *= ScaleFactor;
DynamicProperties.Remove("ySize");
return true;
}
UMesh* UBoxx::ToMesh(UObject* Outer) const
{
TArray<FVector> Vertices = {
FVector(),
FVector(),
FVector(),
FVector(),
FVector(),
FVector(),
};
TArray<int32> Faces = {
};
//FMatrix transform =
UMesh* Mesh = NewObject<UMesh>(Outer);
return Mesh;
}
@@ -47,7 +47,7 @@ bool UMesh::Parse(const TSharedPtr<FJsonObject> Obj, const TScriptInterface<ITra
{
const TArray<TSharedPtr<FJsonValue>> FaceVertices = USpeckleObjectUtils::CombineChunks(Obj->GetArrayField("faces"), ReadTransport);
Faces.Reserve(FaceVertices.Num());
for(const auto& VertIndex : FaceVertices)
for(const auto VertIndex : FaceVertices)
{
Faces.Add(VertIndex->AsNumber());
}
@@ -105,64 +105,6 @@ bool UMesh::Parse(const TSharedPtr<FJsonObject> Obj, const TScriptInterface<ITra
return Vertices.Num() > 0 && Faces.Num() > 0;
}
void UMesh::ToJson(TJsonWriter<TCHAR, TCondensedJsonPrintPolicy<TCHAR>> Writer)
{
Super::ToJson(Writer);
// Serialize Transform
// TODO todo transform
// Serialize Vertices
{
TArray<double> FlattenedVertices;
FlattenedVertices.Reserve(Vertices.Num() * 3);
for(size_t i = 0, j = 0; i < Vertices.Num(); i++)
{
const FVector& v = Vertices[i];
FlattenedVertices[j++] = v.X;
FlattenedVertices[j++] = -v.Y;
FlattenedVertices[j++] = v.Z;
}
Writer.WriteValue(TEXT("vertices"), FlattenedVertices);
}
// Serialize Faces
Writer.WriteValue(TEXT("faces"), Faces);
//Parse TextureCoords
{
TArray<double> FlattenedTexCoords;
FlattenedTexCoords.Reserve(TextureCoordinates.Num() * 2);
for(size_t i = 0, j = 0; i < TextureCoordinates.Num(); i++)
{
const FVector2D& c = TextureCoordinates[i];
FlattenedTexCoords[j++] = c.X;
FlattenedTexCoords[j++] = -c.Y;
}
Writer.WriteValue(TEXT("textureCoordinates"), FlattenedTexCoords);
}
//Parse VertexColors
{
TArray<int32> ArgbColors;
ArgbColors.Reserve(VertexColors.Num());
for(size_t i = 0; i < VertexColors.Num(); i++)
{
ArgbColors[i] = VertexColors[i].ToPackedARGB();
}
Writer.WriteValue(TEXT("colors"), ArgbColors);
}
// Parse Optional RenderMaterial
//if (RenderMaterial != nullptr)
{
//TODO renderMaterial
}
}
/**
* If not already so, this method will align vertices
@@ -0,0 +1,31 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "Objects/Geometry/Plane.h"
#include "Objects/Utils/SpeckleObjectUtils.h"
bool UPlane::Parse(const TSharedPtr<FJsonObject> Obj, const TScriptInterface<ITransport> ReadTransport)
{
if(!Super::Parse(Obj, ReadTransport)) return false;
const float ScaleFactor = USpeckleObjectUtils::ParseScaleFactor(Units);
if(!USpeckleObjectUtils::ParseVectorProperty(Obj, "origin", ReadTransport, Origin)) return false;
Origin *= ScaleFactor;
DynamicProperties.Remove("origin");
if(!USpeckleObjectUtils::ParseVectorProperty(Obj, "normal", ReadTransport, Normal)) return false;
Normal *= ScaleFactor;
DynamicProperties.Remove("normal");
if(!USpeckleObjectUtils::ParseVectorProperty(Obj, "ydir", ReadTransport, XDir)) return false;
XDir *= ScaleFactor;
DynamicProperties.Remove("ydir");
if(!USpeckleObjectUtils::ParseVectorProperty(Obj, "xdir", ReadTransport, YDir)) return false;
YDir *= ScaleFactor;
DynamicProperties.Remove("xdir");
return true;
}
@@ -37,7 +37,7 @@ bool UBlockInstance::Parse(const TSharedPtr<FJsonObject> Obj, const TScriptInte
return false;
}
for(const auto& Geo : Geometries)
for(const auto Geo : Geometries)
{
const TSharedPtr<FJsonObject> MeshReference = Geo->AsObject();
const FString ChildId = MeshReference->GetStringField("referencedId");
@@ -143,6 +143,41 @@ bool USpeckleObjectUtils::ParseVector(const TSharedPtr<FJsonObject> Object,
return ParseSpeckleObject<UMesh>(Obj, Transport, Mesh);
}
bool USpeckleObjectUtils::ParseIntervalProperty(const TSharedPtr<FJsonObject> Base, const FString& PropertyName,
const TScriptInterface<ITransport> ReadTransport, FVector2f<float>& OutObject)
{
const TSharedPtr<FJsonObject>* OriginObject;
if(Base->TryGetObjectField(PropertyName, OriginObject)
&& ParseInterval(*OriginObject, ReadTransport, OutObject))
{
return true;
}
return false;
}
bool USpeckleObjectUtils::ParseInterval(const TSharedPtr<FJsonObject> Object,
const TScriptInterface<ITransport> Transport, FVector2f& OutObject)
{
if(!ensure(Object != nullptr)) return false;
TSharedPtr<FJsonObject> Obj;
if(!ResolveReference(Object, Transport, Obj)) Obj = Object;
double x = 0, y = 0, z = 0;
if(!(Obj->TryGetNumberField("start", x)
&& Obj->TryGetNumberField("end", y)) return false;
OutObject = FVector2f(x,y,z);
//return true;
UMesh* Mesh;
return ParseSpeckleObject<UMesh>(Obj, Transport, Mesh);
}
template <typename TBase>
bool USpeckleObjectUtils::ParseSpeckleObject(const TSharedPtr<FJsonObject> Object,
const TScriptInterface<ITransport> Transport, TBase*& OutObject)
@@ -6,13 +6,14 @@
void FSpeckleUnrealModule::StartupModule()
{
// This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module
// This code will execute after your module is loaded into memory.
// The exact timing is specified in the .uplugin file per-module
}
void FSpeckleUnrealModule::ShutdownModule()
{
// This function may be called during shutdown to clean up your module. For modules that support dynamic reloading,
// we call this function before unloading the module.
// This function may be called during shutdown to clean up your module.
// For modules that support dynamic reloading, we call this function before unloading the module.
}
#undef LOCTEXT_NAMESPACE
@@ -1,6 +1,7 @@
#include "SpeckleUnrealManager.h"
#include "API/Operations/ReceiveOperation.h"
#include "Transports/MemoryTransport.h"
#include "Transports/ServerTransport.h"
#include "LogSpeckle.h"
@@ -10,6 +11,7 @@
#include "Objects/Base.h"
#include "Mixpanel.h"
#include "Engine/Engine.h"
#include "Interfaces/IHttpRequest.h"
#define LOCTEXT_NAMESPACE "FSpeckleUnrealModule"
@@ -21,6 +23,7 @@ ASpeckleUnrealManager::ASpeckleUnrealManager()
RootComponent->SetRelativeScale3D(FVector(1,1,1));
RootComponent->SetMobility(EComponentMobility::Static);
// Convert JSON to object models
Converter = CreateDefaultSubobject<USpeckleConverterComponent>(FName("Converter"));
KeepCache = true;
@@ -28,6 +31,7 @@ ASpeckleUnrealManager::ASpeckleUnrealManager()
ServerUrl = "https://speckle.xyz";
}
// Begin Play function (Receive)
void ASpeckleUnrealManager::BeginPlay()
{
Super::BeginPlay();
@@ -35,6 +39,7 @@ void ASpeckleUnrealManager::BeginPlay()
if(ImportAtRuntime) Receive();
}
// Start the Receive process
void ASpeckleUnrealManager::Receive()
{
DeleteObjects();
@@ -46,63 +51,92 @@ void ASpeckleUnrealManager::Receive()
ObjectID.TrimEndInline();
AuthToken.TrimEndInline();
FAnalytics::TrackEvent("unknown", "unknown", "NodeRun", TMap<FString, FString> { {"name", StaticClass()->GetName() }, {"worldType", FString::FromInt(GetWorld()->WorldType)}});
// Analytics
FAnalytics::TrackEvent(
"unknown",
"unknown",
"NodeRun",
TMap<FString, FString> {
{"name", StaticClass()->GetName() },
{"worldType", FString::FromInt(GetWorld()->WorldType)}}
);
// Clear cache
if(!KeepCache && LocalObjectCache.GetObjectRef() != nullptr)
{
LocalObjectCache.GetObjectRef()->ConditionalBeginDestroy();
LocalObjectCache = UMemoryTransport::CreateEmptyMemoryTransport();
}
// Probably a duplication
if(LocalObjectCache.GetObjectRef() == nullptr)
{
LocalObjectCache = UMemoryTransport::CreateEmptyMemoryTransport();
}
UServerTransport* ServerTransport = UServerTransport::CreateServerTransport(ServerUrl,StreamID,AuthToken);
// Debug message
FString Message = FString::Printf(TEXT("Fetching Objects from Speckle Server: %s"), *ServerUrl);
PrintMessage(Message);
// Error delegate
FTransportErrorDelegate ErrorDelegate;
ErrorDelegate.BindUObject(this, &ASpeckleUnrealManager::HandleError);
// Complete delegate
FTransportCopyObjectCompleteDelegate CompleteDelegate;
CompleteDelegate.BindUObject(this, &ASpeckleUnrealManager::HandleReceive, DisplayProgressBar);
// Create a server transport
UServerTransport* ServerTransport = UServerTransport::CreateServerTransport(ServerUrl,StreamID,AuthToken);
//Receive
// Receive
ServerTransport->CopyObjectAndChildren(ObjectID, LocalObjectCache, CompleteDelegate, ErrorDelegate);
}
// Handle Received JSON
void ASpeckleUnrealManager::HandleReceive(TSharedPtr<FJsonObject> RootObject, bool DisplayProgress)
{
if(RootObject == nullptr) return;
// Create a Base Deserialization Object Model
const UBase* Res = USpeckleSerializer::DeserializeBase(RootObject, LocalObjectCache);
if(IsValid(Res))
{
// Start conversion
Converter->RecursivelyConvertToNative(this, Res, LocalObjectCache, DisplayProgress, Actors);
// Finished Conversion - show debug message
FString Message = FString::Printf(TEXT("Converted %d Actors"), Actors.Num());
PrintMessage(Message);
}
else
{
// Object id from Json
FString Id;
// Try to get JSON id field
RootObject->TryGetStringField("id", Id);
// Debug message for error wrt to id
FString Message = FString::Printf(TEXT("Failed to deserialise root object: %s"), *Id);
// Print Message
HandleError(Message);
}
}
// Error handler just prints a debug message
void ASpeckleUnrealManager::HandleError(FString& Message)
{
PrintMessage(Message, true);
}
// Print debug message
void ASpeckleUnrealManager::PrintMessage(FString& Message, bool IsError) const
{
// Show at Console log: "Error" or just "Log" message (Errors are shown in red in output console)
if(IsError)
{
UE_LOG(LogSpeckle, Error, TEXT("%s"), *Message);
@@ -112,15 +146,18 @@ void ASpeckleUnrealManager::PrintMessage(FString& Message, bool IsError) const
UE_LOG(LogSpeckle, Log, TEXT("%s"), *Message);
}
// Error as a debug message
FColor Color = IsError? FColor::Red : FColor::Green;
GEngine->AddOnScreenDebugMessage(0, 5.0f, Color, Message);
}
// Delete Actors containing all the 3D models
void ASpeckleUnrealManager::DeleteObjects()
{
// If still converting, terminate process
Converter->FinishConversion();
// Destroy actors
for (AActor* a : Actors)
{
if(IsValid(a)) a->Destroy();
@@ -129,4 +166,7 @@ void ASpeckleUnrealManager::DeleteObjects()
Actors.Empty();
}
#undef LOCTEXT_NAMESPACE
@@ -1,79 +0,0 @@
#include "FBatchSender.h"
FBatchSender::FBatchSender(FString& ServerUrl, FString& StreamId, FString& AuthToken, int32 MaxBatchSizeMb,
int32 MaxBufferLength, int32 ThreadCount)
: ServerUrl(ServerUrl)
, StreamId(StreamId)
, AuthToken(AuthToken)
, MaxBatchSizeMb(MaxBatchSizeMb)
, MaxBufferLength(MaxBufferLength)
, ThreadCount(ThreadCount)
{
SendingThread = FRunnableThread::Create(this, TEXT("Speckle Transport Send Thread"), 0);
ensure(SendingThread != nullptr);
}
FBatchSender::~FBatchSender()
{
if (SendingThread)
{
SendingThread->Kill();
delete SendingThread;
SendingThread = nullptr;
}
}
uint32 FBatchSender::Run()
{
while(true)
{
if(!ShouldSendThreadRun) return 0;
TArray<TTuple<FString, FString>> Buffer;
FScopeLock Lock(&Lock_SendBuffer);
if(SendBuffer.Num() > 0)
{
Buffer.Append(SendBuffer);
SendBuffer.Empty();
}
else
{
IsWriteComplete = true;
}
if(Buffer.Num() <= 0)
{
FPlatformProcess::Sleep(0.1);
continue;
}
TArray<FString> ObjectIds;
ObjectIds.Reserve(Buffer.Num());
for(const auto& Item: Buffer)
{
ObjectIds.Add(Item.Key);
}
//TODO only send objects that aren't already on the server.
//TMap<FString, bool> HasObjects = API.HasObjects(StreamId, ObjectIds);
//TODO api upload
//API.UploadObjects(StreamId, Buffer);
}
}
void FBatchSender::Stop()
{
ShouldSendThreadRun = false;
}
void FBatchSender::EnqueueSend(const FString& Id, const FString& Object)
{
FScopeLock Lock(&Lock_SendBuffer);
SendBuffer.Emplace(Id, Object);
IsWriteComplete = false;
}
@@ -1,40 +0,0 @@
#pragma once
/**
*
*/
class SPECKLEUNREAL_API FBatchSender : public FRunnable
{
protected:
FString ServerUrl;
FString StreamId;
FString AuthToken;
int32 MaxBatchSizeMb;
int32 MaxBufferLength;
int32 ThreadCount;
bool ShouldSendThreadRun = false;
bool IsWriteComplete = false;
FRunnableThread* SendingThread;
FCriticalSection Lock_SendBuffer;
TArray<TTuple<const FString, const FString>> SendBuffer;
public:
FBatchSender(FString& ServerUrl, FString& StreamId, FString& AuthToken, int32 MaxBatchSizeMb=1, int32 MaxBufferLength = 10, int32 ThreadCount = 4);
virtual ~FBatchSender() override;
virtual uint32 Run() override;
virtual void Stop() override;
virtual void EnqueueSend(const FString& Id, const FString& Object);
virtual void Flush();
protected:
virtual void SendingThreadMain();
};
@@ -2,12 +2,14 @@
#include "Transports/MemoryTransport.h"
#include "LogSpeckle.h"
bool UMemoryTransport::HasObject(const FString& ObjectId) const
{
return SpeckleObjects.Contains(ObjectId);
}
TSharedPtr<FJsonObject> UMemoryTransport::GetSpeckleObject(const FString& ObjectId) const
{
return SpeckleObjects.FindRef(ObjectId);
@@ -16,4 +18,5 @@ TSharedPtr<FJsonObject> UMemoryTransport::GetSpeckleObject(const FString& Object
void UMemoryTransport::SaveObject(const FString& ObjectId, const TSharedPtr<FJsonObject> SerializedObject)
{
SpeckleObjects.Add(ObjectId, SerializedObject);
UE_LOG(LogSpeckle, Log, TEXT("-----------> ADDED <-------------- %d"), SpeckleObjects.Num());
}
@@ -2,53 +2,67 @@
#include "Transports/ServerTransport.h"
#include "FBatchSender.h"
#include "LogSpeckle.h"
#include "HttpModule.h"
#include "Mixpanel.h"
#include "JsonObjectConverter.h"
#include "HttpModule.h"
#include "Interfaces/IHttpRequest.h"
#include "Interfaces/IHttpResponse.h"
#include "Mixpanel.h"
#include "Policies/CondensedJsonPrintPolicy.h"
TSharedPtr<FJsonObject> UServerTransport::GetSpeckleObject(const FString& ObjectId) const
{
unimplemented();
return nullptr;
}
void UServerTransport::SaveObject(const FString& ObjectId, const TSharedPtr<FJsonObject> Object)
void UServerTransport::SaveObject(const FString& ObjectId, const TSharedPtr<FJsonObject> SerializedObject)
{
FString SerializedObject;
{
auto Writer = TJsonWriterFactory<TCHAR, TCondensedJsonPrintPolicy<TCHAR>>::Create(&SerializedObject);
FJsonSerializerWriter<TCHAR, TCondensedJsonPrintPolicy<TCHAR>> SerializerWriter(Writer);
FJsonSerializer::Serialize(Object.ToSharedRef(), Writer);
}
BatchSender.EnqueueSend(ObjectId, SerializedObject);
}
void UServerTransport::BeginWrite()
{
}
void UServerTransport::EndWrite()
{
BatchSender.Flush();
unimplemented(); //TODO implement
}
bool UServerTransport::HasObject(const FString& ObjectId) const
{
unimplemented();
unimplemented(); //TODO implement
return false;
}
// Parse Root JSON
void UServerTransport::HandleRootObjectResponse(const FString& RootObjSerialized,
TScriptInterface<ITransport> TargetTransport,
const FString& ObjectId) const
{
TSharedPtr<FJsonObject> RootObj;
if(!LoadJson(RootObjSerialized, RootObj))
{
FString Message = FString::Printf( TEXT("A Root Object %s was recieved but was invalid and could not be deserialied"), *ObjectId);
InvokeOnError(Message);
return;
}
TargetTransport->SaveObject(ObjectId, RootObj);
// Find children are not already in the target transport
const auto Closures = RootObj->GetObjectField("__closure")->Values;
TArray<FString> ChildrenIds;
Closures.GetKeys(ChildrenIds);
TArray<FString> NewChildrenIds;
for(const FString& Id : ChildrenIds)
{
if(TargetTransport->HasObject(Id)) continue;
NewChildrenIds.Add(Id);
}
FetchChildren(TargetTransport, ObjectId, NewChildrenIds);
}
// Create HTTP Request for Commit Root objects (only ids of children)
void UServerTransport::CopyObjectAndChildren(const FString& ObjectId,
TScriptInterface<ITransport> TargetTransport,
const FTransportCopyObjectCompleteDelegate& OnCompleteAction,
@@ -64,8 +78,7 @@ void UServerTransport::CopyObjectAndChildren(const FString& ObjectId,
Request->SetURL(Endpoint);
Request->SetHeader("Accept", TEXT("text/plain"));
Request->SetHeader("Authorization", "Bearer " + AuthToken);
// Response Callback
auto ResponseHandler = [=](FHttpRequestPtr, FHttpResponsePtr Response, bool bWasSuccessful) mutable
{
@@ -85,7 +98,6 @@ void UServerTransport::CopyObjectAndChildren(const FString& ObjectId,
}
HandleRootObjectResponse(Response->GetContentAsString(), TargetTransport, ObjectId);
};
Request->OnProcessRequestComplete().BindLambda(ResponseHandler);
@@ -103,15 +115,16 @@ void UServerTransport::CopyObjectAndChildren(const FString& ObjectId,
FAnalytics::TrackEvent("unknown", ServerUrl, "Receive");
}
void UServerTransport::FetchChildren(TScriptInterface<ITransport> TargetTransport, const FString& ObjectId, const TArray<FString>& ChildrenIds, int32 CStart) const
// Fetch Children JSON and parse it
void UServerTransport::FetchChildren(TScriptInterface<ITransport> TargetTransport, const FString& ObjectId,
const TArray<FString>& ChildrenIds, int32 CStart) const
{
// Check if all children have been fetched
if(ChildrenIds.Num() <= CStart)
{
ensureAlwaysMsgf(this->OnComplete.ExecuteIfBound(TargetTransport->GetSpeckleObject(ObjectId)), TEXT("Complete handler was not bound properly"));
UE_LOG(LogSpeckle, Log, TEXT("----------->PJSON < CSTART <-----------"));
ensureAlwaysMsgf(this->OnComplete.ExecuteIfBound(TargetTransport->GetSpeckleObject(ObjectId)),
TEXT("Complete handler was not bound properly"));
return;
}
@@ -154,30 +167,39 @@ void UServerTransport::FetchChildren(TScriptInterface<ITransport> TargetTranspor
// Response Callback
auto ResponseHandler = [=](FHttpRequestPtr, FHttpResponsePtr Response, bool bWasSuccessful) mutable
{
// Any Fail
if(!bWasSuccessful)
{
FString Message = FString::Printf(TEXT("Request for children of root object %s/%s failed: %s"), *StreamId, *ObjectId, *Response->GetContentAsString());
InvokeOnError(Message);
return;
}
const int32 ResponseCode = Response->GetResponseCode();
if (ResponseCode != 200)
{
FString Message = FString::Printf(TEXT("Request for children of root object %s/%s failed:\nHTTP response %d"), *StreamId, *ObjectId, ResponseCode);
FString Message = FString::Printf(TEXT("Request for children of root object %s/%s failed: %s"),
*StreamId, *ObjectId, *Response->GetContentAsString());
InvokeOnError(Message);
return;
}
// Any HTTP Fail
const int32 ResponseCode = Response->GetResponseCode();
if (ResponseCode != 200)
{
FString Message = FString::Printf(
TEXT("Request for children of root object %s/%s failed:\nHTTP response %d"),
*StreamId, *ObjectId, ResponseCode);
InvokeOnError(Message);
return;
}
// Success: Start parsing
TArray<FString> Lines;
const int32 LineCount = SplitLines(Response->GetContentAsString(), Lines);
UE_LOG(LogSpeckle, Verbose, TEXT("Parsing %d downloaded objects..."), LineCount)
// Warning: Less objects then expected
if(LineCount != CEnd - CStart)
{
UE_LOG(LogSpeckle, Warning, TEXT("Requested %d objects, but recieved %d"), CEnd - CStart, LineCount);
UE_LOG(LogSpeckle, Warning, TEXT("Requested %d objects, but received %d"), CEnd - CStart, LineCount);
}
// Load JSON as objects
for (const FString& Line : Lines)
{
FString Id, ObjectJson;
@@ -187,14 +209,13 @@ void UServerTransport::FetchChildren(TScriptInterface<ITransport> TargetTranspor
TSharedPtr<FJsonObject> JsonObject;
if(!LoadJson(ObjectJson, JsonObject)) continue;
TargetTransport->SaveObject(Id, JsonObject);
}
UE_LOG(LogSpeckle, Log, TEXT("Processed %d/%d Child objects"), CEnd, ChildrenIds.Num())
//Iterate again for any missing children
FetchChildren(TargetTransport, ObjectId, ChildrenIds , CEnd);
FetchChildren(TargetTransport, ObjectId, ChildrenIds, CEnd);
};
Request->OnProcessRequestComplete().BindLambda(ResponseHandler);
@@ -208,36 +229,15 @@ void UServerTransport::FetchChildren(TScriptInterface<ITransport> TargetTranspor
InvokeOnError(Message);
return;
}
UE_LOG(LogSpeckle, Verbose, TEXT("Requesting %d child objects"), CEnd - CStart);
}
void UServerTransport::HandleRootObjectResponse(const FString& RootObjSerialized, TScriptInterface<ITransport> TargetTransport, const FString& ObjectId) const
void UServerTransport::InvokeOnError(FString& Message) const
{
TSharedPtr<FJsonObject> RootObj;
if(!LoadJson(RootObjSerialized, RootObj))
{
FString Message = FString::Printf( TEXT("A Root Object %s was recieved but was invalid and could not be deserialied"), *ObjectId);
InvokeOnError(Message);
return;
}
TargetTransport->SaveObject(ObjectId, RootObj);
// Find children are not already in the target transport
const auto Closures = RootObj->GetObjectField("__closure")->Values;
TArray<FString> ChildrenIds;
Closures.GetKeys(ChildrenIds);
TArray<FString> NewChildrenIds;
for(const FString& Id : ChildrenIds)
{
if(TargetTransport->HasObject(Id)) continue;
NewChildrenIds.Add(Id);
}
FetchChildren(TargetTransport, ObjectId, NewChildrenIds);
ensureAlwaysMsgf(this->OnError.ExecuteIfBound(Message), TEXT("ServerTransport: Unhandled error - %s"), *Message);
}
int32 UServerTransport::SplitLines(const FString& Content, TArray<FString>& OutLines)
@@ -251,14 +251,9 @@ int32 UServerTransport::SplitLines(const FString& Content, TArray<FString>& OutL
return LineCount;
}
bool UServerTransport::LoadJson(const FString& ObjectJson, TSharedPtr<FJsonObject>& OutJsonObject)
bool UServerTransport::LoadJson(const FString& StringJson, TSharedPtr<FJsonObject>& OutJsonObject)
{
TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(ObjectJson);
TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(StringJson);
return FJsonSerializer::Deserialize(Reader, OutJsonObject);
}
void UServerTransport::InvokeOnError(FString& Message) const
{
ensureAlwaysMsgf(this->OnError.ExecuteIfBound(Message), TEXT("ServerTransport: Unhandled error - %s"), *Message);
}
-29
View File
@@ -1,29 +0,0 @@
// Copyright 2022 AEC Systems, Licensed under the Apache License, Version 2.0
//#pragma once
//#include "CoreMinimal.h"
//#include "Client.generated.h"
//
// /**
// *
// */
// UCLASS()
// class SPECKLEUNREAL_API UClient : public UClass
// {
// GENERATED_BODY()
//
// public:
//
// static int DefaultBranchLimit = 10;
//
// //UFUNCTION(BlueprintCallable, Category="Speckle")
// //void GetAccounts();
//
// //UFUNCTION(BlueprintCallable, Category="Speckle")
// //Branch StreamGetBranches(FString StreamID, int BranchesLimit = DefaultBranchLimit, int CommitLimit = DefaultBranchLimit);
//
//
// };
@@ -0,0 +1,80 @@
// Copyright 2022 AEC Systems, Licensed under the Apache License, Version 2.0
#pragma once
#include "Interfaces/IHttpRequest.h"
struct FSpeckleStream;
struct FSpeckleBranch;
struct FSpeckleCommit;
struct FSpeckleGlobals;
struct FSpeckleUser;
DECLARE_DELEGATE_OneParam(FErrorDelegate, const FString&);
DECLARE_DELEGATE_OneParam(FFetchStreamDelegate, const TArray<FSpeckleStream>&);
DECLARE_DELEGATE_OneParam(FFetchBranchDelegate, const TArray<FSpeckleBranch>&);
DECLARE_DELEGATE_OneParam(FFetchCommitDelegate, const TArray<FSpeckleCommit>&);
DECLARE_DELEGATE_OneParam(FFetchGlobalsDelegate, const FSpeckleGlobals&);
DECLARE_DELEGATE_OneParam(FFetchUserDelegate, const FSpeckleUser&);
/**
* C++ wrapper for GraphQL requests
* See Operations to use with blueprint
*/
class FClientAPI
{
public:
static void StreamsGet( const FString& ServerUrl,
const FString& AuthToken,
const int32 Limit,
const FFetchStreamDelegate OnCompleteAction,
const FErrorDelegate OnErrorAction);
static void StreamGetBranches( const FString& ServerUrl,
const FString& AuthToken,
const FString& StreamId,
const int32 Limit,
const FFetchBranchDelegate OnCompleteAction,
const FErrorDelegate OnErrorAction);
static void StreamGetCommits( const FString& ServerUrl,
const FString& AuthToken,
const FString& StreamId,
const FString& BranchName,
const int32 Limit,
const FFetchCommitDelegate OnCompleteAction,
const FErrorDelegate OnErrorAction);
static void FetchGlobals( const FString& ServerUrl,
const FString& AuthToken,
const FString& StreamId,
const FString& ReferencedObjectId,
const FFetchGlobalsDelegate OnCompleteAction,
const FErrorDelegate OnErrorAction);
static void FetchUserData( const FString& ServerUrl,
const FString& AuthToken,
const FFetchUserDelegate OnCompleteAction,
const FErrorDelegate OnErrorAction);
//Utility functions
static FHttpRequestRef CreateGraphQLRequest(const FString& ServerUrl, FString AuthToken, const FString& PostPayload,
const FString& Encoding = TEXT("gzip"));
static bool SendGraphQLRequest(const FHttpRequestRef Request, const FString& RequestName, const TFunctionRef<void(const FString& Message)> OnErrorAction);
static bool GetResponseAsJSON(const FHttpResponsePtr Response, const FString& RequestLogName, TSharedPtr<FJsonObject>& OutObject, const TFunctionRef<void(const FString& Message)> OnErrorAction);
static bool CheckForOperationErrors(const TSharedPtr<FJsonObject> GraphQLResponse, FString& OutErrorMessage);
static bool CheckRequestFailed(bool bWasSuccessful, FHttpResponsePtr Response, const FString& RequestName, const TFunctionRef<void(const FString& Message)> OnErrorAction);
};
@@ -0,0 +1,48 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Kismet/BlueprintAsyncActionBase.h"
#include "Objects/HighLevel/SpeckleBranch.h"
#include "ReceiveBranchesOperation.generated.h"
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FReceiveBranchesOperationHandler,
const TArray<FSpeckleBranch>&, Branches,
const FString&, ErrorMessage);
/**
* Receive All streams
*/
UCLASS()
class SPECKLEUNREAL_API UReceiveBranchesOperation : public UBlueprintAsyncActionBase
{
GENERATED_BODY()
public:
UPROPERTY(BlueprintAssignable)
FReceiveBranchesOperationHandler OnReceiveSuccessfully;
UPROPERTY(BlueprintAssignable)
FReceiveBranchesOperationHandler OnError;
UFUNCTION(BlueprintCallable, BlueprintInternalUseOnly, Category = "Speckle|Operations", meta = (WorldContext = "WorldContextObject"))
static UReceiveBranchesOperation* ReceiveBranchesOperation(UObject* WorldContextObject,
const FString& ServerUrl, const FString& AuthToken, const FString& StreamId, int32 Limit = 20);
virtual void Activate() override;
protected:
void Request();
FString ServerUrl;
FString AuthToken;
FString StreamId;
int32 Limit;
void HandleReceive(const TArray<FSpeckleBranch>& Branches);
void HandleError(const FString& Message);
};
@@ -0,0 +1,53 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Kismet/BlueprintAsyncActionBase.h"
#include "Objects/HighLevel/SpeckleCommit.h"
#include "ReceiveCommitsOperation.generated.h"
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FReceiveCommitsOperationHandler, const TArray<FSpeckleCommit>&, Commits, FString, ErrorMessage);
/**
* Receive All Commits
*/
UCLASS()
class SPECKLEUNREAL_API UReceiveCommitsOperation : public UBlueprintAsyncActionBase
{
GENERATED_BODY()
public:
UPROPERTY(BlueprintAssignable)
FReceiveCommitsOperationHandler OnReceiveSuccessfully;
UPROPERTY(BlueprintAssignable)
FReceiveCommitsOperationHandler OnError;
UFUNCTION(BlueprintCallable, BlueprintInternalUseOnly, Category = "Speckle|Operations",
meta = (WorldContext = "WorldContextObject", BranchName = "main"))
static UReceiveCommitsOperation* ReceiveCommitsOperation(UObject* WorldContextObject,
const FString& ServerUrl,
const FString& AuthToken,
const FString& StreamId,
const FString& BranchName,
const int32 Limit = 20);
virtual void Activate() override;
protected:
void Request();
FString ServerUrl;
FString AuthToken;
FString StreamId;
FString BranchName;
int32 Limit;
void HandleReceive(const TArray<FSpeckleCommit>& Commits);
void HandleError(const FString& Message);
};
@@ -0,0 +1,48 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Kismet/BlueprintAsyncActionBase.h"
#include "Objects/HighLevel/SpeckleGlobals.h"
#include "ReceiveGlobalsOperation.generated.h"
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FReceiveGlobalsOperationHandler, const FSpeckleGlobals, Globals, FString, ErrorMessage);
/**
* Receive My User Data in Speckle
*/
UCLASS()
class SPECKLEUNREAL_API UReceiveGlobalsOperation : public UBlueprintAsyncActionBase
{
GENERATED_BODY()
public:
UPROPERTY(BlueprintAssignable)
FReceiveGlobalsOperationHandler OnReceiveSuccessfully;
UPROPERTY(BlueprintAssignable)
FReceiveGlobalsOperationHandler OnError;
UFUNCTION(BlueprintCallable, BlueprintInternalUseOnly, Category = "Speckle|Operations", meta = (WorldContext = "WorldContextObject"))
static UReceiveGlobalsOperation* ReceiveGlobalsOperation(UObject* WorldContextObject,
const FString& ServerUrl, const FString& AuthToken,
const FString& StreamId, const FString& ReferencedObjectId);
virtual void Activate() override;
protected:
void Request();
FString ServerUrl;
FString AuthToken;
FString StreamId;
FString ReferencedObjectId;
void HandleReceive(const FSpeckleGlobals& Object);
void HandleError(const FString& Message);
};
@@ -0,0 +1,49 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Kismet/BlueprintAsyncActionBase.h"
#include "Objects/HighLevel/SpeckleUser.h"
#include "ReceiveMyUserDataOperation.generated.h"
struct FSpeckleUser;
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FReceiveMyUserDataOperationHandler, const FSpeckleUser, MyUserData, FString, ErrorMessage);
/**
* Receive My User Data in Speckle
*/
UCLASS()
class SPECKLEUNREAL_API UReceiveMyUserDataOperation : public UBlueprintAsyncActionBase
{
GENERATED_BODY()
public:
UPROPERTY(BlueprintAssignable)
FReceiveMyUserDataOperationHandler OnReceiveSuccessfully;
UPROPERTY(BlueprintAssignable)
FReceiveMyUserDataOperationHandler OnError;
UFUNCTION(BlueprintCallable, BlueprintInternalUseOnly, Category = "Speckle|Operations",
meta = (WorldContext = "WorldContextObject"))
static UReceiveMyUserDataOperation* ReceiveMyUserDataOperation(UObject* WorldContextObject,
const FString& ServerUrl, const FString& AuthToken);
virtual void Activate() override;
protected:
void Request();
FString ServerUrl;
FString AuthToken;
void HandleReceive(const FSpeckleUser& Object);
void HandleError(const FString& Message);
};
@@ -39,7 +39,8 @@ public:
FRecieveOperationHandler OnError;
UFUNCTION(BlueprintCallable, BlueprintInternalUseOnly, Category = "Speckle|Operations", meta = (WorldContext = "WorldContextObject"))
static UReceiveOperation* ReceiveOperation(UObject* WorldContextObject, const FString& ObjectId, TScriptInterface<ITransport> RemoteTransport, TScriptInterface<ITransport> LocalTransport);
static UReceiveOperation* ReceiveOperation(UObject* WorldContextObject, const FString& ObjectId,
TScriptInterface<ITransport> RemoteTransport, TScriptInterface<ITransport> LocalTransport);
virtual void Activate() override;
@@ -0,0 +1,44 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Kismet/BlueprintAsyncActionBase.h"
#include "Objects/HighLevel/SpeckleStream.h"
#include "ReceiveStreamsOperation.generated.h"
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FReceiveStreamsOperationHandler, const TArray<FSpeckleStream>&, Streams, FString, ErrorMessage);
/**
* Receive All streams
*/
UCLASS()
class SPECKLEUNREAL_API UReceiveStreamsOperation : public UBlueprintAsyncActionBase
{
GENERATED_BODY()
public:
UPROPERTY(BlueprintAssignable)
FReceiveStreamsOperationHandler OnReceiveSuccessfully;
UPROPERTY(BlueprintAssignable)
FReceiveStreamsOperationHandler OnError;
UFUNCTION(BlueprintCallable, BlueprintInternalUseOnly, Category = "Speckle|Operations", meta = (WorldContext = "WorldContextObject"))
static UReceiveStreamsOperation* ReceiveStreamsOperation(UObject* WorldContextObject, const FString& ServerUrl, const FString& AuthToken, const int32 Limit = 20);
virtual void Activate() override;
protected:
void Request();
FString ServerUrl;
FString AuthToken;
int32 Limit;
void HandleReceive(const TArray<FSpeckleStream>& Streams);
void HandleError(const FString& Message);
};
@@ -1,48 +1,47 @@
// Copyright 2022 AEC Systems, Licensed under the Apache License, Version 2.0
#pragma once
#include "CoreMinimal.h"
#include "Kismet/BlueprintAsyncActionBase.h"
#include "SendOperation.generated.h"
class ITransport;
class UBase;
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FSendOperationHandler, const FString&, Id, const FString&, ErrorMessage);
/**
*
*/
UCLASS()
class SPECKLEUNREAL_API USendOperation : public UBlueprintAsyncActionBase
{
GENERATED_BODY()
public:
UPROPERTY(BlueprintAssignable)
FSendOperationHandler OnSendSuccessfully;
UPROPERTY(BlueprintAssignable)
FSendOperationHandler OnErrorAction;
UFUNCTION(BlueprintCallable, Category = "Speckle|Operations", meta = (WorldContext = "WorldContextObject"))
static USendOperation* SendOperation(UObject* WorldContextObject, UBase* Base, TArray<TScriptInterface<ITransport>> Transports);
virtual void Activate() override;
void Send();
protected:
TWeakObjectPtr<UBase> Base;
TArray<TScriptInterface<ITransport>> Transports;
};
// // Copyright 2022 AEC Systems, Licensed under the Apache License, Version 2.0
//
// #pragma once
//
// #include "CoreMinimal.h"
// #include "Kismet/BlueprintAsyncActionBase.h"
//
// #include "SendOperation.generated.h"
//
//
// class ITransport;
// class UBase;
//
// DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FSendOperationHandler, const FString&, Id, const FString&, ErrorMessage);
//
// /**
// *
// */
// UCLASS()
// class SPECKLEUNREAL_API USendOperation : public UBlueprintAsyncActionBase
// {
// GENERATED_BODY()
//
// public:
//
// UPROPERTY(BlueprintAssignable)
// FSendOperationHandler OnSendSuccessfully;
//
//
// UPROPERTY(BlueprintAssignable)
// FSendOperationHandler OnErrorAction;
//
//
// UFUNCTION(BlueprintCallable, Category = "Speckle|Operations", meta = (WorldContext = "WorldContextObject"))
// static USendOperation* SendOperation(UObject* WorldContextObject, UBase* Base, TArray<TScriptInterface<ITransport>> Transports);
//
// virtual void Activate() override;
//
// protected:
//
//
// TWeakObjectPtr<UBase> Base;
//
// TScriptArray<TScriptInterface<ITransport>> Transports;
//
//
// };
@@ -5,6 +5,7 @@
#include "CoreMinimal.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "SpeckleSerializer.generated.h"
class UBase;
@@ -21,6 +22,5 @@ public:
static UBase* DeserializeBaseById(const FString& ObjectId, const TScriptInterface<ITransport> ReadTransport);
static UBase* DeserializeBase(const TSharedPtr<FJsonObject> Obj, const TScriptInterface<ITransport> ReadTransport);
};
@@ -36,7 +36,7 @@ public:
virtual bool CanConvertToNative_Implementation(TSubclassOf<UBase> BaseType) override;
virtual void ConvertToSpeckle_Implementation(const UObject* Object, UBase* SpeckleObject) override;
virtual UBase* ConvertToSpeckle_Implementation(const UObject* Object) override;
UFUNCTION(BlueprintCallable, Category="Speckle|Conversion")
@@ -41,7 +41,9 @@ public:
// Sets default values for this actor's properties
UProceduralMeshConverter();
virtual UObject* ConvertToNative_Implementation(const UBase* SpeckleBase, UWorld* World, TScriptInterface<ISpeckleConverter>& AvailableConverters) override;
virtual UObject* ConvertToNative_Implementation(const UBase* SpeckleBase, UWorld* World,
TScriptInterface<ISpeckleConverter>& AvailableConverters) override;
virtual UBase* ConvertToSpeckle_Implementation(const UObject* Object) override;
UFUNCTION(BlueprintCallable, Category="ToNative")
@@ -50,6 +52,7 @@ public:
UFUNCTION(BlueprintCallable, Category="ToNative")
virtual UMesh* MeshToSpeckle(const UProceduralMeshComponent* Object);
virtual AActor* CreateEmptyActor(UWorld* World, const FTransform& Transform, const FActorSpawnParameters& SpawnParameters = FActorSpawnParameters());
virtual AActor* CreateEmptyActor(UWorld* World, const FTransform& Transform,
const FActorSpawnParameters& SpawnParameters = FActorSpawnParameters());
};
@@ -76,7 +76,7 @@ public:
UStaticMeshConverter();
virtual UObject* ConvertToNative_Implementation(const UBase* SpeckleBase, UWorld* World, TScriptInterface<ISpeckleConverter>& AvailableConverters) override;
virtual void ConvertToSpeckle_Implementation(const UObject* Object, UBase* SpeckleObject) override;
virtual UBase* ConvertToSpeckle_Implementation(const UObject* Object) override;
virtual void FinishConversion_Implementation() override;
// Converts a multiple Speckle Meshes to a native actor of type MeshActorType
@@ -91,7 +91,7 @@ public:
FActorSpawnParameters());
UFUNCTION(BlueprintCallable, Category="ToSpeckle")
virtual TArray<UMesh*> MeshToSpeckle(const UStaticMeshComponent* Object);
virtual UBase* MeshToSpeckle(const UStaticMeshComponent* Object);
protected:
@@ -34,22 +34,13 @@ public:
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category="ToNative")
UObject* ConvertToNative(const UBase* SpeckleBase, UWorld* World, UPARAM(ref) TScriptInterface<ISpeckleConverter>& AvailableConverters);
/// Clean up cached resources, and finish any pending build tasks to complete ToNative conversion.
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category="ToNative")
void FinishConversion();
/// Will return true if this converter can convert a given
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category="ToSpeckle")
void CanConvertToSpeckle(const AActor* Actor);
/// Tries to convert a given Actor or Component into a Speckle Base
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category="ToSpeckle")
void ConvertToSpeckle(const UObject* Object, UBase* SpeckleObject);
UBase* ConvertToSpeckle(const UObject* Object);
/// Clean up any cached assets that now may be unused
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category="ToNative")
void FinishConversion();
};
@@ -4,10 +4,10 @@
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "Objects/HighLevel/SpeckleStream.h"
#include "SpeckleConverterComponent.generated.h"
DECLARE_DYNAMIC_DELEGATE_TwoParams(FActorPredicate, const AActor*, Actor, bool&, OutShouldConvert);
class ITransport;
class ISpeckleConverter;
@@ -31,27 +31,33 @@ public:
// Sets default values for this component's properties
USpeckleConverterComponent();
// Converts the given Base and all children into native actors.
UFUNCTION(BlueprintCallable, Category="Speckle|Conversion|ToNative")
UPARAM(DisplayName = "RootActor") AActor* RecursivelyConvertToNative(AActor* AOwner, const UBase* Base, const TScriptInterface<ITransport>& LocalTransport, bool DisplayProgressBar, TArray<AActor*>& OutActors);
UFUNCTION(BlueprintCallable, Category="Speckle|Conversion")
UPARAM(DisplayName = "RootActor") AActor* RecursivelyConvertToNative(AActor* AOwner, const UBase* Base,
const TScriptInterface<ITransport>& LocalTransport, bool DisplayProgressBar, TArray<AActor*>& OutActors);
UFUNCTION(BlueprintCallable, Category="Speckle|Conversion|ToNative")
// Converts the given Base and all children into native actors.
UFUNCTION(BlueprintCallable, Category="Speckle|Conversion")
UPARAM(DisplayName = "RootActor") TArray<FSpeckleStream> ConvertStreamsToNative(
AActor* AOwner,
const UBase* Base,
const TScriptInterface<ITransport>& LocalTransport,
bool DisplayProgressBar,
TArray<AActor*>& OutActors
);
UFUNCTION(BlueprintCallable, Category="Speckle|Conversion")
virtual void FinishConversion();
// Converts the given Base and all children into native actors.
UFUNCTION(BlueprintCallable, Category="Speckle|Conversion|ToSpeckle")
virtual UBase* RecursivelyConvertToSpeckle(const TArray<AActor*>& RootActors, FActorPredicate& Predicate);
UFUNCTION(BlueprintCallable, Category="Speckle|Conversion|ToSpeckle")
virtual void RecurseTreeToSpeckle(const AActor* RootActor, FActorPredicate& Predicate, TArray<UBase*>& OutConverted);
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Speckle|Conversion")
TArray<FSpeckleStream> ArrayOfStreams;
protected:
virtual AActor* RecursivelyConvertToNative_Internal(AActor* AOwner, const UBase* Base, const TScriptInterface<ITransport>& LocalTransport, FSlowTask* Task, TArray<AActor*>& OutActors);
virtual void ConvertChild(const TSharedPtr<FJsonValue> Object, AActor* AOwner, const TScriptInterface<ITransport>& LocalTransport, FSlowTask* Task, TArray<AActor*>& OutActors);
+2 -1
View File
@@ -15,6 +15,7 @@ protected:
public:
static void TrackEvent(const FString& Email, const FString& Server, const FString& EventName);
static void TrackEvent(const FString& Email, const FString& Server, const FString& EventName, const TMap<FString, FString>& CustomProperties);
static void TrackEvent(const FString& Email, const FString& Server, const FString& EventName,
const TMap<FString, FString>& CustomProperties);
static FString Hash(const FString& Input);
};
+34 -19
View File
@@ -3,7 +3,6 @@
#pragma once
#include "CoreMinimal.h"
#include "DynamicBase.h"
#include "Dom/JsonObject.h"
#include "Base.generated.h"
@@ -14,8 +13,8 @@ class ASpeckleUnrealManager;
/**
* Base type that all Object Models inherit from
*/
UCLASS(BlueprintType, meta=(ScriptName="Base (Speckle.Objects)"))
class SPECKLEUNREAL_API UBase : public UDynamicBase
UCLASS(BlueprintType)
class SPECKLEUNREAL_API UBase : public UObject
{
public:
@@ -23,7 +22,7 @@ public:
protected:
explicit UBase(const TCHAR* SpeckleType): SpeckleType(FString(SpeckleType)) {}
explicit UBase(const wchar_t* SpeckleType): SpeckleType(SpeckleType) {}
explicit UBase(const FString& SpeckleType) : SpeckleType(SpeckleType) {}
public:
@@ -34,6 +33,8 @@ public:
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category="Speckle|Objects")
FString Id;
TMap<FString, TSharedPtr<FJsonValue>> DynamicProperties; //TODO this won't be serialised!
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category="Speckle|Objects")
FString Units;
@@ -43,12 +44,7 @@ public:
virtual bool Parse(const TSharedPtr<FJsonObject> Obj, const TScriptInterface<ITransport> ReadTransport)
{
bool IsValid = false;
DynamicProperties.Reserve(Obj->Values.Num());
for(const auto kvp : Obj->Values)
{
SetDynamicProperty(kvp.Key, kvp.Value->Type);
}
DynamicProperties = Obj->Values;
if(Obj->TryGetStringField("id", Id))
{
IsValid = true;
@@ -61,18 +57,37 @@ public:
return IsValid;
}
protected:
virtual void ToJson(TJsonWriter<TCHAR, TCondensedJsonPrintPolicy<TCHAR>> Writer)
UFUNCTION(BlueprintCallable, Category="Speckle|Objects")
int32 RemoveDynamicProperty(UPARAM(ref) const FString& Key)
{
Writer.WriteValue(TEXT("units"), Units);
Writer.WriteValue(TEXT("speckle_type"), SpeckleType);
for(const auto& p : DynamicProperties)
{
//Writer.WriteValue(p.Key, p.Value.mmmmmm));
}
return DynamicProperties.Remove(Key);
}
public:
UFUNCTION(BlueprintCallable, Category="Speckle|Objects")
bool TryGetDynamicString(UPARAM(ref) const FString& Key, FString& OutString) const
{
const TSharedPtr<FJsonValue> Value = DynamicProperties.FindRef(Key);
if(Value == nullptr) return false;
return Value->TryGetString(OutString);
}
UFUNCTION(BlueprintCallable, Category="Speckle|Objects")
bool TryGetDynamicNumber(UPARAM(ref) const FString& Key, float& OutNumber) const
{
const TSharedPtr<FJsonValue> Value = DynamicProperties.FindRef(Key);
if(Value == nullptr) return false;
return Value->TryGetNumber(OutNumber);
}
UFUNCTION(BlueprintCallable, Category="Speckle|Objects")
bool TryGetDynamicBool(UPARAM(ref) const FString& Key, bool& OutBool) const
{
const TSharedPtr<FJsonValue> Value = DynamicProperties.FindRef(Key);
if(Value == nullptr) return false;
return Value->TryGetBool(OutBool);
}
};
@@ -13,7 +13,7 @@ class UMesh;
/**
*
*/
UCLASS()
UCLASS(meta=(ScriptName="Display Value Element (Speckle.Objects)"))
class SPECKLEUNREAL_API UDisplayValueElement : public UBase
{
GENERATED_BODY()
@@ -1,66 +0,0 @@
// Copyright AEC Systems Ltd
#pragma once
#include "CoreMinimal.h"
#include "UObject/Object.h"
#include "DynamicBase.generated.h"
class UBase;
/**
*
*/
UCLASS(Abstract)
class SPECKLEUNREAL_API UDynamicBase : public UObject
{
GENERATED_BODY()
protected:
TMap<FString, TSharedPtr<FVariant>> DynamicProperties;
public:
template <typename T>
bool TryGetDynamicProperty(const FString& Key, T& OutValue) const;
UFUNCTION(BlueprintCallable, Category="Speckle|Objects")
bool TryGetDynamicStringProperty(UPARAM(ref) const FString& Key, FString& OutValue) const;
UFUNCTION(BlueprintCallable, Category="Speckle|Objects")
bool TryGetDynamicIntProperty(UPARAM(ref) const FString& Key, int32& OutValue) const;
UFUNCTION(BlueprintCallable, Category="Speckle|Objects")
bool TryGetDynamicFloatProperty(UPARAM(ref) const FString& Key, float& OutValue) const;
UFUNCTION(BlueprintCallable, Category="Speckle|Objects")
bool TryGetDynamicBoolProperty(UPARAM(ref) const FString& Key, bool& OutValue) const;
UFUNCTION(BlueprintCallable, Category="Speckle|Objects")
bool TryGetDynamicBaseProperty(UPARAM(ref) const FString& Key, UBase*& OutValue) const;
template <typename T>
void SetDynamicProperty(const FString& Key, T Value);
UFUNCTION(BlueprintCallable, Category="Speckle|Objects")
void SetDynamicStringProperty(UPARAM(ref) const FString& Key, FString& OutValue);
UFUNCTION(BlueprintCallable, Category="Speckle|Objects")
void SetDynamicIntProperty(UPARAM(ref) const FString& Key, int32& OutValue);
UFUNCTION(BlueprintCallable, Category="Speckle|Objects")
void SetDynamicFloatProperty(UPARAM(ref) const FString& Key, float& OutValue);
UFUNCTION(BlueprintCallable, Category="Speckle|Objects")
void SetDynamicBoolProperty(UPARAM(ref) const FString& Key, bool& OutValue);
UFUNCTION(BlueprintCallable, Category="Speckle|Objects")
void SetDynamicBaseProperty(UPARAM(ref) const FString& Key, UBase*& OutValue);
UFUNCTION(BlueprintCallable, Category="Speckle|Objects")
int32 RemoveDynamicProperty(UPARAM(ref) const FString& Key);
};
@@ -0,0 +1,39 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Mesh.h"
#include "Objects/Base.h"
#include "Box.generated.h"
class UPlane;
/**
*
*/
UCLASS(meta=(ScriptName="Box (Speckle.Objects)"))
class SPECKLEUNREAL_API UBoxx : public UBase
{
GENERATED_BODY()
public:
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Speckle|Objects")
UPlane* BasePlane;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Speckle|Objects")
FVector2f XSize, YSize;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Speckle|Objects")
float Area;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Speckle|Objects")
float Volume;
virtual bool Parse(const TSharedPtr<FJsonObject> Obj, const TScriptInterface<ITransport> ReadTransport) override;
UFUNCTION(BlueprintCallable)
virtual UMesh* ToMesh(UObject* Outer = GetTransientPackage()) const;
};
@@ -12,7 +12,7 @@ class URenderMaterial;
/**
*
*/
UCLASS()
UCLASS(meta=(ScriptName="Mesh (Speckle.Objects)"))
class SPECKLEUNREAL_API UMesh : public UBase
{
GENERATED_BODY()
@@ -41,8 +41,6 @@ public:
virtual bool Parse(const TSharedPtr<FJsonObject> Obj, const TScriptInterface<ITransport> ReadTransport) override;
virtual void ToJson(TJsonWriter<TCHAR, TCondensedJsonPrintPolicy<TCHAR>> Writer) override;
protected:
virtual void AlignVerticesWithTexCoordsByIndex();
};
@@ -0,0 +1,25 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Objects/Base.h"
#include "Plane.generated.h"
/**
*
*/
UCLASS(meta=(ScriptName="Plane (Speckle.Objects)"))
class SPECKLEUNREAL_API UPlane : public UBase
{
GENERATED_BODY()
public:
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Speckle|Objects")
FVector Origin, Normal, XDir, YDir;
virtual bool Parse(const TSharedPtr<FJsonObject> Obj, const TScriptInterface<ITransport> ReadTransport) override;
};
@@ -10,7 +10,7 @@
/**
*
*/
UCLASS()
UCLASS(meta=(ScriptName="Point Cloud (Speckle.Objects)"))
class SPECKLEUNREAL_API UPointCloud : public UBase
{
GENERATED_BODY()
@@ -0,0 +1,44 @@
#pragma once
#include "CoreMinimal.h"
#include "FSpeckleActivity.generated.h"
/*
* Struct that holds all the properties required
* for the User Activities
* received from GraphQL.
*/
USTRUCT(BlueprintType)
struct FSpeckleActivity
{
GENERATED_USTRUCT_BODY()
UPROPERTY(BlueprintReadWrite)
FString ActionType;
UPROPERTY(BlueprintReadWrite)
FString Time;
UPROPERTY(BlueprintReadWrite)
FString Message;
UPROPERTY(BlueprintReadWrite)
FString StreamId;
UPROPERTY(BlueprintReadWrite)
FString ResourceType;
UPROPERTY(BlueprintReadWrite)
FString ResourceId;
UPROPERTY(BlueprintReadWrite)
FString Info;
FSpeckleActivity(){};
FSpeckleActivity(const FString& ActionType, const FString& Time, const FString& Message,
const FString& StreamId, const FString& ResourceType, const FString& ResourceId,
const FString& Info):
ActionType(ActionType), Time(Time), Message(Message), StreamId(StreamId),
ResourceType(ResourceType), ResourceId(ResourceId), Info(Info){}
};
@@ -0,0 +1,7 @@
#pragma once
#include "CoreMinimal.h"
#include "FSpeckleEnum.generated.h"
UENUM()
enum ESpeckleItemType {Stream, Commit, Branch};
@@ -0,0 +1,55 @@
#pragma once
#include "CoreMinimal.h"
#include "SpeckleCollaborator.h"
#include "SpeckleBranch.generated.h"
/*
* Struct that holds all the properties required
* from a speckle Branch
* received from GraphQL.
*/
USTRUCT(BlueprintType)
struct FSpeckleBranch
{
GENERATED_BODY()
UPROPERTY(BlueprintReadWrite, Category="Speckle|API Models")
FString ID;
UPROPERTY(BlueprintReadWrite, Category="Speckle|API Models")
FString Name;
UPROPERTY(BlueprintReadWrite, Category="Speckle|API Models")
FString Description;
UPROPERTY(BlueprintReadWrite, Category="Speckle|API Models")
FString Author;
UPROPERTY(BlueprintReadWrite, Category="Speckle|API Models")
FString Commits;
void DisplayAsString(const FString& msg, const TSharedPtr<FJsonObject> Obj) const
{
FString OutputString;
TSharedRef< TJsonWriter<> > Writer = TJsonWriterFactory<>::Create(&OutputString);
FJsonSerializer::Serialize(Obj.ToSharedRef(), Writer);
UE_LOG(LogTemp, Log, TEXT("resulting jsonString from %s -> %s"), *msg, *OutputString);
}
FSpeckleBranch(const TSharedPtr<FJsonObject> Obj)
{
ensureAlways(Obj->TryGetStringField("id", ID));
ensureAlways(Obj->TryGetStringField("name", Name));
Obj->TryGetStringField("description", Description);
}
FSpeckleBranch(){};
//
// FSpeckleBranch(const FString& ID, const FString& Name, const FString& Description):
// ID(ID), Name(Name), Description(Description){}
//
// FSpeckleBranch(const FString& ID, const FString& Name, const FString& Description, const FString& Author, const FString& Commits):
// ID(ID), Name(Name), Description(Description), Author(Author), Commits(Commits){}
};
@@ -0,0 +1,46 @@
#pragma once
#include "CoreMinimal.h"
#include "SpeckleCollaborator.generated.h"
/*
* Struct that holds all the properties required
* from a Collaborator in a Stream
* received from GraphQL.
* See https://github.com/specklesystems/speckle-sharp/blob/main/Core/Core/Api/GraphQL/Models.cs
*/
USTRUCT(BlueprintType)
struct FSpeckleCollaborator
{
GENERATED_BODY()
UPROPERTY(BlueprintReadWrite, Category="Speckle|API Models")
FString Id;
UPROPERTY(BlueprintReadWrite, Category="Speckle|API Models")
FString Name;
UPROPERTY(BlueprintReadWrite, Category="Speckle|API Models")
FString Role;
UPROPERTY(BlueprintReadWrite, Category="Speckle|API Models")
FString Avatar;
FSpeckleCollaborator() { }
FSpeckleCollaborator(const TSharedPtr<FJsonObject> JsonObject)
{
ensureAlways(JsonObject->TryGetStringField("id", Id));
ensureAlways(JsonObject->TryGetStringField("name", Name));
JsonObject->TryGetStringField("role", Role);
JsonObject->TryGetStringField("avatar", Avatar);
}
FSpeckleCollaborator(const FString& Id, const FString& Name, const FString& Company, const FString& Role, const FString& Avatar)
: Id(Id),
Name(Name),
Role(Role),
Avatar(Avatar)
{
}
};
@@ -0,0 +1,115 @@
#pragma once
#include "CoreMinimal.h"
#include "SpeckleCommit.generated.h"
/*
* Struct that holds all the properties required
* from a speckle commit
* received from GraphQL.
*/
USTRUCT(BlueprintType)
struct FSpeckleCommit
{
GENERATED_BODY()
UPROPERTY(BlueprintReadWrite, Category="Speckle|API Models")
FString ID;
UPROPERTY(BlueprintReadWrite, Category="Speckle|API Models")
FString Message;
UPROPERTY(BlueprintReadWrite, Category="Speckle|API Models")
FString BranchName;
UPROPERTY(BlueprintReadWrite, Category="Speckle|API Models")
FString AuthorName;
UPROPERTY(BlueprintReadWrite, Category="Speckle|API Models")
FString AuthorId;
UPROPERTY(BlueprintReadWrite, Category="Speckle|API Models")
FString AuthorAvatar;
UPROPERTY(BlueprintReadWrite, Category="Speckle|API Models")
FString CreatedAt;
UPROPERTY(BlueprintReadWrite, Category="Speckle|API Models")
FString SourceApplication;
UPROPERTY(BlueprintReadWrite, Category="Speckle|API Models")
FString ReferenceObjectID;
UPROPERTY(BlueprintReadWrite, Category="Speckle|API Models")
FString TotalChildrenCount;
UPROPERTY(BlueprintReadWrite, Category="Speckle|API Models")
TArray<FString> Parents;
UPROPERTY(BlueprintReadWrite, Category="Speckle|API Models")
FString CommentCount;
void DisplayAsString(const FString& msg, const TSharedPtr<FJsonObject> Obj) const
{
FString OutputString;
TSharedRef< TJsonWriter<> > Writer = TJsonWriterFactory<>::Create(&OutputString);
FJsonSerializer::Serialize(Obj.ToSharedRef(), Writer);
UE_LOG(LogTemp, Log, TEXT("resulting jsonString from %s -> %s"), *msg, *OutputString);
}
FSpeckleCommit(){};
FSpeckleCommit(const TSharedPtr<FJsonValue> CommitAsJSONValue)
{
TSharedPtr<FJsonObject> obj = CommitAsJSONValue->AsObject();
ensureAlways(obj->TryGetStringField("id", ID));
obj->TryGetStringField("message", Message);
obj->TryGetStringField("branchName", BranchName);
obj->TryGetStringField("authorName", AuthorName);
obj->TryGetStringField("authorId", AuthorId);
obj->TryGetStringField("authorAvatar", AuthorAvatar);
obj->TryGetStringField("createdAt", CreatedAt);
obj->TryGetStringField("sourceApplication", SourceApplication);
obj->TryGetStringField("totalChildrenCount", TotalChildrenCount);
ensureAlways(obj->TryGetStringField("referencedObject", ReferenceObjectID));
obj->TryGetStringArrayField("parents", Parents);
obj->TryGetStringField("commentCount", CommentCount); //TODO is this a prop?
}
// FSpeckleCommit(const FString& ReferenceObjectID, const FString& Author, const FString& Message, const FString& BranchName)
// : ReferenceObjectID(ReferenceObjectID),
// Author(Author),
// Message(Message),
// BranchName(BranchName)
// {
// }
// FSpeckleCommit(const FString& ReferenceObjectID, const FString& AuthorName, const FString& Message, const FString& BranchName,
// const FString& Id, const FString& SourceApplication, const FString& TotalChildrenCount, const FString& Parents,
// const FString& AuthorId, const FString& AuthorAvatar, const FString& CreatedAt)
// : ReferenceObjectID(ReferenceObjectID),
// Author(Author),
// Message(Message),
// BranchName(BranchName),
// ID(Id),
// SourceApplication(SourceApplication),
// TotalChildrenCount(TotalChildrenCount),
// Parents(Parents),
// AuthorId(AuthorId),
// AuthorAvatar(AuthorAvatar),
// CreatedAt(CreatedAt)
// {
// }
//Operators overloading
// FORCEINLINE bool operator==(const FSpeckleCommit &Other) const
// {
// return ReferenceObjectID == Other.ReferenceObjectID;
// }
};
@@ -0,0 +1,66 @@
#pragma once
#include "CoreMinimal.h"
#include "SpeckleGlobals.generated.h"
/*
* Struct that holds all the properties required
* from a speckle Branch
* received from GraphQL.
*/
USTRUCT(BlueprintType)
struct FSpeckleGlobals
{
GENERATED_USTRUCT_BODY()
UPROPERTY(BlueprintReadWrite)
FString ID;
UPROPERTY(BlueprintReadWrite)
FString Region;
UPROPERTY(BlueprintReadWrite)
float Latitude;
UPROPERTY(BlueprintReadWrite)
float Longitude;
UPROPERTY(BlueprintReadWrite)
float Height;
FSpeckleGlobals(): Latitude(0), Longitude(0), Height(0)
{
};
FSpeckleGlobals(const TSharedPtr<FJsonObject> GlobalsJSONObject)
{
ID = *GlobalsJSONObject->GetStringField("id");
//TArray<TSharedPtr<FJsonValue>> RegionAsArray = GlobalsJSONObject->GetArrayField("region");
Region = ""; // RegionAsArray[0]->AsString();
Latitude = static_cast<float>(GlobalsJSONObject->GetNumberField("Latitude"));
Longitude= static_cast<float>(GlobalsJSONObject->GetNumberField("Longitude"));
Height = static_cast<float>(GlobalsJSONObject->GetNumberField("Height"));
}
FSpeckleGlobals(const FString& ID, const FString& Region, float Latitude, float Longitude)
: ID(ID),
Region(Region),
Latitude(Latitude),
Longitude(Longitude)
{
}
FSpeckleGlobals(const FString& ID, const FString& Region, float Latitude, float Longitude, float Height)
: ID(ID),
Region(Region),
Latitude(Latitude),
Longitude(Longitude),
Height(Height)
{
}
};
@@ -0,0 +1,98 @@
#pragma once
#include "CoreMinimal.h"
#include "LogSpeckle.h"
#include "SpeckleCollaborator.h"
#include "SpeckleStream.generated.h"
/*
* Class that holds all the properties required
* from a speckle Branch
* received from GraphQL.
*/
USTRUCT(BlueprintType)
struct FSpeckleStream
{
GENERATED_BODY()
UPROPERTY(BlueprintReadWrite, Category="Speckle|API Models")
FString ID;
UPROPERTY(BlueprintReadWrite, Category="Speckle|API Models")
FString Name;
UPROPERTY(BlueprintReadWrite, Category="Speckle|API Models")
FString Description;
// UPROPERTY(BlueprintReadWrite)
// bool IsStreamPublic;
UPROPERTY(BlueprintReadWrite, Category="Speckle|API Models")
FString Role;
UPROPERTY(BlueprintReadWrite, Category="Speckle|API Models")
FString CreatedAt;
UPROPERTY(BlueprintReadWrite, Category="Speckle|API Models")
FString UpdatedAt;
UPROPERTY(BlueprintReadWrite, Category="Speckle|API Models")
TArray<FSpeckleCollaborator> Collaborators;
void DisplayAsString(const FString& msg, const TSharedPtr<FJsonObject> Obj) const
{
FString OutputString;
TSharedRef< TJsonWriter<> > Writer = TJsonWriterFactory<>::Create(&OutputString);
FJsonSerializer::Serialize(Obj.ToSharedRef(), Writer);
UE_LOG(LogTemp, Log, TEXT("resulting jsonString from %s -> %s"), *msg, *OutputString);
}
FSpeckleStream(const TSharedPtr<FJsonValue> StreamAsJSONValue)
{
TSharedPtr<FJsonObject> Obj = StreamAsJSONValue->AsObject();
//DisplayAsString("Collaborators insider --->", Obj);
ensureAlways(Obj->TryGetStringField("id", ID));
ensureAlways(Obj->TryGetStringField("name", Name));
Obj->TryGetStringField("description", Description);
Obj->TryGetStringField("updatedAt", UpdatedAt);
Obj->TryGetStringField("createdAt", CreatedAt);
Obj->TryGetStringField("role", Role);
const TArray<TSharedPtr<FJsonValue>>* CollaboratorsArrJSONValues;
Obj->TryGetArrayField("collaborators", CollaboratorsArrJSONValues);
for (const TSharedPtr<FJsonValue>& c : *CollaboratorsArrJSONValues)
{
const TSharedPtr<FJsonObject>* o;
if(ensure(c->TryGetObject(o)))
{
FSpeckleCollaborator Collaborator = FSpeckleCollaborator(*o);
Collaborators.Add(Collaborator);
}
}
}
FSpeckleStream(){};
//
// FSpeckleStream(const FString& ID, const FString& Name, const FString& Description):
// ID(ID), Name(Name), Description(Description){};
//
// FSpeckleStream( const FString& ID,
// const FString& Name,
// const FString& Description,
// const bool& IsPublic,
// const FString& Role,
// const FString& CreatedAt,
// const FString& UpdatedAt):
// ID(ID),
// Name(Name),
// Description(Description),
// IsPublic(IsPublic),
// Role(Role),
// CreatedAt(CreatedAt),
// UpdatedAt(UpdatedAt){}
};
@@ -0,0 +1,88 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "SpeckleUser.generated.h"
/*
* Struct that holds all the properties required
* for a User
* received from GraphQL.
*/
USTRUCT(BlueprintType)
struct FSpeckleUser
{
GENERATED_BODY()
UPROPERTY(BlueprintReadWrite, Category="Speckle|API Models")
FString Id;
UPROPERTY(BlueprintReadWrite, Category="Speckle|API Models")
FString Email;
UPROPERTY(BlueprintReadWrite, Category="Speckle|API Models")
FString Name;
UPROPERTY(BlueprintReadWrite, Category="Speckle|API Models")
FString Bio;
UPROPERTY(BlueprintReadWrite, Category="Speckle|API Models")
FString Company;
UPROPERTY(BlueprintReadWrite, Category="Speckle|API Models")
FString Avatar;
UPROPERTY(BlueprintReadWrite, Category="Speckle|API Models")
FString Suuid;
UPROPERTY(BlueprintReadWrite, Category="Speckle|API Models")
FString Role;
FSpeckleUser(){};
FString DisplayAsString(const FString& msg, const TSharedPtr<FJsonObject> Obj) const
{
FString OutputString;
TSharedRef<TJsonWriter<>> Writer = TJsonWriterFactory<>::Create(&OutputString);
FJsonSerializer::Serialize(Obj.ToSharedRef(), Writer);
UE_LOG(LogSpeckle, Log, TEXT("resulting jsonString from %s -> %s"), *msg, *OutputString);
}
FSpeckleUser(const TSharedPtr<FJsonObject> MyUserDataJSONObject)
{
ensureAlways(MyUserDataJSONObject->TryGetStringField("id", Id));
MyUserDataJSONObject->TryGetStringField("name", Name);
MyUserDataJSONObject->TryGetStringField("company", Company);
MyUserDataJSONObject->TryGetStringField("role", Role);
MyUserDataJSONObject->TryGetStringField("suuid", Suuid); //TODO Is this a prop?
MyUserDataJSONObject->TryGetStringField("email", Email);
MyUserDataJSONObject->TryGetStringField("bio", Bio);
MyUserDataJSONObject->TryGetStringField("avatar", Avatar);
}
//query{user{id,name,email,company,role,suuid,bio,profiles,avatar}}
FSpeckleUser(
const FString& Id,
const FString& Email,
const FString& Bio,
const FString& Company,
const FString& Name,
const FString& Avatar,
const FString& Suuid,
const FString& Role)
:
Id(Id),
Email(Email),
Name(Name),
Bio(Bio),
Company(Company),
Avatar(Avatar),
Suuid(Suuid),
Role(Role)
{}
};
@@ -10,7 +10,7 @@
/**
*
*/
UCLASS()
UCLASS(meta=(ScriptName="Block Instance (Speckle.Objects)"))
class SPECKLEUNREAL_API UBlockInstance : public UBase
{
GENERATED_BODY()
@@ -10,7 +10,7 @@
/**
*
*/
UCLASS()
UCLASS(meta=(ScriptName="Render Material (Speckle.Objects)"))
class SPECKLEUNREAL_API URenderMaterial : public UBase
{
GENERATED_BODY()
@@ -10,7 +10,7 @@
/**
*
*/
UCLASS()
UCLASS(meta=(ScriptName="View3D (Speckle.Objects)"))
class SPECKLEUNREAL_API UView3D : public UBase
{
GENERATED_BODY()
@@ -44,6 +44,6 @@ public:
UFUNCTION(BlueprintPure, Category="Speckle/ObjectUtils")
static FTransform CreateTransform(UPARAM(ref) const FMatrix& TransformMatrix);
UFUNCTION(BlueprintCallable, meta = (DeterminesOutputType = "Class"), Category="Speckle/ObjectUtils")
UFUNCTION(BlueprintCallable, Category="Speckle/ObjectUtils")
static AActor* SpawnActorInWorld(const TSubclassOf<AActor> Class, UWorld* World, UPARAM(ref) const FTransform& Transform);
};
@@ -59,6 +59,7 @@ public:
// Deletes the Actors created by the previous receive operation
UFUNCTION(BlueprintCallable, CallInEditor, Category="Speckle" , meta=(DisplayAfter="Receive"))
virtual void DeleteObjects();
virtual void BeginPlay() override;
@@ -20,11 +20,16 @@ class SPECKLEUNREAL_API UMemoryTransport : public UObject, public ITransport
public:
virtual TSharedPtr<FJsonObject> GetSpeckleObject(const FString& ObjectId) const override;
virtual void SaveObject(const FString& ObjectId, const FString& SerializedObject) override;
virtual void SaveObject(const FString& ObjectId, const TSharedPtr<FJsonObject> SerializedObject) override;
virtual bool HasObject(const FString& ObjectId) const override;
virtual void CopyObjectAndChildren(const FString& ObjectId, TScriptInterface<ITransport> TargetTransport, const FTransportCopyObjectCompleteDelegate& OnCompleteAction, const FTransportErrorDelegate& OnErrorAction) override { unimplemented(); }
virtual void CopyObjectAndChildren(const FString& ObjectId,
TScriptInterface<ITransport> TargetTransport,
const FTransportCopyObjectCompleteDelegate& OnCompleteAction,
const FTransportErrorDelegate& OnErrorAction) override { unimplemented(); }
UFUNCTION(BlueprintPure, Category = "Speckle|Transports")
static UMemoryTransport* CreateEmptyMemoryTransport()
{
@@ -4,10 +4,11 @@
#include "CoreMinimal.h"
#include "Transport.h"
#include "Objects/HighLevel/SpeckleStream.h"
#include "ServerTransport.generated.h"
class FBatchSender;
class FHttpModule;
// Data for graphQL request for object ids.
@@ -26,31 +27,52 @@ struct FObjectIdRequest
UCLASS(BlueprintType)
class SPECKLEUNREAL_API UServerTransport : public UObject, public ITransport
{
GENERATED_BODY()
GENERATED_BODY()
protected:
UPROPERTY()
FString ServerUrl;
UPROPERTY()
FString StreamId;
UPROPERTY(meta=(PasswordField))
FString AuthToken;
UPROPERTY()
int32 MaxNumberOfObjectsPerRequest = 20000;
UPROPERTY()
FString ResponseListOfStreamsSerialized = "";
UPROPERTY()
FString ResponseListOfBranchesSerialized = "";
UPROPERTY()
FString ResponseListOfCommitsSerialized = "";
UPROPERTY()
FString ResponseGlobalsSerialized = "";
UPROPERTY()
TArray<FSpeckleStream> ArrayOfStreams;
UPROPERTY()
TArray<FSpeckleStream> ArrayOfBranches;
FTransportCopyObjectCompleteDelegate OnComplete;
FTransportErrorDelegate OnError;
public:
virtual ~UServerTransport() override;
UFUNCTION(BlueprintPure, Category = "Speckle|Transports")
static UServerTransport* CreateServerTransport(UPARAM(ref) FString& _ServerUrl, UPARAM(ref) FString& _StreamId, UPARAM(ref) FString& _AuthToken)
static UServerTransport* CreateServerTransport(UPARAM(ref) FString& _ServerUrl,
UPARAM(ref) FString& _StreamId,
UPARAM(ref) FString& _AuthToken)
{
UServerTransport* Transport = NewObject<UServerTransport>();
Transport->ServerUrl = _ServerUrl;
@@ -60,21 +82,24 @@ public:
}
virtual TSharedPtr<FJsonObject> GetSpeckleObject(const FString& ObjectId) const override;
virtual void SaveObject(const FString& ObjectId, const TSharedPtr<FJsonObject> SerializedObject) override;
virtual void BeginWrite() override;
virtual void EndWrite() override;
virtual bool HasObject(const FString& ObjectId) const override;
virtual void CopyObjectAndChildren(const FString& ObjectId,
TScriptInterface<ITransport> TargetTransport,
const FTransportCopyObjectCompleteDelegate& OnCompleteAction,
const FTransportErrorDelegate& OnErrorAction) override;
TScriptInterface<ITransport> TargetTransport,
const FTransportCopyObjectCompleteDelegate& OnCompleteAction,
const FTransportErrorDelegate& OnErrorAction) override;
protected:
virtual void HandleRootObjectResponse(const FString& RootObjSerialized, TScriptInterface<ITransport> TargetTransport, const FString& ObjectId) const;
virtual void HandleRootObjectResponse(const FString& RootObjSerialized,
TScriptInterface<ITransport> TargetTransport,
const FString& ObjectId) const;
//
// virtual void HandleListOfStreamsResponse(const FString& RootObjSerialized,
// TScriptInterface<ITransport> TargetTransport
// );
/**
* Iteratively fetches chunks of children
@@ -91,13 +116,8 @@ protected:
virtual void InvokeOnError(FString& Message) const;
static bool LoadJson(const FString& ObjectJson, TSharedPtr<FJsonObject>& OutJsonObject);
static int32 SplitLines(const FString& Content, TArray<FString>& OutLines);
FBatchSender BatchSender;
// FCriticalSection Lock_SendBuffer;
// TArray<TTuple<const FString, const FString>> SendBuffer;
// FRunnableThread* SendingThread;
static int32 SplitLines(const FString& Content, TArray<FString>& OutLines);
};
@@ -5,11 +5,14 @@
#include "CoreMinimal.h"
#include "UObject/Interface.h"
#include "Dom/JsonObject.h"
#include "Objects/HighLevel/SpeckleStream.h"
#include "Transport.generated.h"
DECLARE_DELEGATE_OneParam(FTransportCopyObjectCompleteDelegate, TSharedPtr<FJsonObject>);
DECLARE_DELEGATE_OneParam(FTransportErrorDelegate, FString&);
DECLARE_DELEGATE_OneParam(FStreamsRequestProcessedDelegate, const TArray<FSpeckleStream>&);
//DECLARE_DELEGATE_OneParam(FTransportTotalChildrenCountKnownDelegate, int32);
//DECLARE_DELEGATE_OneParam(FTransportProgressDelegate, int32);
@@ -28,20 +31,21 @@ class SPECKLEUNREAL_API ITransport
GENERATED_BODY()
public:
//TODO consider changing SerializedObject to FString&
virtual void SaveObject(const FString& ObjectId, const TSharedPtr<FJsonObject> SerializedObject) = 0;
FString ResponseListOfStreamsSerialized = "";
virtual void SaveObject(const FString& ObjectId, const TSharedPtr<FJsonObject> SerializedObject) = 0;
//virtual void SaveObjectFromTransport(FString& ObjectID, TScriptInterface<ITransport> SourceTransport) = 0;
virtual TSharedPtr<FJsonObject> GetSpeckleObject(const FString& ObjectId) const = 0;
virtual bool HasObject(const FString& ObjectId) const;
virtual void BeginWrite();
virtual void EndWrite();
virtual bool HasObject(const FString& ObjectId) const = 0;
virtual void CopyObjectAndChildren(const FString& ObjectId,
TScriptInterface<ITransport> TargetTransport,
const FTransportCopyObjectCompleteDelegate& OnCompleteAction,
const FTransportErrorDelegate& OnErrorAction) = 0;
TScriptInterface<ITransport> TargetTransport,
const FTransportCopyObjectCompleteDelegate& OnCompleteAction,
const FTransportErrorDelegate& OnErrorAction) = 0;
};
+1 -1
View File
@@ -32,7 +32,7 @@ public class SpeckleUnreal : ModuleRules
"ProceduralMeshComponent",
"MeshDescription",
"StaticMeshDescription",
"LidarPointCloudRuntime",
"LidarPointCloudRuntime"
// ... add other public dependencies that you statically link with here ...
}
);
+2 -2
View File
@@ -1,8 +1,8 @@
{
"FileVersion": 3,
"Version": 1,
"VersionName": "2.5.2",
"FriendlyName": "Speckle Unreal",
"VersionName": "2.5.1",
"FriendlyName": "SpeckleUnreal",
"Description": "Speckle is an open source data platform for Architecture, Engineering, and Construction. It has been open sourced under the MIT license, is customizable, and available in the cloud or via a self-hosted server. It allows users to exchange data between various AEC modelling and content creation platforms.",
"Category": "AEC",
"CreatedBy": "Speckle",