├── .gitattributes ├── .gitignore ├── FingerControlUE4 ├── Config │ ├── DefaultEditor.ini │ ├── DefaultEditorPerProjectUserSettings.ini │ ├── DefaultEngine.ini │ ├── DefaultGame.ini │ └── DefaultInput.ini ├── Content │ ├── Blueprints │ │ ├── FingerBoneEnum.uasset │ │ ├── FingerBoneStruct.uasset │ │ ├── FingerController.uasset │ │ ├── FingerSensorEnum.uasset │ │ ├── GUIWidget_BP.uasset │ │ └── UDPServerController.uasset │ ├── Maps │ │ ├── FingerControlUE4_Map.umap │ │ └── FingerControlUE4_Map_BuiltData.uasset │ └── MixamoCharacter │ │ ├── Materials │ │ ├── Beta_HighLimbsGeoSG2.uasset │ │ └── Beta_Joints_MAT.uasset │ │ ├── Mixamo_Character_BP.uasset │ │ ├── Mixamo_FingerControl_Anim_BP.uasset │ │ ├── Mixamo_PhysicsAsset.uasset │ │ ├── Mixamo_SkeletalMesh.uasset │ │ └── Mixamo_Skeleton.uasset ├── FingerControlUE4.uproject └── Plugins │ └── UDPWrapper │ ├── .gitignore │ ├── LICENSE │ ├── README.md │ ├── Resources │ └── Icon128.png │ ├── Source │ ├── SIOJEditorPlugin │ │ ├── Private │ │ │ ├── SIOJEditorPlugin.cpp │ │ │ └── SIOJ_BreakJson.cpp │ │ ├── Public │ │ │ ├── SIOJEditorPlugin.h │ │ │ └── SIOJ_BreakJson.h │ │ └── SIOJEditorPlugin.Build.cs │ ├── SIOJson │ │ ├── Private │ │ │ ├── SIOJConvert.cpp │ │ │ ├── SIOJLibrary.cpp │ │ │ ├── SIOJRequestJSON.cpp │ │ │ ├── SIOJson.cpp │ │ │ ├── SIOJsonObject.cpp │ │ │ └── SIOJsonValue.cpp │ │ ├── Public │ │ │ ├── ISIOJson.h │ │ │ ├── SIOJConvert.h │ │ │ ├── SIOJLibrary.h │ │ │ ├── SIOJRequestJSON.h │ │ │ ├── SIOJTypes.h │ │ │ ├── SIOJsonObject.h │ │ │ └── SIOJsonValue.h │ │ └── SIOJson.Build.cs │ └── UDPWrapper │ │ ├── Private │ │ ├── UDPWrapper.cpp │ │ └── udpcomponent.cpp │ │ ├── Public │ │ ├── UDPComponent.h │ │ └── UDPWrapper.h │ │ └── UDPWrapper.Build.cs │ └── UDPWrapper.uplugin ├── FingerControl_ESP32 ├── DataUtils.ino ├── EEPROMUtils.ino ├── FingerControl_ESP32.ino ├── ProtocolHelper.ino ├── SerialPortHelper.ino ├── SettingsUtils.ino ├── UDPClient.ino └── WiFiHelper.ino ├── README.md └── Screenshots ├── Screenshot01.jpg └── Screenshot02.jpg /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /FingerControlUE4/Saved/ 2 | /FingerControlUE4/Intermediate/ 3 | /FingerControlUE4/Content/Collections/ 4 | /FingerControlUE4/Content/Developers/ 5 | /FingerControlUE4/Plugins/UDPWrapper/Intermediate/ 6 | /FingerControlUE4/Plugins/UDPWrapper/Binaries/ -------------------------------------------------------------------------------- /FingerControlUE4/Config/DefaultEditor.ini: -------------------------------------------------------------------------------- 1 | [UnrealEd.SimpleMap] 2 | SimpleMapName=/Game/TP_ThirdPerson/Maps/ThirdPersonExampleMap 3 | 4 | [EditoronlyBP] 5 | bAllowClassAndBlueprintPinMatching=true 6 | bReplaceBlueprintWithClass= true 7 | bDontLoadBlueprintOutsideEditor= true 8 | bBlueprintIsNotBlueprintType= true 9 | 10 | 11 | -------------------------------------------------------------------------------- /FingerControlUE4/Config/DefaultEditorPerProjectUserSettings.ini: -------------------------------------------------------------------------------- 1 | [ContentBrowser] 2 | ContentBrowserTab1.SelectedPaths=/Game/ThirdPersonBP -------------------------------------------------------------------------------- /FingerControlUE4/Config/DefaultEngine.ini: -------------------------------------------------------------------------------- 1 | [URL] 2 | GameName=MocapUE4 3 | 4 | [/Script/EngineSettings.GameMapsSettings] 5 | EditorStartupMap=/Game/Maps/FingerControlUE4_Map.FingerControlUE4_Map 6 | GameDefaultMap=/Game/Maps/FingerControlUE4_Map.FingerControlUE4_Map 7 | TransitionMap= 8 | bUseSplitscreen=True 9 | TwoPlayerSplitscreenLayout=Horizontal 10 | ThreePlayerSplitscreenLayout=FavorTop 11 | GlobalDefaultGameMode=/Game/ThirdPersonBP/Blueprints/ThirdPersonGameMode.ThirdPersonGameMode_C 12 | GlobalDefaultServerGameMode=None 13 | 14 | [/Script/IOSRuntimeSettings.IOSRuntimeSettings] 15 | MinimumiOSVersion=IOS_10 16 | 17 | [/Script/Engine.Engine] 18 | +ActiveGameNameRedirects=(OldGameName="TP_ThirdPersonBP",NewGameName="/Script/MocapUE4") 19 | +ActiveGameNameRedirects=(OldGameName="/Script/TP_ThirdPersonBP",NewGameName="/Script/MocapUE4") 20 | 21 | [/Script/HardwareTargeting.HardwareTargetingSettings] 22 | TargetedHardwareClass=Desktop 23 | AppliedTargetedHardwareClass=Desktop 24 | DefaultGraphicsPerformance=Maximum 25 | AppliedDefaultGraphicsPerformance=Maximum 26 | 27 | [/Script/Engine.PhysicsSettings] 28 | DefaultGravityZ=-980.000000 29 | DefaultTerminalVelocity=4000.000000 30 | DefaultFluidFriction=0.300000 31 | SimulateScratchMemorySize=262144 32 | RagdollAggregateThreshold=4 33 | TriangleMeshTriangleMinAreaThreshold=5.000000 34 | bEnableShapeSharing=False 35 | bEnablePCM=True 36 | bEnableStabilization=False 37 | bWarnMissingLocks=True 38 | bEnable2DPhysics=False 39 | PhysicErrorCorrection=(PingExtrapolation=0.100000,PingLimit=100.000000,ErrorPerLinearDifference=1.000000,ErrorPerAngularDifference=1.000000,MaxRestoredStateError=1.000000,MaxLinearHardSnapDistance=400.000000,PositionLerp=0.000000,AngleLerp=0.400000,LinearVelocityCoefficient=100.000000,AngularVelocityCoefficient=10.000000,ErrorAccumulationSeconds=0.500000,ErrorAccumulationDistanceSq=15.000000,ErrorAccumulationSimilarity=100.000000) 40 | LockedAxis=Invalid 41 | DefaultDegreesOfFreedom=Full3D 42 | BounceThresholdVelocity=200.000000 43 | FrictionCombineMode=Average 44 | RestitutionCombineMode=Average 45 | MaxAngularVelocity=3600.000000 46 | MaxDepenetrationVelocity=0.000000 47 | ContactOffsetMultiplier=0.020000 48 | MinContactOffset=2.000000 49 | MaxContactOffset=8.000000 50 | bSimulateSkeletalMeshOnDedicatedServer=True 51 | DefaultShapeComplexity=CTF_UseSimpleAndComplex 52 | bDefaultHasComplexCollision=True 53 | bSuppressFaceRemapTable=False 54 | bSupportUVFromHitResults=False 55 | bDisableActiveActors=False 56 | bDisableKinematicStaticPairs=False 57 | bDisableKinematicKinematicPairs=False 58 | bDisableCCD=False 59 | bEnableEnhancedDeterminism=False 60 | MaxPhysicsDeltaTime=0.033333 61 | bSubstepping=False 62 | bSubsteppingAsync=False 63 | MaxSubstepDeltaTime=0.016667 64 | MaxSubsteps=6 65 | SyncSceneSmoothingFactor=0.000000 66 | InitialAverageFrameRate=0.016667 67 | PhysXTreeRebuildRate=10 68 | DefaultBroadphaseSettings=(bUseMBPOnClient=False,bUseMBPOnServer=False,MBPBounds=(Min=(X=0.000000,Y=0.000000,Z=0.000000),Max=(X=0.000000,Y=0.000000,Z=0.000000),IsValid=0),MBPNumSubdivs=2) 69 | 70 | 71 | -------------------------------------------------------------------------------- /FingerControlUE4/Config/DefaultGame.ini: -------------------------------------------------------------------------------- 1 | [/Script/EngineSettings.GeneralProjectSettings] 2 | ProjectID=389C634949605ACCDB5E23BC65376F5F 3 | ProjectName= 4 | CopyrightNotice= 5 | 6 | -------------------------------------------------------------------------------- /FingerControlUE4/Config/DefaultInput.ini: -------------------------------------------------------------------------------- 1 | 2 | [/Script/Engine.InputSettings] 3 | -AxisConfig=(AxisKeyName="Gamepad_LeftX",AxisProperties=(DeadZone=0.25,Exponent=1.f,Sensitivity=1.f)) 4 | -AxisConfig=(AxisKeyName="Gamepad_LeftY",AxisProperties=(DeadZone=0.25,Exponent=1.f,Sensitivity=1.f)) 5 | -AxisConfig=(AxisKeyName="Gamepad_RightX",AxisProperties=(DeadZone=0.25,Exponent=1.f,Sensitivity=1.f)) 6 | -AxisConfig=(AxisKeyName="Gamepad_RightY",AxisProperties=(DeadZone=0.25,Exponent=1.f,Sensitivity=1.f)) 7 | -AxisConfig=(AxisKeyName="MouseX",AxisProperties=(DeadZone=0.f,Exponent=1.f,Sensitivity=0.07f)) 8 | -AxisConfig=(AxisKeyName="MouseY",AxisProperties=(DeadZone=0.f,Exponent=1.f,Sensitivity=0.07f)) 9 | +AxisConfig=(AxisKeyName="Gamepad_LeftX",AxisProperties=(DeadZone=0.250000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 10 | +AxisConfig=(AxisKeyName="Gamepad_LeftY",AxisProperties=(DeadZone=0.250000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 11 | +AxisConfig=(AxisKeyName="Gamepad_RightX",AxisProperties=(DeadZone=0.250000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 12 | +AxisConfig=(AxisKeyName="Gamepad_RightY",AxisProperties=(DeadZone=0.250000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 13 | +AxisConfig=(AxisKeyName="MouseX",AxisProperties=(DeadZone=0.000000,Sensitivity=0.070000,Exponent=1.000000,bInvert=False)) 14 | +AxisConfig=(AxisKeyName="MouseY",AxisProperties=(DeadZone=0.000000,Sensitivity=0.070000,Exponent=1.000000,bInvert=False)) 15 | +AxisConfig=(AxisKeyName="MouseWheelAxis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 16 | +AxisConfig=(AxisKeyName="Gamepad_LeftTriggerAxis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 17 | +AxisConfig=(AxisKeyName="Gamepad_RightTriggerAxis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 18 | +AxisConfig=(AxisKeyName="MotionController_Left_Thumbstick_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 19 | +AxisConfig=(AxisKeyName="MotionController_Left_Thumbstick_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 20 | +AxisConfig=(AxisKeyName="MotionController_Left_TriggerAxis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 21 | +AxisConfig=(AxisKeyName="MotionController_Left_Grip1Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 22 | +AxisConfig=(AxisKeyName="MotionController_Left_Grip2Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 23 | +AxisConfig=(AxisKeyName="MotionController_Right_Thumbstick_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 24 | +AxisConfig=(AxisKeyName="MotionController_Right_Thumbstick_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 25 | +AxisConfig=(AxisKeyName="MotionController_Right_TriggerAxis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 26 | +AxisConfig=(AxisKeyName="MotionController_Right_Grip1Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 27 | +AxisConfig=(AxisKeyName="MotionController_Right_Grip2Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 28 | +AxisConfig=(AxisKeyName="Gamepad_Special_Left_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 29 | +AxisConfig=(AxisKeyName="Gamepad_Special_Left_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 30 | +AxisConfig=(AxisKeyName="MotionController_Left_Thumbstick_Z",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 31 | +AxisConfig=(AxisKeyName="MotionController_Right_Thumbstick_Z",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 32 | +AxisConfig=(AxisKeyName="OculusTouch_Left_Thumbstick",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 33 | +AxisConfig=(AxisKeyName="OculusTouch_Left_FaceButton1",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 34 | +AxisConfig=(AxisKeyName="OculusTouch_Left_Trigger",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 35 | +AxisConfig=(AxisKeyName="OculusTouch_Left_FaceButton2",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 36 | +AxisConfig=(AxisKeyName="OculusTouch_Left_IndexPointing",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 37 | +AxisConfig=(AxisKeyName="OculusTouch_Left_ThumbUp",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 38 | +AxisConfig=(AxisKeyName="OculusTouch_Right_Thumbstick",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 39 | +AxisConfig=(AxisKeyName="OculusTouch_Right_FaceButton1",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 40 | +AxisConfig=(AxisKeyName="OculusTouch_Right_Trigger",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 41 | +AxisConfig=(AxisKeyName="OculusTouch_Right_FaceButton2",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 42 | +AxisConfig=(AxisKeyName="OculusTouch_Right_IndexPointing",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 43 | +AxisConfig=(AxisKeyName="OculusTouch_Right_ThumbUp",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 44 | +AxisConfig=(AxisKeyName="OculusTouchpad_Touchpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 45 | +AxisConfig=(AxisKeyName="OculusTouchpad_Touchpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 46 | +AxisConfig=(AxisKeyName="SteamVR_Knuckles_Left_HandGrip",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 47 | +AxisConfig=(AxisKeyName="SteamVR_Knuckles_Left_IndexGrip",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 48 | +AxisConfig=(AxisKeyName="SteamVR_Knuckles_Left_MiddleGrip",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 49 | +AxisConfig=(AxisKeyName="SteamVR_Knuckles_Left_RingGrip",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 50 | +AxisConfig=(AxisKeyName="SteamVR_Knuckles_Left_PinkyGrip",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 51 | +AxisConfig=(AxisKeyName="SteamVR_Knuckles_Right_HandGrip",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 52 | +AxisConfig=(AxisKeyName="SteamVR_Knuckles_Right_IndexGrip",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 53 | +AxisConfig=(AxisKeyName="SteamVR_Knuckles_Right_MiddleGrip",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 54 | +AxisConfig=(AxisKeyName="SteamVR_Knuckles_Right_RingGrip",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 55 | +AxisConfig=(AxisKeyName="SteamVR_Knuckles_Right_PinkyGrip",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 56 | bAltEnterTogglesFullscreen=True 57 | bF11TogglesFullscreen=True 58 | bUseMouseForTouch=False 59 | bEnableMouseSmoothing=True 60 | bEnableFOVScaling=True 61 | bCaptureMouseOnLaunch=True 62 | bDefaultViewportMouseLock=True 63 | bAlwaysShowTouchInterface=False 64 | bShowConsoleOnFourFingerTap=True 65 | bEnableGestureRecognizer=False 66 | bUseAutocorrect=False 67 | DefaultViewportMouseCaptureMode=CapturePermanently_IncludingInitialMouseDown 68 | DefaultViewportMouseLockMode=LockOnCapture 69 | FOVScale=0.011110 70 | DoubleClickTime=0.200000 71 | +ActionMappings=(ActionName="Jump",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=SpaceBar) 72 | +ActionMappings=(ActionName="Jump",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=Gamepad_FaceButton_Bottom) 73 | +ActionMappings=(ActionName="Jump",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=MotionController_Left_Trigger) 74 | +ActionMappings=(ActionName="ResetVR",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=R) 75 | +ActionMappings=(ActionName="ResetVR",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=MotionController_Left_Grip1) 76 | +ActionMappings=(ActionName="Jump",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=MotionController_Right_Trigger) 77 | +ActionMappings=(ActionName="Jump",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=OculusTouchpad_Touchpad) 78 | +AxisMappings=(AxisName="MoveForward",Scale=1.000000,Key=W) 79 | +AxisMappings=(AxisName="MoveForward",Scale=-1.000000,Key=S) 80 | +AxisMappings=(AxisName="MoveForward",Scale=1.000000,Key=Up) 81 | +AxisMappings=(AxisName="MoveForward",Scale=-1.000000,Key=Down) 82 | +AxisMappings=(AxisName="MoveForward",Scale=1.000000,Key=Gamepad_LeftY) 83 | +AxisMappings=(AxisName="MoveRight",Scale=-1.000000,Key=A) 84 | +AxisMappings=(AxisName="MoveRight",Scale=1.000000,Key=D) 85 | +AxisMappings=(AxisName="MoveRight",Scale=1.000000,Key=Gamepad_LeftX) 86 | +AxisMappings=(AxisName="TurnRate",Scale=1.000000,Key=Gamepad_RightX) 87 | +AxisMappings=(AxisName="TurnRate",Scale=-1.000000,Key=Left) 88 | +AxisMappings=(AxisName="TurnRate",Scale=1.000000,Key=Right) 89 | +AxisMappings=(AxisName="Turn",Scale=1.000000,Key=MouseX) 90 | +AxisMappings=(AxisName="LookUpRate",Scale=1.000000,Key=Gamepad_RightY) 91 | +AxisMappings=(AxisName="LookUp",Scale=-1.000000,Key=MouseY) 92 | +AxisMappings=(AxisName="MoveForward",Scale=-1.000000,Key=MotionController_Left_Thumbstick_Y) 93 | +AxisMappings=(AxisName="MoveRight",Scale=1.000000,Key=MotionController_Left_Thumbstick_X) 94 | +AxisMappings=(AxisName="TurnRate",Scale=-1.000000,Key=MotionController_Right_Thumbstick_X) 95 | DefaultTouchInterface=/Engine/MobileResources/HUD/DefaultVirtualJoysticks.DefaultVirtualJoysticks 96 | ConsoleKey=None 97 | -ConsoleKeys=Tilde 98 | +ConsoleKeys=Tilde 99 | 100 | 101 | -------------------------------------------------------------------------------- /FingerControlUE4/Content/Blueprints/FingerBoneEnum.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pgii/FingerControlUE4/688e42dc5027c285f46e3050d6115d7dfc9711ac/FingerControlUE4/Content/Blueprints/FingerBoneEnum.uasset -------------------------------------------------------------------------------- /FingerControlUE4/Content/Blueprints/FingerBoneStruct.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pgii/FingerControlUE4/688e42dc5027c285f46e3050d6115d7dfc9711ac/FingerControlUE4/Content/Blueprints/FingerBoneStruct.uasset -------------------------------------------------------------------------------- /FingerControlUE4/Content/Blueprints/FingerController.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pgii/FingerControlUE4/688e42dc5027c285f46e3050d6115d7dfc9711ac/FingerControlUE4/Content/Blueprints/FingerController.uasset -------------------------------------------------------------------------------- /FingerControlUE4/Content/Blueprints/FingerSensorEnum.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pgii/FingerControlUE4/688e42dc5027c285f46e3050d6115d7dfc9711ac/FingerControlUE4/Content/Blueprints/FingerSensorEnum.uasset -------------------------------------------------------------------------------- /FingerControlUE4/Content/Blueprints/GUIWidget_BP.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pgii/FingerControlUE4/688e42dc5027c285f46e3050d6115d7dfc9711ac/FingerControlUE4/Content/Blueprints/GUIWidget_BP.uasset -------------------------------------------------------------------------------- /FingerControlUE4/Content/Blueprints/UDPServerController.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pgii/FingerControlUE4/688e42dc5027c285f46e3050d6115d7dfc9711ac/FingerControlUE4/Content/Blueprints/UDPServerController.uasset -------------------------------------------------------------------------------- /FingerControlUE4/Content/Maps/FingerControlUE4_Map.umap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pgii/FingerControlUE4/688e42dc5027c285f46e3050d6115d7dfc9711ac/FingerControlUE4/Content/Maps/FingerControlUE4_Map.umap -------------------------------------------------------------------------------- /FingerControlUE4/Content/Maps/FingerControlUE4_Map_BuiltData.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pgii/FingerControlUE4/688e42dc5027c285f46e3050d6115d7dfc9711ac/FingerControlUE4/Content/Maps/FingerControlUE4_Map_BuiltData.uasset -------------------------------------------------------------------------------- /FingerControlUE4/Content/MixamoCharacter/Materials/Beta_HighLimbsGeoSG2.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pgii/FingerControlUE4/688e42dc5027c285f46e3050d6115d7dfc9711ac/FingerControlUE4/Content/MixamoCharacter/Materials/Beta_HighLimbsGeoSG2.uasset -------------------------------------------------------------------------------- /FingerControlUE4/Content/MixamoCharacter/Materials/Beta_Joints_MAT.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pgii/FingerControlUE4/688e42dc5027c285f46e3050d6115d7dfc9711ac/FingerControlUE4/Content/MixamoCharacter/Materials/Beta_Joints_MAT.uasset -------------------------------------------------------------------------------- /FingerControlUE4/Content/MixamoCharacter/Mixamo_Character_BP.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pgii/FingerControlUE4/688e42dc5027c285f46e3050d6115d7dfc9711ac/FingerControlUE4/Content/MixamoCharacter/Mixamo_Character_BP.uasset -------------------------------------------------------------------------------- /FingerControlUE4/Content/MixamoCharacter/Mixamo_FingerControl_Anim_BP.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pgii/FingerControlUE4/688e42dc5027c285f46e3050d6115d7dfc9711ac/FingerControlUE4/Content/MixamoCharacter/Mixamo_FingerControl_Anim_BP.uasset -------------------------------------------------------------------------------- /FingerControlUE4/Content/MixamoCharacter/Mixamo_PhysicsAsset.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pgii/FingerControlUE4/688e42dc5027c285f46e3050d6115d7dfc9711ac/FingerControlUE4/Content/MixamoCharacter/Mixamo_PhysicsAsset.uasset -------------------------------------------------------------------------------- /FingerControlUE4/Content/MixamoCharacter/Mixamo_SkeletalMesh.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pgii/FingerControlUE4/688e42dc5027c285f46e3050d6115d7dfc9711ac/FingerControlUE4/Content/MixamoCharacter/Mixamo_SkeletalMesh.uasset -------------------------------------------------------------------------------- /FingerControlUE4/Content/MixamoCharacter/Mixamo_Skeleton.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pgii/FingerControlUE4/688e42dc5027c285f46e3050d6115d7dfc9711ac/FingerControlUE4/Content/MixamoCharacter/Mixamo_Skeleton.uasset -------------------------------------------------------------------------------- /FingerControlUE4/FingerControlUE4.uproject: -------------------------------------------------------------------------------- 1 | { 2 | "FileVersion": 3, 3 | "EngineAssociation": "4.22", 4 | "Category": "", 5 | "Description": "", 6 | "Plugins": [ 7 | { 8 | "Name": "UE4Duino", 9 | "Enabled": false 10 | }, 11 | { 12 | "Name": "Smartsuit", 13 | "Enabled": false, 14 | "MarketplaceURL": "com.epicgames.launcher://ue/marketplace/content/7e20fe7d4247410cb4f7d3e162d61c21" 15 | } 16 | ] 17 | } -------------------------------------------------------------------------------- /FingerControlUE4/Plugins/UDPWrapper/.gitignore: -------------------------------------------------------------------------------- 1 | # Visual Studio 2015 user specific files 2 | .vs/ 3 | 4 | # Visual Studio 2015 database file 5 | *.VC.db 6 | 7 | # Compiled Object files 8 | *.slo 9 | *.lo 10 | *.o 11 | *.obj 12 | 13 | # Precompiled Headers 14 | *.gch 15 | *.pch 16 | 17 | # Compiled Dynamic libraries 18 | *.so 19 | *.dylib 20 | *.dll 21 | 22 | # Fortran module files 23 | *.mod 24 | 25 | # Compiled Static libraries 26 | *.lai 27 | *.la 28 | *.a 29 | *.lib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.ipa 36 | 37 | # These project files can be generated by the engine 38 | *.xcodeproj 39 | *.xcworkspace 40 | *.sln 41 | *.suo 42 | *.opensdf 43 | *.sdf 44 | *.VC.db 45 | *.VC.opendb 46 | 47 | # Precompiled Assets 48 | SourceArt/**/*.png 49 | SourceArt/**/*.tga 50 | 51 | # Binary Files 52 | Binaries/* 53 | 54 | # Builds 55 | Build/* 56 | 57 | # Whitelist PakBlacklist-.txt files 58 | !Build/*/ 59 | Build/*/** 60 | !Build/*/PakBlacklist*.txt 61 | 62 | # Don't ignore icon files in Build 63 | !Build/**/*.ico 64 | 65 | # Built data for maps 66 | *_BuiltData.uasset 67 | 68 | # Configuration files generated by the Editor 69 | Saved/* 70 | 71 | # Compiled source files for the engine to use 72 | Intermediate/* 73 | 74 | # Cache files for the editor to use 75 | DerivedDataCache/* 76 | -------------------------------------------------------------------------------- /FingerControlUE4/Plugins/UDPWrapper/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018-present, Jan Kaniewski (getnamo) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /FingerControlUE4/Plugins/UDPWrapper/README.md: -------------------------------------------------------------------------------- 1 | # udp-ue4 2 | Convenience ActorComponent UDP wrapper for Unreal Engine 4. 3 | 4 | [![GitHub release](https://img.shields.io/github/release/getnamo/udp-ue4.svg)](https://github.com/getnamo/udp-ue4/releases) 5 | [![Github All Releases](https://img.shields.io/github/downloads/getnamo/udp-ue4/total.svg)](https://github.com/getnamo/udp-ue4/releases) 6 | 7 | This may not be the most sensible wrapper for your use case, but is meant to co-exist with https://github.com/getnamo/socketio-client-ue4 with similar workflow. 8 | 9 | Wraps built-in ue4 udp functionality as an actor component with both sending and receiving capabilities. Confirmed working with node.js [dgram](https://nodejs.org/api/dgram.html) (see [example echo server gist](https://gist.github.com/getnamo/8117fdc64209af086ce0337310c52a51) for testing). 10 | 11 | ## Quick Install & Setup 12 | 13 | 1. [Download Latest Release](https://github.com/getnamo/udp-ue4/releases) 14 | 2. Create new or choose project. 15 | 3. Browse to your project folder (typically found at Documents/Unreal Project/{Your Project Root}) 16 | 4. Copy *Plugins* folder into your Project root. 17 | 5. Plugin should be now ready to use. 18 | 19 | ## How to use - Basics 20 | 21 | Select an actor of choice. Add UDP component to that actor. 22 | 23 | ![add component](https://i.imgur.com/EnCiU4K.png) 24 | 25 | Select the newly created component and modify any default settings 26 | 27 | ![defaults](https://i.imgur.com/nANqpPF.png) 28 | 29 | e.g. if you're only interested in sending, untick should auto-listen and modify your send ip/port to match your desired settings. Conversely you can untick auto-connect if you're not interested in sending. 30 | 31 | Also if you want to connect/listen on your own time untick both and connect manually via e.g. key event 32 | 33 | ![manual connect](https://i.imgur.com/HVrsO2p.png) 34 | 35 | ### Sending 36 | 37 | Once you've auto-connected or manually connected to the sending socket, use emit to send some data, utf8 conversion provided by socket.io plugin. 38 | 39 | ![emit](https://i.imgur.com/3EIT8TL.png) 40 | 41 | ### Receiving 42 | 43 | ![events](https://i.imgur.com/IRE54zq.png) 44 | 45 | Once you've started listening to data you'll receive data on the ```OnReceivedBytes``` event 46 | 47 | ![receive bytes](https://i.imgur.com/YCEUCkW.png) 48 | 49 | which you can convert to convenient strings or structures via socket.io (optional). 50 | 51 | ### Reliable Stream 52 | 53 | Each relase includes the socket.io client plugin, that plugin is intended to be used for reliable control and then real-time/freshest data component of your network can be piped using this udp plugin. Consider timestamping your data so you can know which packets to drop/ignore. 54 | 55 | 56 | ## Notes 57 | MIT licensed. 58 | 59 | Largely inspired from https://wiki.unrealengine.com/UDP_Socket_Sender_Receiver_From_One_UE4_Instance_To_Another. 60 | -------------------------------------------------------------------------------- /FingerControlUE4/Plugins/UDPWrapper/Resources/Icon128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pgii/FingerControlUE4/688e42dc5027c285f46e3050d6115d7dfc9711ac/FingerControlUE4/Plugins/UDPWrapper/Resources/Icon128.png -------------------------------------------------------------------------------- /FingerControlUE4/Plugins/UDPWrapper/Source/SIOJEditorPlugin/Private/SIOJEditorPlugin.cpp: -------------------------------------------------------------------------------- 1 | // Modifications Copyright 2018-current Getnamo. All Rights Reserved 2 | 3 | 4 | // Copyright 2015 Vladimir Alyamkin. All Rights Reserved. 5 | // Original code by https://github.com/unktomi 6 | 7 | #include "SIOJEditorPlugin.h" 8 | 9 | #define LOCTEXT_NAMESPACE "FSIOJEditorPluginModule" 10 | 11 | void FSIOJEditorPluginModule::StartupModule() 12 | { 13 | // This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module 14 | } 15 | 16 | void FSIOJEditorPluginModule::ShutdownModule() 17 | { 18 | // This function may be called during shutdown to clean up your module. For modules that support dynamic reloading, 19 | // we call this function before unloading the module. 20 | } 21 | 22 | #undef LOCTEXT_NAMESPACE 23 | 24 | IMPLEMENT_MODULE(FSIOJEditorPluginModule, SIOJEditorPlugin) 25 | -------------------------------------------------------------------------------- /FingerControlUE4/Plugins/UDPWrapper/Source/SIOJEditorPlugin/Private/SIOJ_BreakJson.cpp: -------------------------------------------------------------------------------- 1 | // Modifications Copyright 2018-current Getnamo. All Rights Reserved 2 | 3 | 4 | // Copyright 2015 Vladimir Alyamkin. All Rights Reserved. 5 | // Original code by https://github.com/unktomi 6 | 7 | #include "SIOJ_BreakJson.h" 8 | #include "EdGraphUtilities.h" 9 | #include "KismetCompiler.h" 10 | #include "EditorCategoryUtils.h" 11 | #include "EdGraph/EdGraph.h" 12 | #include "EdGraph/EdGraphNodeUtils.h" // for FNodeTextCache 13 | #include "EdGraphSchema_K2.h" 14 | #include "BlueprintNodeSpawner.h" 15 | #include "BlueprintActionDatabaseRegistrar.h" 16 | #include "BlueprintFieldNodeSpawner.h" 17 | #include "EditorCategoryUtils.h" 18 | #include "BlueprintActionFilter.h" 19 | #include "Runtime/Launch/Resources/Version.h" 20 | 21 | #define LOCTEXT_NAMESPACE "SIOJ_BreakJson" 22 | 23 | class FKCHandler_BreakJson : public FNodeHandlingFunctor 24 | { 25 | 26 | public: 27 | FKCHandler_BreakJson(FKismetCompilerContext& InCompilerContext) 28 | : FNodeHandlingFunctor(InCompilerContext) 29 | { 30 | } 31 | 32 | virtual void Compile(FKismetFunctionContext& Context, UEdGraphNode* Node) override 33 | { 34 | UEdGraphPin* InputPin = NULL; 35 | 36 | for (int32 PinIndex = 0; PinIndex < Node->Pins.Num(); ++PinIndex) 37 | { 38 | UEdGraphPin* Pin = Node->Pins[PinIndex]; 39 | if (Pin && (EGPD_Input == Pin->Direction)) 40 | { 41 | InputPin = Pin; 42 | break; 43 | } 44 | } 45 | 46 | UEdGraphPin *InNet = FEdGraphUtilities::GetNetFromPin(InputPin); 47 | UClass *Class = Cast(StaticLoadObject(UClass::StaticClass(), NULL, TEXT("class'SIOJPlugin.SIOJJsonObject'"))); 48 | 49 | FBPTerminal **SourceTerm = Context.NetMap.Find(InNet); 50 | if (SourceTerm == nullptr) 51 | { 52 | return; 53 | } 54 | 55 | for (int32 PinIndex = 0; PinIndex < Node->Pins.Num(); ++PinIndex) 56 | { 57 | UEdGraphPin* Pin = Node->Pins[PinIndex]; 58 | if (Pin && (EGPD_Output == Pin->Direction)) 59 | { 60 | if (Pin->LinkedTo.Num() < 1) 61 | { 62 | continue; 63 | } 64 | 65 | FBPTerminal **Target = Context.NetMap.Find(Pin); 66 | 67 | const FName&FieldName = Pin->PinName; 68 | const FName&FieldType = Pin->PinType.PinCategory; 69 | 70 | FBPTerminal* FieldNameTerm = Context.CreateLocalTerminal(ETerminalSpecification::TS_Literal); 71 | FieldNameTerm->Type.PinCategory = CompilerContext.GetSchema()->PC_String; 72 | #if ENGINE_MINOR_VERSION >= 13 73 | FieldNameTerm->SourcePin = Pin; 74 | #else 75 | FieldNameTerm->Source = Pin; 76 | #endif 77 | FieldNameTerm->Name = FieldName.ToString(); 78 | FieldNameTerm->TextLiteral = FText::FromName(FieldName); 79 | 80 | FBlueprintCompiledStatement& Statement = Context.AppendStatementForNode(Node); 81 | FName FunctionName; 82 | 83 | bool bIsArray = Pin->PinType.IsArray(); 84 | 85 | if (FieldType == CompilerContext.GetSchema()->PC_Boolean) 86 | { 87 | FunctionName = bIsArray ? TEXT("GetBoolArrayField") : TEXT("GetBoolField"); 88 | } 89 | else if (FieldType == CompilerContext.GetSchema()->PC_Float) 90 | { 91 | FunctionName = bIsArray ? TEXT("GetNumberArrayField") : TEXT("GetNumberField"); 92 | } 93 | else if (FieldType == CompilerContext.GetSchema()->PC_String) 94 | { 95 | FunctionName = bIsArray ? TEXT("GetStringArrayField") : TEXT("GetStringField"); 96 | } 97 | else if (FieldType == CompilerContext.GetSchema()->PC_Object) 98 | { 99 | FunctionName = bIsArray ? TEXT("GetObjectArrayField") : TEXT("GetObjectField"); 100 | } 101 | else 102 | { 103 | continue; 104 | } 105 | 106 | UFunction *FunctionPtr = Class->FindFunctionByName(FunctionName); 107 | Statement.Type = KCST_CallFunction; 108 | Statement.FunctionToCall = FunctionPtr; 109 | Statement.FunctionContext = *SourceTerm; 110 | Statement.bIsParentContext = false; 111 | Statement.LHS = *Target; 112 | Statement.RHS.Add(FieldNameTerm); 113 | } 114 | } 115 | } 116 | 117 | FBPTerminal* RegisterInputTerm(FKismetFunctionContext& Context, USIOJ_BreakJson* Node) 118 | { 119 | // Find input pin 120 | UEdGraphPin* InputPin = NULL; 121 | for (int32 PinIndex = 0; PinIndex < Node->Pins.Num(); ++PinIndex) 122 | { 123 | UEdGraphPin* Pin = Node->Pins[PinIndex]; 124 | if (Pin && (EGPD_Input == Pin->Direction)) 125 | { 126 | InputPin = Pin; 127 | break; 128 | } 129 | } 130 | check(NULL != InputPin); 131 | 132 | // Find structure source net 133 | UEdGraphPin* Net = FEdGraphUtilities::GetNetFromPin(InputPin); 134 | FBPTerminal **TermPtr = Context.NetMap.Find(Net); 135 | 136 | if (!TermPtr) 137 | { 138 | FBPTerminal *Term = Context.CreateLocalTerminalFromPinAutoChooseScope(Net, Context.NetNameMap->MakeValidName(Net)); 139 | 140 | Context.NetMap.Add(Net, Term); 141 | 142 | return Term; 143 | } 144 | 145 | return *TermPtr; 146 | } 147 | 148 | void RegisterOutputTerm(FKismetFunctionContext& Context, UEdGraphPin* OutputPin, FBPTerminal* ContextTerm) 149 | { 150 | FBPTerminal *Term = Context.CreateLocalTerminalFromPinAutoChooseScope(OutputPin, Context.NetNameMap->MakeValidName(OutputPin)); 151 | Context.NetMap.Add(OutputPin, Term); 152 | } 153 | 154 | virtual void RegisterNets(FKismetFunctionContext& Context, UEdGraphNode* InNode) override 155 | { 156 | USIOJ_BreakJson* Node = Cast(InNode); 157 | FNodeHandlingFunctor::RegisterNets(Context, Node); 158 | 159 | check(NULL != Node); 160 | 161 | if (FBPTerminal* StructContextTerm = RegisterInputTerm(Context, Node)) 162 | { 163 | for (int32 PinIndex = 0; PinIndex < Node->Pins.Num(); ++PinIndex) 164 | { 165 | UEdGraphPin* Pin = Node->Pins[PinIndex]; 166 | if (NULL != Pin && EGPD_Output == Pin->Direction) 167 | { 168 | RegisterOutputTerm(Context, Pin, StructContextTerm); 169 | } 170 | } 171 | } 172 | } 173 | }; 174 | 175 | /** 176 | * Main node class 177 | */ 178 | USIOJ_BreakJson::USIOJ_BreakJson(const FObjectInitializer &ObjectInitializer) 179 | : Super(ObjectInitializer) 180 | { 181 | } 182 | 183 | FNodeHandlingFunctor* USIOJ_BreakJson::CreateNodeHandler(class FKismetCompilerContext& CompilerContext) const 184 | { 185 | return new FKCHandler_BreakJson(CompilerContext); 186 | } 187 | 188 | void USIOJ_BreakJson::AllocateDefaultPins() 189 | { 190 | const UEdGraphSchema_K2* K2Schema = GetDefault(); 191 | 192 | UClass *Class = Cast(StaticLoadObject(UClass::StaticClass(), NULL, TEXT("class'SIOJPlugin.SIOJJsonObject'"))); 193 | UEdGraphPin* Pin = CreatePin(EGPD_Input, K2Schema->PC_Object, TEXT(""), Class, TEXT("Target")); 194 | 195 | K2Schema->SetPinAutogeneratedDefaultValueBasedOnType(Pin); 196 | 197 | CreateProjectionPins(Pin); 198 | } 199 | 200 | FLinearColor USIOJ_BreakJson::GetNodeTitleColor() const 201 | { 202 | return FLinearColor(255.0f, 255.0f, 0.0f); 203 | } 204 | 205 | void USIOJ_BreakJson::PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent) 206 | { 207 | bool bIsDirty = false; 208 | 209 | FName PropertyName = (PropertyChangedEvent.Property != NULL) ? PropertyChangedEvent.Property->GetFName() : NAME_None; 210 | if (true || PropertyName == TEXT("Outputs")) 211 | { 212 | bIsDirty = true; 213 | } 214 | 215 | if (bIsDirty) 216 | { 217 | ReconstructNode(); 218 | GetGraph()->NotifyGraphChanged(); 219 | } 220 | 221 | Super::PostEditChangeProperty(PropertyChangedEvent); 222 | } 223 | 224 | void USIOJ_BreakJson::GetMenuActions(FBlueprintActionDatabaseRegistrar& ActionRegistrar) const 225 | { 226 | // actions get registered under specific object-keys; the idea is that 227 | // actions might have to be updated (or deleted) if their object-key is 228 | // mutated (or removed)... here we use the node's class (so if the node 229 | // type disappears, then the action should go with it) 230 | UClass* ActionKey = GetClass(); 231 | 232 | // to keep from needlessly instantiating a UBlueprintNodeSpawner, first 233 | // check to make sure that the registrar is looking for actions of this type 234 | // (could be regenerating actions for a specific asset, and therefore the 235 | // registrar would only accept actions corresponding to that asset) 236 | if (ActionRegistrar.IsOpenForRegistration(ActionKey)) 237 | { 238 | UBlueprintNodeSpawner* NodeSpawner = UBlueprintNodeSpawner::Create(GetClass()); 239 | check(NodeSpawner != nullptr); 240 | 241 | ActionRegistrar.AddBlueprintAction(ActionKey, NodeSpawner); 242 | } 243 | } 244 | 245 | FText USIOJ_BreakJson::GetMenuCategory() const 246 | { 247 | static FNodeTextCache CachedCategory; 248 | 249 | if (CachedCategory.IsOutOfDate(this)) 250 | { 251 | // FText::Format() is slow, so we cache this to save on performance 252 | CachedCategory.SetCachedText(FEditorCategoryUtils::BuildCategoryString(FCommonEditorCategory::Utilities, LOCTEXT("ActionMenuCategory", "Va Rest")), this); 253 | } 254 | return CachedCategory; 255 | } 256 | 257 | void USIOJ_BreakJson::CreateProjectionPins(UEdGraphPin *Source) 258 | { 259 | const UEdGraphSchema_K2* K2Schema = GetDefault(); 260 | UClass *Class = Cast(StaticLoadObject(UClass::StaticClass(), NULL, TEXT("class'SIOJPlugin.SIOJJsonObject'"))); 261 | 262 | for (TArray::TIterator it(Outputs); it; ++it) 263 | { 264 | FName Type; 265 | UObject *Subtype = nullptr; 266 | FString FieldName = (*it).Name; 267 | 268 | switch ((*it).Type) { 269 | case ESIOJ_JsonType::JSON_Bool: 270 | Type = K2Schema->PC_Boolean; 271 | break; 272 | 273 | case ESIOJ_JsonType::JSON_Number: 274 | Type = K2Schema->PC_Float; 275 | break; 276 | 277 | case ESIOJ_JsonType::JSON_String: 278 | Type = K2Schema->PC_String; 279 | break; 280 | 281 | case ESIOJ_JsonType::JSON_Object: 282 | Type = K2Schema->PC_Object; 283 | Subtype = Class; 284 | break; 285 | } 286 | 287 | FCreatePinParams PinParams; 288 | if ((*it).bIsArray) 289 | { 290 | PinParams.ContainerType = EPinContainerType::Array; 291 | } 292 | else 293 | { 294 | PinParams.ContainerType = EPinContainerType::None; 295 | } 296 | PinParams.bIsConst = false; 297 | PinParams.bIsReference = false; 298 | FName Name = FName(*(*it).Name); 299 | 300 | UEdGraphPin *OutputPin = CreatePin(EGPD_Output, Type, TEXT(""), Subtype, Name, PinParams); 301 | } 302 | } 303 | 304 | FText USIOJ_BreakJson::GetNodeTitle(ENodeTitleType::Type TitleType) const 305 | { 306 | return LOCTEXT("SIOJ_Break_Json.NodeTitle", "Break Json"); 307 | } 308 | 309 | #undef LOCTEXT_NAMESPACE 310 | -------------------------------------------------------------------------------- /FingerControlUE4/Plugins/UDPWrapper/Source/SIOJEditorPlugin/Public/SIOJEditorPlugin.h: -------------------------------------------------------------------------------- 1 | // Modifications Copyright 2018-current Getnamo. All Rights Reserved 2 | 3 | 4 | // Copyright 2015 Vladimir Alyamkin. All Rights Reserved. 5 | // Original code by https://github.com/unktomi 6 | 7 | #pragma once 8 | 9 | #include "Runtime/Core/Public/Modules/ModuleManager.h" 10 | 11 | class FSIOJEditorPluginModule : public IModuleInterface 12 | { 13 | 14 | public: 15 | /** IModuleInterface implementation */ 16 | virtual void StartupModule() override; 17 | virtual void ShutdownModule() override; 18 | 19 | }; 20 | -------------------------------------------------------------------------------- /FingerControlUE4/Plugins/UDPWrapper/Source/SIOJEditorPlugin/Public/SIOJ_BreakJson.h: -------------------------------------------------------------------------------- 1 | // Modifications Copyright 2018-current Getnamo. All Rights Reserved 2 | 3 | 4 | // Copyright 2015 Vladimir Alyamkin. All Rights Reserved. 5 | // Original code by https://github.com/unktomi 6 | 7 | #pragma once 8 | 9 | #include "K2Node.h" 10 | #include "ISIOJson.h" 11 | #include "SIOJConvert.h" 12 | #include "SIOJsonObject.h" 13 | #include "SIOJsonValue.h" 14 | #include "SIOJLibrary.h" 15 | #include "SIOJRequestJSON.h" 16 | #include "SIOJTypes.h" 17 | 18 | #include "SIOJ_BreakJson.generated.h" 19 | 20 | UENUM(BlueprintType) 21 | enum class ESIOJ_JsonType : uint8 22 | { 23 | //JSON_Null UMETA(DisplayName = "Null"), 24 | JSON_Bool UMETA(DisplayName = "Boolean"), 25 | JSON_Number UMETA(DisplayName = "Number"), 26 | JSON_String UMETA(DisplayName = "String"), 27 | JSON_Object UMETA(DisplayName = "Object") 28 | }; 29 | 30 | USTRUCT(BlueprintType) 31 | struct FSIOJ_NamedType 32 | { 33 | GENERATED_USTRUCT_BODY(); 34 | 35 | UPROPERTY(EditAnywhere, Category = NamedType) 36 | FString Name; 37 | 38 | UPROPERTY(EditAnywhere, Category = NamedType) 39 | ESIOJ_JsonType Type; 40 | 41 | UPROPERTY(EditAnywhere, Category = NamedType) 42 | bool bIsArray; 43 | }; 44 | 45 | UCLASS(BlueprintType, Blueprintable) 46 | class SIOJEDITORPLUGIN_API USIOJ_BreakJson : public UK2Node 47 | { 48 | GENERATED_UCLASS_BODY() 49 | 50 | public: 51 | // Begin UEdGraphNode interface. 52 | virtual void AllocateDefaultPins() override; 53 | virtual FLinearColor GetNodeTitleColor() const override; 54 | virtual void PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent) override; 55 | // End UEdGraphNode interface. 56 | 57 | // Begin UK2Node interface 58 | virtual bool IsNodePure() const { return true; } 59 | virtual bool ShouldShowNodeProperties() const { return true; } 60 | void GetMenuActions(FBlueprintActionDatabaseRegistrar& ActionRegistrar) const override; 61 | virtual FText GetMenuCategory() const override; 62 | virtual FText GetNodeTitle(ENodeTitleType::Type TitleType) const override; 63 | virtual class FNodeHandlingFunctor* CreateNodeHandler(class FKismetCompilerContext& CompilerContext) const override; 64 | // End UK2Node interface. 65 | 66 | protected: 67 | virtual void CreateProjectionPins(UEdGraphPin *Source); 68 | 69 | public: 70 | UPROPERTY(EditAnywhere, Category = PinOptions) 71 | TArray Outputs; 72 | 73 | }; 74 | -------------------------------------------------------------------------------- /FingerControlUE4/Plugins/UDPWrapper/Source/SIOJEditorPlugin/SIOJEditorPlugin.Build.cs: -------------------------------------------------------------------------------- 1 | // Modifications Copyright 2018-current Getnamo. All Rights Reserved 2 | 3 | 4 | // Copyright 2015 Vladimir Alyamkin. All Rights Reserved. 5 | 6 | using UnrealBuildTool; 7 | using System.IO; 8 | 9 | public class SIOJEditorPlugin : ModuleRules 10 | { 11 | public SIOJEditorPlugin(ReadOnlyTargetRules Target) : base(Target) 12 | { 13 | PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; 14 | 15 | PublicIncludePaths.AddRange( 16 | new string[] { 17 | Path.Combine(ModuleDirectory, "Public"), 18 | Path.Combine(ModuleDirectory, "../SIOJson", "Public"), 19 | 20 | // ... add public include paths required here ... 21 | }); 22 | 23 | 24 | PrivateIncludePaths.AddRange( 25 | new string[] { 26 | "SIOJEditorPlugin/Private", 27 | 28 | // ... add other private include paths required here ... 29 | }); 30 | 31 | 32 | PublicDependencyModuleNames.AddRange( 33 | new string[] 34 | { 35 | "Core", 36 | "SIOJson" 37 | 38 | // ... add other public dependencies that you statically link with here ... 39 | }); 40 | 41 | 42 | PrivateDependencyModuleNames.AddRange( 43 | new string[] 44 | { 45 | "CoreUObject", 46 | "Engine", 47 | "Slate", 48 | "SlateCore", 49 | "InputCore", 50 | "AssetTools", 51 | "UnrealEd", // for FAssetEditorManager 52 | "KismetWidgets", 53 | "KismetCompiler", 54 | "BlueprintGraph", 55 | "GraphEditor", 56 | "Kismet", // for FWorkflowCentricApplication 57 | "PropertyEditor", 58 | "EditorStyle", 59 | "Sequencer", 60 | "DetailCustomizations", 61 | "Settings", 62 | "RenderCore" 63 | }); 64 | 65 | 66 | DynamicallyLoadedModuleNames.AddRange( 67 | new string[] 68 | { 69 | // ... add any modules that your module loads dynamically here ... 70 | }); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /FingerControlUE4/Plugins/UDPWrapper/Source/SIOJson/Private/SIOJConvert.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018-current Getnamo. All Rights Reserved 2 | 3 | 4 | #include "SIOJConvert.h" 5 | //#include "Runtime/Json/Public/Json.h" 6 | #include "JsonGlobals.h" 7 | #include "Policies/CondensedJsonPrintPolicy.h" 8 | #include "Runtime/JsonUtilities/Public/JsonObjectConverter.h" 9 | #include "Runtime/Core/Public/Misc/FileHelper.h" 10 | #include "SIOJsonValue.h" 11 | #include "SIOJsonObject.h" 12 | 13 | typedef TJsonWriterFactory< TCHAR, TCondensedJsonPrintPolicy > FCondensedJsonStringWriterFactory; 14 | typedef TJsonWriter< TCHAR, TCondensedJsonPrintPolicy > FCondensedJsonStringWriter; 15 | 16 | //The one key that will break 17 | #define TMAP_STRING TEXT("!__!INTERNAL_TMAP") 18 | 19 | 20 | FString FTrimmedKeyMap::ToString() 21 | { 22 | FString SubMapString; 23 | for (auto Pair : SubMap) 24 | { 25 | FString PairString = FString::Printf(TEXT("{%s:%s}"), *Pair.Key, *Pair.Value->ToString()); 26 | SubMapString.Append(PairString); 27 | SubMapString.Append(","); 28 | } 29 | return FString::Printf(TEXT("{%s:%s}"), *LongKey, *SubMapString); 30 | } 31 | 32 | FString USIOJConvert::ToJsonString(const TSharedPtr& JsonObject) 33 | { 34 | FString OutputString; 35 | TSharedRef< FCondensedJsonStringWriter > Writer = FCondensedJsonStringWriterFactory::Create(&OutputString); 36 | FJsonSerializer::Serialize(JsonObject.ToSharedRef(), Writer); 37 | return OutputString; 38 | } 39 | 40 | FString USIOJConvert::ToJsonString(const TArray>& JsonValueArray) 41 | { 42 | FString OutputString; 43 | TSharedRef< FCondensedJsonStringWriter > Writer = FCondensedJsonStringWriterFactory::Create(&OutputString); 44 | FJsonSerializer::Serialize(JsonValueArray, Writer); 45 | return OutputString; 46 | } 47 | 48 | FString USIOJConvert::ToJsonString(const TSharedPtr& JsonValue) 49 | { 50 | if (JsonValue->Type == EJson::None) 51 | { 52 | return FString(); 53 | } 54 | else if (JsonValue->Type == EJson::Null) 55 | { 56 | return FString(); 57 | } 58 | else if (JsonValue->Type == EJson::String) 59 | { 60 | return JsonValue->AsString(); 61 | } 62 | else if (JsonValue->Type == EJson::Number) 63 | { 64 | return FString::Printf(TEXT("%f"),JsonValue->AsNumber()); 65 | } 66 | else if (JsonValue->Type == EJson::Boolean) 67 | { 68 | return FString::Printf(TEXT("%d"), JsonValue->AsBool()); 69 | } 70 | else if (JsonValue->Type == EJson::Array) 71 | { 72 | return ToJsonString(JsonValue->AsArray()); 73 | } 74 | else if (JsonValue->Type == EJson::Object) 75 | { 76 | return ToJsonString(JsonValue->AsObject()); 77 | } 78 | else 79 | { 80 | return FString(); 81 | } 82 | } 83 | 84 | USIOJsonValue* USIOJConvert::ToSIOJsonValue(const TArray>& JsonValueArray) 85 | { 86 | TArray< TSharedPtr > ValueArray; 87 | for (auto InVal : JsonValueArray) 88 | { 89 | ValueArray.Add(InVal); 90 | } 91 | 92 | USIOJsonValue* ResultValue = NewObject(); 93 | TSharedPtr NewVal = MakeShareable(new FJsonValueArray(ValueArray)); 94 | ResultValue->SetRootValue(NewVal); 95 | 96 | return ResultValue; 97 | } 98 | 99 | #if PLATFORM_WINDOWS 100 | #pragma endregion ToJsonValue 101 | #endif 102 | 103 | TSharedPtr USIOJConvert::JsonStringToJsonValue(const FString& JsonString) 104 | { 105 | //Null 106 | if (JsonString.IsEmpty()) 107 | { 108 | return MakeShareable(new FJsonValueNull); 109 | } 110 | 111 | //Number 112 | if (JsonString.IsNumeric()) 113 | { 114 | //convert to double 115 | return MakeShareable(new FJsonValueNumber(FCString::Atod(*JsonString))); 116 | } 117 | 118 | //Object 119 | if (JsonString.StartsWith(FString(TEXT("{")))) 120 | { 121 | TSharedPtr< FJsonObject > JsonObject = MakeShareable(new FJsonObject); 122 | TSharedRef< TJsonReader<> > Reader = TJsonReaderFactory<>::Create(*JsonString); 123 | bool success = FJsonSerializer::Deserialize(Reader, JsonObject); 124 | 125 | if (success) 126 | { 127 | return MakeShareable(new FJsonValueObject(JsonObject)); 128 | } 129 | } 130 | 131 | //Array 132 | if (JsonString.StartsWith(FString(TEXT("[")))) 133 | { 134 | TArray < TSharedPtr> RawJsonValueArray; 135 | TSharedRef< TJsonReader<> > Reader = TJsonReaderFactory<>::Create(*JsonString); 136 | bool success = FJsonSerializer::Deserialize(Reader, RawJsonValueArray); 137 | 138 | if (success) 139 | { 140 | return MakeShareable(new FJsonValueArray(RawJsonValueArray)); 141 | } 142 | } 143 | 144 | //Bool 145 | if (JsonString == FString("true") || JsonString == FString("false")) 146 | { 147 | bool BooleanValue = (JsonString == FString("true")); 148 | return MakeShareable(new FJsonValueBoolean(BooleanValue)); 149 | } 150 | 151 | //String 152 | return MakeShareable(new FJsonValueString(JsonString)); 153 | } 154 | 155 | TSharedPtr USIOJConvert::ToJsonValue(const TSharedPtr& JsonObject) 156 | { 157 | return MakeShareable(new FJsonValueObject(JsonObject)); 158 | } 159 | 160 | TSharedPtr USIOJConvert::ToJsonValue(const FString& StringValue) 161 | { 162 | return MakeShareable(new FJsonValueString(StringValue)); 163 | } 164 | 165 | TSharedPtr USIOJConvert::ToJsonValue(double NumberValue) 166 | { 167 | return MakeShareable(new FJsonValueNumber(NumberValue)); 168 | } 169 | 170 | TSharedPtr USIOJConvert::ToJsonValue(bool BoolValue) 171 | { 172 | return MakeShareable(new FJsonValueBoolean(BoolValue)); 173 | } 174 | 175 | TSharedPtr USIOJConvert::ToJsonValue(const TArray& BinaryValue) 176 | { 177 | return MakeShareable(new FJsonValueBinary(BinaryValue)); 178 | } 179 | 180 | TSharedPtr USIOJConvert::ToJsonValue(const TArray>& ArrayValue) 181 | { 182 | return MakeShareable(new FJsonValueArray(ArrayValue)); 183 | } 184 | 185 | #if PLATFORM_WINDOWS 186 | #pragma endregion ToJsonValue 187 | #endif 188 | 189 | TArray> USIOJConvert::JsonStringToJsonArray(const FString& JsonString) 190 | { 191 | TArray < TSharedPtr> RawJsonValueArray; 192 | TSharedRef< TJsonReader<> > Reader = TJsonReaderFactory<>::Create(*JsonString); 193 | FJsonSerializer::Deserialize(Reader, RawJsonValueArray); 194 | 195 | return RawJsonValueArray; 196 | } 197 | 198 | TSharedPtr USIOJConvert::ToJsonObject(const FString& JsonString) 199 | { 200 | TSharedPtr< FJsonObject > JsonObject = MakeShareable(new FJsonObject); 201 | TSharedRef< TJsonReader<> > Reader = TJsonReaderFactory<>::Create(*JsonString); 202 | FJsonSerializer::Deserialize(Reader, JsonObject); 203 | return JsonObject; 204 | } 205 | 206 | TSharedPtr USIOJConvert::ToJsonObject(UStruct* Struct, void* StructPtr, bool IsBlueprintStruct) 207 | { 208 | if (IsBlueprintStruct) 209 | { 210 | //Get the object keys 211 | TSharedPtr Object = ToJsonObject(Struct, StructPtr, false); 212 | 213 | //Wrap it into a value and pass it into the trimmer 214 | TSharedPtr JsonValue = MakeShareable(new FJsonValueObject(Object)); 215 | TrimValueKeyNames(JsonValue); 216 | 217 | //Return object with trimmed names 218 | return JsonValue->AsObject(); 219 | } 220 | else 221 | { 222 | TSharedRef JsonObject = MakeShareable(new FJsonObject); 223 | bool success = FJsonObjectConverter::UStructToJsonObject(Struct, StructPtr, JsonObject, 0, 0); 224 | return JsonObject; 225 | } 226 | } 227 | 228 | TSharedPtr USIOJConvert::MakeJsonObject() 229 | { 230 | return MakeShareable(new FJsonObject); 231 | } 232 | 233 | bool USIOJConvert::JsonObjectToUStruct(TSharedPtr JsonObject, UStruct* Struct, void* StructPtr, bool IsBlueprintStruct) 234 | { 235 | if (IsBlueprintStruct) 236 | { 237 | //Json object we pass will have their trimmed BP names, e.g. boolKey vs boolKey_8_EDBB36654CF43866C376DE921373AF23 238 | //so we have to match them to the verbose versions, get a map of the names 239 | 240 | TSharedPtr KeyMap = MakeShareable(new FTrimmedKeyMap); 241 | SetTrimmedKeyMapForStruct(KeyMap, Struct); 242 | 243 | //Print our keymap for debug 244 | //UE_LOG(LogTemp, Log, TEXT("Keymap: %s"), *KeyMap->ToString()); 245 | 246 | //Adjust our passed in JsonObject to use the long key names 247 | TSharedPtr JsonValue = MakeShareable(new FJsonValueObject(JsonObject)); 248 | ReplaceJsonValueNamesWithMap(JsonValue, KeyMap); 249 | 250 | //Now it's a regular struct and will fill correctly 251 | return JsonObjectToUStruct(JsonObject, Struct, StructPtr, false); 252 | } 253 | else 254 | { 255 | return FJsonObjectConverter::JsonObjectToUStruct(JsonObject.ToSharedRef(), Struct, StructPtr, 0, 0); 256 | } 257 | } 258 | 259 | bool USIOJConvert::JsonFileToUStruct(const FString& FilePath, UStruct* Struct, void* StructPtr, bool IsBlueprintStruct /*= false*/) 260 | { 261 | //Read bytes from file 262 | TArray OutBytes; 263 | if (!FFileHelper::LoadFileToArray(OutBytes, *FilePath)) 264 | { 265 | return false; 266 | } 267 | 268 | //Convert to json string 269 | FString JsonString; 270 | FFileHelper::BufferToString(JsonString, OutBytes.GetData(), OutBytes.Num()); 271 | 272 | //Read into struct 273 | return JsonObjectToUStruct(ToJsonObject(JsonString), Struct, StructPtr, IsBlueprintStruct); 274 | } 275 | 276 | 277 | bool USIOJConvert::ToJsonFile(const FString& FilePath, UStruct* Struct, void* StructPtr, bool IsBlueprintStruct /*= false*/) 278 | { 279 | //Get json object with trimmed values 280 | TSharedPtr JsonObject = ToJsonObject(Struct, StructPtr, IsBlueprintStruct); 281 | TSharedPtr TrimmedValue = MakeShareable(new FJsonValueObject(JsonObject)); 282 | TrimValueKeyNames(TrimmedValue); 283 | 284 | //Convert to string 285 | FString JsonString = ToJsonString(TrimmedValue); 286 | FTCHARToUTF8 Utf8String(*JsonString); 287 | 288 | TArray Bytes; 289 | Bytes.Append((uint8*)Utf8String.Get(), Utf8String.Length()); 290 | 291 | //flush to disk 292 | return FFileHelper::SaveArrayToFile(Bytes, *FilePath); 293 | } 294 | 295 | void USIOJConvert::TrimValueKeyNames(const TSharedPtr& JsonValue) 296 | { 297 | //Array? 298 | if (JsonValue->Type == EJson::Array) 299 | { 300 | auto Array = JsonValue->AsArray(); 301 | 302 | for (auto SubValue : Array) 303 | { 304 | TrimValueKeyNames(SubValue); 305 | } 306 | } 307 | //Object? 308 | else if (JsonValue->Type == EJson::Object) 309 | { 310 | auto JsonObject = JsonValue->AsObject(); 311 | for (auto Pair : JsonObject->Values) 312 | { 313 | const FString& Key = Pair.Key; 314 | FString TrimmedKey; 315 | 316 | bool DidNeedTrimming = TrimKey(Key, TrimmedKey); 317 | 318 | //keep attempting sub keys even if we have a valid string 319 | auto SubValue = Pair.Value; 320 | TrimValueKeyNames(SubValue); 321 | 322 | if (DidNeedTrimming) 323 | { 324 | //Replace field names with the trimmed key 325 | JsonObject->SetField(TrimmedKey, SubValue); 326 | JsonObject->RemoveField(Key); 327 | } 328 | } 329 | } 330 | else 331 | { 332 | //UE_LOG(LogTemp, Warning, TEXT("TrimValueKeyNames:: uncaught type is: %d"), (int)JsonValue->Type); 333 | } 334 | } 335 | 336 | bool USIOJConvert::TrimKey(const FString& InLongKey, FString& OutTrimmedKey) 337 | { 338 | //Look for the position of the 2nd '_' 339 | int32 LastIndex = InLongKey.Find(TEXT("_"), ESearchCase::IgnoreCase, ESearchDir::FromEnd); 340 | LastIndex = InLongKey.Find(TEXT("_"), ESearchCase::IgnoreCase, ESearchDir::FromEnd, LastIndex); 341 | 342 | if (LastIndex >= 0) 343 | { 344 | OutTrimmedKey = InLongKey.Mid(0, LastIndex);; 345 | return true; 346 | } 347 | else 348 | { 349 | return false; 350 | } 351 | } 352 | 353 | void USIOJConvert::SetTrimmedKeyMapForStruct(TSharedPtr& InMap, UStruct* Struct) 354 | { 355 | //Get the child fields 356 | UField* FieldPtr = Struct->Children; 357 | 358 | //If it hasn't been set, the long key is the json standardized long name 359 | if (InMap->LongKey.IsEmpty()) 360 | { 361 | InMap->LongKey = FJsonObjectConverter::StandardizeCase(Struct->GetName()); 362 | } 363 | 364 | //For each child field... 365 | while (FieldPtr != nullptr) 366 | { 367 | //Map our trimmed name to our full name 368 | const FString& LowerKey = FJsonObjectConverter::StandardizeCase(FieldPtr->GetName()); 369 | FString TrimmedKey; 370 | bool DidTrim = TrimKey(LowerKey, TrimmedKey); 371 | 372 | //Set the key map 373 | TSharedPtr SubMap = MakeShareable(new FTrimmedKeyMap); 374 | SubMap->LongKey = LowerKey; 375 | 376 | //No-trim case, trim = long 377 | if (!DidTrim) 378 | { 379 | TrimmedKey = SubMap->LongKey; 380 | } 381 | 382 | //Did we get a substructure? 383 | UStructProperty* SubStruct = Cast(FieldPtr); 384 | UArrayProperty* ArrayProp = Cast(FieldPtr); 385 | UMapProperty* MapProperty = Cast(FieldPtr); 386 | 387 | if (SubStruct != nullptr) 388 | { 389 | //We did, embed the sub-map 390 | SetTrimmedKeyMapForStruct(SubMap, SubStruct->Struct); 391 | } 392 | 393 | //Did we get a sub-array? 394 | else if (ArrayProp != nullptr) 395 | { 396 | //set the inner map for the inner property 397 | //UE_LOG(LogTemp, Log, TEXT("found array: %s"), *ArrayProp->GetName()); 398 | SetTrimmedKeyMapForProp(SubMap, ArrayProp->Inner); 399 | } 400 | else if (MapProperty != nullptr) 401 | { 402 | //UE_LOG(LogTemp, Log, TEXT("I'm a tmap: %s"), *MapProperty->GetName()); 403 | SetTrimmedKeyMapForProp(SubMap, MapProperty); 404 | } 405 | 406 | //Debug types 407 | /* 408 | UProperty* ObjectProp = Cast(FieldPtr); 409 | if (ObjectProp) 410 | { 411 | UE_LOG(LogTemp, Log, TEXT("found map: %s, %s, type: %s, %s"), 412 | *ObjectProp->GetName(), 413 | *ObjectProp->GetNameCPP(), 414 | *ObjectProp->GetClass()->GetFName().ToString(), 415 | *ObjectProp->GetCPPType()); 416 | }*/ 417 | 418 | InMap->SubMap.Add(TrimmedKey, SubMap); 419 | //UE_LOG(LogTemp, Log, TEXT("long: %s, trim: %s, is struct: %d"), *SubMap->LongKey, *TrimmedKey, SubStruct != NULL); 420 | 421 | FieldPtr = FieldPtr->Next; 422 | } 423 | 424 | //UE_LOG(LogTemp, Log, TEXT("Final map: %d"), InMap->SubMap.Num()); 425 | } 426 | 427 | void USIOJConvert::SetTrimmedKeyMapForProp(TSharedPtr& InMap, UProperty* InnerProperty) 428 | { 429 | 430 | //UE_LOG(LogTemp, Log, TEXT("got prop: %s"), *InnerProperty->GetName()); 431 | UStructProperty* SubStruct = Cast(InnerProperty); 432 | UArrayProperty* ArrayProp = Cast(InnerProperty); 433 | UMapProperty* MapProperty = Cast(InnerProperty); 434 | 435 | if (SubStruct != nullptr) 436 | { 437 | //We did, embed the sub-map 438 | SetTrimmedKeyMapForStruct(InMap, SubStruct->Struct); 439 | } 440 | //Did we get a sub-array? 441 | else if (ArrayProp != nullptr) 442 | { 443 | SetTrimmedKeyMapForProp(InMap, ArrayProp->Inner); 444 | } 445 | else if (MapProperty != nullptr) 446 | { 447 | //Make a special submap with special TMAP identifier key 448 | TSharedPtr SubMap = MakeShareable(new FTrimmedKeyMap); 449 | SubMap->LongKey = TMAP_STRING; 450 | InMap->SubMap.Add(SubMap->LongKey, SubMap); 451 | 452 | //Take the value property and set it as it's unique child 453 | SetTrimmedKeyMapForProp(SubMap, MapProperty->ValueProp); 454 | 455 | //Each child in the JSON object map will use the same structure (it's a UE4 limitation of maps anyway 456 | } 457 | } 458 | 459 | void USIOJConvert::ReplaceJsonValueNamesWithMap(TSharedPtr& JsonValue, TSharedPtr KeyMap) 460 | { 461 | if (JsonValue->Type == EJson::Object) 462 | { 463 | //Go through each key in the object 464 | auto Object = JsonValue->AsObject(); 465 | auto SubMap = KeyMap->SubMap; 466 | auto AllValues = Object->Values; 467 | 468 | FString PreviewPreValue = USIOJConvert::ToJsonString(Object); 469 | //UE_LOG(LogTemp, Log, TEXT("Rep::PreObject: <%s>"), *PreviewPreValue); 470 | 471 | for (auto Pair : AllValues) 472 | { 473 | if (SubMap.Contains(TMAP_STRING)) 474 | { 475 | FString TMapString = FString(TMAP_STRING); 476 | //If we found a tmap, replace each sub key with list of keys 477 | ReplaceJsonValueNamesWithMap(Pair.Value, SubMap[TMapString]); 478 | } 479 | else if (SubMap.Num() > 0 && SubMap.Contains(Pair.Key)) 480 | { 481 | //Get the long key for entry 482 | const FString& LongKey = SubMap[Pair.Key]->LongKey; 483 | 484 | //loop nested structures 485 | ReplaceJsonValueNamesWithMap(Pair.Value, SubMap[Pair.Key]); 486 | 487 | if (Pair.Key != LongKey) 488 | { 489 | //finally set the field and remove the old field 490 | Object->SetField(LongKey, Pair.Value); 491 | Object->RemoveField(Pair.Key); 492 | } 493 | } 494 | } 495 | 496 | FString PreviewPostValue = USIOJConvert::ToJsonString(Object); 497 | //UE_LOG(LogTemp, Log, TEXT("Rep::PostObject: <%s>"), *PreviewPostValue); 498 | } 499 | else if (JsonValue->Type == EJson::Array) 500 | { 501 | auto Array = JsonValue->AsArray(); 502 | for (auto Item : Array) 503 | { 504 | //UE_LOG(LogTemp, Log, TEXT("%s"), *Item->AsString()); 505 | ReplaceJsonValueNamesWithMap(Item, KeyMap); 506 | } 507 | } 508 | } -------------------------------------------------------------------------------- /FingerControlUE4/Plugins/UDPWrapper/Source/SIOJson/Private/SIOJLibrary.cpp: -------------------------------------------------------------------------------- 1 | // Modifications Copyright 2018-current Getnamo. All Rights Reserved 2 | 3 | 4 | // Copyright 2016 Vladimir Alyamkin. All Rights Reserved. 5 | 6 | #include "SIOJLibrary.h" 7 | #include "ISIOJson.h" 8 | #include "Runtime/Json/Public/Dom/JsonObject.h" 9 | #include "Runtime/Json/Public/Dom/JsonValue.h" 10 | #include "SIOJsonValue.h" 11 | #include "SIOJsonObject.h" 12 | #include "Runtime/Core/Public/Misc/Base64.h" 13 | #include "Engine/Engine.h" 14 | 15 | ////////////////////////////////////////////////////////////////////////// 16 | // Helpers 17 | 18 | FString USIOJLibrary::PercentEncode(const FString& Source) 19 | { 20 | FString OutText = Source; 21 | 22 | OutText = OutText.Replace(TEXT(" "), TEXT("%20")); 23 | OutText = OutText.Replace(TEXT("!"), TEXT("%21")); 24 | OutText = OutText.Replace(TEXT("\""), TEXT("%22")); 25 | OutText = OutText.Replace(TEXT("#"), TEXT("%23")); 26 | OutText = OutText.Replace(TEXT("$"), TEXT("%24")); 27 | OutText = OutText.Replace(TEXT("&"), TEXT("%26")); 28 | OutText = OutText.Replace(TEXT("'"), TEXT("%27")); 29 | OutText = OutText.Replace(TEXT("("), TEXT("%28")); 30 | OutText = OutText.Replace(TEXT(")"), TEXT("%29")); 31 | OutText = OutText.Replace(TEXT("*"), TEXT("%2A")); 32 | OutText = OutText.Replace(TEXT("+"), TEXT("%2B")); 33 | OutText = OutText.Replace(TEXT(","), TEXT("%2C")); 34 | OutText = OutText.Replace(TEXT("/"), TEXT("%2F")); 35 | OutText = OutText.Replace(TEXT(":"), TEXT("%3A")); 36 | OutText = OutText.Replace(TEXT(";"), TEXT("%3B")); 37 | OutText = OutText.Replace(TEXT("="), TEXT("%3D")); 38 | OutText = OutText.Replace(TEXT("?"), TEXT("%3F")); 39 | OutText = OutText.Replace(TEXT("@"), TEXT("%40")); 40 | OutText = OutText.Replace(TEXT("["), TEXT("%5B")); 41 | OutText = OutText.Replace(TEXT("]"), TEXT("%5D")); 42 | OutText = OutText.Replace(TEXT("{"), TEXT("%7B")); 43 | OutText = OutText.Replace(TEXT("}"), TEXT("%7D")); 44 | 45 | return OutText; 46 | } 47 | 48 | FString USIOJLibrary::Base64Encode(const FString& Source) 49 | { 50 | return FBase64::Encode(Source); 51 | } 52 | 53 | bool USIOJLibrary::Base64Decode(const FString& Source, FString& Dest) 54 | { 55 | return FBase64::Decode(Source, Dest); 56 | } 57 | 58 | 59 | bool USIOJLibrary::StringToJsonValueArray(const FString& JsonString, TArray& OutJsonValueArray) 60 | { 61 | TArray < TSharedPtr> RawJsonValueArray; 62 | TSharedRef< TJsonReader<> > Reader = TJsonReaderFactory<>::Create(*JsonString); 63 | FJsonSerializer::Deserialize(Reader, RawJsonValueArray); 64 | 65 | for (auto Value : RawJsonValueArray) 66 | { 67 | auto SJsonValue = NewObject(); 68 | SJsonValue->SetRootValue(Value); 69 | OutJsonValueArray.Add(SJsonValue); 70 | } 71 | 72 | return OutJsonValueArray.Num() > 0; 73 | } 74 | 75 | ////////////////////////////////////////////////////////////////////////// 76 | // Easy URL processing 77 | 78 | TMap USIOJLibrary::RequestMap; 79 | 80 | 81 | FString USIOJLibrary::Conv_JsonObjectToString(USIOJsonObject* InObject) 82 | { 83 | if(InObject) 84 | { 85 | return InObject->EncodeJson(); 86 | } 87 | 88 | return ""; 89 | } 90 | 91 | 92 | USIOJsonObject* USIOJLibrary::Conv_JsonValueToJsonObject(class USIOJsonValue* InValue) 93 | { 94 | if(InValue) 95 | { 96 | return InValue->AsObject(); 97 | } 98 | 99 | return nullptr; 100 | } 101 | 102 | USIOJsonValue* USIOJLibrary::Conv_ArrayToJsonValue(const TArray& InArray) 103 | { 104 | return USIOJsonValue::ConstructJsonValueArray(nullptr, InArray); 105 | } 106 | 107 | 108 | USIOJsonValue* USIOJLibrary::Conv_JsonObjectToJsonValue(USIOJsonObject* InObject) 109 | { 110 | return USIOJsonValue::ConstructJsonValueObject(InObject, nullptr); 111 | } 112 | 113 | 114 | USIOJsonValue* USIOJLibrary::Conv_BytesToJsonValue(const TArray& InBytes) 115 | { 116 | return USIOJsonValue::ConstructJsonValueBinary(nullptr, InBytes); 117 | } 118 | 119 | 120 | USIOJsonValue* USIOJLibrary::Conv_StringToJsonValue(const FString& InString) 121 | { 122 | return USIOJsonValue::ConstructJsonValueString(nullptr, InString); 123 | } 124 | 125 | 126 | USIOJsonValue* USIOJLibrary::Conv_IntToJsonValue(int32 InInt) 127 | { 128 | TSharedPtr NewVal = MakeShareable(new FJsonValueNumber(InInt)); 129 | 130 | USIOJsonValue* NewValue = NewObject(); 131 | NewValue->SetRootValue(NewVal); 132 | 133 | return NewValue; 134 | } 135 | 136 | USIOJsonValue* USIOJLibrary::Conv_FloatToJsonValue(float InFloat) 137 | { 138 | return USIOJsonValue::ConstructJsonValueNumber(nullptr, InFloat); 139 | } 140 | 141 | 142 | USIOJsonValue* USIOJLibrary::Conv_BoolToJsonValue(bool InBool) 143 | { 144 | return USIOJsonValue::ConstructJsonValueBool(nullptr, InBool); 145 | } 146 | 147 | 148 | int32 USIOJLibrary::Conv_JsonValueToInt(USIOJsonValue* InValue) 149 | { 150 | if(InValue) 151 | { 152 | return (int32)InValue->AsNumber(); 153 | } 154 | 155 | return 0; 156 | } 157 | 158 | 159 | float USIOJLibrary::Conv_JsonValueToFloat(USIOJsonValue* InValue) 160 | { 161 | if (InValue) 162 | { 163 | return InValue->AsNumber(); 164 | } 165 | 166 | return 0.f; 167 | } 168 | 169 | 170 | bool USIOJLibrary::Conv_JsonValueToBool(USIOJsonValue* InValue) 171 | { 172 | if (InValue) 173 | { 174 | return InValue->AsBool(); 175 | } 176 | 177 | return false; 178 | } 179 | 180 | 181 | TArray USIOJLibrary::Conv_JsonValueToBytes(USIOJsonValue* InValue) 182 | { 183 | if (InValue) 184 | { 185 | return InValue->AsBinary(); 186 | } 187 | 188 | return TArray(); 189 | } 190 | 191 | void USIOJLibrary::CallURL(UObject* WorldContextObject, const FString& URL, ESIORequestVerb Verb, ESIORequestContentType ContentType, USIOJsonObject* SIOJJson, const FSIOJCallDelegate& Callback) 192 | { 193 | UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::LogAndReturnNull); 194 | if (World == nullptr) 195 | { 196 | UE_LOG(LogSIOJ, Error, TEXT("USIOJLibrary: Wrong world context")) 197 | return; 198 | } 199 | 200 | // Check we have valid data json 201 | if (SIOJJson == nullptr) 202 | { 203 | SIOJJson = USIOJsonObject::ConstructJsonObject(WorldContextObject); 204 | } 205 | 206 | USIOJRequestJSON* Request = NewObject(); 207 | 208 | Request->SetVerb(Verb); 209 | Request->SetContentType(ContentType); 210 | Request->SetRequestObject(SIOJJson); 211 | 212 | FSIOJCallResponse Response; 213 | Response.Request = Request; 214 | Response.WorldContextObject = WorldContextObject; 215 | Response.Callback = Callback; 216 | 217 | Response.CompleteDelegateHandle = Request->OnStaticRequestComplete.AddStatic(&USIOJLibrary::OnCallComplete); 218 | Response.FailDelegateHandle = Request->OnStaticRequestFail.AddStatic(&USIOJLibrary::OnCallComplete); 219 | 220 | RequestMap.Add(Request, Response); 221 | 222 | Request->ResetResponseData(); 223 | Request->ProcessURL(URL); 224 | } 225 | 226 | void USIOJLibrary::OnCallComplete(USIOJRequestJSON* Request) 227 | { 228 | if (!RequestMap.Contains(Request)) 229 | { 230 | return; 231 | } 232 | 233 | FSIOJCallResponse* Response = RequestMap.Find(Request); 234 | 235 | Request->OnStaticRequestComplete.Remove(Response->CompleteDelegateHandle); 236 | Request->OnStaticRequestFail.Remove(Response->FailDelegateHandle); 237 | 238 | Response->Callback.ExecuteIfBound(Request); 239 | 240 | Response->WorldContextObject = nullptr; 241 | Response->Request = nullptr; 242 | RequestMap.Remove(Request); 243 | } 244 | -------------------------------------------------------------------------------- /FingerControlUE4/Plugins/UDPWrapper/Source/SIOJson/Private/SIOJRequestJSON.cpp: -------------------------------------------------------------------------------- 1 | // Modifications Copyright 2018-current Getnamo. All Rights Reserved 2 | 3 | 4 | // Copyright 2014 Vladimir Alyamkin. All Rights Reserved. 5 | 6 | #include "SIOJRequestJSON.h" 7 | #include "SIOJsonValue.h" 8 | #include "SIOJsonObject.h" 9 | 10 | template void FSIOJLatentAction::Cancel() 11 | { 12 | UObject *Obj = Request.Get(); 13 | if (Obj != nullptr) 14 | { 15 | ((USIOJRequestJSON*)Obj)->Cancel(); 16 | } 17 | } 18 | 19 | USIOJRequestJSON::USIOJRequestJSON(const class FObjectInitializer& PCIP) 20 | : Super(PCIP), 21 | BinaryContentType(TEXT("application/octet-stream")) 22 | { 23 | RequestVerb = ESIORequestVerb::GET; 24 | RequestContentType = ESIORequestContentType::x_www_form_urlencoded_url; 25 | 26 | ResetData(); 27 | } 28 | 29 | USIOJRequestJSON* USIOJRequestJSON::ConstructRequest(UObject* WorldContextObject) 30 | { 31 | return NewObject(); 32 | } 33 | 34 | USIOJRequestJSON* USIOJRequestJSON::ConstructRequestExt( 35 | UObject* WorldContextObject, 36 | ESIORequestVerb Verb, 37 | ESIORequestContentType ContentType) 38 | { 39 | USIOJRequestJSON* Request = ConstructRequest(WorldContextObject); 40 | 41 | Request->SetVerb(Verb); 42 | Request->SetContentType(ContentType); 43 | 44 | return Request; 45 | } 46 | 47 | void USIOJRequestJSON::SetVerb(ESIORequestVerb Verb) 48 | { 49 | RequestVerb = Verb; 50 | } 51 | 52 | void USIOJRequestJSON::SetCustomVerb(FString Verb) 53 | { 54 | CustomVerb = Verb; 55 | } 56 | 57 | void USIOJRequestJSON::SetContentType(ESIORequestContentType ContentType) 58 | { 59 | RequestContentType = ContentType; 60 | } 61 | 62 | void USIOJRequestJSON::SetBinaryContentType(const FString &ContentType) 63 | { 64 | BinaryContentType = ContentType; 65 | } 66 | 67 | void USIOJRequestJSON::SetBinaryRequestContent(const TArray &Bytes) 68 | { 69 | RequestBytes = Bytes; 70 | } 71 | 72 | void USIOJRequestJSON::SetHeader(const FString& HeaderName, const FString& HeaderValue) 73 | { 74 | RequestHeaders.Add(HeaderName, HeaderValue); 75 | } 76 | 77 | 78 | ////////////////////////////////////////////////////////////////////////// 79 | // Destruction and reset 80 | 81 | void USIOJRequestJSON::ResetData() 82 | { 83 | ResetRequestData(); 84 | ResetResponseData(); 85 | } 86 | 87 | void USIOJRequestJSON::ResetRequestData() 88 | { 89 | if (RequestJsonObj != nullptr) 90 | { 91 | RequestJsonObj->Reset(); 92 | } 93 | else 94 | { 95 | RequestJsonObj = NewObject(); 96 | } 97 | 98 | HttpRequest = FHttpModule::Get().CreateRequest(); 99 | } 100 | 101 | void USIOJRequestJSON::ResetResponseData() 102 | { 103 | if (ResponseJsonObj != nullptr) 104 | { 105 | ResponseJsonObj->Reset(); 106 | } 107 | else 108 | { 109 | ResponseJsonObj = NewObject(); 110 | } 111 | 112 | ResponseHeaders.Empty(); 113 | ResponseCode = -1; 114 | 115 | bIsValidJsonResponse = false; 116 | } 117 | 118 | void USIOJRequestJSON::Cancel() 119 | { 120 | ContinueAction = nullptr; 121 | 122 | ResetResponseData(); 123 | } 124 | 125 | 126 | ////////////////////////////////////////////////////////////////////////// 127 | // JSON data accessors 128 | 129 | USIOJsonObject* USIOJRequestJSON::GetRequestObject() 130 | { 131 | return RequestJsonObj; 132 | } 133 | 134 | void USIOJRequestJSON::SetRequestObject(USIOJsonObject* JsonObject) 135 | { 136 | RequestJsonObj = JsonObject; 137 | } 138 | 139 | USIOJsonObject* USIOJRequestJSON::GetResponseObject() 140 | { 141 | return ResponseJsonObj; 142 | } 143 | 144 | void USIOJRequestJSON::SetResponseObject(USIOJsonObject* JsonObject) 145 | { 146 | ResponseJsonObj = JsonObject; 147 | } 148 | 149 | 150 | /////////////////////////////////////////////////////////////////////////// 151 | // Response data access 152 | 153 | FString USIOJRequestJSON::GetURL() 154 | { 155 | return HttpRequest->GetURL(); 156 | } 157 | 158 | ESIORequestStatus USIOJRequestJSON::GetStatus() 159 | { 160 | return ESIORequestStatus((uint8)HttpRequest->GetStatus()); 161 | } 162 | 163 | int32 USIOJRequestJSON::GetResponseCode() 164 | { 165 | return ResponseCode; 166 | } 167 | 168 | FString USIOJRequestJSON::GetResponseHeader(const FString HeaderName) 169 | { 170 | FString Result; 171 | 172 | FString* Header = ResponseHeaders.Find(HeaderName); 173 | if (Header != nullptr) 174 | { 175 | Result = *Header; 176 | } 177 | 178 | return Result; 179 | } 180 | 181 | TArray USIOJRequestJSON::GetAllResponseHeaders() 182 | { 183 | TArray Result; 184 | for (TMap::TConstIterator It(ResponseHeaders); It; ++It) 185 | { 186 | Result.Add(It.Key() + TEXT(": ") + It.Value()); 187 | } 188 | return Result; 189 | } 190 | 191 | 192 | ////////////////////////////////////////////////////////////////////////// 193 | // URL processing 194 | 195 | void USIOJRequestJSON::ProcessURL(const FString& Url) 196 | { 197 | HttpRequest->SetURL(Url); 198 | 199 | ProcessRequest(); 200 | } 201 | 202 | void USIOJRequestJSON::ApplyURL(const FString& Url, USIOJsonObject *&Result, UObject* WorldContextObject, FLatentActionInfo LatentInfo) 203 | { 204 | HttpRequest->SetURL(Url); 205 | 206 | // Prepare latent action 207 | if (UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::LogAndReturnNull)) 208 | { 209 | FLatentActionManager& LatentActionManager = World->GetLatentActionManager(); 210 | FSIOJLatentAction *Kont = LatentActionManager.FindExistingAction>(LatentInfo.CallbackTarget, LatentInfo.UUID); 211 | 212 | if (Kont != nullptr) 213 | { 214 | Kont->Cancel(); 215 | LatentActionManager.RemoveActionsForObject(LatentInfo.CallbackTarget); 216 | } 217 | 218 | LatentActionManager.AddNewAction(LatentInfo.CallbackTarget, LatentInfo.UUID, ContinueAction = new FSIOJLatentAction(this, Result, LatentInfo)); 219 | } 220 | 221 | ProcessRequest(); 222 | } 223 | 224 | void USIOJRequestJSON::ProcessRequest() 225 | { 226 | // Set verb 227 | switch (RequestVerb) 228 | { 229 | case ESIORequestVerb::GET: 230 | HttpRequest->SetVerb(TEXT("GET")); 231 | break; 232 | 233 | case ESIORequestVerb::POST: 234 | HttpRequest->SetVerb(TEXT("POST")); 235 | break; 236 | 237 | case ESIORequestVerb::PUT: 238 | HttpRequest->SetVerb(TEXT("PUT")); 239 | break; 240 | 241 | case ESIORequestVerb::DEL: 242 | HttpRequest->SetVerb(TEXT("DELETE")); 243 | break; 244 | 245 | case ESIORequestVerb::CUSTOM: 246 | HttpRequest->SetVerb(CustomVerb); 247 | break; 248 | 249 | default: 250 | break; 251 | } 252 | 253 | // Set content-type 254 | switch (RequestContentType) 255 | { 256 | case ESIORequestContentType::x_www_form_urlencoded_url: 257 | { 258 | HttpRequest->SetHeader(TEXT("Content-Type"), TEXT("application/x-www-form-urlencoded")); 259 | 260 | FString UrlParams = ""; 261 | uint16 ParamIdx = 0; 262 | 263 | // Loop through all the values and prepare additional url part 264 | for (auto RequestIt = RequestJsonObj->GetRootObject()->Values.CreateIterator(); RequestIt; ++RequestIt) 265 | { 266 | FString Key = RequestIt.Key(); 267 | FString Value = RequestIt.Value().Get()->AsString(); 268 | 269 | if (!Key.IsEmpty() && !Value.IsEmpty()) 270 | { 271 | UrlParams += ParamIdx == 0 ? "?" : "&"; 272 | UrlParams += USIOJLibrary::PercentEncode(Key) + "=" + USIOJLibrary::PercentEncode(Value); 273 | } 274 | 275 | ParamIdx++; 276 | } 277 | 278 | // Apply params 279 | HttpRequest->SetURL(HttpRequest->GetURL() + UrlParams); 280 | 281 | UE_LOG(LogSIOJ, Log, TEXT("Request (urlencoded): %s %s %s"), *HttpRequest->GetVerb(), *HttpRequest->GetURL(), *UrlParams); 282 | 283 | break; 284 | } 285 | case ESIORequestContentType::x_www_form_urlencoded_body: 286 | { 287 | HttpRequest->SetHeader(TEXT("Content-Type"), TEXT("application/x-www-form-urlencoded")); 288 | 289 | FString UrlParams = ""; 290 | uint16 ParamIdx = 0; 291 | 292 | // Loop through all the values and prepare additional url part 293 | for (auto RequestIt = RequestJsonObj->GetRootObject()->Values.CreateIterator(); RequestIt; ++RequestIt) 294 | { 295 | FString Key = RequestIt.Key(); 296 | FString Value = RequestIt.Value().Get()->AsString(); 297 | 298 | if (!Key.IsEmpty() && !Value.IsEmpty()) 299 | { 300 | UrlParams += ParamIdx == 0 ? "" : "&"; 301 | UrlParams += USIOJLibrary::PercentEncode(Key) + "=" + USIOJLibrary::PercentEncode(Value); 302 | } 303 | 304 | ParamIdx++; 305 | } 306 | 307 | // Apply params 308 | HttpRequest->SetContentAsString(UrlParams); 309 | 310 | UE_LOG(LogSIOJ, Log, TEXT("Request (url body): %s %s %s"), *HttpRequest->GetVerb(), *HttpRequest->GetURL(), *UrlParams); 311 | 312 | break; 313 | } 314 | case ESIORequestContentType::binary: 315 | { 316 | HttpRequest->SetHeader(TEXT("Content-Type"), BinaryContentType); 317 | HttpRequest->SetContent(RequestBytes); 318 | 319 | UE_LOG(LogSIOJ, Log, TEXT("Request (binary): %s %s"), *HttpRequest->GetVerb(), *HttpRequest->GetURL()); 320 | 321 | break; 322 | } 323 | case ESIORequestContentType::json: 324 | { 325 | HttpRequest->SetHeader(TEXT("Content-Type"), TEXT("application/json")); 326 | 327 | // Serialize data to json string 328 | FString OutputString; 329 | TSharedRef< TJsonWriter<> > Writer = TJsonWriterFactory<>::Create(&OutputString); 330 | FJsonSerializer::Serialize(RequestJsonObj->GetRootObject().ToSharedRef(), Writer); 331 | 332 | // Set Json content 333 | HttpRequest->SetContentAsString(OutputString); 334 | 335 | UE_LOG(LogSIOJ, Log, TEXT("Request (json): %s %s %s"), *HttpRequest->GetVerb(), *HttpRequest->GetURL(), *OutputString); 336 | 337 | break; 338 | } 339 | 340 | default: 341 | break; 342 | } 343 | 344 | // Apply additional headers 345 | for (TMap::TConstIterator It(RequestHeaders); It; ++It) 346 | { 347 | HttpRequest->SetHeader(It.Key(), It.Value()); 348 | } 349 | 350 | // Bind event 351 | HttpRequest->OnProcessRequestComplete().BindUObject(this, &USIOJRequestJSON::OnProcessRequestComplete); 352 | 353 | // Execute the request 354 | HttpRequest->ProcessRequest(); 355 | } 356 | 357 | 358 | ////////////////////////////////////////////////////////////////////////// 359 | // Request callbacks 360 | 361 | void USIOJRequestJSON::OnProcessRequestComplete(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful) 362 | { 363 | // Be sure that we have no data from previous response 364 | ResetResponseData(); 365 | 366 | // Check we have a response and save response code as int32 367 | if(Response.IsValid()) 368 | { 369 | ResponseCode = Response->GetResponseCode(); 370 | } 371 | 372 | // Check we have result to process futher 373 | if (!bWasSuccessful || !Response.IsValid()) 374 | { 375 | UE_LOG(LogSIOJ, Error, TEXT("Request failed (%d): %s"), ResponseCode, *Request->GetURL()); 376 | 377 | // Broadcast the result event 378 | OnRequestFail.Broadcast(this); 379 | OnStaticRequestFail.Broadcast(this); 380 | 381 | return; 382 | } 383 | 384 | // Save response data as a string 385 | ResponseContent = Response->GetContentAsString(); 386 | 387 | // Log response state 388 | UE_LOG(LogSIOJ, Log, TEXT("Response (%d): %s"), ResponseCode, *ResponseContent); 389 | 390 | // Process response headers 391 | TArray Headers = Response->GetAllHeaders(); 392 | for (FString Header : Headers) 393 | { 394 | FString Key; 395 | FString Value; 396 | if (Header.Split(TEXT(": "), &Key, &Value)) 397 | { 398 | ResponseHeaders.Add(Key, Value); 399 | } 400 | } 401 | 402 | // Try to deserialize data to JSON 403 | TSharedRef> JsonReader = TJsonReaderFactory::Create(ResponseContent); 404 | FJsonSerializer::Deserialize(JsonReader, ResponseJsonObj->GetRootObject()); 405 | 406 | // Decide whether the request was successful 407 | bIsValidJsonResponse = bWasSuccessful && ResponseJsonObj->GetRootObject().IsValid(); 408 | 409 | // Log errors 410 | if (!bIsValidJsonResponse) 411 | { 412 | if (!ResponseJsonObj->GetRootObject().IsValid()) 413 | { 414 | // As we assume it's recommended way to use current class, but not the only one, 415 | // it will be the warning instead of error 416 | UE_LOG(LogSIOJ, Warning, TEXT("JSON could not be decoded!")); 417 | } 418 | } 419 | 420 | // Broadcast the result event 421 | OnRequestComplete.Broadcast(this); 422 | OnStaticRequestComplete.Broadcast(this); 423 | 424 | // Finish the latent action 425 | if (ContinueAction) 426 | { 427 | FSIOJLatentAction *K = ContinueAction; 428 | ContinueAction = nullptr; 429 | 430 | K->Call(ResponseJsonObj); 431 | } 432 | } 433 | 434 | 435 | ////////////////////////////////////////////////////////////////////////// 436 | // Tags 437 | 438 | void USIOJRequestJSON::AddTag(FName Tag) 439 | { 440 | if (Tag != NAME_None) 441 | { 442 | Tags.AddUnique(Tag); 443 | } 444 | } 445 | 446 | int32 USIOJRequestJSON::RemoveTag(FName Tag) 447 | { 448 | return Tags.Remove(Tag); 449 | } 450 | 451 | bool USIOJRequestJSON::HasTag(FName Tag) const 452 | { 453 | return (Tag != NAME_None) && Tags.Contains(Tag); 454 | } 455 | -------------------------------------------------------------------------------- /FingerControlUE4/Plugins/UDPWrapper/Source/SIOJson/Private/SIOJson.cpp: -------------------------------------------------------------------------------- 1 | // Modifications Copyright 2018-current Getnamo. All Rights Reserved 2 | 3 | 4 | // Copyright 2014 Vladimir Alyamkin. All Rights Reserved. 5 | 6 | #include "ISIOJson.h" 7 | #include "SIOJsonObject.h" 8 | #include "SIOJsonValue.h" 9 | #include "SIOJRequestJSON.h" 10 | 11 | class FSIOJson : public ISIOJson 12 | { 13 | /** IModuleInterface implementation */ 14 | virtual void StartupModule() override 15 | { 16 | // @HACK Force classes to be compiled on shipping build 17 | USIOJsonObject::StaticClass(); 18 | USIOJsonValue::StaticClass(); 19 | USIOJRequestJSON::StaticClass(); 20 | } 21 | 22 | virtual void ShutdownModule() override 23 | { 24 | 25 | } 26 | }; 27 | 28 | IMPLEMENT_MODULE(FSIOJson, SIOJson) 29 | 30 | DEFINE_LOG_CATEGORY(LogSIOJ); 31 | -------------------------------------------------------------------------------- /FingerControlUE4/Plugins/UDPWrapper/Source/SIOJson/Private/SIOJsonObject.cpp: -------------------------------------------------------------------------------- 1 | // Modifications Copyright 2018-current Getnamo. All Rights Reserved 2 | 3 | 4 | // Copyright 2014 Vladimir Alyamkin. All Rights Reserved. 5 | 6 | #include "SIOJsonObject.h" 7 | #include "Runtime/Json/Public/Policies/CondensedJsonPrintPolicy.h" 8 | #include "Runtime/Json/Public/Serialization/JsonWriter.h" 9 | #include "Runtime/Json/Public/Serialization/JsonSerializer.h" 10 | 11 | typedef TJsonWriterFactory< TCHAR, TCondensedJsonPrintPolicy > FCondensedJsonStringWriterFactory; 12 | typedef TJsonWriter< TCHAR, TCondensedJsonPrintPolicy > FCondensedJsonStringWriter; 13 | 14 | USIOJsonObject::USIOJsonObject(const class FObjectInitializer& PCIP) 15 | : Super(PCIP) 16 | { 17 | Reset(); 18 | } 19 | 20 | USIOJsonObject* USIOJsonObject::ConstructJsonObject(UObject* WorldContextObject) 21 | { 22 | return NewObject(); 23 | } 24 | 25 | void USIOJsonObject::Reset() 26 | { 27 | if (JsonObj.IsValid()) 28 | { 29 | JsonObj.Reset(); 30 | } 31 | 32 | JsonObj = MakeShareable(new FJsonObject()); 33 | } 34 | 35 | TSharedPtr& USIOJsonObject::GetRootObject() 36 | { 37 | return JsonObj; 38 | } 39 | 40 | void USIOJsonObject::SetRootObject(const TSharedPtr& JsonObject) 41 | { 42 | JsonObj = JsonObject; 43 | } 44 | 45 | 46 | ////////////////////////////////////////////////////////////////////////// 47 | // Serialization 48 | 49 | FString USIOJsonObject::EncodeJson() const 50 | { 51 | if (!JsonObj.IsValid()) 52 | { 53 | return TEXT(""); 54 | } 55 | 56 | FString OutputString; 57 | TSharedRef< FCondensedJsonStringWriter > Writer = FCondensedJsonStringWriterFactory::Create(&OutputString); 58 | FJsonSerializer::Serialize(JsonObj.ToSharedRef(), Writer); 59 | 60 | return OutputString; 61 | } 62 | 63 | FString USIOJsonObject::EncodeJsonToSingleString() const 64 | { 65 | FString OutputString = EncodeJson(); 66 | 67 | // Remove line terminators 68 | OutputString.Replace(LINE_TERMINATOR, TEXT("")); 69 | 70 | // Remove tabs 71 | OutputString.Replace(LINE_TERMINATOR, TEXT("\t")); 72 | 73 | return OutputString; 74 | } 75 | 76 | bool USIOJsonObject::DecodeJson(const FString& JsonString) 77 | { 78 | TSharedRef< TJsonReader<> > Reader = TJsonReaderFactory<>::Create(*JsonString); 79 | if (FJsonSerializer::Deserialize(Reader, JsonObj) && JsonObj.IsValid()) 80 | { 81 | return true; 82 | } 83 | 84 | // If we've failed to deserialize the string, we should clear our internal data 85 | Reset(); 86 | 87 | UE_LOG(LogSIOJ, Error, TEXT("Json decoding failed for: %s"), *JsonString); 88 | 89 | return false; 90 | } 91 | 92 | 93 | ////////////////////////////////////////////////////////////////////////// 94 | // FJsonObject API 95 | 96 | TArray USIOJsonObject::GetFieldNames() 97 | { 98 | TArray Result; 99 | 100 | if (!JsonObj.IsValid()) 101 | { 102 | return Result; 103 | } 104 | 105 | JsonObj->Values.GetKeys(Result); 106 | 107 | return Result; 108 | } 109 | 110 | bool USIOJsonObject::HasField(const FString& FieldName) const 111 | { 112 | if (!JsonObj.IsValid() || FieldName.IsEmpty()) 113 | { 114 | return false; 115 | } 116 | 117 | return JsonObj->HasField(FieldName); 118 | } 119 | 120 | void USIOJsonObject::RemoveField(const FString& FieldName) 121 | { 122 | if (!JsonObj.IsValid() || FieldName.IsEmpty()) 123 | { 124 | return; 125 | } 126 | 127 | JsonObj->RemoveField(FieldName); 128 | } 129 | 130 | USIOJsonValue* USIOJsonObject::GetField(const FString& FieldName) const 131 | { 132 | if (!JsonObj.IsValid() || FieldName.IsEmpty()) 133 | { 134 | return nullptr; 135 | } 136 | 137 | TSharedPtr NewVal = JsonObj->TryGetField(FieldName); 138 | if (NewVal.IsValid()) 139 | { 140 | USIOJsonValue* NewValue = NewObject(); 141 | NewValue->SetRootValue(NewVal); 142 | 143 | return NewValue; 144 | } 145 | 146 | return nullptr; 147 | } 148 | 149 | void USIOJsonObject::SetField(const FString& FieldName, USIOJsonValue* JsonValue) 150 | { 151 | if (!JsonObj.IsValid() || FieldName.IsEmpty()) 152 | { 153 | return; 154 | } 155 | 156 | JsonObj->SetField(FieldName, JsonValue->GetRootValue()); 157 | } 158 | 159 | 160 | ////////////////////////////////////////////////////////////////////////// 161 | // FJsonObject API Helpers (easy to use with simple Json objects) 162 | 163 | float USIOJsonObject::GetNumberField(const FString& FieldName) const 164 | { 165 | if (!JsonObj.IsValid() || !JsonObj->HasTypedField(FieldName)) 166 | { 167 | UE_LOG(LogSIOJ, Warning, TEXT("No field with name %s of type Number"), *FieldName); 168 | return 0.0f; 169 | } 170 | 171 | return JsonObj->GetNumberField(FieldName); 172 | } 173 | 174 | void USIOJsonObject::SetNumberField(const FString& FieldName, float Number) 175 | { 176 | if (!JsonObj.IsValid() || FieldName.IsEmpty()) 177 | { 178 | return; 179 | } 180 | 181 | JsonObj->SetNumberField(FieldName, Number); 182 | } 183 | 184 | FString USIOJsonObject::GetStringField(const FString& FieldName) const 185 | { 186 | if (!JsonObj.IsValid() || !JsonObj->HasTypedField(FieldName)) 187 | { 188 | UE_LOG(LogSIOJ, Warning, TEXT("No field with name %s of type String"), *FieldName); 189 | return TEXT(""); 190 | } 191 | 192 | return JsonObj->GetStringField(FieldName); 193 | } 194 | 195 | void USIOJsonObject::SetStringField(const FString& FieldName, const FString& StringValue) 196 | { 197 | if (!JsonObj.IsValid() || FieldName.IsEmpty()) 198 | { 199 | return; 200 | } 201 | 202 | JsonObj->SetStringField(FieldName, StringValue); 203 | } 204 | 205 | bool USIOJsonObject::GetBoolField(const FString& FieldName) const 206 | { 207 | if (!JsonObj.IsValid() || !JsonObj->HasTypedField(FieldName)) 208 | { 209 | UE_LOG(LogSIOJ, Warning, TEXT("No field with name %s of type Boolean"), *FieldName); 210 | return false; 211 | } 212 | 213 | return JsonObj->GetBoolField(FieldName); 214 | } 215 | 216 | void USIOJsonObject::SetBoolField(const FString& FieldName, bool InValue) 217 | { 218 | if (!JsonObj.IsValid() || FieldName.IsEmpty()) 219 | { 220 | return; 221 | } 222 | 223 | JsonObj->SetBoolField(FieldName, InValue); 224 | } 225 | 226 | TArray USIOJsonObject::GetArrayField(const FString& FieldName) 227 | { 228 | if (!JsonObj->HasTypedField(FieldName)) 229 | { 230 | UE_LOG(LogSIOJ, Warning, TEXT("No field with name %s of type Array"), *FieldName); 231 | } 232 | 233 | TArray OutArray; 234 | if (!JsonObj.IsValid() || FieldName.IsEmpty()) 235 | { 236 | return OutArray; 237 | } 238 | 239 | TArray< TSharedPtr > ValArray = JsonObj->GetArrayField(FieldName); 240 | for (auto Value : ValArray) 241 | { 242 | USIOJsonValue* NewValue = NewObject(); 243 | NewValue->SetRootValue(Value); 244 | 245 | OutArray.Add(NewValue); 246 | } 247 | 248 | return OutArray; 249 | } 250 | 251 | void USIOJsonObject::SetArrayField(const FString& FieldName, const TArray& InArray) 252 | { 253 | if (!JsonObj.IsValid() || FieldName.IsEmpty()) 254 | { 255 | return; 256 | } 257 | 258 | TArray< TSharedPtr > ValArray; 259 | 260 | // Process input array and COPY original values 261 | for (auto InVal : InArray) 262 | { 263 | TSharedPtr JsonVal = InVal->GetRootValue(); 264 | 265 | switch (InVal->GetType()) 266 | { 267 | case ESIOJson::None: 268 | break; 269 | 270 | case ESIOJson::Null: 271 | ValArray.Add(MakeShareable(new FJsonValueNull())); 272 | break; 273 | 274 | case ESIOJson::String: 275 | ValArray.Add(MakeShareable(new FJsonValueString(JsonVal->AsString()))); 276 | break; 277 | 278 | case ESIOJson::Number: 279 | ValArray.Add(MakeShareable(new FJsonValueNumber(JsonVal->AsNumber()))); 280 | break; 281 | 282 | case ESIOJson::Boolean: 283 | ValArray.Add(MakeShareable(new FJsonValueBoolean(JsonVal->AsBool()))); 284 | break; 285 | 286 | case ESIOJson::Array: 287 | ValArray.Add(MakeShareable(new FJsonValueArray(JsonVal->AsArray()))); 288 | break; 289 | 290 | case ESIOJson::Object: 291 | ValArray.Add(MakeShareable(new FJsonValueObject(JsonVal->AsObject()))); 292 | break; 293 | 294 | default: 295 | break; 296 | } 297 | } 298 | 299 | JsonObj->SetArrayField(FieldName, ValArray); 300 | } 301 | 302 | void USIOJsonObject::MergeJsonObject(USIOJsonObject* InJsonObject, bool Overwrite) 303 | { 304 | TArray Keys = InJsonObject->GetFieldNames(); 305 | 306 | for (auto Key : Keys) 307 | { 308 | if (Overwrite == false && HasField(Key)) 309 | { 310 | continue; 311 | } 312 | 313 | SetField(Key, InJsonObject->GetField(Key)); 314 | } 315 | } 316 | 317 | USIOJsonObject* USIOJsonObject::GetObjectField(const FString& FieldName) const 318 | { 319 | if (!JsonObj.IsValid() || !JsonObj->HasTypedField(FieldName)) 320 | { 321 | UE_LOG(LogSIOJ, Warning, TEXT("No field with name %s of type Object"), *FieldName); 322 | return nullptr; 323 | } 324 | 325 | TSharedPtr JsonObjField = JsonObj->GetObjectField(FieldName); 326 | 327 | USIOJsonObject* OutRestJsonObj = NewObject(); 328 | OutRestJsonObj->SetRootObject(JsonObjField); 329 | 330 | return OutRestJsonObj; 331 | } 332 | 333 | void USIOJsonObject::SetObjectField(const FString& FieldName, USIOJsonObject* JsonObject) 334 | { 335 | if (!JsonObj.IsValid() || FieldName.IsEmpty()) 336 | { 337 | return; 338 | } 339 | 340 | JsonObj->SetObjectField(FieldName, JsonObject->GetRootObject()); 341 | } 342 | 343 | 344 | TArray USIOJsonObject::GetBinaryField(const FString& FieldName) const 345 | { 346 | if (!JsonObj->HasTypedField(FieldName)) 347 | { 348 | UE_LOG(LogSIOJ, Warning, TEXT("No field with name %s of type String"), *FieldName); 349 | } 350 | TSharedPtr JsonValue = JsonObj->TryGetField(FieldName); 351 | 352 | if (FJsonValueBinary::IsBinary(JsonValue)) 353 | { 354 | return FJsonValueBinary::AsBinary(JsonValue); 355 | } 356 | else 357 | { 358 | TArray EmptyArray; 359 | return EmptyArray; 360 | } 361 | } 362 | 363 | void USIOJsonObject::SetBinaryField(const FString& FieldName, const TArray& Bytes) 364 | { 365 | if (!JsonObj.IsValid() || FieldName.IsEmpty()) 366 | { 367 | return; 368 | } 369 | TSharedPtr JsonValue = MakeShareable(new FJsonValueBinary(Bytes)); 370 | JsonObj->SetField(FieldName, JsonValue); 371 | } 372 | 373 | ////////////////////////////////////////////////////////////////////////// 374 | // Array fields helpers (uniform arrays) 375 | 376 | TArray USIOJsonObject::GetNumberArrayField(const FString& FieldName) 377 | { 378 | if (!JsonObj->HasTypedField(FieldName)) 379 | { 380 | UE_LOG(LogSIOJ, Warning, TEXT("No field with name %s of type Array"), *FieldName); 381 | } 382 | 383 | TArray NumberArray; 384 | if (!JsonObj.IsValid() || FieldName.IsEmpty()) 385 | { 386 | return NumberArray; 387 | } 388 | 389 | TArray > JsonArrayValues = JsonObj->GetArrayField(FieldName); 390 | for (TArray >::TConstIterator It(JsonArrayValues); It; ++It) 391 | { 392 | auto Value = (*It).Get(); 393 | if (Value->Type != EJson::Number) 394 | { 395 | UE_LOG(LogSIOJ, Error, TEXT("Not Number element in array with field name %s"), *FieldName); 396 | } 397 | 398 | NumberArray.Add((*It)->AsNumber()); 399 | } 400 | 401 | return NumberArray; 402 | } 403 | 404 | void USIOJsonObject::SetNumberArrayField(const FString& FieldName, const TArray& NumberArray) 405 | { 406 | if (!JsonObj.IsValid() || FieldName.IsEmpty()) 407 | { 408 | return; 409 | } 410 | 411 | TArray< TSharedPtr > EntriesArray; 412 | 413 | for (auto Number : NumberArray) 414 | { 415 | EntriesArray.Add(MakeShareable(new FJsonValueNumber(Number))); 416 | } 417 | 418 | JsonObj->SetArrayField(FieldName, EntriesArray); 419 | } 420 | 421 | TArray USIOJsonObject::GetStringArrayField(const FString& FieldName) 422 | { 423 | if (!JsonObj->HasTypedField(FieldName)) 424 | { 425 | UE_LOG(LogSIOJ, Warning, TEXT("No field with name %s of type Array"), *FieldName); 426 | } 427 | 428 | TArray StringArray; 429 | if (!JsonObj.IsValid() || FieldName.IsEmpty()) 430 | { 431 | return StringArray; 432 | } 433 | 434 | TArray > JsonArrayValues = JsonObj->GetArrayField(FieldName); 435 | for (TArray >::TConstIterator It(JsonArrayValues); It; ++It) 436 | { 437 | auto Value = (*It).Get(); 438 | if (Value->Type != EJson::String) 439 | { 440 | UE_LOG(LogSIOJ, Error, TEXT("Not String element in array with field name %s"), *FieldName); 441 | } 442 | 443 | StringArray.Add((*It)->AsString()); 444 | } 445 | 446 | return StringArray; 447 | } 448 | 449 | void USIOJsonObject::SetStringArrayField(const FString& FieldName, const TArray& StringArray) 450 | { 451 | if (!JsonObj.IsValid() || FieldName.IsEmpty()) 452 | { 453 | return; 454 | } 455 | 456 | TArray< TSharedPtr > EntriesArray; 457 | for (auto String : StringArray) 458 | { 459 | EntriesArray.Add(MakeShareable(new FJsonValueString(String))); 460 | } 461 | 462 | JsonObj->SetArrayField(FieldName, EntriesArray); 463 | } 464 | 465 | TArray USIOJsonObject::GetBoolArrayField(const FString& FieldName) 466 | { 467 | if (!JsonObj->HasTypedField(FieldName)) 468 | { 469 | UE_LOG(LogSIOJ, Warning, TEXT("No field with name %s of type Array"), *FieldName); 470 | } 471 | 472 | TArray BoolArray; 473 | if (!JsonObj.IsValid() || FieldName.IsEmpty()) 474 | { 475 | return BoolArray; 476 | } 477 | 478 | TArray > JsonArrayValues = JsonObj->GetArrayField(FieldName); 479 | for (TArray >::TConstIterator It(JsonArrayValues); It; ++It) 480 | { 481 | auto Value = (*It).Get(); 482 | if (Value->Type != EJson::Boolean) 483 | { 484 | UE_LOG(LogSIOJ, Error, TEXT("Not Boolean element in array with field name %s"), *FieldName); 485 | } 486 | 487 | BoolArray.Add((*It)->AsBool()); 488 | } 489 | 490 | return BoolArray; 491 | } 492 | 493 | void USIOJsonObject::SetBoolArrayField(const FString& FieldName, const TArray& BoolArray) 494 | { 495 | if (!JsonObj.IsValid() || FieldName.IsEmpty()) 496 | { 497 | return; 498 | } 499 | 500 | TArray< TSharedPtr > EntriesArray; 501 | for (auto Boolean : BoolArray) 502 | { 503 | EntriesArray.Add(MakeShareable(new FJsonValueBoolean(Boolean))); 504 | } 505 | 506 | JsonObj->SetArrayField(FieldName, EntriesArray); 507 | } 508 | 509 | TArray USIOJsonObject::GetObjectArrayField(const FString& FieldName) 510 | { 511 | if (!JsonObj->HasTypedField(FieldName)) 512 | { 513 | UE_LOG(LogSIOJ, Warning, TEXT("No field with name %s of type Array"), *FieldName); 514 | } 515 | 516 | TArray OutArray; 517 | if (!JsonObj.IsValid() || FieldName.IsEmpty()) 518 | { 519 | return OutArray; 520 | } 521 | 522 | TArray< TSharedPtr > ValArray = JsonObj->GetArrayField(FieldName); 523 | for (auto Value : ValArray) 524 | { 525 | if (Value->Type != EJson::Object) 526 | { 527 | UE_LOG(LogSIOJ, Error, TEXT("Not Object element in array with field name %s"), *FieldName); 528 | } 529 | 530 | TSharedPtr NewObj = Value->AsObject(); 531 | 532 | USIOJsonObject* NewJson = NewObject(); 533 | NewJson->SetRootObject(NewObj); 534 | 535 | OutArray.Add(NewJson); 536 | } 537 | 538 | return OutArray; 539 | } 540 | 541 | void USIOJsonObject::SetObjectArrayField(const FString& FieldName, const TArray& ObjectArray) 542 | { 543 | if (!JsonObj.IsValid() || FieldName.IsEmpty()) 544 | { 545 | return; 546 | } 547 | 548 | TArray< TSharedPtr > EntriesArray; 549 | for (auto Value : ObjectArray) 550 | { 551 | EntriesArray.Add(MakeShareable(new FJsonValueObject(Value->GetRootObject()))); 552 | } 553 | 554 | JsonObj->SetArrayField(FieldName, EntriesArray); 555 | } 556 | -------------------------------------------------------------------------------- /FingerControlUE4/Plugins/UDPWrapper/Source/SIOJson/Private/SIOJsonValue.cpp: -------------------------------------------------------------------------------- 1 | // Modifications Copyright 2018-current Getnamo. All Rights Reserved 2 | 3 | 4 | // Copyright 2014 Vladimir Alyamkin. All Rights Reserved. 5 | 6 | #include "SIOJsonValue.h" 7 | #include "SIOJConvert.h" 8 | 9 | #if PLATFORM_WINDOWS 10 | #pragma region FJsonValueBinary 11 | #endif 12 | 13 | 14 | TArray FJsonValueBinary::AsBinary(const TSharedPtr& InJsonValue) 15 | { 16 | if (FJsonValueBinary::IsBinary(InJsonValue)) 17 | { 18 | TSharedPtr BinaryValue = StaticCastSharedPtr(InJsonValue); 19 | return BinaryValue->AsBinary(); 20 | } 21 | else 22 | { 23 | TArray EmptyArray; 24 | return EmptyArray; 25 | } 26 | } 27 | 28 | 29 | bool FJsonValueBinary::IsBinary(const TSharedPtr& InJsonValue) 30 | { 31 | //use our hackery to determine if we got a binary string 32 | bool IgnoreBool; 33 | return !InJsonValue->TryGetBool(IgnoreBool); 34 | } 35 | 36 | #if PLATFORM_WINDOWS 37 | #pragma endregion FJsonValueBinary 38 | #pragma region USIOJsonValue 39 | #endif 40 | 41 | USIOJsonValue::USIOJsonValue(const class FObjectInitializer& PCIP) 42 | : Super(PCIP) 43 | { 44 | 45 | } 46 | 47 | USIOJsonValue* USIOJsonValue::ConstructJsonValueNumber(UObject* WorldContextObject, float Number) 48 | { 49 | TSharedPtr NewVal = MakeShareable(new FJsonValueNumber(Number)); 50 | 51 | USIOJsonValue* NewValue = NewObject(); 52 | NewValue->SetRootValue(NewVal); 53 | 54 | return NewValue; 55 | } 56 | 57 | USIOJsonValue* USIOJsonValue::ConstructJsonValueString(UObject* WorldContextObject, const FString& StringValue) 58 | { 59 | TSharedPtr NewVal = MakeShareable(new FJsonValueString(StringValue)); 60 | 61 | USIOJsonValue* NewValue = NewObject(); 62 | NewValue->SetRootValue(NewVal); 63 | 64 | return NewValue; 65 | } 66 | 67 | USIOJsonValue* USIOJsonValue::ConstructJsonValueBool(UObject* WorldContextObject, bool InValue) 68 | { 69 | TSharedPtr NewVal = MakeShareable(new FJsonValueBoolean(InValue)); 70 | 71 | USIOJsonValue* NewValue = NewObject(); 72 | NewValue->SetRootValue(NewVal); 73 | 74 | return NewValue; 75 | } 76 | 77 | USIOJsonValue* USIOJsonValue::ConstructJsonValueArray(UObject* WorldContextObject, const TArray& InArray) 78 | { 79 | // Prepare data array to create new value 80 | TArray< TSharedPtr > ValueArray; 81 | for (auto InVal : InArray) 82 | { 83 | ValueArray.Add(InVal->GetRootValue()); 84 | } 85 | 86 | TSharedPtr NewVal = MakeShareable(new FJsonValueArray(ValueArray)); 87 | 88 | USIOJsonValue* NewValue = NewObject(); 89 | NewValue->SetRootValue(NewVal); 90 | 91 | return NewValue; 92 | } 93 | 94 | USIOJsonValue* USIOJsonValue::ConstructJsonValueObject(USIOJsonObject *JsonObject, UObject* WorldContextObject) 95 | { 96 | TSharedPtr NewVal = MakeShareable(new FJsonValueObject(JsonObject->GetRootObject())); 97 | 98 | USIOJsonValue* NewValue = NewObject(); 99 | NewValue->SetRootValue(NewVal); 100 | 101 | return NewValue; 102 | } 103 | 104 | 105 | USIOJsonValue* USIOJsonValue::ConstructJsonValueBinary(UObject* WorldContextObject, TArray ByteArray) 106 | { 107 | TSharedPtr NewVal = MakeShareable(new FJsonValueBinary(ByteArray)); 108 | 109 | USIOJsonValue* NewValue = NewObject(); 110 | NewValue->SetRootValue(NewVal); 111 | 112 | return NewValue; 113 | } 114 | 115 | USIOJsonValue* ConstructJsonValue(UObject* WorldContextObject, const TSharedPtr& InValue) 116 | { 117 | TSharedPtr NewVal = InValue; 118 | 119 | USIOJsonValue* NewValue = NewObject(); 120 | NewValue->SetRootValue(NewVal); 121 | 122 | return NewValue; 123 | } 124 | 125 | 126 | USIOJsonValue* USIOJsonValue::ValueFromJsonString(UObject* WorldContextObject, const FString& StringValue) 127 | { 128 | TSharedPtr NewVal = USIOJConvert::JsonStringToJsonValue(StringValue); 129 | 130 | USIOJsonValue* NewValue = NewObject(); 131 | NewValue->SetRootValue(NewVal); 132 | 133 | return NewValue; 134 | } 135 | 136 | TSharedPtr& USIOJsonValue::GetRootValue() 137 | { 138 | return JsonVal; 139 | } 140 | 141 | void USIOJsonValue::SetRootValue(TSharedPtr& JsonValue) 142 | { 143 | JsonVal = JsonValue; 144 | } 145 | 146 | 147 | ////////////////////////////////////////////////////////////////////////// 148 | // FJsonValue API 149 | 150 | ESIOJson::Type USIOJsonValue::GetType() const 151 | { 152 | if (!JsonVal.IsValid()) 153 | { 154 | return ESIOJson::None; 155 | } 156 | 157 | switch (JsonVal->Type) 158 | { 159 | case EJson::None: 160 | return ESIOJson::None; 161 | 162 | case EJson::Null: 163 | return ESIOJson::Null; 164 | 165 | case EJson::String: 166 | if (FJsonValueBinary::IsBinary(JsonVal)) 167 | { 168 | return ESIOJson::Binary; 169 | } 170 | else 171 | { 172 | return ESIOJson::String; 173 | } 174 | case EJson::Number: 175 | return ESIOJson::Number; 176 | 177 | case EJson::Boolean: 178 | return ESIOJson::Boolean; 179 | 180 | case EJson::Array: 181 | return ESIOJson::Array; 182 | 183 | case EJson::Object: 184 | return ESIOJson::Object; 185 | 186 | default: 187 | return ESIOJson::None; 188 | } 189 | } 190 | 191 | FString USIOJsonValue::GetTypeString() const 192 | { 193 | if (!JsonVal.IsValid()) 194 | { 195 | return "None"; 196 | } 197 | 198 | switch (JsonVal->Type) 199 | { 200 | case EJson::None: 201 | return TEXT("None"); 202 | 203 | case EJson::Null: 204 | return TEXT("Null"); 205 | 206 | case EJson::String: 207 | return TEXT("String"); 208 | 209 | case EJson::Number: 210 | return TEXT("Number"); 211 | 212 | case EJson::Boolean: 213 | return TEXT("Boolean"); 214 | 215 | case EJson::Array: 216 | return TEXT("Array"); 217 | 218 | case EJson::Object: 219 | return TEXT("Object"); 220 | 221 | default: 222 | return TEXT("None"); 223 | } 224 | } 225 | 226 | bool USIOJsonValue::IsNull() const 227 | { 228 | if (!JsonVal.IsValid()) 229 | { 230 | return true; 231 | } 232 | 233 | return JsonVal->IsNull(); 234 | } 235 | 236 | float USIOJsonValue::AsNumber() const 237 | { 238 | if (!JsonVal.IsValid()) 239 | { 240 | ErrorMessage(TEXT("Number")); 241 | return 0.f; 242 | } 243 | 244 | return JsonVal->AsNumber(); 245 | } 246 | 247 | FString USIOJsonValue::AsString() const 248 | { 249 | if (!JsonVal.IsValid()) 250 | { 251 | ErrorMessage(TEXT("String")); 252 | return FString(); 253 | } 254 | 255 | //Auto-convert non-strings instead of getting directly 256 | if (JsonVal->Type != EJson::String) 257 | { 258 | return EncodeJson(); 259 | } 260 | else 261 | { 262 | return JsonVal->AsString(); 263 | } 264 | } 265 | 266 | bool USIOJsonValue::AsBool() const 267 | { 268 | if (!JsonVal.IsValid()) 269 | { 270 | ErrorMessage(TEXT("Boolean")); 271 | return false; 272 | } 273 | 274 | return JsonVal->AsBool(); 275 | } 276 | 277 | TArray USIOJsonValue::AsArray() const 278 | { 279 | TArray OutArray; 280 | 281 | if (!JsonVal.IsValid()) 282 | { 283 | ErrorMessage(TEXT("Array")); 284 | return OutArray; 285 | } 286 | 287 | TArray< TSharedPtr > ValArray = JsonVal->AsArray(); 288 | for (auto Value : ValArray) 289 | { 290 | USIOJsonValue* NewValue = NewObject(); 291 | NewValue->SetRootValue(Value); 292 | 293 | OutArray.Add(NewValue); 294 | } 295 | 296 | return OutArray; 297 | } 298 | 299 | USIOJsonObject* USIOJsonValue::AsObject() 300 | { 301 | if (!JsonVal.IsValid()) 302 | { 303 | ErrorMessage(TEXT("Object")); 304 | return nullptr; 305 | } 306 | 307 | TSharedPtr NewObj = JsonVal->AsObject(); 308 | 309 | USIOJsonObject* JsonObj = NewObject(); 310 | JsonObj->SetRootObject(NewObj); 311 | 312 | return JsonObj; 313 | } 314 | 315 | 316 | TArray USIOJsonValue::AsBinary() 317 | { 318 | if (!JsonVal.IsValid()) 319 | { 320 | ErrorMessage(TEXT("Binary")); 321 | TArray ByteArray; 322 | return ByteArray; 323 | } 324 | 325 | //binary object pretending & starts with non-json format? it's our disguise binary 326 | if (JsonVal->Type == EJson::String) 327 | { 328 | //it's a legit binary 329 | if (FJsonValueBinary::IsBinary(JsonVal)) 330 | { 331 | //Valid binary available 332 | return FJsonValueBinary::AsBinary(JsonVal); 333 | } 334 | 335 | //It's a string, decode as if hex encoded binary 336 | else 337 | { 338 | const FString& HexString = JsonVal->AsString(); 339 | 340 | TArray ByteArray; 341 | ByteArray.AddUninitialized(HexString.Len() / 2); 342 | 343 | bool DidConvert = FString::ToHexBlob(HexString, ByteArray.GetData(), ByteArray.Num()); 344 | 345 | //Empty our array if conversion failed 346 | if (!DidConvert) 347 | { 348 | ByteArray.Empty(); 349 | } 350 | return ByteArray; 351 | } 352 | } 353 | //Not a binary nor binary string, return empty array 354 | else 355 | { 356 | //Empty array 357 | TArray ByteArray; 358 | return ByteArray; 359 | } 360 | } 361 | 362 | FString USIOJsonValue::EncodeJson() const 363 | { 364 | return USIOJConvert::ToJsonString(JsonVal); 365 | } 366 | 367 | ////////////////////////////////////////////////////////////////////////// 368 | // Helpers 369 | 370 | void USIOJsonValue::ErrorMessage(const FString& InType) const 371 | { 372 | UE_LOG(LogSIOJ, Error, TEXT("Json Value of type '%s' used as a '%s'."), *GetTypeString(), *InType); 373 | } 374 | 375 | #if PLATFORM_WINDOWS 376 | #pragma endregion USIOJsonValue 377 | #endif -------------------------------------------------------------------------------- /FingerControlUE4/Plugins/UDPWrapper/Source/SIOJson/Public/ISIOJson.h: -------------------------------------------------------------------------------- 1 | // Modifications Copyright 2018-current Getnamo. All Rights Reserved 2 | 3 | 4 | // Copyright 2014 Vladimir Alyamkin. All Rights Reserved. 5 | 6 | #pragma once 7 | 8 | #include "Runtime/Core/Public/Modules/ModuleManager.h" 9 | 10 | DECLARE_LOG_CATEGORY_EXTERN(LogSIOJ, Log, All); 11 | 12 | 13 | /** 14 | * The public interface to this module. In most cases, this interface is only public to sibling modules 15 | * within this plugin. 16 | */ 17 | class ISIOJson : public IModuleInterface 18 | { 19 | 20 | public: 21 | 22 | /** 23 | * Singleton-like access to this module's interface. This is just for convenience! 24 | * Beware of calling this during the shutdown phase, though. Your module might have been unloaded already. 25 | * 26 | * @return Returns singleton instance, loading the module on demand if needed 27 | */ 28 | static inline ISIOJson& Get() 29 | { 30 | return FModuleManager::LoadModuleChecked< ISIOJson >( "SIOJson" ); 31 | } 32 | 33 | /** 34 | * Checks to see if this module is loaded and ready. It is only valid to call Get() if IsAvailable() returns true. 35 | * 36 | * @return True if the module is loaded and ready to use 37 | */ 38 | static inline bool IsAvailable() 39 | { 40 | return FModuleManager::Get().IsModuleLoaded( "SIOJson" ); 41 | } 42 | }; 43 | 44 | -------------------------------------------------------------------------------- /FingerControlUE4/Plugins/UDPWrapper/Source/SIOJson/Public/SIOJConvert.h: -------------------------------------------------------------------------------- 1 | // Modifications Copyright 2018-current Getnamo. All Rights Reserved 2 | 3 | 4 | #pragma once 5 | 6 | #include "CoreMinimal.h" 7 | #include "UObject/Package.h" 8 | #include "UObject/ObjectMacros.h" 9 | #include "Runtime/Json/Public/Dom/JsonObject.h" 10 | #include "Runtime/Json/Public/Dom/JsonValue.h" 11 | #include "SIOJConvert.generated.h" 12 | 13 | struct FTrimmedKeyMap 14 | { 15 | FString LongKey; 16 | TMap> SubMap; 17 | 18 | FString ToString(); 19 | }; 20 | 21 | /** 22 | * 23 | */ 24 | UCLASS() 25 | class SIOJSON_API USIOJConvert : public UObject 26 | { 27 | GENERATED_BODY() 28 | public: 29 | 30 | //encode/decode json convenience wrappers 31 | static FString ToJsonString(const TSharedPtr& JsonObject); 32 | static FString ToJsonString(const TSharedPtr& JsonValue); 33 | static FString ToJsonString(const TArray>& JsonValueArray); 34 | 35 | static TSharedPtr ToJsonObject(const FString& JsonString); 36 | static TSharedPtr MakeJsonObject(); 37 | 38 | 39 | //Structs 40 | 41 | //Will trim names if specified as blueprint 42 | static TSharedPtr ToJsonObject(UStruct* Struct, void* StructPtr, bool IsBlueprintStruct = false); 43 | 44 | //Expects a JsonObject, if blueprint struct it will lengthen the names to fill properly 45 | static bool JsonObjectToUStruct(TSharedPtr JsonObject, UStruct* Struct, void* StructPtr, bool IsBlueprintStruct = false); 46 | 47 | //Files - convenience read/write files 48 | static bool JsonFileToUStruct(const FString& FilePath, UStruct* Struct, void* StructPtr, bool IsBlueprintStruct = false); 49 | static bool ToJsonFile(const FString& FilePath, UStruct* Struct, void* StructPtr, bool IsBlueprintStruct = false); 50 | 51 | 52 | //typically from callbacks 53 | static class USIOJsonValue* ToSIOJsonValue(const TArray>& JsonValueArray); 54 | 55 | //Convenience overrides for JsonValues 56 | static TSharedPtr ToJsonValue(const TSharedPtr& JsonObject); 57 | static TSharedPtr ToJsonValue(const FString& StringValue); 58 | static TSharedPtr ToJsonValue(double NumberValue); 59 | static TSharedPtr ToJsonValue(bool BoolValue); 60 | static TSharedPtr ToJsonValue(const TArray& BinaryValue); 61 | static TSharedPtr ToJsonValue(const TArray>& ArrayValue); 62 | 63 | static TSharedPtr JsonStringToJsonValue(const FString& JsonString); 64 | static TArray> JsonStringToJsonArray(const FString& JsonString); 65 | 66 | 67 | //internal utility, exposed for modularity 68 | static void TrimValueKeyNames(const TSharedPtr& JsonValue); 69 | static bool TrimKey(const FString& InLongKey, FString& OutTrimmedKey); 70 | static void SetTrimmedKeyMapForStruct(TSharedPtr& InMap, UStruct* Struct); 71 | static void SetTrimmedKeyMapForProp(TSharedPtr& InMap, UProperty* ArrayInnerProp); 72 | static void ReplaceJsonValueNamesWithMap(TSharedPtr& InValue, TSharedPtr KeyMap); 73 | 74 | template 75 | static FString EnumToString(const FString& enumName, const T value) 76 | { 77 | UEnum* pEnum = FindObject(ANY_PACKAGE, *enumName); 78 | return *(pEnum ? pEnum->GetNameStringByIndex(static_cast(value)) : "null"); 79 | } 80 | }; 81 | 82 | 83 | -------------------------------------------------------------------------------- /FingerControlUE4/Plugins/UDPWrapper/Source/SIOJson/Public/SIOJLibrary.h: -------------------------------------------------------------------------------- 1 | // Modifications Copyright 2018-current Getnamo. All Rights Reserved 2 | 3 | 4 | // Copyright 2016 Vladimir Alyamkin. All Rights Reserved. 5 | 6 | #pragma once 7 | 8 | #include "Kismet/BlueprintFunctionLibrary.h" 9 | 10 | #include "SIOJTypes.h" 11 | #include "SIOJConvert.h" 12 | #include "SIOJsonObject.h" 13 | #include "SIOJRequestJSON.h" 14 | #include "SIOJLibrary.generated.h" 15 | 16 | DECLARE_DYNAMIC_DELEGATE_OneParam(FSIOJCallDelegate, USIOJRequestJSON*, Request); 17 | 18 | USTRUCT() 19 | struct FSIOJCallResponse 20 | { 21 | GENERATED_USTRUCT_BODY() 22 | 23 | UPROPERTY() 24 | USIOJRequestJSON* Request; 25 | 26 | UPROPERTY() 27 | UObject* WorldContextObject; 28 | 29 | UPROPERTY() 30 | FSIOJCallDelegate Callback; 31 | 32 | FDelegateHandle CompleteDelegateHandle; 33 | FDelegateHandle FailDelegateHandle; 34 | 35 | FSIOJCallResponse() 36 | : Request(nullptr) 37 | , WorldContextObject(nullptr) 38 | { 39 | } 40 | 41 | }; 42 | 43 | /** 44 | * Usefull tools for REST communications 45 | */ 46 | UCLASS() 47 | class USIOJLibrary : public UBlueprintFunctionLibrary 48 | { 49 | GENERATED_BODY() 50 | 51 | 52 | ////////////////////////////////////////////////////////////////////////// 53 | // Helpers 54 | 55 | public: 56 | /** Applies percent-encoding to text */ 57 | UFUNCTION(BlueprintCallable, Category = "SIOJ|Utility") 58 | static FString PercentEncode(const FString& Source); 59 | 60 | /** 61 | * Encodes a FString into a Base64 string 62 | * 63 | * @param Source The string data to convert 64 | * @return A string that encodes the binary data in a way that can be safely transmitted via various Internet protocols 65 | */ 66 | UFUNCTION(BlueprintCallable, Category = "SIOJ|Utility", meta = (DisplayName = "Base64 Encode")) 67 | static FString Base64Encode(const FString& Source); 68 | 69 | /** 70 | * Decodes a Base64 string into a FString 71 | * 72 | * @param Source The stringified data to convert 73 | * @param Dest The out buffer that will be filled with the decoded data 74 | * @return True if the buffer was decoded, false if it failed to decode 75 | */ 76 | UFUNCTION(BlueprintCallable, Category = "SIOJ|Utility", meta = (DisplayName = "Base64 Decode")) 77 | static bool Base64Decode(const FString& Source, FString& Dest); 78 | 79 | ////////////////////////////////////////////////////////////////////////// 80 | // Easy URL processing 81 | 82 | /** 83 | * Decodes a json string into an array of stringified json Values 84 | * 85 | * @param JsonString Input stringified json 86 | * @param OutJsonValueArray The decoded Array of JsonValue 87 | */ 88 | UFUNCTION(BlueprintPure, Category = "SIOJ|Utility") 89 | static bool StringToJsonValueArray(const FString& JsonString, TArray& OutJsonValueArray); 90 | 91 | /** 92 | * Uses the reflection system to convert an unreal struct into a JsonObject 93 | * 94 | * @param AnyStruct The struct you wish to convert 95 | * @return Converted Json Object 96 | */ 97 | UFUNCTION(BlueprintPure, Category = "SocketIOFunctions", CustomThunk, meta = (CustomStructureParam = "AnyStruct")) 98 | static USIOJsonObject* StructToJsonObject(UProperty* AnyStruct); 99 | 100 | /** 101 | * Uses the reflection system to fill an unreal struct from data defined in JsonObject. 102 | * 103 | * @param JsonObject The source JsonObject for properties to fill 104 | * @param AnyStruct The struct you wish to fill 105 | * @return Whether all properties filled correctly 106 | */ 107 | UFUNCTION(BlueprintCallable, Category = "SocketIOFunctions", CustomThunk, meta = (CustomStructureParam = "AnyStruct")) 108 | static bool JsonObjectToStruct(USIOJsonObject* JsonObject, UProperty* AnyStruct); 109 | 110 | //Convert property into c++ accessible form 111 | DECLARE_FUNCTION(execStructToJsonObject) 112 | { 113 | //Get properties and pointers from stack 114 | Stack.Step(Stack.Object, NULL); 115 | UStructProperty* StructProperty = ExactCast(Stack.MostRecentProperty); 116 | void* StructPtr = Stack.MostRecentPropertyAddress; 117 | 118 | // We need this to wrap up the stack 119 | P_FINISH; 120 | 121 | auto BPJsonObject = NewObject(); 122 | 123 | auto JsonObject = USIOJConvert::ToJsonObject(StructProperty->Struct, StructPtr, true); 124 | BPJsonObject->SetRootObject(JsonObject); 125 | 126 | *(USIOJsonObject**)RESULT_PARAM = BPJsonObject; 127 | } 128 | 129 | DECLARE_FUNCTION(execJsonObjectToStruct) 130 | { 131 | //Get properties and pointers from stack 132 | P_GET_OBJECT(USIOJsonObject, JsonObject); 133 | 134 | Stack.Step(Stack.Object, NULL); 135 | UStructProperty* StructProperty = ExactCast(Stack.MostRecentProperty); 136 | void* StructPtr = Stack.MostRecentPropertyAddress; 137 | 138 | P_FINISH; 139 | 140 | //Pass in the reference to the json object 141 | bool Success = USIOJConvert::JsonObjectToUStruct(JsonObject->GetRootObject(), StructProperty->Struct, StructPtr, true); 142 | 143 | *(bool*)RESULT_PARAM = Success; 144 | } 145 | 146 | //Convenience - Saving/Loading structs from files 147 | UFUNCTION(BlueprintCallable, Category = "SocketIOFunctions", CustomThunk, meta = (CustomStructureParam = "AnyStruct")) 148 | static bool SaveStructToJsonFile(UProperty* AnyStruct, const FString& FilePath); 149 | 150 | UFUNCTION(BlueprintCallable, Category = "SocketIOFunctions", CustomThunk, meta = (CustomStructureParam = "AnyStruct")) 151 | static bool LoadJsonFileToStruct(const FString& FilePath, UProperty* AnyStruct); 152 | 153 | //custom thunk needed to handle wildcard structs 154 | DECLARE_FUNCTION(execSaveStructToJsonFile) 155 | { 156 | //Get properties and pointers from stack (nb, it's reverse order, right to left!) 157 | Stack.StepCompiledIn(NULL); 158 | UStructProperty* StructProp = ExactCast(Stack.MostRecentProperty); 159 | void* StructPtr = Stack.MostRecentPropertyAddress; 160 | Stack.StepCompiledIn(NULL); 161 | UStrProperty* FilePathProp = ExactCast(Stack.MostRecentProperty); 162 | FString FilePath = FilePathProp->GetPropertyValue(Stack.MostRecentPropertyAddress); 163 | P_FINISH; 164 | 165 | P_NATIVE_BEGIN; 166 | *(bool*)RESULT_PARAM = USIOJConvert::ToJsonFile(FilePath, StructProp->Struct, StructPtr); 167 | P_NATIVE_END; 168 | } 169 | 170 | //custom thunk needed to handle wildcard structs 171 | DECLARE_FUNCTION(execLoadJsonFileToStruct) 172 | { 173 | //Get properties and pointers from stack (nb, it's reverse order, right to left!) 174 | Stack.StepCompiledIn(NULL); 175 | UStrProperty* FilePathProp = ExactCast(Stack.MostRecentProperty); 176 | FString FilePath = FilePathProp->GetPropertyValue(Stack.MostRecentPropertyAddress); 177 | Stack.StepCompiledIn(NULL); 178 | UStructProperty* StructProp = ExactCast(Stack.MostRecentProperty); 179 | void* StructPtr = Stack.MostRecentPropertyAddress; 180 | P_FINISH; 181 | 182 | P_NATIVE_BEGIN; 183 | *(bool*)RESULT_PARAM = USIOJConvert::JsonFileToUStruct(FilePath, StructProp->Struct, StructPtr, true); 184 | P_NATIVE_END; 185 | } 186 | 187 | //Conversion Nodes 188 | 189 | //ToJsonValue 190 | 191 | UFUNCTION(BlueprintPure, meta = (DisplayName = "To JsonValue (Array)", BlueprintAutocast), Category = "Utilities|SocketIO") 192 | static USIOJsonValue* Conv_ArrayToJsonValue(const TArray& InArray); 193 | 194 | UFUNCTION(BlueprintPure, meta = (DisplayName = "To JsonValue (JsonObject)", BlueprintAutocast), Category = "Utilities|SocketIO") 195 | static USIOJsonValue* Conv_JsonObjectToJsonValue(USIOJsonObject* InObject); 196 | 197 | UFUNCTION(BlueprintPure, meta = (DisplayName = "To JsonValue (Bytes)", BlueprintAutocast), Category = "Utilities|SocketIO") 198 | static USIOJsonValue* Conv_BytesToJsonValue(const TArray& InBytes); 199 | 200 | UFUNCTION(BlueprintPure, meta = (DisplayName = "To JsonValue (String)", BlueprintAutocast), Category = "Utilities|SocketIO") 201 | static USIOJsonValue* Conv_StringToJsonValue(const FString& InString); 202 | 203 | UFUNCTION(BlueprintPure, meta = (DisplayName = "To JsonValue (Integer)", BlueprintAutocast), Category = "Utilities|SocketIO") 204 | static USIOJsonValue* Conv_IntToJsonValue(int32 InInt); 205 | 206 | UFUNCTION(BlueprintPure, meta = (DisplayName = "To JsonValue (Float)", BlueprintAutocast), Category = "Utilities|SocketIO") 207 | static USIOJsonValue* Conv_FloatToJsonValue(float InFloat); 208 | 209 | UFUNCTION(BlueprintPure, meta = (DisplayName = "To JsonValue (Bool)", BlueprintAutocast), Category = "Utilities|SocketIO") 210 | static USIOJsonValue* Conv_BoolToJsonValue(bool InBool); 211 | 212 | //To Native Types 213 | UFUNCTION(BlueprintPure, meta = (DisplayName = "To Integer (JsonValue)", BlueprintAutocast), Category = "Utilities|SocketIO") 214 | static int32 Conv_JsonValueToInt(class USIOJsonValue* InValue); 215 | 216 | UFUNCTION(BlueprintPure, meta = (DisplayName = "To Float (JsonValue)", BlueprintAutocast), Category = "Utilities|SocketIO") 217 | static float Conv_JsonValueToFloat(class USIOJsonValue* InValue); 218 | 219 | UFUNCTION(BlueprintPure, meta = (DisplayName = "To Bool (JsonValue)", BlueprintAutocast), Category = "Utilities|SocketIO") 220 | static bool Conv_JsonValueToBool(class USIOJsonValue* InValue); 221 | 222 | UFUNCTION(BlueprintPure, meta = (DisplayName = "To Bytes (JsonValue)", BlueprintAutocast), Category = "Utilities|SocketIO") 223 | static TArray Conv_JsonValueToBytes(class USIOJsonValue* InValue); 224 | 225 | //ToString - these never get called sadly, kismet library get display name takes priority 226 | UFUNCTION(BlueprintPure, meta = (DisplayName = "To String (SIOJsonObject)", CompactNodeTitle = "->", BlueprintAutocast), Category = "Utilities|SocketIO") 227 | static FString Conv_JsonObjectToString(class USIOJsonObject* InObject); 228 | 229 | UFUNCTION(BlueprintPure, meta = (DisplayName = "To Object (JsonValue)", BlueprintAutocast), Category = "Utilities|SocketIO") 230 | static USIOJsonObject* Conv_JsonValueToJsonObject(class USIOJsonValue* InValue); 231 | 232 | public: 233 | /** Easy way to process http requests */ 234 | UFUNCTION(BlueprintCallable, Category = "SIOJ|Utility", meta = (WorldContext = "WorldContextObject")) 235 | static void CallURL(UObject* WorldContextObject, const FString& URL, ESIORequestVerb Verb, ESIORequestContentType ContentType, USIOJsonObject* SIOJJson, const FSIOJCallDelegate& Callback); 236 | 237 | /** Called when URL is processed (one for both success/unsuccess events)*/ 238 | static void OnCallComplete(USIOJRequestJSON* Request); 239 | 240 | private: 241 | static TMap RequestMap; 242 | 243 | }; 244 | -------------------------------------------------------------------------------- /FingerControlUE4/Plugins/UDPWrapper/Source/SIOJson/Public/SIOJRequestJSON.h: -------------------------------------------------------------------------------- 1 | // Modifications Copyright 2018-current Getnamo. All Rights Reserved 2 | 3 | 4 | // Copyright 2014 Vladimir Alyamkin. All Rights Reserved. 5 | 6 | #pragma once 7 | 8 | #include "Delegates/Delegate.h" 9 | #include "Http.h" 10 | #include "Runtime/Core/Public/Containers/Map.h" 11 | #include "Runtime/Json/Public/Dom/JsonObject.h" 12 | #include "Runtime/Json/Public/Dom/JsonValue.h" 13 | #include "LatentActions.h" 14 | #include "Engine/LatentActionManager.h" 15 | #include "SIOJTypes.h" 16 | #include "SIOJRequestJSON.generated.h" 17 | 18 | /** 19 | * @author Original latent action class by https://github.com/unktomi 20 | */ 21 | template class FSIOJLatentAction : public FPendingLatentAction 22 | { 23 | public: 24 | virtual void Call(const T &Value) 25 | { 26 | Result = Value; 27 | Called = true; 28 | } 29 | 30 | void operator()(const T &Value) 31 | { 32 | Call(Value); 33 | } 34 | 35 | void Cancel(); 36 | 37 | FSIOJLatentAction(FWeakObjectPtr RequestObj, T& ResultParam, const FLatentActionInfo& LatentInfo) : 38 | Called(false), 39 | Request(RequestObj), 40 | ExecutionFunction(LatentInfo.ExecutionFunction), 41 | OutputLink(LatentInfo.Linkage), 42 | CallbackTarget(LatentInfo.CallbackTarget), 43 | Result(ResultParam) 44 | { 45 | } 46 | 47 | virtual void UpdateOperation(FLatentResponse& Response) override 48 | { 49 | Response.FinishAndTriggerIf(Called, ExecutionFunction, OutputLink, CallbackTarget); 50 | } 51 | 52 | virtual void NotifyObjectDestroyed() 53 | { 54 | Cancel(); 55 | } 56 | 57 | virtual void NotifyActionAborted() 58 | { 59 | Cancel(); 60 | } 61 | 62 | private: 63 | bool Called; 64 | FWeakObjectPtr Request; 65 | 66 | public: 67 | const FName ExecutionFunction; 68 | const int32 OutputLink; 69 | const FWeakObjectPtr CallbackTarget; 70 | T &Result; 71 | }; 72 | 73 | 74 | /** Generate a delegates for callback events */ 75 | DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnRequestComplete, class USIOJRequestJSON*, Request); 76 | DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnRequestFail, class USIOJRequestJSON*, Request); 77 | 78 | DECLARE_MULTICAST_DELEGATE_OneParam(FOnStaticRequestComplete, class USIOJRequestJSON*); 79 | DECLARE_MULTICAST_DELEGATE_OneParam(FOnStaticRequestFail, class USIOJRequestJSON*); 80 | 81 | 82 | /** 83 | * General helper class http requests via blueprints 84 | */ 85 | UCLASS(BlueprintType, Blueprintable) 86 | class SIOJSON_API USIOJRequestJSON : public UObject 87 | { 88 | GENERATED_UCLASS_BODY() 89 | 90 | public: 91 | ////////////////////////////////////////////////////////////////////////// 92 | // Construction 93 | 94 | /** Creates new request (totally empty) */ 95 | UFUNCTION(BlueprintPure, meta = (DisplayName = "Construct Json Request (Empty)", HidePin = "WorldContextObject", DefaultToSelf = "WorldContextObject"), Category = "SIOJ|Request") 96 | static USIOJRequestJSON* ConstructRequest(UObject* WorldContextObject); 97 | 98 | /** Creates new request with defined verb and content type */ 99 | UFUNCTION(BlueprintPure, meta = (DisplayName = "Construct Json Request", HidePin = "WorldContextObject", DefaultToSelf = "WorldContextObject"), Category = "SIOJ|Request") 100 | static USIOJRequestJSON* ConstructRequestExt(UObject* WorldContextObject, ESIORequestVerb Verb, ESIORequestContentType ContentType); 101 | 102 | /** Set verb to the request */ 103 | UFUNCTION(BlueprintCallable, Category = "SIOJ|Request") 104 | void SetVerb(ESIORequestVerb Verb); 105 | 106 | /** Set custom verb to the request */ 107 | UFUNCTION(BlueprintCallable, Category = "SIOJ|Request") 108 | void SetCustomVerb(FString Verb); 109 | 110 | /** Set content type to the request. If you're using the x-www-form-urlencoded, 111 | * params/constaints should be defined as key=ValueString pairs from Json data */ 112 | UFUNCTION(BlueprintCallable, Category = "SIOJ|Request") 113 | void SetContentType(ESIORequestContentType ContentType); 114 | 115 | /** Set content type of the request for binary post data */ 116 | UFUNCTION(BlueprintCallable, Category = "SIOJ|Request") 117 | void SetBinaryContentType(const FString &ContentType); 118 | 119 | /** Set content of the request for binary post data */ 120 | UFUNCTION(BlueprintCallable, Category = "SIOJ|Request") 121 | void SetBinaryRequestContent(const TArray &Content); 122 | 123 | /** Sets optional header info */ 124 | UFUNCTION(BlueprintCallable, Category = "SIOJ|Request") 125 | void SetHeader(const FString& HeaderName, const FString& HeaderValue); 126 | 127 | 128 | ////////////////////////////////////////////////////////////////////////// 129 | // Destruction and reset 130 | 131 | /** Reset all internal saved data */ 132 | UFUNCTION(BlueprintCallable, Category = "SIOJ|Utility") 133 | void ResetData(); 134 | 135 | /** Reset saved request data */ 136 | UFUNCTION(BlueprintCallable, Category = "SIOJ|Request") 137 | void ResetRequestData(); 138 | 139 | /** Reset saved response data */ 140 | UFUNCTION(BlueprintCallable, Category = "SIOJ|Response") 141 | void ResetResponseData(); 142 | 143 | /** Cancel latent response waiting */ 144 | UFUNCTION(BlueprintCallable, Category = "SIOJ|Response") 145 | void Cancel(); 146 | 147 | 148 | ////////////////////////////////////////////////////////////////////////// 149 | // JSON data accessors 150 | 151 | /** Get the Request Json object */ 152 | UFUNCTION(BlueprintCallable, Category = "SIOJ|Request") 153 | USIOJsonObject* GetRequestObject(); 154 | 155 | /** Set the Request Json object */ 156 | UFUNCTION(BlueprintCallable, Category = "SIOJ|Request") 157 | void SetRequestObject(USIOJsonObject* JsonObject); 158 | 159 | /** Get the Response Json object */ 160 | UFUNCTION(BlueprintCallable, Category = "SIOJ|Response") 161 | USIOJsonObject* GetResponseObject(); 162 | 163 | /** Set the Response Json object */ 164 | UFUNCTION(BlueprintCallable, Category = "SIOJ|Response") 165 | void SetResponseObject(USIOJsonObject* JsonObject); 166 | 167 | 168 | /////////////////////////////////////////////////////////////////////////// 169 | // Request/response data access 170 | 171 | /** Get url of http request */ 172 | UFUNCTION(BlueprintCallable, Category = "SIOJ|Request") 173 | FString GetURL(); 174 | 175 | /** Get status of http request */ 176 | UFUNCTION(BlueprintCallable, Category = "SIOJ|Request") 177 | ESIORequestStatus GetStatus(); 178 | 179 | /** Get the response code of the last query */ 180 | UFUNCTION(BlueprintCallable, Category = "SIOJ|Response") 181 | int32 GetResponseCode(); 182 | 183 | /** Get value of desired response header */ 184 | UFUNCTION(BlueprintCallable, Category = "SIOJ|Response") 185 | FString GetResponseHeader(const FString HeaderName); 186 | 187 | /** Get list of all response headers */ 188 | UFUNCTION(BlueprintCallable, Category = "SIOJ|Response") 189 | TArray GetAllResponseHeaders(); 190 | 191 | 192 | ////////////////////////////////////////////////////////////////////////// 193 | // URL processing 194 | 195 | /** Open URL with current setup */ 196 | UFUNCTION(BlueprintCallable, Category = "SIOJ|Request") 197 | virtual void ProcessURL(const FString& Url = TEXT("http://alyamkin.com")); 198 | 199 | /** Open URL in latent mode */ 200 | UFUNCTION(BlueprintCallable, Category = "SIOJ|Request", meta = (Latent, LatentInfo = "LatentInfo", HidePin = "WorldContextObject", DefaultToSelf = "WorldContextObject")) 201 | virtual void ApplyURL(const FString& Url, USIOJsonObject *&Result, UObject* WorldContextObject, struct FLatentActionInfo LatentInfo); 202 | 203 | /** Apply current internal setup to request and process it */ 204 | void ProcessRequest(); 205 | 206 | 207 | ////////////////////////////////////////////////////////////////////////// 208 | // Request callbacks 209 | 210 | private: 211 | /** Internal bind function for the IHTTPRequest::OnProcessRequestCompleted() event */ 212 | void OnProcessRequestComplete(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful); 213 | 214 | public: 215 | /** Event occured when the request has been completed */ 216 | UPROPERTY(BlueprintAssignable, Category = "SIOJ|Event") 217 | FOnRequestComplete OnRequestComplete; 218 | 219 | /** Event occured when the request wasn't successfull */ 220 | UPROPERTY(BlueprintAssignable, Category = "SIOJ|Event") 221 | FOnRequestFail OnRequestFail; 222 | 223 | /** Event occured when the request has been completed */ 224 | FOnStaticRequestComplete OnStaticRequestComplete; 225 | 226 | /** Event occured when the request wasn't successfull */ 227 | FOnStaticRequestFail OnStaticRequestFail; 228 | 229 | 230 | ////////////////////////////////////////////////////////////////////////// 231 | // Tags 232 | 233 | public: 234 | /** Add tag to this request */ 235 | UFUNCTION(BlueprintCallable, Category = "SIOJ|Utility") 236 | void AddTag(FName Tag); 237 | 238 | /** 239 | * Remove tag from this request 240 | * 241 | * @return Number of removed elements 242 | */ 243 | UFUNCTION(BlueprintCallable, Category = "SIOJ|Utility") 244 | int32 RemoveTag(FName Tag); 245 | 246 | /** See if this request contains the supplied tag */ 247 | UFUNCTION(BlueprintCallable, Category = "SIOJ|Utility") 248 | bool HasTag(FName Tag) const; 249 | 250 | protected: 251 | /** Array of tags that can be used for grouping and categorizing */ 252 | TArray Tags; 253 | 254 | 255 | ////////////////////////////////////////////////////////////////////////// 256 | // Data 257 | 258 | public: 259 | /** Request response stored as a string */ 260 | UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "SIOJ|Response") 261 | FString ResponseContent; 262 | 263 | /** Is the response valid JSON? */ 264 | UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "SIOJ|Response") 265 | bool bIsValidJsonResponse; 266 | 267 | protected: 268 | /** Latent action helper */ 269 | FSIOJLatentAction* ContinueAction; 270 | 271 | /** Internal request data stored as JSON */ 272 | UPROPERTY() 273 | USIOJsonObject* RequestJsonObj; 274 | 275 | UPROPERTY() 276 | TArray RequestBytes; 277 | 278 | UPROPERTY() 279 | FString BinaryContentType; 280 | 281 | /** Response data stored as JSON */ 282 | UPROPERTY() 283 | USIOJsonObject* ResponseJsonObj; 284 | 285 | /** Verb for making request (GET,POST,etc) */ 286 | ESIORequestVerb RequestVerb; 287 | 288 | /** Content type to be applied for request */ 289 | ESIORequestContentType RequestContentType; 290 | 291 | /** Mapping of header section to values. Used to generate final header string for request */ 292 | TMap RequestHeaders; 293 | 294 | /** Cached key/value header pairs. Parsed once request completes */ 295 | TMap ResponseHeaders; 296 | 297 | /** Http Response code */ 298 | int32 ResponseCode; 299 | 300 | /** Custom verb that will be used with RequestContentType == CUSTOM */ 301 | FString CustomVerb; 302 | 303 | /** Request we're currently processing */ 304 | TSharedRef HttpRequest = FHttpModule::Get().CreateRequest(); 305 | 306 | }; 307 | -------------------------------------------------------------------------------- /FingerControlUE4/Plugins/UDPWrapper/Source/SIOJson/Public/SIOJTypes.h: -------------------------------------------------------------------------------- 1 | // Modifications Copyright 2018-current Getnamo. All Rights Reserved 2 | 3 | 4 | // Copyright 2016 Vladimir Alyamkin. All Rights Reserved. 5 | 6 | #pragma once 7 | 8 | /** Verb (GET, PUT, POST) used by the request */ 9 | UENUM(BlueprintType) 10 | enum class ESIORequestVerb : uint8 11 | { 12 | GET, 13 | POST, 14 | PUT, 15 | DEL UMETA(DisplayName = "DELETE"), 16 | /** Set CUSTOM verb by SetCustomVerb() function */ 17 | CUSTOM 18 | }; 19 | 20 | /** Content type (json, urlencoded, etc.) used by the request */ 21 | UENUM(BlueprintType) 22 | enum class ESIORequestContentType : uint8 23 | { 24 | x_www_form_urlencoded_url UMETA(DisplayName = "x-www-form-urlencoded (URL)"), 25 | x_www_form_urlencoded_body UMETA(DisplayName = "x-www-form-urlencoded (Request Body)"), 26 | json, 27 | binary 28 | }; 29 | 30 | /** Enumerates the current state of an Http request */ 31 | UENUM(BlueprintType) 32 | enum class ESIORequestStatus : uint8 33 | { 34 | /** Has not been started via ProcessRequest() */ 35 | NotStarted, 36 | /** Currently being ticked and processed */ 37 | Processing, 38 | /** Finished but failed */ 39 | Failed, 40 | /** Failed because it was unable to connect (safe to retry) */ 41 | Failed_ConnectionError, 42 | /** Finished and was successful */ 43 | Succeeded 44 | }; 45 | -------------------------------------------------------------------------------- /FingerControlUE4/Plugins/UDPWrapper/Source/SIOJson/Public/SIOJsonObject.h: -------------------------------------------------------------------------------- 1 | // Modifications Copyright 2018-current Getnamo. All Rights Reserved 2 | 3 | 4 | // Copyright 1998-2014 Epic Games, Inc. All Rights Reserved. 5 | // Copyright 2014 Vladimir Alyamkin. All Rights Reserved. 6 | 7 | #pragma once 8 | 9 | #include "Runtime/Json/Public/Dom/JsonObject.h" 10 | #include "SIOJsonObject.generated.h" 11 | 12 | class USIOJsonValue; 13 | 14 | /** 15 | * Blueprintable FJsonObject wrapper 16 | */ 17 | UCLASS(BlueprintType, Blueprintable) 18 | class SIOJSON_API USIOJsonObject : public UObject 19 | { 20 | GENERATED_UCLASS_BODY() 21 | 22 | /** Create new Json object, cannot be pure */ 23 | UFUNCTION(BlueprintCallable , meta = (DisplayName = "Construct Json Object", HidePin = "WorldContextObject", DefaultToSelf = "WorldContextObject"), Category = "SIOJ|Json") 24 | static USIOJsonObject* ConstructJsonObject(UObject* WorldContextObject); 25 | 26 | /** Reset all internal data */ 27 | UFUNCTION(BlueprintCallable, Category = "SIOJ|Json") 28 | void Reset(); 29 | 30 | /** Get the root Json object */ 31 | TSharedPtr& GetRootObject(); 32 | 33 | /** Set the root Json object */ 34 | void SetRootObject(const TSharedPtr& JsonObject); 35 | 36 | 37 | ////////////////////////////////////////////////////////////////////////// 38 | // Serialization 39 | 40 | /** Serialize Json to string (formatted with line breaks) */ 41 | UFUNCTION(BlueprintCallable, Category = "SIOJ|Json") 42 | FString EncodeJson() const; 43 | 44 | /** Serialize Json to string (single string without line breaks) */ 45 | UFUNCTION(BlueprintCallable, Category = "SIOJ|Json") 46 | FString EncodeJsonToSingleString() const; 47 | 48 | /** Construct Json object from string */ 49 | UFUNCTION(BlueprintCallable, Category = "SIOJ|Json") 50 | bool DecodeJson(const FString& JsonString); 51 | 52 | 53 | ////////////////////////////////////////////////////////////////////////// 54 | // FJsonObject API 55 | 56 | /** Returns a list of field names that exist in the object */ 57 | UFUNCTION(BlueprintPure, Category = "SIOJ|Json") 58 | TArray GetFieldNames(); 59 | 60 | /** Checks to see if the FieldName exists in the object */ 61 | UFUNCTION(BlueprintCallable, Category = "SIOJ|Json") 62 | bool HasField(const FString& FieldName) const; 63 | 64 | /** Remove field named FieldName */ 65 | UFUNCTION(BlueprintCallable, Category = "SIOJ|Json") 66 | void RemoveField(const FString& FieldName); 67 | 68 | /** Get the field named FieldName as a JsonValue */ 69 | UFUNCTION(BlueprintCallable, Category = "SIOJ|Json") 70 | USIOJsonValue* GetField(const FString& FieldName) const; 71 | 72 | /** Add a field named FieldName with a Value */ 73 | UFUNCTION(BlueprintCallable, Category = "SIOJ|Json") 74 | void SetField(const FString& FieldName, USIOJsonValue* JsonValue); 75 | 76 | /** Get the field named FieldName as a Json Array */ 77 | UFUNCTION(BlueprintCallable, Category = "SIOJ|Json") 78 | TArray GetArrayField(const FString& FieldName); 79 | 80 | /** Set an ObjectField named FieldName and value of Json Array */ 81 | UFUNCTION(BlueprintCallable, Category = "SIOJ|Json") 82 | void SetArrayField(const FString& FieldName, const TArray& InArray); 83 | 84 | /** Adds all of the fields from one json object to this one */ 85 | UFUNCTION(BlueprintCallable, Category = "SIOJ|Json") 86 | void MergeJsonObject(USIOJsonObject* InJsonObject, bool Overwrite); 87 | 88 | 89 | ////////////////////////////////////////////////////////////////////////// 90 | // FJsonObject API Helpers (easy to use with simple Json objects) 91 | 92 | /** Get the field named FieldName as a number. Ensures that the field is present and is of type Json number. 93 | * Attn.!! float used instead of double to make the function blueprintable! */ 94 | UFUNCTION(BlueprintCallable, Category = "SIOJ|Json") 95 | float GetNumberField(const FString& FieldName) const; 96 | 97 | /** Add a field named FieldName with Number as value 98 | * Attn.!! float used instead of double to make the function blueprintable! */ 99 | UFUNCTION(BlueprintCallable, Category = "SIOJ|Json") 100 | void SetNumberField(const FString& FieldName, float Number); 101 | 102 | /** Get the field named FieldName as a string. */ 103 | UFUNCTION(BlueprintCallable, Category = "SIOJ|Json") 104 | FString GetStringField(const FString& FieldName) const; 105 | 106 | /** Add a field named FieldName with value of StringValue */ 107 | UFUNCTION(BlueprintCallable, Category = "SIOJ|Json") 108 | void SetStringField(const FString& FieldName, const FString& StringValue); 109 | 110 | /** Get the field named FieldName as a boolean. */ 111 | UFUNCTION(BlueprintCallable, Category = "SIOJ|Json") 112 | bool GetBoolField(const FString& FieldName) const; 113 | 114 | /** Set a boolean field named FieldName and value of InValue */ 115 | UFUNCTION(BlueprintCallable, Category = "SIOJ|Json") 116 | void SetBoolField(const FString& FieldName, bool InValue); 117 | 118 | /** Get the field named FieldName as a Json object. */ 119 | UFUNCTION(BlueprintCallable, Category = "SIOJ|Json") 120 | USIOJsonObject* GetObjectField(const FString& FieldName) const; 121 | 122 | /** Set an ObjectField named FieldName and value of JsonObject */ 123 | UFUNCTION(BlueprintCallable, Category = "SIOJ|Json") 124 | void SetObjectField(const FString& FieldName, USIOJsonObject* JsonObject); 125 | 126 | /** Get the field named FieldName as a binary buffer array. */ 127 | UFUNCTION(BlueprintCallable, Category = "SIOJ|Json") 128 | TArray GetBinaryField(const FString& FieldName) const; 129 | 130 | /** Set an BinaryField named FieldName and binary buffer array */ 131 | UFUNCTION(BlueprintCallable, Category = "SIOJ|Json") 132 | void SetBinaryField(const FString& FieldName, const TArray& Bytes); 133 | 134 | 135 | ////////////////////////////////////////////////////////////////////////// 136 | // Array fields helpers (uniform arrays) 137 | 138 | /** Get the field named FieldName as a Number Array. Use it only if you're sure that array is uniform! 139 | * Attn.!! float used instead of double to make the function blueprintable! */ 140 | UFUNCTION(BlueprintCallable, Category = "SIOJ|Json") 141 | TArray GetNumberArrayField(const FString& FieldName); 142 | 143 | /** Set an ObjectField named FieldName and value of Number Array 144 | * Attn.!! float used instead of double to make the function blueprintable! */ 145 | UFUNCTION(BlueprintCallable, Category = "SIOJ|Json") 146 | void SetNumberArrayField(const FString& FieldName, const TArray& NumberArray); 147 | 148 | /** Get the field named FieldName as a String Array. Use it only if you're sure that array is uniform! */ 149 | UFUNCTION(BlueprintCallable, Category = "SIOJ|Json") 150 | TArray GetStringArrayField(const FString& FieldName); 151 | 152 | /** Set an ObjectField named FieldName and value of String Array */ 153 | UFUNCTION(BlueprintCallable, Category = "SIOJ|Json") 154 | void SetStringArrayField(const FString& FieldName, const TArray& StringArray); 155 | 156 | /** Get the field named FieldName as a Bool Array. Use it only if you're sure that array is uniform! */ 157 | UFUNCTION(BlueprintCallable, Category = "SIOJ|Json") 158 | TArray GetBoolArrayField(const FString& FieldName); 159 | 160 | /** Set an ObjectField named FieldName and value of Bool Array */ 161 | UFUNCTION(BlueprintCallable, Category = "SIOJ|Json") 162 | void SetBoolArrayField(const FString& FieldName, const TArray& BoolArray); 163 | 164 | /** Get the field named FieldName as an Object Array. Use it only if you're sure that array is uniform! */ 165 | UFUNCTION(BlueprintCallable, Category = "SIOJ|Json") 166 | TArray GetObjectArrayField(const FString& FieldName); 167 | 168 | /** Set an ObjectField named FieldName and value of Ob Array */ 169 | UFUNCTION(BlueprintCallable, Category = "SIOJ|Json") 170 | void SetObjectArrayField(const FString& FieldName, const TArray& ObjectArray); 171 | 172 | 173 | ////////////////////////////////////////////////////////////////////////// 174 | // Data 175 | 176 | private: 177 | /** Internal JSON data */ 178 | TSharedPtr JsonObj; 179 | 180 | }; 181 | -------------------------------------------------------------------------------- /FingerControlUE4/Plugins/UDPWrapper/Source/SIOJson/Public/SIOJsonValue.h: -------------------------------------------------------------------------------- 1 | // Modifications Copyright 2018-current Getnamo. All Rights Reserved 2 | 3 | 4 | // Copyright 1998-2014 Epic Games, Inc. All Rights Reserved. 5 | // Copyright 2014 Vladimir Alyamkin. All Rights Reserved. 6 | 7 | #pragma once 8 | 9 | #include "Runtime/Json/Public/Dom/JsonValue.h" 10 | #include "SIOJsonValue.generated.h" 11 | 12 | class USIOJsonObject; 13 | 14 | /** 15 | * Represents all the types a Json Value can be. 16 | */ 17 | UENUM(BlueprintType) 18 | namespace ESIOJson 19 | { 20 | enum Type 21 | { 22 | None, 23 | Null, 24 | String, 25 | Number, 26 | Boolean, 27 | Array, 28 | Object, 29 | Binary 30 | }; 31 | } 32 | 33 | class SIOJSON_API FJsonValueBinary : public FJsonValue 34 | { 35 | public: 36 | FJsonValueBinary(const TArray& InBinary) : Value(InBinary) { Type = EJson::String; } //pretends to be none 37 | 38 | virtual bool TryGetString(FString& OutString) const override 39 | { 40 | OutString = FString::FromHexBlob(Value.GetData(), Value.Num()); //encode the binary into the string directly 41 | return true; 42 | } 43 | virtual bool TryGetNumber(double& OutDouble) const override 44 | { 45 | OutDouble = Value.Num(); 46 | return true; 47 | } 48 | 49 | //hackery: we use this as an indicator we have a binary (strings don't normally do this) 50 | virtual bool TryGetBool(bool& OutBool) const override { return false; } 51 | 52 | /** Return our binary data from this value */ 53 | TArray AsBinary() { return Value; } 54 | 55 | /** Convenience method to determine if passed FJsonValue is a FJsonValueBinary or not. */ 56 | static bool IsBinary(const TSharedPtr& InJsonValue); 57 | 58 | /** Convenience method to get binary array from unknown JsonValue, test with IsBinary first. */ 59 | static TArray AsBinary(const TSharedPtr& InJsonValue); 60 | 61 | protected: 62 | TArray Value; 63 | 64 | virtual FString GetType() const override { return TEXT("Binary"); } 65 | }; 66 | 67 | /** 68 | * Blueprintable FJsonValue wrapper 69 | */ 70 | UCLASS(BlueprintType, Blueprintable) 71 | class SIOJSON_API USIOJsonValue : public UObject 72 | { 73 | GENERATED_UCLASS_BODY() 74 | 75 | /** Create new Json Number value 76 | * Attn.!! float used instead of double to make the function blueprintable! */ 77 | UFUNCTION(BlueprintPure, meta = (DisplayName = "Construct Json Number Value", HidePin = "WorldContextObject", DefaultToSelf = "WorldContextObject"), Category = "SIOJ|Json") 78 | static USIOJsonValue* ConstructJsonValueNumber(UObject* WorldContextObject, float Number); 79 | 80 | /** Create new Json String value */ 81 | UFUNCTION(BlueprintPure, meta = (DisplayName = "Construct Json String Value", HidePin = "WorldContextObject", DefaultToSelf = "WorldContextObject"), Category = "SIOJ|Json") 82 | static USIOJsonValue* ConstructJsonValueString(UObject* WorldContextObject, const FString& StringValue); 83 | 84 | /** Create new Json Bool value */ 85 | UFUNCTION(BlueprintPure, meta = (DisplayName = "Construct Json Bool Value", HidePin = "WorldContextObject", DefaultToSelf = "WorldContextObject"), Category = "SIOJ|Json") 86 | static USIOJsonValue* ConstructJsonValueBool(UObject* WorldContextObject, bool InValue); 87 | 88 | /** Create new Json Array value */ 89 | UFUNCTION(BlueprintPure, meta = (DisplayName = "Construct Json Array Value", HidePin = "WorldContextObject", DefaultToSelf = "WorldContextObject"), Category = "SIOJ|Json") 90 | static USIOJsonValue* ConstructJsonValueArray(UObject* WorldContextObject, const TArray& InArray); 91 | 92 | /** Create new Json Object value */ 93 | UFUNCTION(BlueprintPure, meta = (DisplayName = "Construct Json Object Value", HidePin = "WorldContextObject", DefaultToSelf = "WorldContextObject"), Category = "SIOJ|Json") 94 | static USIOJsonValue* ConstructJsonValueObject(USIOJsonObject *JsonObject, UObject* WorldContextObject); 95 | 96 | /** Create new Json Binary value */ 97 | UFUNCTION(BlueprintPure, meta = (DisplayName = "Construct Json Binary Value", HidePin = "WorldContextObject", DefaultToSelf = "WorldContextObject"), Category = "SIOJ|Json") 98 | static USIOJsonValue* ConstructJsonValueBinary(UObject* WorldContextObject, TArray ByteArray); 99 | 100 | /** Create new Json value from FJsonValue (to be used from USIOJsonObject) */ 101 | static USIOJsonValue* ConstructJsonValue(UObject* WorldContextObject, const TSharedPtr& InValue); 102 | 103 | /** Create new Json value from JSON encoded string*/ 104 | UFUNCTION(BlueprintPure, meta = (DisplayName = "Value From Json String", HidePin = "WorldContextObject", DefaultToSelf = "WorldContextObject"), Category = "SIOJ|Json") 105 | static USIOJsonValue* ValueFromJsonString(UObject* WorldContextObject, const FString& StringValue); 106 | 107 | /** Get the root Json value */ 108 | TSharedPtr& GetRootValue(); 109 | 110 | /** Set the root Json value */ 111 | void SetRootValue(TSharedPtr& JsonValue); 112 | 113 | 114 | ////////////////////////////////////////////////////////////////////////// 115 | // FJsonValue API 116 | 117 | /** Get type of Json value (Enum) */ 118 | UFUNCTION(BlueprintCallable, Category = "SIOJ|Json") 119 | ESIOJson::Type GetType() const; 120 | 121 | /** Get type of Json value (String) */ 122 | UFUNCTION(BlueprintCallable, Category = "SIOJ|Json") 123 | FString GetTypeString() const; 124 | 125 | /** Returns true if this value is a 'null' */ 126 | UFUNCTION(BlueprintCallable, Category = "SIOJ|Json") 127 | bool IsNull() const; 128 | 129 | /** Returns this value as a double, throwing an error if this is not an Json Number 130 | * Attn.!! float used instead of double to make the function blueprintable! */ 131 | UFUNCTION(BlueprintCallable, Category = "SIOJ|Json") 132 | float AsNumber() const; 133 | 134 | /** Returns this value as a number, throwing an error if this is not an Json String */ 135 | UFUNCTION(BlueprintCallable, Category = "SIOJ|Json") 136 | FString AsString() const; 137 | 138 | /** Returns this value as a boolean, throwing an error if this is not an Json Bool */ 139 | UFUNCTION(BlueprintCallable, Category = "SIOJ|Json") 140 | bool AsBool() const; 141 | 142 | /** Returns this value as an array, throwing an error if this is not an Json Array */ 143 | UFUNCTION(BlueprintCallable, Category = "SIOJ|Json") 144 | TArray AsArray() const; 145 | 146 | /** Returns this value as an object, throwing an error if this is not an Json Object */ 147 | UFUNCTION(BlueprintCallable, Category = "SIOJ|Json") 148 | USIOJsonObject* AsObject(); 149 | 150 | //todo: add basic binary e.g. tarray 151 | UFUNCTION(BlueprintCallable, Category = "SIOJ|Json") 152 | TArray AsBinary(); 153 | 154 | UFUNCTION(BlueprintCallable, Category = "SIOJ|Json") 155 | FString EncodeJson() const; 156 | 157 | ////////////////////////////////////////////////////////////////////////// 158 | // Data 159 | 160 | private: 161 | /** Internal JSON data */ 162 | TSharedPtr JsonVal; 163 | 164 | 165 | ////////////////////////////////////////////////////////////////////////// 166 | // Helpers 167 | 168 | protected: 169 | /** Simple error logger */ 170 | void ErrorMessage(const FString& InType) const; 171 | 172 | }; 173 | -------------------------------------------------------------------------------- /FingerControlUE4/Plugins/UDPWrapper/Source/SIOJson/SIOJson.Build.cs: -------------------------------------------------------------------------------- 1 | // Modifications Copyright 2018-current Getnamo. All Rights Reserved 2 | 3 | 4 | // Copyright 2014 Vladimir Alyamkin. All Rights Reserved. 5 | 6 | using System.IO; 7 | 8 | namespace UnrealBuildTool.Rules 9 | { 10 | public class SIOJson : ModuleRules 11 | { 12 | public SIOJson(ReadOnlyTargetRules Target) : base(Target) 13 | { 14 | PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; 15 | 16 | PrivateIncludePaths.AddRange( 17 | new string[] { 18 | "SIOJson/Private", 19 | // ... add other private include paths required here ... 20 | }); 21 | 22 | PublicDependencyModuleNames.AddRange( 23 | new string[] 24 | { 25 | "Core", 26 | "CoreUObject", 27 | "Engine", 28 | "HTTP", 29 | "Json", 30 | "JsonUtilities" 31 | // ... add other public dependencies that you statically link with here ... 32 | }); 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /FingerControlUE4/Plugins/UDPWrapper/Source/UDPWrapper/Private/UDPWrapper.cpp: -------------------------------------------------------------------------------- 1 | #include "UDPWrapper.h" 2 | 3 | #define LOCTEXT_NAMESPACE "FUDPWrapperModule" 4 | 5 | void FUDPWrapperModule::StartupModule() 6 | { 7 | 8 | } 9 | 10 | void FUDPWrapperModule::ShutdownModule() 11 | { 12 | 13 | } 14 | 15 | #undef LOCTEXT_NAMESPACE 16 | 17 | IMPLEMENT_MODULE(FUDPWrapperModule, UDPWrapper) -------------------------------------------------------------------------------- /FingerControlUE4/Plugins/UDPWrapper/Source/UDPWrapper/Private/udpcomponent.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "UDPComponent.h" 3 | #include "Async.h" 4 | #include "Runtime/Sockets/Public/SocketSubsystem.h" 5 | #include "Runtime/Engine/Classes/Kismet/KismetSystemLibrary.h" 6 | #include 7 | 8 | UUDPComponent::UUDPComponent(const FObjectInitializer &init) : UActorComponent(init) 9 | { 10 | bShouldAutoConnect = true; 11 | bShouldAutoListen = true; 12 | bReceiveDataOnGameThread = true; 13 | bWantsInitializeComponent = true; 14 | bAutoActivate = true; 15 | SendIP = FString(TEXT("127.0.0.1")); 16 | SendPort = 7766; 17 | ReceivePort = 7755; 18 | SendSocketName = FString(TEXT("GyroMocapSend")); 19 | ReceiveSocketName = FString(TEXT("GyroMocapReceive")); 20 | 21 | BufferSize = 2 * 1024 * 1024; 22 | 23 | SenderSocket = nullptr; 24 | ReceiverSocket = nullptr; 25 | } 26 | 27 | void UUDPComponent::ConnectToSendSocket(const FString& InIP, const int32 InPort) 28 | { 29 | RemoteAdress = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->CreateInternetAddr(); 30 | 31 | bool bIsValid; 32 | RemoteAdress->SetIp(*InIP, bIsValid); 33 | RemoteAdress->SetPort(InPort); 34 | 35 | if (!bIsValid) 36 | { 37 | UE_LOG(LogTemp, Error, TEXT("UDP address is invalid <%s:%d>"), *InIP, InPort); 38 | return ; 39 | } 40 | 41 | SenderSocket = FUdpSocketBuilder(*SendSocketName).AsReusable().WithBroadcast(); 42 | 43 | SenderSocket->SetSendBufferSize(BufferSize, BufferSize); 44 | SenderSocket->SetReceiveBufferSize(BufferSize, BufferSize); 45 | 46 | bool bDidConnect = SenderSocket->Connect(*RemoteAdress); 47 | } 48 | 49 | void UUDPComponent::StartReceiveSocketListening(const int32 InListenPort) 50 | { 51 | FIPv4Address Addr; 52 | FIPv4Address::Parse(TEXT("0.0.0.0"), Addr); 53 | 54 | FIPv4Endpoint Endpoint(Addr, InListenPort); 55 | 56 | ReceiverSocket = FUdpSocketBuilder(*ReceiveSocketName) 57 | .AsNonBlocking() 58 | .AsReusable() 59 | .BoundToEndpoint(Endpoint) 60 | .WithReceiveBufferSize(BufferSize); 61 | 62 | FTimespan ThreadWaitTime = FTimespan::FromMilliseconds(100); 63 | FString ThreadName = FString::Printf(TEXT("UDP RECEIVER-%s"), *UKismetSystemLibrary::GetDisplayName(this)); 64 | UDPReceiver = new FUdpSocketReceiver(ReceiverSocket, ThreadWaitTime, *ThreadName); 65 | 66 | UDPReceiver->OnDataReceived().BindUObject(this, &UUDPComponent::OnDataReceivedDelegate); 67 | OnReceiveSocketStartedListening.Broadcast(); 68 | 69 | UDPReceiver->Start(); 70 | } 71 | 72 | void UUDPComponent::CloseReceiveSocket() 73 | { 74 | if (ReceiverSocket) 75 | { 76 | UDPReceiver->Stop(); 77 | delete UDPReceiver; 78 | UDPReceiver = nullptr; 79 | 80 | ReceiverSocket->Close(); 81 | ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->DestroySocket(ReceiverSocket); 82 | ReceiverSocket = nullptr; 83 | 84 | OnReceiveSocketStoppedListening.Broadcast(); 85 | } 86 | } 87 | 88 | void UUDPComponent::CloseSendSocket() 89 | { 90 | if (SenderSocket) 91 | { 92 | SenderSocket->Close(); 93 | ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->DestroySocket(SenderSocket); 94 | SenderSocket = nullptr; 95 | } 96 | } 97 | 98 | void UUDPComponent::Emit(const TArray& Bytes) 99 | { 100 | if (SenderSocket->GetConnectionState() == SCS_Connected) 101 | { 102 | int32 BytesSent = 0; 103 | SenderSocket->Send(Bytes.GetData(), Bytes.Num(), BytesSent); 104 | } 105 | } 106 | 107 | void UUDPComponent::InitializeComponent() 108 | { 109 | Super::InitializeComponent(); 110 | } 111 | 112 | void UUDPComponent::UninitializeComponent() 113 | { 114 | Super::UninitializeComponent(); 115 | } 116 | 117 | void UUDPComponent::BeginPlay() 118 | { 119 | Super::BeginPlay(); 120 | 121 | if (bShouldAutoListen) 122 | { 123 | StartReceiveSocketListening(ReceivePort); 124 | } 125 | if (bShouldAutoConnect) 126 | { 127 | ConnectToSendSocket(SendIP, SendPort); 128 | } 129 | } 130 | 131 | void UUDPComponent::EndPlay(const EEndPlayReason::Type EndPlayReason) 132 | { 133 | CloseSendSocket(); 134 | CloseReceiveSocket(); 135 | 136 | Super::EndPlay(EndPlayReason); 137 | } 138 | 139 | void UUDPComponent::OnDataReceivedDelegate(const FArrayReaderPtr& DataPtr, const FIPv4Endpoint& Endpoint) 140 | { 141 | TArray Data; 142 | Data.AddUninitialized(DataPtr->TotalSize()); 143 | DataPtr->Serialize(Data.GetData(), DataPtr->TotalSize()); 144 | 145 | if (bReceiveDataOnGameThread) 146 | { 147 | AsyncTask(ENamedThreads::GameThread, [&, Data]() 148 | { 149 | OnReceivedBytes.Broadcast(Data); 150 | }); 151 | } 152 | else 153 | { 154 | OnReceivedBytes.Broadcast(Data); 155 | } 156 | } 157 | 158 | FString UUDPComponent::StringFromBinaryArray(const TArray& BinaryArray) 159 | { 160 | std::string cstr(reinterpret_cast(BinaryArray.GetData()), BinaryArray.Num()); 161 | return FString(cstr.c_str()); 162 | } 163 | -------------------------------------------------------------------------------- /FingerControlUE4/Plugins/UDPWrapper/Source/UDPWrapper/Public/UDPComponent.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Components/ActorComponent.h" 4 | #include "Networking.h" 5 | #include "Runtime/Sockets/Public/IPAddress.h" 6 | #include "UDPComponent.generated.h" 7 | 8 | DECLARE_DYNAMIC_MULTICAST_DELEGATE(FUDPEventSignature); 9 | DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FUDPMessageSignature, const TArray&, Bytes); 10 | 11 | UCLASS(ClassGroup = "Networking", meta = (BlueprintSpawnableComponent)) 12 | class UDPWRAPPER_API UUDPComponent : public UActorComponent 13 | { 14 | GENERATED_UCLASS_BODY() 15 | public: 16 | UPROPERTY(BlueprintAssignable, Category = "UDP Events") 17 | FUDPMessageSignature OnReceivedBytes; 18 | 19 | UPROPERTY(BlueprintAssignable, Category = "UDP Events") 20 | FUDPEventSignature OnReceiveSocketStartedListening; 21 | 22 | UPROPERTY(BlueprintAssignable, Category = "UDP Events") 23 | FUDPEventSignature OnReceiveSocketStoppedListening; 24 | 25 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "UDP Connection Properties") 26 | FString SendIP; 27 | 28 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "UDP Connection Properties") 29 | int32 SendPort; 30 | 31 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "UDP Connection Properties") 32 | int32 ReceivePort; 33 | 34 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "UDP Connection Properties") 35 | FString SendSocketName; 36 | 37 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "UDP Connection Properties") 38 | FString ReceiveSocketName; 39 | 40 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "UDP Connection Properties") 41 | int32 BufferSize; 42 | 43 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "UDP Connection Properties") 44 | bool bShouldAutoConnect; 45 | 46 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "UDP Connection Properties") 47 | bool bShouldAutoListen; 48 | 49 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "UDP Connection Properties") 50 | bool bReceiveDataOnGameThread; 51 | 52 | UPROPERTY(BlueprintReadOnly, Category = "UDP Connection Properties") 53 | bool bIsConnected; 54 | 55 | UFUNCTION(BlueprintCallable, Category = "UDP Functions") 56 | FString StringFromBinaryArray(const TArray& BinaryArray); 57 | 58 | UFUNCTION(BlueprintCallable, Category = "UDP Functions") 59 | void ConnectToSendSocket(const FString& InIP = TEXT("127.0.0.1"), const int32 InPort = 3000); 60 | 61 | UFUNCTION(BlueprintCallable, Category = "UDP Functions") 62 | void CloseSendSocket(); 63 | 64 | UFUNCTION(BlueprintCallable, Category = "UDP Functions") 65 | void StartReceiveSocketListening(const int32 InListenPort = 3002); 66 | 67 | UFUNCTION(BlueprintCallable, Category = "UDP Functions") 68 | void CloseReceiveSocket(); 69 | 70 | UFUNCTION(BlueprintCallable, Category = "UDP Functions") 71 | void Emit(const TArray& Bytes); 72 | 73 | virtual void InitializeComponent() override; 74 | virtual void UninitializeComponent() override; 75 | virtual void BeginPlay() override; 76 | virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; 77 | 78 | protected: 79 | FSocket* SenderSocket; 80 | FSocket* ReceiverSocket; 81 | 82 | void OnDataReceivedDelegate(const FArrayReaderPtr& DataPtr, const FIPv4Endpoint& Endpoint); 83 | 84 | FUdpSocketReceiver* UDPReceiver; 85 | FString SocketDescription; 86 | TSharedPtr RemoteAdress; 87 | ISocketSubsystem* SocketSubsystem; 88 | }; -------------------------------------------------------------------------------- /FingerControlUE4/Plugins/UDPWrapper/Source/UDPWrapper/Public/UDPWrapper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "CoreMinimal.h" 4 | #include "ModuleManager.h" 5 | 6 | class FUDPWrapperModule : public IModuleInterface 7 | { 8 | public: 9 | 10 | /** IModuleInterface implementation */ 11 | virtual void StartupModule() override; 12 | virtual void ShutdownModule() override; 13 | }; -------------------------------------------------------------------------------- /FingerControlUE4/Plugins/UDPWrapper/Source/UDPWrapper/UDPWrapper.Build.cs: -------------------------------------------------------------------------------- 1 | using UnrealBuildTool; 2 | using System.IO; 3 | 4 | public class UDPWrapper : ModuleRules 5 | { 6 | public UDPWrapper(ReadOnlyTargetRules Target) : base(Target) 7 | { 8 | PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; 9 | 10 | PublicIncludePaths.AddRange( 11 | new string[] { 12 | Path.Combine(ModuleDirectory, "Public"), 13 | } 14 | ); 15 | 16 | 17 | PrivateIncludePaths.AddRange( 18 | new string[] { 19 | Path.Combine(ModuleDirectory, "Private"), 20 | } 21 | ); 22 | 23 | 24 | PublicDependencyModuleNames.AddRange( 25 | new string[] 26 | { 27 | "Core", 28 | "Sockets", 29 | "Networking" 30 | } 31 | ); 32 | 33 | 34 | PrivateDependencyModuleNames.AddRange( 35 | new string[] 36 | { 37 | "CoreUObject", 38 | "Engine", 39 | "Slate", 40 | "SlateCore" 41 | } 42 | ); 43 | 44 | 45 | DynamicallyLoadedModuleNames.AddRange( 46 | new string[] 47 | { 48 | } 49 | ); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /FingerControlUE4/Plugins/UDPWrapper/UDPWrapper.uplugin: -------------------------------------------------------------------------------- 1 | { 2 | "FileVersion": 3, 3 | "Version": 1, 4 | "VersionName": "0.4.0", 5 | "FriendlyName": "UDPWrapper", 6 | "Description": "Convenience UDP wrapper plugin.", 7 | "Category": "Networking", 8 | "CreatedBy": "getnamo", 9 | "CreatedByURL": "http://getnamo.com/", 10 | "DocsURL": "https://github.com/getnamo/udp-ue4", 11 | "MarketplaceURL": "", 12 | "SupportURL": "https://github.com/getnamo/udp-ue4/issues", 13 | "CanContainContent": true, 14 | "Installed": false, 15 | "Modules": [ 16 | { 17 | "Name": "UDPWrapper", 18 | "Type": "Runtime", 19 | "LoadingPhase": "Default" 20 | }, 21 | { 22 | "Name": "SIOJson", 23 | "Type": "Runtime", 24 | "LoadingPhase": "PreDefault" 25 | }, 26 | { 27 | "Name": "SIOJEditorPlugin", 28 | "Type": "Developer", 29 | "LoadingPhase": "Default" 30 | } 31 | ] 32 | } 33 | -------------------------------------------------------------------------------- /FingerControl_ESP32/DataUtils.ino: -------------------------------------------------------------------------------- 1 | String IPToString(IPAddress ip) 2 | { 3 | String str = ""; 4 | for (int i = 0; i < 4; i++) 5 | str += i ? "." + String(ip[i]) : String(ip[i]); 6 | return str; 7 | } 8 | -------------------------------------------------------------------------------- /FingerControl_ESP32/EEPROMUtils.ino: -------------------------------------------------------------------------------- 1 | #define EEPROM_SIZE 24 2 | 3 | String ReadStringEEPROM(char slot) 4 | { 5 | int i; 6 | char data[EEPROM_SIZE]; 7 | int length = 0; 8 | unsigned char k; 9 | k = EEPROM.read(EEPROM_SIZE * slot); 10 | while(k != '\0' && length < EEPROM_SIZE) 11 | { 12 | k = EEPROM.read(EEPROM_SIZE * slot + length); 13 | data[length] = k; 14 | length++; 15 | } 16 | data[length] = '\0'; 17 | return String(data); 18 | } 19 | 20 | bool CheckIsEmptyEEPROM(char slot) 21 | { 22 | bool isEmpty = true; 23 | for (int i = EEPROM_SIZE * slot; i < EEPROM_SIZE * slot + EEPROM_SIZE; i++) 24 | { 25 | unsigned char val = EEPROM.read(i); 26 | if (val != 255) 27 | { 28 | isEmpty = false; 29 | break; 30 | } 31 | } 32 | return isEmpty; 33 | } 34 | 35 | void WriteStringEEPROM(char slot, String data) 36 | { 37 | int dataLength = data.length(); 38 | for(int i = 0; i < dataLength; i++) 39 | EEPROM.write(EEPROM_SIZE * slot + i, data[i]); 40 | EEPROM.write(EEPROM_SIZE * slot + dataLength, '\0'); 41 | EEPROM.commit(); 42 | delay(50); 43 | } 44 | 45 | void EraseSlotEEPROM(char slot) 46 | { 47 | for (int i = EEPROM_SIZE * slot; i < EEPROM_SIZE * slot + EEPROM_SIZE; i++) 48 | EEPROM.write(EEPROM_SIZE * slot + i, 255); 49 | EEPROM.commit(); 50 | delay(50); 51 | } 52 | 53 | void EraseEEPROM() 54 | { 55 | for (int i = 0; i < 500; i++) 56 | EEPROM.write(i, 255); 57 | EEPROM.commit(); 58 | delay(50); 59 | } 60 | -------------------------------------------------------------------------------- /FingerControl_ESP32/FingerControl_ESP32.ino: -------------------------------------------------------------------------------- 1 | #include "EEPROM.h" 2 | #include 3 | #include "AsyncUDP.h" 4 | 5 | #define EEPROMUtils 6 | #define SettingsUtils 7 | #define SerialPortHelper 8 | #define WiFiHelper 9 | #define UDPClient 10 | #define ProtocolHelper 11 | #define DataUtils 12 | 13 | const int thumbPin = 34; //SVP 14 | const int indexPin = 33; //SVN 15 | const int middlePin = 35; 16 | const int ringPin = 39; 17 | const int pinkyPin = 36; 18 | 19 | void setup() 20 | { 21 | Serial.begin(115200); 22 | EEPROM.begin(500); 23 | 24 | InitSettings(); 25 | InitWiFi(); 26 | UDPConnect(); 27 | 28 | pinMode(thumbPin, INPUT); 29 | pinMode(indexPin, INPUT); 30 | pinMode(middlePin, INPUT); 31 | pinMode(ringPin, INPUT); 32 | pinMode(pinkyPin, INPUT); 33 | } 34 | 35 | void loop() 36 | { 37 | 38 | String sensorName = ReadStringEEPROM(2); 39 | int thumb = analogRead(thumbPin); 40 | int index = analogRead(indexPin); 41 | int middle = analogRead(middlePin); 42 | int ring = analogRead(ringPin); 43 | int pinky = analogRead(pinkyPin); 44 | String fingerDataJSONString = GetFingerDataJSONString(sensorName, thumb, index, middle, ring, pinky); 45 | UDPSendData(fingerDataJSONString); 46 | 47 | SerialPortReceive(); 48 | } 49 | -------------------------------------------------------------------------------- /FingerControl_ESP32/ProtocolHelper.ino: -------------------------------------------------------------------------------- 1 | #include "ArduinoJson.h" 2 | 3 | String GetStatusJSONString(int wifiStatus, String localIP) 4 | { 5 | StaticJsonDocument<1024> staticJsonDocument; 6 | staticJsonDocument["type"] = "getStatusResult"; 7 | staticJsonDocument["wifi_status"] = wifiStatus; 8 | staticJsonDocument["local_ip"] = localIP; 9 | 10 | char docBuf[1024]; 11 | serializeJson(staticJsonDocument, docBuf); 12 | 13 | return String(docBuf); 14 | } 15 | 16 | String GetFingerDataJSONString(String sensorName, int thumb, int index, int middle, int ring, int pinky) 17 | { 18 | StaticJsonDocument<1024> staticJsonDocument; 19 | staticJsonDocument["type"] = "fingerData"; 20 | staticJsonDocument["sensorName"] = sensorName; 21 | staticJsonDocument["Thumb"] = String(thumb); 22 | staticJsonDocument["Index"] = String(index); 23 | staticJsonDocument["Middle"] = String(middle); 24 | staticJsonDocument["Ring"] = String(ring); 25 | staticJsonDocument["Pinky"] = String(pinky); 26 | 27 | char docBuf[1024]; 28 | serializeJson(staticJsonDocument, docBuf); 29 | 30 | return String(docBuf); 31 | } 32 | -------------------------------------------------------------------------------- /FingerControl_ESP32/SerialPortHelper.ino: -------------------------------------------------------------------------------- 1 | void SerialPortReceive() 2 | { 3 | String receivedString; 4 | 5 | while(Serial.available()) 6 | { 7 | receivedString = Serial.readString(); 8 | } 9 | 10 | if (receivedString.length() > 0) 11 | { 12 | SerialPortParseReceived(receivedString); 13 | receivedString = ""; 14 | } 15 | } 16 | 17 | void SerialPortSend(String sendStr) 18 | { 19 | Serial.println(sendStr); 20 | } 21 | 22 | void SerialPortParseReceived(String receivedString) 23 | { 24 | char charBuf[1024]; 25 | receivedString.toCharArray(charBuf, 1024); 26 | StaticJsonDocument<1024> jsonDoc; 27 | DeserializationError error = deserializeJson(jsonDoc, charBuf); 28 | if (error) 29 | { 30 | Serial.print(receivedString); 31 | Serial.print(F("deserializeJson() failed: ")); 32 | Serial.println(error.c_str()); 33 | return; 34 | } 35 | 36 | const char * jsonType = jsonDoc["type"]; 37 | 38 | if (String(jsonType) == "loadSettings") 39 | { 40 | String loadSettingsJSONString = LoadSettingsJSONString(); 41 | Serial.println(loadSettingsJSONString); 42 | } 43 | 44 | if (String(jsonType) == "saveSettings") 45 | { 46 | const char * wifi_ssid = jsonDoc["wifi_ssid"]; 47 | const char * wifi_pass = jsonDoc["wifi_pass"]; 48 | const char * sensor_name = jsonDoc["sensor_name"]; 49 | const char * sensor_id = jsonDoc["sensor_id"]; 50 | const char * mocap_server = jsonDoc["mocap_server"]; 51 | const char * mocap_server_port = jsonDoc["mocap_server_port"]; 52 | 53 | String saveSettingsJSONStringResult = SaveSettingsFromJsonDocument(String(wifi_ssid), String(wifi_pass), String(sensor_name), String(mocap_server), String(mocap_server_port)); 54 | 55 | Serial.println(saveSettingsJSONStringResult); 56 | 57 | InitWiFi(); 58 | } 59 | 60 | if (String(jsonType) == "resetSettings") 61 | { 62 | String resetSettingsJSONStringResult = ResetSettingsJSONString(); 63 | Serial.println(resetSettingsJSONStringResult); 64 | 65 | InitWiFi(); 66 | } 67 | 68 | if (String(jsonType) == "getStatus") 69 | { 70 | int wifiStatus = WiFi.status() == WL_CONNECTED ? 1 : 0; 71 | String localIP = IPToString(WiFi.localIP()); 72 | 73 | String getStatusJSONStringResult = GetStatusJSONString(wifiStatus, localIP); 74 | Serial.println(getStatusJSONStringResult); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /FingerControl_ESP32/SettingsUtils.ino: -------------------------------------------------------------------------------- 1 | void InitSettings() 2 | { 3 | if (CheckIsEmptyEEPROM(0)) WriteStringEEPROM(0, "wifi_ssid"); 4 | if (CheckIsEmptyEEPROM(1)) WriteStringEEPROM(1, "wifi_pass"); 5 | if (CheckIsEmptyEEPROM(2)) WriteStringEEPROM(2, "GyroSensor00"); 6 | if (CheckIsEmptyEEPROM(3)) WriteStringEEPROM(3, "127.0.0.1"); 7 | if (CheckIsEmptyEEPROM(4)) WriteStringEEPROM(4, "7755"); 8 | } 9 | 10 | String ResetSettingsJSONString() 11 | { 12 | WriteStringEEPROM(0, "wifi_ssid"); 13 | WriteStringEEPROM(1, "wifi_pass"); 14 | WriteStringEEPROM(2, "GyroSensor00"); 15 | WriteStringEEPROM(3, "127.0.0.1"); 16 | WriteStringEEPROM(4, "7755"); 17 | 18 | delay(100); 19 | 20 | StaticJsonDocument<1024> staticJsonDocument; 21 | char docBuf[1024]; 22 | staticJsonDocument["type"] = "resetSettingsResult"; 23 | staticJsonDocument["error"] = 0; 24 | 25 | serializeJson(staticJsonDocument, docBuf); 26 | 27 | return String(docBuf); 28 | } 29 | 30 | String LoadSettingsJSONString() 31 | { 32 | StaticJsonDocument<1024> staticJsonDocument; 33 | staticJsonDocument["type"] = "loadSettingsResult"; 34 | staticJsonDocument["wifi_ssid"] = ReadStringEEPROM(0); 35 | staticJsonDocument["wifi_pass"] = ReadStringEEPROM(1); 36 | staticJsonDocument["sensor_name"] = ReadStringEEPROM(2); 37 | staticJsonDocument["mocap_server"] = ReadStringEEPROM(3); 38 | staticJsonDocument["mocap_server_port"] = ReadStringEEPROM(4); 39 | 40 | delay(100); 41 | 42 | char docBuf[1024]; 43 | serializeJson(staticJsonDocument, docBuf); 44 | 45 | return String(docBuf); 46 | } 47 | 48 | String SaveSettingsFromJsonDocument(String wifi_ssid, String wifi_pass, String sensor_name, String mocap_server, String mocap_server_port) 49 | { 50 | WriteStringEEPROM(0, wifi_ssid); 51 | WriteStringEEPROM(1, wifi_pass); 52 | WriteStringEEPROM(2, sensor_name); 53 | WriteStringEEPROM(3, mocap_server); 54 | WriteStringEEPROM(4, mocap_server_port); 55 | 56 | delay(100); 57 | 58 | StaticJsonDocument<1024> staticJsonDocument; 59 | char docBuf[1024]; 60 | staticJsonDocument["type"] = "saveSettingsResult"; 61 | staticJsonDocument["error"] = 0; 62 | 63 | serializeJson(staticJsonDocument, docBuf); 64 | 65 | return String(docBuf); 66 | } 67 | -------------------------------------------------------------------------------- /FingerControl_ESP32/UDPClient.ino: -------------------------------------------------------------------------------- 1 | AsyncUDP udpClient; 2 | 3 | void UDPConnect() 4 | { 5 | String mocapServer = ReadStringEEPROM(3); 6 | String mocapServerPort = ReadStringEEPROM(4); 7 | 8 | IPAddress ipAddress = IPAddress(); 9 | ipAddress.fromString(mocapServer); 10 | 11 | int port = mocapServerPort.toInt(); 12 | 13 | udpClient.connect(ipAddress, port); 14 | } 15 | 16 | void UDPSendData(String message) 17 | { 18 | String mocapServerPort = ReadStringEEPROM(4); 19 | int port = mocapServerPort.toInt(); 20 | 21 | char charBuffer[1024]; 22 | message.toCharArray(charBuffer, 1024); 23 | 24 | if (udpClient.connected()) 25 | udpClient.broadcastTo(charBuffer, port); 26 | else 27 | UDPConnect(); 28 | } 29 | -------------------------------------------------------------------------------- /FingerControl_ESP32/WiFiHelper.ino: -------------------------------------------------------------------------------- 1 | void InitWiFi() 2 | { 3 | String ssidStr = ReadStringEEPROM(0); 4 | const char *ssid = ssidStr.c_str(); 5 | String passStr = ReadStringEEPROM(1); 6 | const char *pass = passStr.c_str(); 7 | 8 | WiFi.begin(ssid, pass); 9 | 10 | for(int i = 0; i < 5; i++) 11 | { 12 | if (WiFi.status() == WL_CONNECTED) 13 | break; 14 | delay(1000); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Fingers control with ESP32 and flexible sensor in Unreal Engine 2 | 3 | https://youtu.be/rlmHPGfcShs 4 | 5 | ![alt text](https://github.com/pgii/FingerControlUE4/blob/master/Screenshots/Screenshot01.jpg) 6 | 7 | ![alt text](https://github.com/pgii/FingerControlUE4/blob/master/Screenshots/Screenshot02.jpg) 8 | -------------------------------------------------------------------------------- /Screenshots/Screenshot01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pgii/FingerControlUE4/688e42dc5027c285f46e3050d6115d7dfc9711ac/Screenshots/Screenshot01.jpg -------------------------------------------------------------------------------- /Screenshots/Screenshot02.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pgii/FingerControlUE4/688e42dc5027c285f46e3050d6115d7dfc9711ac/Screenshots/Screenshot02.jpg --------------------------------------------------------------------------------