Merge from Release-Engine-Test @ 16758890 to UE5/Main

This represents UE4/Main @ 16738161 and Dev-PerfTest @ 16737719 (and Release-17.00 @ 16658211)

[CL 16763350 by aurel cordonnier in ue5-main branch]
This commit is contained in:
aurel cordonnier
2021-06-23 17:51:32 -04:00
parent 0d7a7d4e5d
commit d17d20ca36
27594 changed files with 146950 additions and 4625614 deletions

View File

@@ -8,8 +8,6 @@
#if WITH_EDITOR
#include "IMessageLogListing.h"
#include "MessageLogModule.h"
#else
#include "Widgets/SNullWidget.h"
#endif
#define LOCTEXT_NAMESPACE "RemoteControlLogger"
@@ -28,18 +26,6 @@ FRemoteControlLogger::FRemoteControlLogger()
LogOptions.MaxPageCount = 1;
MessageLogListing = MessageLogModule.CreateLogListing("Remote control logging", LogOptions);
// Create widget
LogListingWidget = MessageLogModule.CreateLogListingWidget(MessageLogListing.ToSharedRef());
#endif
}
TSharedRef<SWidget> FRemoteControlLogger::GetWidget() const
{
#if WITH_EDITOR
return LogListingWidget.ToSharedRef();
#else
return SNullWidget::NullWidget;
#endif
}

View File

