diff --git a/Examples/OscDemo/OscDemo.uproject b/Examples/OscDemo/OscDemo.uproject index 648a47f..ebc2bc8 100644 --- a/Examples/OscDemo/OscDemo.uproject +++ b/Examples/OscDemo/OscDemo.uproject @@ -1,6 +1,6 @@ { "FileVersion": 3, - "EngineAssociation": "4.11", + "EngineAssociation": "4.17", "Category": "", "Description": "", "Modules": [ diff --git a/Examples/OscDemo/Plugins/OSC/OSC.uplugin b/Examples/OscDemo/Plugins/OSC/OSC.uplugin index 7efc579..2d662db 100644 --- a/Examples/OscDemo/Plugins/OSC/OSC.uplugin +++ b/Examples/OscDemo/Plugins/OSC/OSC.uplugin @@ -6,10 +6,9 @@ "VersionName" : "1.0", "CreatedBy" : "Guillaume Buisson", "CreatedByURL" : "http://guillaume.io", - "EngineVersion" : "4.4.0", "Description" : "", "Category" : "OSC", - "EnabledByDefault" : false, + "EnabledByDefault" : true, "Modules" : [ diff --git a/Examples/OscDemo/Plugins/OSC/Source/OSC/OSC.Build.cs b/Examples/OscDemo/Plugins/OSC/Source/OSC/OSC.Build.cs index ca6a212..e844ba0 100644 --- a/Examples/OscDemo/Plugins/OSC/Source/OSC/OSC.Build.cs +++ b/Examples/OscDemo/Plugins/OSC/Source/OSC/OSC.Build.cs @@ -2,8 +2,8 @@ namespace UnrealBuildTool.Rules { public class OSC : ModuleRules { - public OSC(TargetInfo Target) - { + public OSC(ReadOnlyTargetRules Target) : base(Target) + { PublicDependencyModuleNames.AddRange( new string[] { @@ -38,7 +38,7 @@ namespace UnrealBuildTool.Rules } ); - if (Target.Type.HasValue && TargetRules.IsEditorType(Target.Type.Value)) + if (Target.Type == TargetRules.TargetType.Editor) { Definitions.Add("OSC_EDITOR_BUILD=1"); diff --git a/Examples/OscDemo/Plugins/OSC/Source/OSC/Private/Common/OscDataElemStruct.h b/Examples/OscDemo/Plugins/OSC/Source/OSC/Private/Common/OscDataElemStruct.h index a4065e8..fe66b6f 100644 --- a/Examples/OscDemo/Plugins/OSC/Source/OSC/Private/Common/OscDataElemStruct.h +++ b/Examples/OscDemo/Plugins/OSC/Source/OSC/Private/Common/OscDataElemStruct.h @@ -8,24 +8,20 @@ struct FOscDataElemStruct { GENERATED_USTRUCT_BODY() - UPROPERTY() - int32 Type; - - UPROPERTY() - int64 Data; - - FOscDataElemStruct() : Type(0), Data(0) - { } - enum { - FLOAT = 0, - INT = 1, - BOOL = 2, + FLOAT = 0, + INT = 1, + BOOL = 2, STRING = 3, + BLOB = 4, }; - - //------------------------------------------------------------------------- + +public: + + FOscDataElemStruct() : Type(0), Data(0) + { + } void SetFloat(double value) { @@ -112,6 +108,27 @@ struct FOscDataElemStruct //------------------------------------------------------------------------- + void SetBlob(TArray value) + { + Data = 0; + Type = BLOB; + Blob = MakeShared>(std::move(value)); + } + + const TArray & AsBlobValue() const + { + check(IsBlob()); + static const TArray empty; + return Blob.IsValid() ? *Blob : empty; + } + + bool IsBlob() const + { + return Type == BLOB; + } + + //------------------------------------------------------------------------- + /// Cast the value to T. template T GetValue() const @@ -150,6 +167,14 @@ struct FOscDataElemStruct return Cast::eval(value); } } + else if(IsBlob()) + { + const bool isBlob = std::is_same>::value; + if(isBlob) + { + return Cast::eval(AsBlobValue()); + } + } return T(); } @@ -163,6 +188,13 @@ private: return T(); } }; + +private: + int32 Type; + + int64 Data; + + TSharedPtr> Blob; }; diff --git a/Examples/OscDemo/Plugins/OSC/Source/OSC/Private/Common/OscFunctionLibrary.cpp b/Examples/OscDemo/Plugins/OSC/Source/OSC/Private/Common/OscFunctionLibrary.cpp index 2778e48..9ad5416 100644 --- a/Examples/OscDemo/Plugins/OSC/Source/OSC/Private/Common/OscFunctionLibrary.cpp +++ b/Examples/OscDemo/Plugins/OSC/Source/OSC/Private/Common/OscFunctionLibrary.cpp @@ -44,6 +44,11 @@ void UOscFunctionLibrary::PopString(const TArray & input, TA PopValueImpl(input, output, Value); } +void UOscFunctionLibrary::PopBlob(const TArray & input, TArray & output, TArray & Value) +{ + PopValueImpl(input, output, Value); +} + void UOscFunctionLibrary::PushBool(const TArray & input, bool Value, TArray & output) { @@ -84,6 +89,14 @@ void UOscFunctionLibrary::PushString(const TArray & input, F output.Add(elem); } +void UOscFunctionLibrary::PushBlob(const TArray & input, const TArray & Value, TArray & output) +{ + output = input; + FOscDataElemStruct elem; + elem.SetBlob(Value); + output.Add(elem); +} + bool UOscFunctionLibrary::AsBool(const FOscDataElemStruct & input) { @@ -105,6 +118,11 @@ FName UOscFunctionLibrary::AsString(const FOscDataElemStruct & input) return input.GetValue(); } +TArray UOscFunctionLibrary::AsBlob(const FOscDataElemStruct & input) +{ + return input.GetValue>(); +} + FOscDataElemStruct UOscFunctionLibrary::FromBool(bool input) { @@ -134,6 +152,13 @@ FOscDataElemStruct UOscFunctionLibrary::FromString(FName input) return result; } +FOscDataElemStruct UOscFunctionLibrary::FromBlob(const TArray & input) +{ + FOscDataElemStruct result; + result.SetBlob(input); + return result; +} + namespace { @@ -188,6 +213,11 @@ namespace { output << elem.AsStringValue().GetPlainANSIString(); } + else if(elem.IsBlob()) + { + const TArray & value = elem.AsBlobValue(); + output << osc::Blob(value.GetData(), value.Num()); + } if(output.State() != osc::SUCCESS) { diff --git a/Examples/OscDemo/Plugins/OSC/Source/OSC/Private/Common/OscFunctionLibrary.h b/Examples/OscDemo/Plugins/OSC/Source/OSC/Private/Common/OscFunctionLibrary.h index d2b1c59..8fbe6da 100644 --- a/Examples/OscDemo/Plugins/OSC/Source/OSC/Private/Common/OscFunctionLibrary.h +++ b/Examples/OscDemo/Plugins/OSC/Source/OSC/Private/Common/OscFunctionLibrary.h @@ -28,6 +28,10 @@ public: UFUNCTION(BlueprintPure, Category=OSC) static void PopString(const TArray & input, TArray & output, FName & Value); + /// Get the next value from an OSC message as a blob. + UFUNCTION(BlueprintPure, Category=OSC) + static void PopBlob(const TArray & input, TArray & output, TArray & Value); + /// Add a boolean value to an OSC message. UFUNCTION(BlueprintPure, Category=OSC, meta=(AutoCreateRefTerm = "input")) @@ -45,6 +49,10 @@ public: UFUNCTION(BlueprintPure, Category=OSC, meta=(AutoCreateRefTerm = "input")) static void PushString(const TArray & input, FName Value, TArray & output); + /// Add a blob to an OSC message. + UFUNCTION(BlueprintPure, Category=OSC, meta=(AutoCreateRefTerm = "input")) + static void PushBlob(const TArray & input, const TArray & Value, TArray & output); + /// Interpret an OSC argument as a boolean UFUNCTION(BlueprintPure, Category=OSC) @@ -62,6 +70,10 @@ public: UFUNCTION(BlueprintPure, Category=OSC) static FName AsString(const FOscDataElemStruct & input); + /// Interpret an OSC argument as a blob. + UFUNCTION(BlueprintPure, Category=OSC) + static TArray AsBlob(const FOscDataElemStruct & input); + /// Create an OSC argument from a boolean UFUNCTION(BlueprintPure, Category=OSC) @@ -79,6 +91,10 @@ public: UFUNCTION(BlueprintPure, Category=OSC) static FOscDataElemStruct FromString(FName input); + /// Create an OSC argument from a blob. + UFUNCTION(BlueprintPure, Category=OSC) + static FOscDataElemStruct FromBlob(const TArray & input); + /** * @brief Send an OSC message. diff --git a/Examples/OscDemo/Plugins/OSC/Source/OSC/Private/Common/oscpack/osc/OscOutboundPacketStream.cpp b/Examples/OscDemo/Plugins/OSC/Source/OSC/Private/Common/oscpack/osc/OscOutboundPacketStream.cpp index 2a908d4..ae94483 100644 --- a/Examples/OscDemo/Plugins/OSC/Source/OSC/Private/Common/oscpack/osc/OscOutboundPacketStream.cpp +++ b/Examples/OscDemo/Plugins/OSC/Source/OSC/Private/Common/oscpack/osc/OscOutboundPacketStream.cpp @@ -148,13 +148,6 @@ static void FromUInt64( char *p, uint64 x ) } -// round up to the next highest multiple of 4. unless x is already a multiple of 4 -static inline std::size_t RoundUp4( std::size_t x ) -{ - return (x + 3) & ~((std::size_t)0x03); -} - - OutboundPacketStream::OutboundPacketStream( char *buffer, std::size_t capacity ) : data_( buffer ) , end_( data_ + capacity ) diff --git a/Examples/OscDemo/Plugins/OSC/Source/OSC/Private/Common/oscpack/osc/OscReceivedElements.cpp b/Examples/OscDemo/Plugins/OSC/Source/OSC/Private/Common/oscpack/osc/OscReceivedElements.cpp index c9d895b..c6f6c70 100644 --- a/Examples/OscDemo/Plugins/OSC/Source/OSC/Private/Common/oscpack/osc/OscReceivedElements.cpp +++ b/Examples/OscDemo/Plugins/OSC/Source/OSC/Private/Common/oscpack/osc/OscReceivedElements.cpp @@ -86,13 +86,6 @@ static inline const char* FindStr4End( const char *p, const char *end ) } -// round up to the next highest multiple of 4. unless x is already a multiple of 4 -static inline uint32 RoundUp4( uint32 x ) -{ - return (x + 3) & ~((uint32)0x03); -} - - static inline int32 ToInt32( const char *p ) { #ifdef OSC_HOST_LITTLE_ENDIAN diff --git a/Examples/OscDemo/Plugins/OSC/Source/OSC/Private/Common/oscpack/osc/OscTypes.h b/Examples/OscDemo/Plugins/OSC/Source/OSC/Private/Common/oscpack/osc/OscTypes.h index aabe09f..c13fb7c 100644 --- a/Examples/OscDemo/Plugins/OSC/Source/OSC/Private/Common/oscpack/osc/OscTypes.h +++ b/Examples/OscDemo/Plugins/OSC/Source/OSC/Private/Common/oscpack/osc/OscTypes.h @@ -110,6 +110,13 @@ inline bool IsMultipleOf4( osc_bundle_element_size_t x ) } +// round up to the next highest multiple of 4. unless x is already a multiple of 4 +static inline std::size_t RoundUp4( std::size_t x ) +{ + return (x + 3) & ~((std::size_t)0x03); +} + + enum TypeTagValues { TRUE_TYPE_TAG = 'T', FALSE_TYPE_TAG = 'F', diff --git a/Examples/OscDemo/Plugins/OSC/Source/OSC/Private/OscModule.cpp b/Examples/OscDemo/Plugins/OSC/Source/OSC/Private/OscModule.cpp index 22fc8af..030bf43 100644 --- a/Examples/OscDemo/Plugins/OSC/Source/OSC/Private/OscModule.cpp +++ b/Examples/OscDemo/Plugins/OSC/Source/OSC/Private/OscModule.cpp @@ -15,7 +15,7 @@ class FOscModule : public IModuleInterface public: virtual void StartupModule( ) override { - if(!FModuleManager::Get().LoadModule(TEXT("Networking")).IsValid()) + if(!FModuleManager::Get().LoadModule(TEXT("Networking"))) { UE_LOG(LogOSC, Error, TEXT("Required module Networking failed to load")); return; @@ -105,7 +105,7 @@ public: uint32_t receivePort; if(UOscSettings::Parse(settings->ReceiveFrom, &receiveAddress, &receivePort)) { - _dispatcher->Listen(receiveAddress, receivePort); + _dispatcher->Listen(receiveAddress, receivePort, settings->MulticastLoopback); } else { diff --git a/Examples/OscDemo/Plugins/OSC/Source/OSC/Private/OscSettings.cpp b/Examples/OscDemo/Plugins/OSC/Source/OSC/Private/OscSettings.cpp index 0578c0b..03e65bb 100644 --- a/Examples/OscDemo/Plugins/OSC/Source/OSC/Private/OscSettings.cpp +++ b/Examples/OscDemo/Plugins/OSC/Source/OSC/Private/OscSettings.cpp @@ -6,6 +6,7 @@ UOscSettings::UOscSettings() : ReceiveFrom("8000"), + MulticastLoopback(true), _sendSocket(FUdpSocketBuilder(TEXT("OscSender")).Build()) { SendTargets.Add(TEXT("127.0.0.1:8000")); @@ -160,7 +161,7 @@ void UOscSettings::ClearKeyInputs(UOscDispatcher & dispatcher) { // Unregister here, not in the OscReceiverInputKey destructor // because it would crash at the application exit. - dispatcher.UnregisterReceiver(&receiver); + dispatcher.UnregisterReceiver(receiver.get()); } _keyReceivers.Reset(0); } @@ -170,7 +171,8 @@ void UOscSettings::UpdateKeyInputs(UOscDispatcher & dispatcher) ClearKeyInputs(dispatcher); for(const auto & address : Inputs) { - _keyReceivers.Emplace(address); - dispatcher.RegisterReceiver(&_keyReceivers.Last()); + auto receiver = std::make_unique(address); + dispatcher.RegisterReceiver(receiver.get()); + _keyReceivers.Add(std::move(receiver)); } } diff --git a/Examples/OscDemo/Plugins/OSC/Source/OSC/Private/OscSettings.h b/Examples/OscDemo/Plugins/OSC/Source/OSC/Private/OscSettings.h index 5b8eeb7..95ce3ee 100644 --- a/Examples/OscDemo/Plugins/OSC/Source/OSC/Private/OscSettings.h +++ b/Examples/OscDemo/Plugins/OSC/Source/OSC/Private/OscSettings.h @@ -8,7 +8,7 @@ class UOscDispatcher; -UCLASS(config=Engine) +UCLASS(Config=Engine, DefaultConfig) class UOscSettings : public UObject { GENERATED_BODY() @@ -44,6 +44,9 @@ public: UPROPERTY(Config, EditAnywhere, Category=Input) TArray Inputs; + UPROPERTY(Config, EditAnywhere, Category=Network) + bool MulticastLoopback; + public: void InitSendTargets(); @@ -70,5 +73,5 @@ private: TSharedRef _sendSocket; TArray> _sendAddresses; TMap _sendAddressesIndex; - TArray _keyReceivers; + TArray> _keyReceivers; }; diff --git a/Examples/OscDemo/Plugins/OSC/Source/OSC/Private/Receive/OscDispatcher.cpp b/Examples/OscDemo/Plugins/OSC/Source/OSC/Private/Receive/OscDispatcher.cpp index 4988f05..662d064 100644 --- a/Examples/OscDemo/Plugins/OSC/Source/OSC/Private/Receive/OscDispatcher.cpp +++ b/Examples/OscDemo/Plugins/OSC/Source/OSC/Private/Receive/OscDispatcher.cpp @@ -25,7 +25,7 @@ UOscDispatcher * UOscDispatcher::Get() return UOscDispatcher::StaticClass()->GetDefaultObject(); } -void UOscDispatcher::Listen(FIPv4Address address, uint32_t port) +void UOscDispatcher::Listen(FIPv4Address address, uint32_t port, bool multicastLoopback) { if(_listening != std::make_pair(address, port)) { @@ -36,6 +36,10 @@ void UOscDispatcher::Listen(FIPv4Address address, uint32_t port) if(address.IsMulticastAddress()) { builder.JoinedToGroup(address); + if(multicastLoopback) + { + builder.WithMulticastLoopback(); + } } else { @@ -131,6 +135,25 @@ static void SendMessage(TCircularQueueAsStringUnchecked())); } + else if(it->IsBlob()) + { + const void* buffer; + osc::osc_bundle_element_size_t size; + osc::Errors error = osc::SUCCESS; + it->AsBlobUnchecked(buffer, size, error); + + TArray blob; + if(size && !error) + { + blob.SetNumUninitialized(size); + FMemory::Memcpy(blob.GetData(), buffer, size); + } + else if(error) + { + UE_LOG(LogOSC, Warning, TEXT("OSC Received Message Error: %s"), osc::errorString(error)); + } + elem.SetBlob(std::move(blob)); + } data.Add(elem); } diff --git a/Examples/OscDemo/Plugins/OSC/Source/OSC/Private/Receive/OscDispatcher.h b/Examples/OscDemo/Plugins/OSC/Source/OSC/Private/Receive/OscDispatcher.h index 4673b92..9318261 100644 --- a/Examples/OscDemo/Plugins/OSC/Source/OSC/Private/Receive/OscDispatcher.h +++ b/Examples/OscDemo/Plugins/OSC/Source/OSC/Private/Receive/OscDispatcher.h @@ -16,7 +16,7 @@ class UOscDispatcher : public UObject friend class FOscModule; - void Listen(FIPv4Address address, uint32_t port); + void Listen(FIPv4Address address, uint32_t port, bool multicastLoopback); void Stop(); public: diff --git a/Examples/OscDemo/Plugins/OSC/Source/OSC/Private/Receive/OscReceiverInterface.h b/Examples/OscDemo/Plugins/OSC/Source/OSC/Private/Receive/OscReceiverInterface.h index 0901967..0a21ab1 100644 --- a/Examples/OscDemo/Plugins/OSC/Source/OSC/Private/Receive/OscReceiverInterface.h +++ b/Examples/OscDemo/Plugins/OSC/Source/OSC/Private/Receive/OscReceiverInterface.h @@ -6,6 +6,7 @@ /// Base class to receive OSC messages. struct IOscReceiverInterface { + virtual ~IOscReceiverInterface() {} virtual const FString & GetAddressFilter() const = 0; virtual void SendEvent(const FName & Address, const TArray & Data, const FString & SenderIp) = 0; }; diff --git a/Examples/OscDemo/Source/OscDemo.Target.cs b/Examples/OscDemo/Source/OscDemo.Target.cs index db48977..f14d29a 100644 --- a/Examples/OscDemo/Source/OscDemo.Target.cs +++ b/Examples/OscDemo/Source/OscDemo.Target.cs @@ -5,21 +5,9 @@ using System.Collections.Generic; public class OscDemoTarget : TargetRules { - public OscDemoTarget(TargetInfo Target) + public OscDemoTarget(TargetInfo Target) : base(Target) { Type = TargetType.Game; - } - - // - // TargetRules interface. - // - - public override void SetupBinaries( - TargetInfo Target, - ref List OutBuildBinaryConfigurations, - ref List OutExtraModuleNames - ) - { - OutExtraModuleNames.AddRange( new string[] { "OscDemo" } ); + ExtraModuleNames.AddRange( new string[] { "OscDemo" } ); } } diff --git a/Examples/OscDemo/Source/OscDemo/OscDemo.Build.cs b/Examples/OscDemo/Source/OscDemo/OscDemo.Build.cs index 6fe9e01..e117f14 100644 --- a/Examples/OscDemo/Source/OscDemo/OscDemo.Build.cs +++ b/Examples/OscDemo/Source/OscDemo/OscDemo.Build.cs @@ -4,8 +4,8 @@ using UnrealBuildTool; public class OscDemo : ModuleRules { - public OscDemo(TargetInfo Target) - { + public OscDemo(ReadOnlyTargetRules Target) : base(Target) + { PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore" }); PrivateDependencyModuleNames.AddRange(new string[] { }); diff --git a/Examples/OscDemo/Source/OscDemoEditor.Target.cs b/Examples/OscDemo/Source/OscDemoEditor.Target.cs index 1628c47..1b2ebea 100644 --- a/Examples/OscDemo/Source/OscDemoEditor.Target.cs +++ b/Examples/OscDemo/Source/OscDemoEditor.Target.cs @@ -5,21 +5,9 @@ using System.Collections.Generic; public class OscDemoEditorTarget : TargetRules { - public OscDemoEditorTarget(TargetInfo Target) - { + public OscDemoEditorTarget(TargetInfo Target) : base(Target) + { Type = TargetType.Editor; - } - - // - // TargetRules interface. - // - - public override void SetupBinaries( - TargetInfo Target, - ref List OutBuildBinaryConfigurations, - ref List OutExtraModuleNames - ) - { - OutExtraModuleNames.AddRange( new string[] { "OscDemo" } ); - } + ExtraModuleNames.AddRange(new string[] { "OscDemo" }); + } }