@@ -28,6 +28,7 @@
#include "Editor.h"
#include "EngineAnalytics.h"
#include "Engine/Blueprint.h"
#include "ScopedTransaction.h"
#include "TimerManager.h"
#endif
@@ -35,7 +36,7 @@ URemoteControlPreset::FOnPostLoadRemoteControlPreset URemoteControlPreset::OnPos
#define LOCTEXT_NAMESPACE "RemoteControlPreset"
static TAutoConsoleVariable<int32> CVarRemoteControlFramesBetweenPropertyWatch(TEXT("RemoteControl.FramesBetweenPropertyWatch"), 30, TEXT("The number of frames between every property value comparison when manually watching for property changes."));
static TAutoConsoleVariable<int32> CVarRemoteControlFramesBetweenPropertyWatch(TEXT("RemoteControl.FramesBetweenPropertyWatch"), 5, TEXT("The number of frames between every property value comparison when manually watching for property changes."));
namespace
{
@@ -497,6 +498,7 @@ TOptional<FRemoteControlFunction> FRemoteControlTarget::GetFunction(FGuid Functi
return Field;
}
PRAGMA_DISABLE_DEPRECATION_WARNINGS
TOptional<FExposedProperty> FRemoteControlTarget::ResolveExposedProperty(FGuid PropertyId) const
{
TOptional<FExposedProperty> OptionalExposedProperty;
@@ -517,7 +519,9 @@ TOptional<FExposedProperty> FRemoteControlTarget::ResolveExposedProperty(FGuid P
return OptionalExposedProperty;
}
PRAGMA_ENABLE_DEPRECATION_WARNINGS
PRAGMA_DISABLE_DEPRECATION_WARNINGS
TOptional<FExposedFunction> FRemoteControlTarget::ResolveExposedFunction(FGuid FunctionId) const
{
TOptional<FExposedFunction> OptionalExposedFunction;
@@ -533,6 +537,7 @@ TOptional<FExposedFunction> FRemoteControlTarget::ResolveExposedFunction(FGuid F
return OptionalExposedFunction;
}
PRAGMA_ENABLE_DEPRECATION_WARNINGS
TArray<UObject*> FRemoteControlTarget::ResolveBoundObjects() const
{
@@ -600,6 +605,7 @@ bool FRemoteControlTarget::CanBindObjects(const TArray<UObject*>& ObjectsToTest)
return OwnersCommonBase && OwnersCommonBase->IsChildOf(Class);
}
PRAGMA_DISABLE_DEPRECATION_WARNINGS
FProperty* FRemoteControlTarget::FindPropertyRecursive(UStruct* Container, TArray<FString>& DesiredPropertyPath) const
{
if (DesiredPropertyPath.Num() <= 0)
@@ -630,6 +636,7 @@ FProperty* FRemoteControlTarget::FindPropertyRecursive(UStruct* Container, TArra
return nullptr;
}
PRAGMA_ENABLE_DEPRECATION_WARNINGS
URemoteControlPreset::URemoteControlPreset()
: Layout(FRemoteControlPresetLayout{ this })
@@ -740,7 +747,6 @@ TWeakPtr<FRemoteControlProperty> URemoteControlPreset::ExposeProperty(UObject* O
FieldName = FieldPath.GetFieldName().ToString();
#endif
FName DesiredName = *Args.Label;
if (DesiredName == NAME_None)
@@ -764,6 +770,30 @@ TWeakPtr<FRemoteControlProperty> URemoteControlPreset::ExposeProperty(UObject* O
DesiredName = *FString::Printf(TEXT("%s (%s)"), *FieldName, *ObjectName);
}
#if WITH_EDITOR
// Enable property if it has an edit condition.
const FString EditConditionPropertyName = Property->GetMetaData("EditCondition");
if (!EditConditionPropertyName.IsEmpty())
{
FRCFieldPathInfo EditConditionPropertyPath = FieldPath;
EditConditionPropertyPath.Segments.Pop();
EditConditionPropertyPath.Segments.Emplace(EditConditionPropertyName);
if (EditConditionPropertyPath.Resolve(Object))
{
FRCFieldResolvedData Data = EditConditionPropertyPath.GetResolvedData();
if (ensure(Data.IsValid() && Data.Field->IsA(FBoolProperty::StaticClass())))
{
if (!Data.Field->HasAnyPropertyFlags(CPF_EditConst))
{
const FScopedTransaction Transaction(FText::Format(LOCTEXT("SetEditConditionState", "Set {0} edit condition state "), FText::FromString(FieldName)));
Object->Modify();
CastFieldChecked<FBoolProperty>(Data.Field)->SetPropertyValue_InContainer(Data.ContainerAddress, true);
}
}
}
}
#endif
FRemoteControlProperty RCProperty{ this, Registry->GenerateUniqueLabel(DesiredName), MoveTemp(FieldPath), { FindOrAddBinding(Object) } };
TSharedPtr<FRemoteControlProperty> RCPropertyPtr = StaticCastSharedPtr<FRemoteControlProperty>(Expose(MoveTemp(RCProperty), FRemoteControlProperty::StaticStruct(), Args.GroupId));
@@ -1054,6 +1084,7 @@ void URemoteControlPreset::RenameField(FName OldFieldLabel, FName NewFieldLabel)
RenameExposedEntity(GetExposedEntityId(OldFieldLabel), NewFieldLabel);
}
PRAGMA_DISABLE_DEPRECATION_WARNINGS
TOptional<FExposedProperty> URemoteControlPreset::ResolveExposedProperty(FName PropertyLabel) const
{
TOptional<FExposedProperty> OptionalExposedProperty;
@@ -1066,7 +1097,9 @@ TOptional<FExposedProperty> URemoteControlPreset::ResolveExposedProperty(FName P
return OptionalExposedProperty;
}
PRAGMA_ENABLE_DEPRECATION_WARNINGS
PRAGMA_DISABLE_DEPRECATION_WARNINGS
TOptional<FExposedFunction> URemoteControlPreset::ResolveExposedFunction(FName FunctionLabel) const
{
TOptional<FExposedFunction> OptionalExposedFunction;
@@ -1080,6 +1113,7 @@ TOptional<FExposedFunction> URemoteControlPreset::ResolveExposedFunction(FName F
return OptionalExposedFunction;
}
PRAGMA_ENABLE_DEPRECATION_WARNINGS
void URemoteControlPreset::Unexpose(FName EntityLabel)
{
@@ -1107,6 +1141,7 @@ FName URemoteControlPreset::CreateTarget(const TArray<UObject*>& TargetObjects)
PRAGMA_ENABLE_DEPRECATION_WARNINGS
}
PRAGMA_DISABLE_DEPRECATION_WARNINGS
FRemoteControlTarget& URemoteControlPreset::CreateAndGetTarget(const TArray<UObject*>& TargetObjects)
{
check(TargetObjects.Num() != 0);
@@ -1125,9 +1160,11 @@ FRemoteControlTarget& URemoteControlPreset::CreateAndGetTarget(const TArray<UObj
return RemoteControlTargets.Add(Alias, MoveTemp(Target));
}
PRAGMA_ENABLE_DEPRECATION_WARNINGS
void URemoteControlPreset::DeleteTarget(FName TargetName)
{
PRAGMA_DISABLE_DEPRECATION_WARNINGS
if (FRemoteControlTarget* Target = RemoteControlTargets.Find(TargetName))
{
for (auto It = Target->ExposedProperties.CreateConstIterator(); It; ++It)
@@ -1137,14 +1174,17 @@ void URemoteControlPreset::DeleteTarget(FName TargetName)
}
RemoteControlTargets.Remove(TargetName);
PRAGMA_ENABLE_DEPRECATION_WARNINGS
}
void URemoteControlPreset::RenameTarget(FName TargetName, FName NewTargetName)
{
PRAGMA_DISABLE_DEPRECATION_WARNINGS
FRemoteControlTarget Target;
RemoteControlTargets.RemoveAndCopyValue(TargetName, Target);
Target.Alias = NewTargetName;
RemoteControlTargets.Add(NewTargetName, MoveTemp(Target));
PRAGMA_ENABLE_DEPRECATION_WARNINGS
}
void URemoteControlPreset::CacheLayoutData()
@@ -1217,6 +1257,7 @@ FRemoteControlField* URemoteControlPreset::GetFieldPtr(FGuid FieldId)
void URemoteControlPreset::ConvertFieldsToRemoveComponentChain()
{
PRAGMA_DISABLE_DEPRECATION_WARNINGS
#if WITH_EDITOR
CacheFieldsData();
@@ -1280,9 +1321,7 @@ void URemoteControlPreset::ConvertFieldsToRemoveComponentChain()
if (!DestinationTarget)
{
PRAGMA_DISABLE_DEPRECATION_WARNINGS
DestinationTarget = &CreateAndGetTarget({ ObjectMapEntry.Key });
PRAGMA_ENABLE_DEPRECATION_WARNINGS
}
MovePropertiesToTarget(MoveTemp(ObjectMapEntry.Value), *DestinationTarget);
@@ -1304,12 +1343,14 @@ void URemoteControlPreset::ConvertFieldsToRemoveComponentChain()
RegroupPropertiesInTargets(GroupPropertiesByObjects());
RemoveEmptyTargets();
#endif
PRAGMA_ENABLE_DEPRECATION_WARNINGS
}
void URemoteControlPreset::ConvertFieldsToEntities()
{
#if WITH_EDITOR
// Convert properties and functions to inherit from FRemoteControlEntities while preserving their old data.
PRAGMA_DISABLE_DEPRECATION_WARNINGS
for (TTuple<FName, FRemoteControlTarget>& Tuple : RemoteControlTargets)
{
for (FRemoteControlProperty& Property : Tuple.Value.ExposedProperties)
@@ -1322,6 +1363,7 @@ void URemoteControlPreset::ConvertFieldsToEntities()
Function.Owner = this;
}
}
PRAGMA_ENABLE_DEPRECATION_WARNINGS
#endif
}
@@ -1329,6 +1371,7 @@ void URemoteControlPreset::ConvertTargetsToBindings()
{
#if WITH_EDITOR
// Convert targets to bindings, and put everything in the registry.
PRAGMA_DISABLE_DEPRECATION_WARNINGS
for (TTuple<FName, FRemoteControlTarget>& Tuple : RemoteControlTargets)
{
TArray<URemoteControlBinding*> NewBindings;
@@ -1362,6 +1405,7 @@ void URemoteControlPreset::ConvertTargetsToBindings()
{
RCActor->Bindings = { FindOrAddBinding(TSoftObjectPtr<UObject>{ RCActor->Path }) };
}
PRAGMA_ENABLE_DEPRECATION_WARNINGS
#endif
}
@@ -1520,6 +1564,7 @@ void URemoteControlPreset::CacheFieldsData()
return;
}
PRAGMA_DISABLE_DEPRECATION_WARNINGS
for (TTuple<FName, FRemoteControlTarget>& Target : RemoteControlTargets)
{
FieldCache.Reserve(FieldCache.Num() + Target.Value.ExposedProperties.Num() + Target.Value.ExposedFunctions.Num());
@@ -1533,6 +1578,7 @@ void URemoteControlPreset::CacheFieldsData()
Algo::ForEach(Target.Value.ExposedProperties, CacheField);
Algo::ForEach(Target.Value.ExposedFunctions, CacheField);
}
PRAGMA_ENABLE_DEPRECATION_WARNINGS
}
void URemoteControlPreset::CacheFieldLayoutData()
@@ -1550,30 +1596,48 @@ void URemoteControlPreset::OnObjectPropertyChanged(UObject* Object, struct FProp
{
// Objects modified should have run through the preobjectmodified. If interesting, they will be cached
TRACE_CPUPROFILER_EVENT_SCOPE(URemoteControlPreset::OnObjectPropertyChanged);
for (auto Iter = PreObjectsModifiedCache.CreateIterator(); Iter; ++Iter)
if (Event.Property == nullptr)
{
FGuid& PropertyId = Iter.Key();
FPreObjectsModifiedCache& CacheEntry = Iter.Value();
if (CacheEntry.Objects.Contains(Object)
&& CacheEntry.Property == Event.Property)
if(Event.MemberProperty == nullptr)
{
if (TSharedPtr<FRemoteControlProperty> Property = Registry->GetExposedEntity<FRemoteControlProperty>(PropertyId))
// When no property is passed to OnObjectPropertyChanged (such as by LevelSnapshot->Restore()), let's assume they all changed since we don't have more context.
for (TSharedPtr<FRemoteControlProperty> Property : Registry->GetExposedEntities<FRemoteControlProperty>())
{
UE_LOG(LogRemoteControl, VeryVerbose, TEXT("(%s) Change detected on %s::%s"), *GetName(), *Object->GetName(), *Event.Property->GetName());
PerFrameModifiedProperties.Add(Property->GetId());
Iter.RemoveCurrent();
if (Property->GetBoundObjects().Contains(Object))
{
PerFrameModifiedProperties.Add(Property->GetId());
}
}
}
}
else
{
for (auto Iter = PreObjectsModifiedCache.CreateIterator(); Iter; ++Iter)
{
FGuid& PropertyId = Iter.Key();
FPreObjectsModifiedCache& CacheEntry = Iter.Value();
if (CacheEntry.Objects.Contains(Object)
&& CacheEntry.Property == Event.Property)
{
if (TSharedPtr<FRemoteControlProperty> Property = Registry->GetExposedEntity<FRemoteControlProperty>(PropertyId))
{
UE_LOG(LogRemoteControl, VeryVerbose, TEXT("(%s) Change detected on %s::%s"), *GetName(), *Object->GetName(), *Event.Property->GetName());
PerFrameModifiedProperties.Add(Property->GetId());
Iter.RemoveCurrent();
}
}
}
}
for (auto Iter = PreObjectsModifiedActorCache.CreateIterator(); Iter; ++Iter)
{
FGuid& ActorId = Iter.Key();
FPreObjectsModifiedCache& CacheEntry = Iter.Value();
if (CacheEntry.Objects.Contains(Object)
&& CacheEntry.Property == Event.Property)
&& CacheEntry.Property == Event.Property)
{
if (TSharedPtr<FRemoteControlActor> RCActor = GetExposedEntity<FRemoteControlActor>(ActorId).Pin())
{
@@ -1673,6 +1737,33 @@ void URemoteControlPreset::OnPreObjectPropertyChanged(UObject* Object, const cla
}
}
void URemoteControlPreset::OnPostPropertyModifiedRemotely(const FRCObjectReference& ObjectRef)
{
TRACE_CPUPROFILER_EVENT_SCOPE(URemoteControlPreset::OnPostPropertyModifiedRemotely);
if (!ObjectRef.Property.IsValid())
{
return;
}
uint32 ModifiedPropertyPathHash = ObjectRef.PropertyPathInfo.PathHash;
for (const TSharedPtr<FRemoteControlProperty>& RCProperty : Registry->GetExposedEntities<FRemoteControlProperty>())
{
if (RCProperty->FieldPathInfo.PathHash == ModifiedPropertyPathHash && RCProperty->GetBoundObjects().Contains(ObjectRef.Object.Get()))
{
PerFrameModifiedProperties.Add(RCProperty->GetId());
}
}
for (const TSharedPtr<FRemoteControlActor>& RCActor : Registry->GetExposedEntities<FRemoteControlActor>())
{
if (RCActor->GetBoundObjects().Contains(ObjectRef.Object.Get()))
{
OnActorPropertyModified().Broadcast(this, *RCActor, ObjectRef.Object.Get(), ObjectRef.Property.Get());
}
}
}
void URemoteControlPreset::RegisterDelegates()
{
UnregisterDelegates();
@@ -1695,10 +1786,15 @@ void URemoteControlPreset::RegisterDelegates()
FCoreDelegates::OnBeginFrame.AddUObject(this, &URemoteControlPreset::OnBeginFrame);
FCoreDelegates::OnEndFrame.AddUObject(this, &URemoteControlPreset::OnEndFrame);
IRemoteControlModule::Get().OnPostPropertyModifiedRemotely().AddUObject(this, &URemoteControlPreset::OnPostPropertyModifiedRemotely);
}
void URemoteControlPreset::UnregisterDelegates()
{
if (FModuleManager::Get().IsModuleLoaded("RemoteControl"))
{
IRemoteControlModule::Get().OnPostPropertyModifiedRemotely().RemoveAll(this);
}
FCoreDelegates::OnBeginFrame.RemoveAll(this);
FCoreDelegates::OnEndFrame.RemoveAll(this);
@@ -1807,6 +1903,11 @@ void URemoteControlPreset::OnReplaceObjects(const TMap<UObject*, UObject*>& Repl
{
for (TWeakObjectPtr<URemoteControlBinding> Binding : Entity->Bindings)
{
if (!Binding.IsValid())
{
continue;
}
if (ModifiedBindings.Contains(Binding.Get()) || ReplacementObjectMap.FindKey(Binding->Resolve()))
{
PerFrameUpdatedEntities.Add(Entity->GetId());

View File

@@ -2,21 +2,65 @@
#pragma once
#include "CoreMinimal.h"
#include "RemoteControlTestData.generated.h"
USTRUCT(BlueprintType)
struct FRemoteControlTestStruct
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, Category = "RC")
bool bSomeBool = true;
UPROPERTY(EditAnywhere, Category = "RC")
uint32 SomeUInt32 = 45;
UPROPERTY(EditAnywhere, Category = "RC")
float SomeFloat = 49.0f;
UPROPERTY(EditAnywhere, Category = "RC")
FVector SomeVector = {0.2f, 0.3f, 0.6f};
UPROPERTY(EditAnywhere, Category = "RC")
FRotator SomeRotator = FRotator::ZeroRotator;
UPROPERTY(EditAnywhere, Category = "RC", meta = (ClampMin = 20, ClampMax = 145))
int32 SomeClampedInt = 5;
UPROPERTY(EditAnywhere, Category = "RC", meta = (ClampMin = 0.2f, ClampMax = 0.92f))
float SomeClampedFloat = 0.25f;
};
USTRUCT()
struct FRemoteControlTestInnerStruct
{
GENERATED_BODY()
FRemoteControlTestInnerStruct() {}
FRemoteControlTestInnerStruct()
{
FloatArray.Add(10.0f);
FloatArray.Add(104.01f);
FloatArray.Add(-9.04f);
// VectorArray.Add({0.5f, 0.6f, 15.05f});
// VectorArray.Add({-45.5f, 55.0f, 98.1f});
ArrayOfVectors.Add({1.0f, 1.0f, 1.0f});
}
FRemoteControlTestInnerStruct(uint8 Index)
: Color(FColor(Index, Index, Index, Index))
{}
{
}
UPROPERTY()
FColor Color = FColor(1,2,3,4 );
UPROPERTY()
TArray<float> FloatArray;
UPROPERTY()
TArray<FVector> ArrayOfVectors;
};
UCLASS()
@@ -31,6 +75,7 @@ public:
{
CStyleIntArray[i] = i+1;
IntArray.Add(i+1);
FloatArray.Add((float)i+1);
IntSet.Add(i+1);
IntMap.Add(i, i+1);
IntInnerStructMap.Add((int32)i, FRemoteControlTestInnerStruct((uint8)i));
@@ -45,6 +90,9 @@ public:
UPROPERTY()
TArray<int32> IntArray;
UPROPERTY()
TArray<float> FloatArray;
UPROPERTY()
TSet<int32> IntSet;

View File

@@ -4,6 +4,10 @@
#include "Misc/AutomationTest.h"
#include "RemoteControlPreset.h"
#include "RemoteControlTestData.h"
#include "StructDeserializer.h"
#include "StructSerializer.h"
#include "Backends/CborStructDeserializerBackend.h"
#include "Backends/CborStructSerializerBackend.h"
#include "UObject/StrongObjectPtr.h"
#define PROP_NAME(Class, Name) GET_MEMBER_NAME_CHECKED(Class, Name)
@@ -97,6 +101,29 @@ bool FRemoteControlPresetIntegrationTest::RunTest(const FString& Parameters)
RemoteControlTest::TestExposeContainerElement(*this, GET_TEST_PROP(IntArray), FString::Printf(TEXT("%s.%s[0]"), *GET_TEST_PROP(IntArray)->GetName(), *GET_TEST_PROP(IntArray)->GetName()), true);
RemoteControlTest::TestExposeContainerElement(*this, GET_TEST_PROP(IntSet), FString::Printf(TEXT("%s.%s[0]"), *GET_TEST_PROP(IntSet)->GetName(), *GET_TEST_PROP(IntSet)->GetName()), true);
RemoteControlTest::TestExposeContainerElement(*this, GET_TEST_PROP(IntMap), FString::Printf(TEXT("%s.%s_Value[0]"), *GET_TEST_PROP(IntMap)->GetName(), *GET_TEST_PROP(IntMap)->GetName()), true);
{
FStructSerializerPolicies Policies;
Policies.MapSerialization = EStructSerializerMapPolicies::Array;
FStructDeserializerPolicies DeserializerPolicies;
DeserializerPolicies.MissingFields = EStructDeserializerErrorPolicies::Warning;
DeserializerPolicies.MapPolicies = EStructDeserializerMapPolicies::Array;
TArray<uint8> Buffer;
FMemoryReader Reader(Buffer);
FMemoryWriter Writer(Buffer);
FCborStructSerializerBackend SerializerBackend(Writer, EStructSerializerBackendFlags::Default);
FCborStructDeserializerBackend DeserializerBackend(Reader);
FRemoteControlTestInnerStruct TestStruct;
const FName Member = GET_MEMBER_NAME_CHECKED(FRemoteControlTestInnerStruct, ArrayOfVectors);
FProperty* Property = FindFProperty<FProperty>(FRemoteControlTestInnerStruct::StaticStruct(), Member);
FStructSerializer::SerializeElement(&TestStruct, Property, INDEX_NONE, SerializerBackend, Policies);
auto o = Buffer;
}
FProperty* RProperty = TBaseStructure<FColor>::Get()->FindPropertyByName(TEXT("R"));
// Test exposing map with array indexing

View File

@@ -14,7 +14,9 @@ REMOTECONTROL_API DECLARE_LOG_CATEGORY_EXTERN(LogRemoteControl, Log, All);
class IStructDeserializerBackend;
class IStructSerializerBackend;
class URemoteControlPreset;
PRAGMA_DISABLE_DEPRECATION_WARNINGS
struct FExposedProperty;
PRAGMA_ENABLE_DEPRECATION_WARNINGS
struct FRemoteControlProperty;
/**
@@ -24,6 +26,10 @@ struct FRemoteControlProperty;
*/
DECLARE_DELEGATE_RetVal_TwoParams(FString /*Value*/, FEntityMetadataInitializer, URemoteControlPreset* /*Preset*/, const FGuid& /*EntityId*/);
/**
* Delegate called after a property has been modified through SetObjectProperties..
*/
DECLARE_MULTICAST_DELEGATE_OneParam(FOnPostPropertyModifiedRemotely, const FRCObjectReference& /*ObjectRef*/);
/**
* Deserialize payload type for interception purposes
@@ -51,6 +57,11 @@ struct FRCCallReference
TWeakObjectPtr<UObject> Object;
TWeakObjectPtr<UFunction> Function;
friend uint32 GetTypeHash(const FRCCallReference& CallRef)
{
return CallRef.IsValid() ? HashCombine(GetTypeHash(CallRef.Object), GetTypeHash(CallRef.Function)) : 0;
}
};
/**
@@ -128,6 +139,11 @@ struct FRCObjectReference
return LHS.Object == RHS.Object && LHS.Property == RHS.Property && LHS.ContainerAdress == RHS.ContainerAdress;
}
friend uint32 GetTypeHash(const FRCObjectReference& ObjectReference)
{
return HashCombine(GetTypeHash(ObjectReference.Object), ObjectReference.PropertyPathInfo.PathHash);
}
/** Type of access on this object (read, write) */
ERCAccess Access = ERCAccess::NO_ACCESS;
@@ -262,14 +278,20 @@ public:
* Resolve the underlying function from a preset.
* @return the underlying function and objects that the property is exposed on.
*/
UE_DEPRECATED(4.27, "This function is deprecated, please resolve directly on the preset.")
PRAGMA_DISABLE_DEPRECATION_WARNINGS
virtual TOptional<struct FExposedFunction> ResolvePresetFunction(const FResolvePresetFieldArgs& Args) const = 0;
PRAGMA_ENABLE_DEPRECATION_WARNINGS
/**
* Resolve the underlying property from a preset.
* @return the underlying property and objects that the property is exposed on.
*/
UE_DEPRECATED(4.27, "This function is deprecated, please resolve directly on the preset.")
PRAGMA_DISABLE_DEPRECATION_WARNINGS
virtual TOptional<struct FExposedProperty> ResolvePresetProperty(const FResolvePresetFieldArgs& Args) const = 0;
PRAGMA_ENABLE_DEPRECATION_WARNINGS
/**
* Get a preset using its name.
* @arg PresetName name of the preset to resolve.
@@ -318,4 +340,9 @@ public:
* Returns whether the property can be modified through SetObjectProperties when running without an editor.
*/
virtual bool PropertySupportsRawModificationWithoutEditor(FProperty* Property) const = 0;
/**
* Returns the delegate called after a property is modified remotely.
*/
virtual FOnPostPropertyModifiedRemotely& OnPostPropertyModifiedRemotely() = 0;
};

View File

@@ -41,11 +41,6 @@ public:
FRemoteControlLogger();
virtual ~FRemoteControlLogger() = default;
/**
* Get Logger SWidget
*/
TSharedRef<SWidget> GetWidget() const;
/**
* Log the message
*
@@ -67,6 +62,11 @@ public:
/** Removes all messages from log */
void ClearLog() const;
#if WITH_EDITOR
/** Log listening interface */
TSharedPtr<IMessageLogListing> GetMessageLogListing() const { return MessageLogListing; }
#endif
private:
#if WITH_EDITOR
@@ -74,9 +74,6 @@ private:
TSharedPtr<IMessageLogListing> MessageLogListing;
#endif
/** Pointer to log widget */
TSharedPtr<SWidget> LogListingWidget;
/** Is the logger enabled */
bool bIsEnabled = false;
};

View File

@@ -56,6 +56,7 @@ struct FRCCachedFieldData
/**
* Holds an exposed property and owner objects.
*/
struct UE_DEPRECATED(4.27, "FExposedProperty is deprecated. Please use FRemoteControlProperty::GetBoundObjects to access an exposed property's owner objects.") FExposedProperty;
struct REMOTECONTROL_API FExposedProperty
{
bool IsValid() const
@@ -70,6 +71,7 @@ struct REMOTECONTROL_API FExposedProperty
/**
* Holds an exposed function, its default parameters and owner objects.
*/
struct UE_DEPRECATED(4.27, "FExposedFunction is deprecated. Please use FRemoteControlFunction::GetBoundObjects to access an exposed function's owner objects.") FExposedFunction;
struct REMOTECONTROL_API FExposedFunction
{
bool IsValid() const
@@ -265,6 +267,7 @@ private:
/**
* Represents objects grouped under a single alias that contain exposed functions and properties.
*/
struct UE_DEPRECATED(4.27, "FRemoteControlTarget is deprecated. Expose properties directly on a remote control preset instead.") FRemoteControlTarget;
USTRUCT()
struct REMOTECONTROL_API FRemoteControlTarget
{
@@ -338,14 +341,17 @@ public:
* @param PropertyLabel the label of the remote controlled property.
* @return The resolved exposed property if found.
*/
PRAGMA_DISABLE_DEPRECATION_WARNINGS
TOptional<FExposedProperty> ResolveExposedProperty(FGuid PropertyId) const;
PRAGMA_ENABLE_DEPRECATION_WARNINGS
/**
* Resolve a remote controlled function to its UFunction and owner objects.
* @param FunctionLabel the label of the remote controlled function.
* @return The resolved exposed function if found.
*/
PRAGMA_DISABLE_DEPRECATION_WARNINGS
TOptional<FExposedFunction> ResolveExposedFunction(FGuid FunctionId) const;
PRAGMA_ENABLE_DEPRECATION_WARNINGS
/**
* Resolve the target bindings to return the target's underlying objects.
@@ -464,14 +470,17 @@ public:
* Get this preset's targets.
*/
UE_DEPRECATED(4.27, "FRemoteControlTarget is deprecated, use URemoteControlPreset::Bindings instead.")
PRAGMA_DISABLE_DEPRECATION_WARNINGS
TMap<FName, FRemoteControlTarget>& GetRemoteControlTargets() { return RemoteControlTargets; }
PRAGMA_ENABLE_DEPRECATION_WARNINGS
/**
* Get this preset's targets.
*/
UE_DEPRECATED(4.27, "FRemoteControlTarget is deprecated, use URemoteControlPreset::Bindings instead.")
PRAGMA_DISABLE_DEPRECATION_WARNINGS
const TMap<FName, FRemoteControlTarget>& GetRemoteControlTargets() const { return RemoteControlTargets; }
PRAGMA_ENABLE_DEPRECATION_WARNINGS
/**
* Get the target that owns this exposed field.
*/
@@ -637,7 +646,9 @@ public:
* @return The resolved exposed property if found.
*/
UE_DEPRECATED(4.27, "Use FRemoteControlProperty::GetProperty and FRemoteControlProperty::ResolveFieldOwners instead.")
PRAGMA_DISABLE_DEPRECATION_WARNINGS
TOptional<FExposedProperty> ResolveExposedProperty(FName PropertyLabel) const;
PRAGMA_ENABLE_DEPRECATION_WARNINGS
/**
* Resolve a remote controlled function to its UFunction and owner objects.
@@ -646,7 +657,9 @@ public:
* @return The resolved exposed function if found.
*/
UE_DEPRECATED(4.27, "Use FRemoteControlFunction::ResolveFieldOwners instead.")
PRAGMA_DISABLE_DEPRECATION_WARNINGS
TOptional<FExposedFunction> ResolveExposedFunction(FName FunctionLabel) const;
PRAGMA_ENABLE_DEPRECATION_WARNINGS
/**
* Unexpose an entity from the preset.
@@ -676,7 +689,9 @@ public:
* @note A target must be created with at least one object and they must have a common base class.
*/
UE_DEPRECATED(4.27, "Targets are deprecated in favor of exposing directly on the preset. You do not need to create a target beforehand.")
PRAGMA_DISABLE_DEPRECATION_WARNINGS
FRemoteControlTarget& CreateAndGetTarget(const TArray<UObject*>& TargetObjects);
PRAGMA_ENABLE_DEPRECATION_WARNINGS
/**
* Remove a target from the preset.
@@ -786,6 +801,7 @@ private:
//~ Keep track of any property change to notify if one of the exposed property has changed
void OnObjectPropertyChanged(UObject* Object, struct FPropertyChangedEvent& Event);
void OnPreObjectPropertyChanged(UObject* Object, const class FEditPropertyChain& PropertyChain);
void OnPostPropertyModifiedRemotely(const FRCObjectReference& ObjectRef);
#if WITH_EDITOR
//~ Handle events that can incur bindings to be modified.
@@ -849,9 +865,11 @@ private:
UPROPERTY(AssetRegistrySearchable)
FGuid PresetId;
PRAGMA_DISABLE_DEPRECATION_WARNINGS
/** The mappings of alias to targets. */
UPROPERTY()
TMap<FName, FRemoteControlTarget> RemoteControlTargets;
PRAGMA_ENABLE_DEPRECATION_WARNINGS
/** The cache for information about an exposed field. */
UPROPERTY(Transient)
@@ -934,14 +952,16 @@ private:
TMap<FGuid, FRCPropertyWatcher> PropertyWatchers;
/** Frame counter for delaying property change checks. */
int8 PropertyChangeWatchFrameCounter = 0;
int32 PropertyChangeWatchFrameCounter = 0;
#if WITH_EDITOR
/** List of blueprints for which we have registered events. */
TSet<TWeakObjectPtr<UBlueprint>> BlueprintsWithRegisteredDelegates;
#endif
PRAGMA_DISABLE_DEPRECATION_WARNINGS
friend FRemoteControlTarget;
PRAGMA_ENABLE_DEPRECATION_WARNINGS
friend FRemoteControlPresetLayout;
friend FRemoteControlEntity;
};

View File

@@ -10,6 +10,8 @@ public class RemoteControl : ModuleRules
new string[] {
"Core",
"CoreUObject",
"Engine",
"RemoteControlCommon",
}
);
@@ -19,7 +21,6 @@ public class RemoteControl : ModuleRules
"Engine",
"RemoteControlInterception",
"Serialization",
"SlateCore"
}
);
@@ -27,12 +28,12 @@ public class RemoteControl : ModuleRules
{
PublicDependencyModuleNames.AddRange(
new string[] {
"RemoteControlCommon",
}
);
PrivateDependencyModuleNames.AddRange(
new string[] {
"AssetTools",
"DeveloperSettings",
"MessageLog",
"UnrealEd",

View File

@@ -10,8 +10,6 @@
#if WITH_EDITOR
template <>
bool RemoteControlPropertyUtilities::Deserialize<FProperty>(const FRCPropertyVariant& InSrc, FRCPropertyVariant& OutDst)
{

View File

@@ -268,10 +268,12 @@ namespace RemoteControlPropertyUtilities
/** Reads the raw data from InSrc and deserializes to OutDst. */
template <typename PropertyType>
typename TEnableIf<
TAnd<
TIsDerivedFrom<PropertyType, FProperty>,
TNot<TIsSame<PropertyType, FProperty>>,
TNot<TIsSame<PropertyType, FNumericProperty>>
TOr<
TAnd<
TIsDerivedFrom<PropertyType, FProperty>,
TNot<TIsSame<PropertyType, FProperty>>,
TNot<TIsSame<PropertyType, FNumericProperty>>>,
TIsSame<PropertyType, FEnumProperty>
>::Value, bool>::Type
Deserialize(const FRCPropertyVariant& InSrc, FRCPropertyVariant& OutDst)
{
@@ -281,23 +283,66 @@ namespace RemoteControlPropertyUtilities
checkf(SrcPropertyContainer != nullptr, TEXT("Deserialize requires Src to have a backing container."));
OutDst.Init(InSrc.Size()); // initializes only if necessary
ValueType* DstCurrentValue = OutDst.GetPropertyValue<ValueType>();
InSrc.GetProperty()->InitializeValue(DstCurrentValue);
const int32 SrcSize = InSrc.Size();
// The stored data size doesn't match, so cast
if(OutDst.GetProperty()->ElementSize != SrcSize)
{
if(const FNumericProperty* DstProperty = OutDst.GetProperty<FNumericProperty>())
{
// @note this only works for integers
if(DstProperty->IsInteger())
{
if(SrcSize == 1)
{
uint8* SrcValue = InSrc.GetPropertyValue<uint8>();
if(SrcValue)
{
DstProperty->SetIntPropertyValue(DstCurrentValue, static_cast<uint64>(*SrcValue));
return true;
}
}
else if(SrcSize == 2)
{
uint16* SrcValue = InSrc.GetPropertyValue<uint16>();
if(SrcValue)
{
DstProperty->SetIntPropertyValue(DstCurrentValue, static_cast<uint64>(*SrcValue));
return true;
}
}
else if(SrcSize == 4)
{
uint32* SrcValue = InSrc.GetPropertyValue<uint32>();
if(SrcValue)
{
DstProperty->SetIntPropertyValue(DstCurrentValue, static_cast<uint64>(*SrcValue));
return true;
}
}
}
}
}
FMemoryReader Reader(*SrcPropertyContainer);
InSrc.GetProperty()->SerializeItem(FStructuredArchiveFromArchive(Reader).GetSlot(), OutDst.GetPropertyData(), nullptr);
InSrc.GetProperty()->SerializeItem(FStructuredArchiveFromArchive(Reader).GetSlot(), DstCurrentValue, nullptr);
//OutDst.InferNum(&InSrc);
return false;
return true;
}
/** Reads the property value from InSrc and serializes to OutDst. */
template <typename PropertyType>
typename TEnableIf<
TAnd<
TIsDerivedFrom<PropertyType, FProperty>,
TNot<TIsSame<PropertyType, FProperty>>,
TNot<TIsSame<PropertyType, FNumericProperty>>
typename TEnableIf<
TOr<
TAnd<
TIsDerivedFrom<PropertyType, FProperty>,
TNot<TIsSame<PropertyType, FProperty>>,
TNot<TIsSame<PropertyType, FNumericProperty>>>,
TIsSame<PropertyType, FEnumProperty>
>::Value, bool>::Type
Serialize(const FRCPropertyVariant& InSrc, FRCPropertyVariant& OutDst)
{
@@ -306,10 +351,13 @@ namespace RemoteControlPropertyUtilities
ValueType* SrcValue = InSrc.GetPropertyValue<ValueType>();
TArray<uint8>* DstPropertyContainer = OutDst.GetPropertyContainer();
checkf(DstPropertyContainer != nullptr, TEXT("Serialize requires Src to have a backing container."));
checkf(DstPropertyContainer != nullptr, TEXT("Serialize requires Dst to have a backing container."));
DstPropertyContainer->Empty();
OutDst.Init(InSrc.GetProperty()->GetSize()); // initializes only if necessary
InSrc.GetProperty()->InitializeValue(DstPropertyContainer->GetData());
FMemoryWriter Writer(*DstPropertyContainer);
OutDst.Init(); // initializes only if necessary
OutDst.GetProperty()->SerializeItem(FStructuredArchiveFromArchive(Writer).GetSlot(), SrcValue, nullptr);
OutDst.InferNum(&InSrc);
@@ -317,6 +365,23 @@ namespace RemoteControlPropertyUtilities
return true;
}
/** Specialization for FStructProperty. */
template <>
inline bool Deserialize<FStructProperty>(const FRCPropertyVariant& InSrc, FRCPropertyVariant& OutDst)
{
TArray<uint8>* SrcPropertyContainer = InSrc.GetPropertyContainer();
checkf(SrcPropertyContainer != nullptr, TEXT("Deserialize requires Src to have a backing container."));
OutDst.Init(InSrc.Size()); // initializes only if necessary
void* DstCurrentValue = OutDst.GetPropertyValue<void>();
InSrc.GetProperty<FStructProperty>()->Struct->InitializeStruct(DstCurrentValue);
FMemoryReader Reader(*SrcPropertyContainer);
InSrc.GetProperty()->SerializeItem(FStructuredArchiveFromArchive(Reader).GetSlot(), DstCurrentValue, nullptr);
return true;
}
/** Specialization for FProperty casts and forwards to specializations. */
template <typename PropertyType>
typename TEnableIf<

View File

@@ -16,6 +16,7 @@ public class RemoteControlProtocol : ModuleRules
PrivateDependencyModuleNames.AddRange(
new string[] {
"Engine",
"RemoteControlCommon",
"RemoteControl",
}
);

View File

@@ -32,13 +32,12 @@ TRemoteControlProtocolCommandChange<ChangeArgsType>::TRemoteControlProtocolComma
, ChangeArgs(MoveTemp(InChangeArgs))
, OnApply(MoveTemp(InOnApply))
, OnRevert(MoveTemp(InOnRevert))
{
}
{}
template <typename ChangeArgsType>
void TRemoteControlProtocolCommandChange<ChangeArgsType>::Apply(UObject* InObject)
{
if(URemoteControlPreset* Preset = PresetPtr.Get())
if (URemoteControlPreset* Preset = PresetPtr.Get())
{
OnApply.ExecuteIfBound(Preset, ChangeArgs);
}
@@ -47,7 +46,7 @@ void TRemoteControlProtocolCommandChange<ChangeArgsType>::Apply(UObject* InObjec
template <typename ChangeArgsType>
void TRemoteControlProtocolCommandChange<ChangeArgsType>::Revert(UObject* InObject)
{
if(URemoteControlPreset* Preset = PresetPtr.Get())
if (URemoteControlPreset* Preset = PresetPtr.Get())
{
OnRevert.ExecuteIfBound(Preset, ChangeArgs);
}

View File

@@ -2,6 +2,10 @@
#include "RemoteControlProtocolWidgetsModule.h"
#include "IRemoteControlModule.h"
#include "IRemoteControlProtocol.h"
#include "IRemoteControlProtocolModule.h"
#include "IRemoteControlModule.h"
#include "RemoteControlPreset.h"
#include "ViewModels/ProtocolEntityViewModel.h"
#include "Widgets/SRCProtocolBindingList.h"
@@ -11,26 +15,26 @@ DEFINE_LOG_CATEGORY(LogRemoteControlProtocolWidgets);
TSharedRef<SWidget> FRemoteControlProtocolWidgetsModule::GenerateDetailsForEntity(URemoteControlPreset* InPreset, const FGuid& InFieldId, const EExposedFieldType& InFieldType)
{
check(InPreset);
ResetProtocolBindingList();
// Currently only supports Properties
if(InFieldId.IsValid() && InFieldType == EExposedFieldType::Property)
if (InFieldId.IsValid() && InFieldType == EExposedFieldType::Property)
{
return SAssignNew(RCProtocolBindingList, SRCProtocolBindingList, FProtocolEntityViewModel::Create(InPreset, InFieldId));
}
return SNullWidget::NullWidget;
}
IMPLEMENT_MODULE(FRemoteControlProtocolWidgetsModule, RemoteControlProtocolWidgets);
void FRemoteControlProtocolWidgetsModule::ResetProtocolBindingList()
{
RCProtocolBindingList = nullptr;
}
TSharedPtr<IRCProtocolBindingList> FRemoteControlProtocolWidgetsModule::GetProtocolBindingList() const
TSharedPtr<IRCProtocolBindingList> FRemoteControlProtocolWidgetsModule::GetProtocolBindingList() const
{
return RCProtocolBindingList;
}
}
IMPLEMENT_MODULE(FRemoteControlProtocolWidgetsModule, RemoteControlProtocolWidgets);

View File

@@ -3,6 +3,7 @@
#pragma once
#include "CoreMinimal.h"
#include "UObject/Object.h"
#include "RemoteControlProtocolWidgetsSettings.generated.h"
@@ -10,13 +11,17 @@
/**
* Remote Control Protocol Widget Settings
*/
UCLASS(Config = Engine, DefaultConfig)
UCLASS(Config = RemoteControlProtocolWidgets)
class REMOTECONTROLPROTOCOLWIDGETS_API URemoteControlProtocolWidgetsSettings : public UObject
{
GENERATED_BODY()
public:
/** Hidden protocol type name */
/** Protocol types to be hidden in the list view. */
UPROPERTY(Config, EditAnywhere, Category = Widgets)
TSet<FName> HiddenProtocolTypeNames;
/** Last protocol added. Used as default in the binding list. */
UPROPERTY(Config)
FName PreferredProtocol;
};

View File

@@ -1,4 +1,4 @@
// Copyright Epic Games, Inc. All Rights Reserved.
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
@@ -6,71 +6,112 @@
#include "EditorUndoClient.h"
#include "IRemoteControlProtocol.h"
#include "RCViewModelCommon.h"
#include "RemoteControlProtocolBinding.h"
#include "UObject/WeakFieldPtr.h"
class FProtocolEntityViewModel;
class FProtocolRangeViewModel;
struct FRemoteControlProtocolBinding;
class URemoteControlPreset;
struct FRemoteControlProtocolBinding;
namespace ProtocolBindingViewModel
{
/** Describes all possible validity states */
enum class EValidity : uint8
{
Unchecked = 0, /** Not yet checked */
Ok = 1, /** Valid */
InvalidChild = 2, /** There are one or more errors in child viewmodels */
DuplicateInput = 3, /** Input event/channel, etc. is the same as another protocol binding */
LessThanTwoRanges = 4, /** Two or more ranges are required */
};
}
/** Represents a single protocol binding for an entity */
class REMOTECONTROLPROTOCOLWIDGETS_API FProtocolBindingViewModel : public TSharedFromThis<FProtocolBindingViewModel>, public FEditorUndoClient
class REMOTECONTROLPROTOCOLWIDGETS_API FProtocolBindingViewModel
: public TSharedFromThis<FProtocolBindingViewModel>
, public FEditorUndoClient
, public TRCValidatableViewModel<ProtocolBindingViewModel::EValidity>
, public IRCTreeNodeViewModel
{
public:
/** Create a new ViewModel for the given Entity and Protocol Binding */
/** Create a new ViewModel for the given Entity and Protocol Binding. */
static TSharedRef<FProtocolBindingViewModel> Create(const TSharedRef<FProtocolEntityViewModel>& InParentViewModel, const TSharedRef<FRemoteControlProtocolBinding>& InBinding);
virtual ~FProtocolBindingViewModel();
virtual ~FProtocolBindingViewModel() override;
/** Add a new RangeMapping */
/** Add a new RangeMapping. */
FGuid AddRangeMapping();
/** Remove a RangeMapping by Id */
/** Remove a RangeMapping by Id. */
void RemoveRangeMapping(const FGuid& InId);
/** Creates default range mappings depending on the input and output types */
/** Removes all RangeMappings. */
void RemoveAllRangeMappings();
/** Creates default range mappings depending on the input and output types. */
void AddDefaultRangeMappings();
/** Get the Binding Id */
/** Get the Binding Id. */
const FGuid& GetId() const { return BindingId; }
/** Get the owning Preset. */
TWeakObjectPtr<URemoteControlPreset> GetPreset() const { return Preset; }
/** Get the bound FProperty. Should always be valid so long as the VM itself is valid. */
TWeakFieldPtr<FProperty> GetProperty() const { return Property; }
/** Get the underlying protocol binding instance */
/** Get the underlying protocol binding instance. */
FRemoteControlProtocolBinding* GetBinding() const;
/** Get the bound protocol */
/** Get the bound protocol. */
TSharedPtr<IRemoteControlProtocol> GetProtocol() const;
/** Get the bound protocol name as Text */
/** Get the bound protocol name as Text. */
FText GetProtocolName() const { return FText::FromName(GetBinding()->GetProtocolName()); }
/** Get the Range ViewModels */
/** Get the Range ViewModels. */
const TArray<TSharedPtr<FProtocolRangeViewModel>>& GetRanges() const { return Ranges; }
/** Get the underlying RangeMapping */
/** Get the underlying RangeMapping. */
FRemoteControlProtocolMapping* GetRangesMapping(const FGuid& InRangeId) const;
/** Removes this Protocol Binding */
/** Removes this Protocol Binding. */
void Remove() const;
bool IsValid() const { return Preset.IsValid() && PropertyId.IsValid() && BindingId.IsValid(); }
/** Get logical children of this ViewModel */
virtual bool GetChildren(TArray<TSharedPtr<IRCTreeNodeViewModel>>& OutChildren) override;
/** Checks (non-critical, fixable) validity */
virtual bool IsValid(FText& OutMessage) override;
/** Checks validity of this ViewModel */
bool IsValid() const;
public:
DECLARE_MULTICAST_DELEGATE_OneParam(FOnRangeMappingAdded, TSharedRef<FProtocolRangeViewModel> /* InRangeViewModel */);
DECLARE_MULTICAST_DELEGATE_OneParam(FOnRangeMappingRemoved, FGuid /* InRangeId */);
DECLARE_MULTICAST_DELEGATE(FOnRangeMappingsRemoved);
DECLARE_MULTICAST_DELEGATE(FOnChanged);
/** When single range mapping added. */
FOnRangeMappingAdded& OnRangeMappingAdded() { return OnRangeMappingAddedDelegate; }
/** When single range mapping removed. */
FOnRangeMappingRemoved& OnRangeMappingRemoved() { return OnRangeMappingRemovedDelegate; }
/** Something has changed within the ViewModel */
/** When all range mappings removed. */
FOnRangeMappingsRemoved& OnRangeMappingsRemoved() { return OnRangeMappingsRemovedDelegate; }
/** Something has changed within the ViewModel. */
FOnChanged& OnChanged() { return OnChangedDelegate; }
/** Allows the view to notify the ViewModel of a change (ie. from SDetailsView) */
void NotifyChanged() const;
private:
friend class FProtocolEntityViewModel;
// Private token only allows members or friends to call MakeShared
struct FPrivateToken { explicit FPrivateToken() = default; };
@@ -88,28 +129,40 @@ private:
virtual void PostRedo(bool bSuccess) override { PostUndo(bSuccess); }
// End of FEditorUndoClient
private:
/** Message for each Validity state */
static TMap<EValidity, FText> ValidityMessages;
private:
friend class FProtocolRangeViewModel;
/** Owning Preset */
/** Owning Preset. */
TWeakObjectPtr<URemoteControlPreset> Preset;
/** Owning Entity (Property within a Preset) */
/** Owning Entity (Property within a Preset). */
TWeakPtr<FProtocolEntityViewModel> ParentViewModel;
/** Bound property */
/** Bound property. */
TWeakFieldPtr<FProperty> Property;
/** Unique Id of the bound Property */
/** Unique Id of the bound Property. */
FGuid PropertyId;
/** Unique Id of this protocol binding */
/** Unique Id of this protocol binding. */
FGuid BindingId;
/** Range ViewModels for this protocol binding */
/** Range ViewModels for this protocol binding. */
TArray<TSharedPtr<FProtocolRangeViewModel>> Ranges;
/** When single range mapping added. */
FOnRangeMappingAdded OnRangeMappingAddedDelegate;
/** When single range mapping removed. */
FOnRangeMappingRemoved OnRangeMappingRemovedDelegate;
/** When all range mappings removed. */
FOnRangeMappingsRemoved OnRangeMappingsRemovedDelegate;
/** Something has changed within the ViewModel. */
FOnChanged OnChangedDelegate;
};

View File

@@ -1,4 +1,4 @@
// Copyright Epic Games, Inc. All Rights Reserved.
// Copyright Epic Games, Inc. All Rights Reserved.
#include "ProtocolEntityViewModel.h"
@@ -8,11 +8,10 @@
#include "ProtocolBindingViewModel.h"
#include "ProtocolCommandChange.h"
#include "RemoteControlPreset.h"
#include "RemoteControlProtocolWidgetsSettings.h"
#include "ScopedTransaction.h"
#include "Algo/AllOf.h"
#include "Algo/AnyOf.h"
#include "Algo/FindSequence.h"
#include "Algo/Partition.h"
#define LOCTEXT_NAMESPACE "ProtocolEntityViewModel"
@@ -50,11 +49,10 @@ namespace Commands
{
if (TSharedPtr<FRemoteControlProperty> RCProperty = InPreset->GetExposedEntity<FRemoteControlProperty>(InArgs.EntityId).Pin())
{
TSet<FRemoteControlProtocolBinding>& Test = RCProperty->ProtocolBindings;
FRemoteControlProtocolBinding* FoundElement = Test.FindByHash(GetTypeHash(InArgs.BindingId), InArgs.BindingId);
FRemoteControlProtocolBinding* FoundElement = RCProperty->ProtocolBindings.FindByHash(GetTypeHash(InArgs.BindingId), InArgs.BindingId);
if (FoundElement)
{
Test.RemoveByHash(GetTypeHash(InArgs.BindingId), InArgs.BindingId);
RCProperty->ProtocolBindings.RemoveByHash(GetTypeHash(InArgs.BindingId), InArgs.BindingId);
return FoundElement->GetProtocolName();
}
}
@@ -63,6 +61,15 @@ namespace Commands
}
}
TMap<FProtocolEntityViewModel::EValidity, FText> FProtocolEntityViewModel::ValidityMessages =
{
{FProtocolEntityViewModel::EValidity::Unchecked, FText::GetEmpty()},
{FProtocolEntityViewModel::EValidity::Ok, FText::GetEmpty()},
{FProtocolEntityViewModel::EValidity::InvalidChild, LOCTEXT("InvalidChild", "There are one or more errors for this binding.")},
{FProtocolEntityViewModel::EValidity::UnsupportedType, LOCTEXT("UnsupportedType", "The input or output types are unsupported.")},
{FProtocolEntityViewModel::EValidity::Unbound, LOCTEXT("Unbound", "The entity is unbound. Rebind to re-enable.")}
};
TSharedRef<FProtocolEntityViewModel> FProtocolEntityViewModel::Create(URemoteControlPreset* InPreset, const FGuid& InEntityId)
{
TSharedRef<FProtocolEntityViewModel> ViewModel = MakeShared<FProtocolEntityViewModel>(FPrivateToken{}, InPreset, InEntityId);
@@ -72,11 +79,12 @@ TSharedRef<FProtocolEntityViewModel> FProtocolEntityViewModel::Create(URemoteCon
}
FProtocolEntityViewModel::FProtocolEntityViewModel(FPrivateToken, URemoteControlPreset* InPreset, const FGuid& InEntityId)
: Preset(InPreset),
PropertyId(InEntityId)
: Preset(InPreset)
, PropertyId(InEntityId)
{
check(Preset != nullptr);
check(Preset->IsExposed(InEntityId));
GEditor->RegisterForUndo(this);
}
@@ -88,6 +96,8 @@ FProtocolEntityViewModel::~FProtocolEntityViewModel()
void FProtocolEntityViewModel::Initialize()
{
Preset->OnEntityUnexposed().AddSP(this, &FProtocolEntityViewModel::OnEntityUnexposed);
Bindings.Empty(Bindings.Num());
if (TSharedPtr<FRemoteControlProperty> RCProperty = Preset->GetExposedEntity<FRemoteControlProperty>(PropertyId).Pin())
{
@@ -105,40 +115,38 @@ void FProtocolEntityViewModel::Initialize()
}
}
// @note: This should closely match RemoteControlProtocolBinding.h
bool FProtocolEntityViewModel::CanAddBinding(const FName& InProtocolName, FText& OutMessage) const
void FProtocolEntityViewModel::OnEntityUnexposed(URemoteControlPreset* InPreset, const FGuid& InEntityId)
{
// It's possible these aren't valid at this point if the owning preset is deleted as well.
if (InPreset && InEntityId.IsValid())
{
if (GetId() == InEntityId)
{
Bindings.Empty();
OnChanged().Broadcast();
}
}
}
// @note: This should closely match RemoteControlProtocolBinding.h
// InProtocolName can be NAME_All which only checks output type support
bool FProtocolEntityViewModel::CanAddBinding(const FName& InProtocolName, FText& OutMessage)
{
check(IsValid());
// If no protocols registered
if (InProtocolName == NAME_None || !GetProperty().IsValid())
if (InProtocolName == NAME_None)
{
return false;
}
FFieldClass* PropertyClass = GetProperty()->GetClass();
if (PropertyClass == FBoolProperty::StaticClass())
{
return FRemoteControlProtocolBinding::IsRangeTypeSupported<bool>();
}
if (PropertyClass->IsChildOf(FNumericProperty::StaticClass()))
{
return true;
}
if (PropertyClass->IsChildOf(FStructProperty::StaticClass()))
{
return true;
}
if (PropertyClass->IsChildOf(FArrayProperty::StaticClass())
|| PropertyClass->IsChildOf(FSetProperty::StaticClass())
|| PropertyClass->IsChildOf(FMapProperty::StaticClass()))
if (RemoteControlTypeUtilities::IsSupportedMappingType(GetProperty().Get()))
{
return true;
}
// Remaining should be strings, enums
OutMessage = FText::Format(LOCTEXT("UnsupportedType", "Unsupported Type \"{0}\" for Protocol Binding"), PropertyClass->GetDisplayNameText());
OutMessage = FText::Format(LOCTEXT("UnsupportedType", "Unsupported Type \"{0}\" for Protocol Binding"), GetProperty()->GetClass()->GetDisplayNameText());
return false;
}
@@ -147,6 +155,7 @@ TSharedPtr<FProtocolBindingViewModel> FProtocolEntityViewModel::AddBinding(const
check(IsValid());
FScopedTransaction Transaction(LOCTEXT("AddProtocolBinding", "Add Protocol Binding"));
Preset->MarkPackageDirty();
const TSharedPtr<FRemoteControlProtocolBinding> ProtocolBinding = Commands::AddProtocolInternal(Preset.Get(), Commands::FAddRemoveProtocolArgs{GetId(), InProtocolName});
if (ProtocolBinding.IsValid())
@@ -165,7 +174,7 @@ TSharedPtr<FProtocolBindingViewModel> FProtocolEntityViewModel::AddBinding(const
);
}
TSharedPtr<FProtocolBindingViewModel>& NewBindingViewModel = Bindings.Add_GetRef(MakeShared<FProtocolBindingViewModel>(FProtocolBindingViewModel::FPrivateToken{}, SharedThis(this), ProtocolBinding.ToSharedRef()));
TSharedPtr<FProtocolBindingViewModel>& NewBindingViewModel = Bindings.Add_GetRef(FProtocolBindingViewModel::Create(AsShared(), ProtocolBinding.ToSharedRef()));
NewBindingViewModel->AddDefaultRangeMappings();
OnBindingAddedDelegate.Broadcast(NewBindingViewModel.ToSharedRef());
@@ -181,6 +190,7 @@ void FProtocolEntityViewModel::RemoveBinding(const FGuid& InBindingId)
check(IsValid());
FScopedTransaction Transaction(LOCTEXT("RemoveProtocolBinding", "Remove Protocol Binding"));
Preset->MarkPackageDirty();
const FName RemovedProtocolName = Commands::RemoveProtocolInternal(Preset.Get(), Commands::FAddRemoveProtocolArgs{GetId(), NAME_None, InBindingId});
if (RemovedProtocolName != NAME_None)
@@ -213,8 +223,20 @@ void FProtocolEntityViewModel::RemoveBinding(const FGuid& InBindingId)
OnBindingRemovedDelegate.Broadcast(InBindingId);
}
TWeakFieldPtr<FProperty> FProtocolEntityViewModel::GetProperty()
{
if (!Property.IsValid())
{
Initialize();
}
return Property;
}
TArray<TSharedPtr<FProtocolBindingViewModel>> FProtocolEntityViewModel::GetFilteredBindings(const TSet<FName>& InHiddenProtocolTypeNames)
{
check(IsValid());
if (InHiddenProtocolTypeNames.Num() == 0)
{
return GetBindings();
@@ -223,7 +245,7 @@ TArray<TSharedPtr<FProtocolBindingViewModel>> FProtocolEntityViewModel::GetFilte
TArray<TSharedPtr<FProtocolBindingViewModel>> FilteredBindings;
for(const TSharedPtr<FProtocolBindingViewModel>& Binding : Bindings)
{
// make sure this bindings protocol name is NOT in the Hidden list, then add it to FilteredBindings
// Make sure this bindings protocol name is NOT in the Hidden list, then add it to FilteredBindings
if (Algo::NoneOf(InHiddenProtocolTypeNames, [&Binding](const FName& InHiddenTypeName)
{
return InHiddenTypeName == Binding->GetBinding()->GetProtocolName();
@@ -236,8 +258,72 @@ TArray<TSharedPtr<FProtocolBindingViewModel>> FProtocolEntityViewModel::GetFilte
return FilteredBindings;
}
bool FProtocolEntityViewModel::IsBound() const
{
return Preset.IsValid()
&& Preset->GetExposedEntity<FRemoteControlField>(PropertyId).IsValid()
&& Preset->GetExposedEntity<FRemoteControlField>(PropertyId).Pin()->IsBound();
}
bool FProtocolEntityViewModel::GetChildren(TArray<TSharedPtr<IRCTreeNodeViewModel>>& OutChildren)
{
const URemoteControlProtocolWidgetsSettings* Settings = GetDefault<URemoteControlProtocolWidgetsSettings>();
const TArray<TSharedPtr<FProtocolBindingViewModel>> Children = GetFilteredBindings(Settings->HiddenProtocolTypeNames);
OutChildren.Append(Children);
return Children.Num() > 0;
}
bool FProtocolEntityViewModel::IsValid(FText& OutMessage)
{
// Check regular validity
check(IsValid());
EValidity Result = EValidity::Ok;
// 1. Check if bound
if (!IsBound())
{
Result = EValidity::Unbound;
}
// 2. Check if input or output containers are invalid, and therefore type is unsupported
if (Result == EValidity::Ok)
{
FText Unused;
if (!CanAddBinding(NAME_All, Unused))
{
Result = EValidity::UnsupportedType;
}
}
// 3. Check if any children aren't valid
if (Result == EValidity::Ok)
{
if (Algo::AnyOf(Bindings, [](const TSharedPtr<FProtocolBindingViewModel>& InBindingViewModel)
{
return !InBindingViewModel->GetCurrentValidity();
}))
{
Result = EValidity::InvalidChild;
}
}
OutMessage = ValidityMessages[Result];
CurrentValidity = Result;
return Result == EValidity::Ok;
}
bool FProtocolEntityViewModel::IsValid() const
{
return Preset.IsValid()
&& PropertyId.IsValid();
}
void FProtocolEntityViewModel::PostUndo(bool bSuccess)
{
check(IsValid());
// Rebuild range ViewModels
Initialize();
OnChangedDelegate.Broadcast();

Some files were not shown because too many files have changed in this diff Show More