diff --git a/Cog.uproject b/Cog.uproject index b370cd6..e23d463 100644 --- a/Cog.uproject +++ b/Cog.uproject @@ -1,6 +1,6 @@ { "FileVersion": 3, - "EngineAssociation": "5.3", + "EngineAssociation": "5.5", "Category": "", "Description": "", "Modules": [ @@ -21,6 +21,10 @@ "TargetAllowList": [ "Editor" ] + }, + { + "Name": "AssetSearch", + "Enabled": true } ] } \ No newline at end of file diff --git a/Config/DefaultEditor.ini b/Config/DefaultEditor.ini index 197e527..27fa7c3 100644 --- a/Config/DefaultEditor.ini +++ b/Config/DefaultEditor.ini @@ -8,4 +8,6 @@ bDontLoadBlueprintOutsideEditor= true bBlueprintIsNotBlueprintType= true [/Script/AdvancedPreviewScene.SharedProfiles] ++Profiles=(ProfileName="Epic Headquarters",bSharedProfile=True,bIsEngineDefaultProfile=True,bUseSkyLighting=True,DirectionalLightIntensity=1.000000,DirectionalLightColor=(R=1.000000,G=1.000000,B=1.000000,A=1.000000),SkyLightIntensity=1.000000,bRotateLightingRig=False,bShowEnvironment=True,bShowFloor=True,bShowGrid=False,EnvironmentColor=(R=0.200000,G=0.200000,B=0.200000,A=1.000000),EnvironmentIntensity=1.000000,EnvironmentCubeMapPath="/Engine/EditorMaterials/AssetViewer/EpicQuadPanorama_CC+EV1.EpicQuadPanorama_CC+EV1",bPostProcessingEnabled=True,PostProcessingSettings=(bOverride_TemperatureType=False,bOverride_WhiteTemp=False,bOverride_WhiteTint=False,bOverride_ColorSaturation=False,bOverride_ColorContrast=False,bOverride_ColorGamma=False,bOverride_ColorGain=False,bOverride_ColorOffset=False,bOverride_ColorSaturationShadows=False,bOverride_ColorContrastShadows=False,bOverride_ColorGammaShadows=False,bOverride_ColorGainShadows=False,bOverride_ColorOffsetShadows=False,bOverride_ColorSaturationMidtones=False,bOverride_ColorContrastMidtones=False,bOverride_ColorGammaMidtones=False,bOverride_ColorGainMidtones=False,bOverride_ColorOffsetMidtones=False,bOverride_ColorSaturationHighlights=False,bOverride_ColorContrastHighlights=False,bOverride_ColorGammaHighlights=False,bOverride_ColorGainHighlights=False,bOverride_ColorOffsetHighlights=False,bOverride_ColorCorrectionShadowsMax=False,bOverride_ColorCorrectionHighlightsMin=False,bOverride_ColorCorrectionHighlightsMax=False,bOverride_BlueCorrection=False,bOverride_ExpandGamut=False,bOverride_ToneCurveAmount=False,bOverride_FilmSlope=False,bOverride_FilmToe=False,bOverride_FilmShoulder=False,bOverride_FilmBlackClip=False,bOverride_FilmWhiteClip=False,bOverride_SceneColorTint=False,bOverride_SceneFringeIntensity=False,bOverride_ChromaticAberrationStartOffset=False,bOverride_bMegaLights=False,bOverride_AmbientCubemapTint=False,bOverride_AmbientCubemapIntensity=False,bOverride_BloomMethod=False,bOverride_BloomIntensity=False,bOverride_BloomThreshold=False,bOverride_Bloom1Tint=False,bOverride_Bloom1Size=False,bOverride_Bloom2Size=False,bOverride_Bloom2Tint=False,bOverride_Bloom3Tint=False,bOverride_Bloom3Size=False,bOverride_Bloom4Tint=False,bOverride_Bloom4Size=False,bOverride_Bloom5Tint=False,bOverride_Bloom5Size=False,bOverride_Bloom6Tint=False,bOverride_Bloom6Size=False,bOverride_BloomSizeScale=False,bOverride_BloomConvolutionTexture=False,bOverride_BloomConvolutionScatterDispersion=False,bOverride_BloomConvolutionSize=False,bOverride_BloomConvolutionCenterUV=False,bOverride_BloomConvolutionPreFilterMin=False,bOverride_BloomConvolutionPreFilterMax=False,bOverride_BloomConvolutionPreFilterMult=False,bOverride_BloomConvolutionBufferScale=False,bOverride_BloomDirtMaskIntensity=False,bOverride_BloomDirtMaskTint=False,bOverride_BloomDirtMask=False,bOverride_CameraShutterSpeed=False,bOverride_CameraISO=False,bOverride_AutoExposureMethod=False,bOverride_AutoExposureLowPercent=False,bOverride_AutoExposureHighPercent=False,bOverride_AutoExposureMinBrightness=False,bOverride_AutoExposureMaxBrightness=False,bOverride_AutoExposureSpeedUp=False,bOverride_AutoExposureSpeedDown=False,bOverride_AutoExposureBias=False,bOverride_AutoExposureBiasCurve=False,bOverride_AutoExposureMeterMask=False,bOverride_AutoExposureApplyPhysicalCameraExposure=False,bOverride_HistogramLogMin=False,bOverride_HistogramLogMax=False,bOverride_LocalExposureMethod=False,bOverride_LocalExposureHighlightContrastScale=False,bOverride_LocalExposureShadowContrastScale=False,bOverride_LocalExposureHighlightContrastCurve=False,bOverride_LocalExposureShadowContrastCurve=False,bOverride_LocalExposureHighlightThreshold=False,bOverride_LocalExposureShadowThreshold=False,bOverride_LocalExposureDetailStrength=False,bOverride_LocalExposureBlurredLuminanceBlend=False,bOverride_LocalExposureBlurredLuminanceKernelSizePercent=False,bOverride_LocalExposureMiddleGreyBias=False,bOverride_LensFlareIntensity=False,bOverride_LensFlareTint=False,bOverride_LensFlareTints=False,bOverride_LensFlareBokehSize=False,bOverride_LensFlareBokehShape=False,bOverride_LensFlareThreshold=False,bOverride_VignetteIntensity=False,bOverride_Sharpen=False,bOverride_FilmGrainIntensity=False,bOverride_FilmGrainIntensityShadows=False,bOverride_FilmGrainIntensityMidtones=False,bOverride_FilmGrainIntensityHighlights=False,bOverride_FilmGrainShadowsMax=False,bOverride_FilmGrainHighlightsMin=False,bOverride_FilmGrainHighlightsMax=False,bOverride_FilmGrainTexelSize=False,bOverride_FilmGrainTexture=False,bOverride_AmbientOcclusionIntensity=False,bOverride_AmbientOcclusionStaticFraction=False,bOverride_AmbientOcclusionRadius=False,bOverride_AmbientOcclusionFadeDistance=False,bOverride_AmbientOcclusionFadeRadius=False,bOverride_AmbientOcclusionRadiusInWS=False,bOverride_AmbientOcclusionPower=False,bOverride_AmbientOcclusionBias=False,bOverride_AmbientOcclusionQuality=False,bOverride_AmbientOcclusionMipBlend=False,bOverride_AmbientOcclusionMipScale=False,bOverride_AmbientOcclusionMipThreshold=False,bOverride_AmbientOcclusionTemporalBlendWeight=False,bOverride_RayTracingAO=False,bOverride_RayTracingAOSamplesPerPixel=False,bOverride_RayTracingAOIntensity=False,bOverride_RayTracingAORadius=False,bOverride_IndirectLightingColor=False,bOverride_IndirectLightingIntensity=False,bOverride_ColorGradingIntensity=False,bOverride_ColorGradingLUT=False,bOverride_DepthOfFieldFocalDistance=False,bOverride_DepthOfFieldFstop=False,bOverride_DepthOfFieldMinFstop=False,bOverride_DepthOfFieldBladeCount=False,bOverride_DepthOfFieldSensorWidth=False,bOverride_DepthOfFieldSqueezeFactor=False,bOverride_DepthOfFieldDepthBlurRadius=False,bOverride_DepthOfFieldUseHairDepth=False,bOverride_DepthOfFieldDepthBlurAmount=False,bOverride_DepthOfFieldFocalRegion=False,bOverride_DepthOfFieldNearTransitionRegion=False,bOverride_DepthOfFieldFarTransitionRegion=False,bOverride_DepthOfFieldScale=False,bOverride_DepthOfFieldNearBlurSize=False,bOverride_DepthOfFieldFarBlurSize=False,bOverride_MobileHQGaussian=False,bOverride_DepthOfFieldOcclusion=False,bOverride_DepthOfFieldSkyFocusDistance=False,bOverride_DepthOfFieldVignetteSize=False,bOverride_MotionBlurAmount=False,bOverride_MotionBlurMax=False,bOverride_MotionBlurTargetFPS=False,bOverride_MotionBlurPerObjectSize=False,bOverride_ReflectionMethod=False,bOverride_LumenReflectionQuality=False,bOverride_ScreenSpaceReflectionIntensity=False,bOverride_ScreenSpaceReflectionQuality=False,bOverride_ScreenSpaceReflectionMaxRoughness=False,bOverride_ScreenSpaceReflectionRoughnessScale=False,bOverride_UserFlags=False,bOverride_RayTracingReflectionsMaxRoughness=False,bOverride_RayTracingReflectionsMaxBounces=False,bOverride_RayTracingReflectionsSamplesPerPixel=False,bOverride_RayTracingReflectionsShadows=False,bOverride_RayTracingReflectionsTranslucency=False,bOverride_TranslucencyType=False,bOverride_RayTracingTranslucencyMaxRoughness=False,bOverride_RayTracingTranslucencyRefractionRays=False,bOverride_RayTracingTranslucencySamplesPerPixel=False,bOverride_RayTracingTranslucencyShadows=False,bOverride_RayTracingTranslucencyRefraction=False,bOverride_DynamicGlobalIlluminationMethod=False,bOverride_LumenSceneLightingQuality=False,bOverride_LumenSceneDetail=False,bOverride_LumenSceneViewDistance=False,bOverride_LumenSceneLightingUpdateSpeed=False,bOverride_LumenFinalGatherQuality=False,bOverride_LumenFinalGatherLightingUpdateSpeed=False,bOverride_LumenFinalGatherScreenTraces=False,bOverride_LumenMaxTraceDistance=False,bOverride_LumenDiffuseColorBoost=False,bOverride_LumenSkylightLeaking=False,bOverride_LumenFullSkylightLeakingDistance=False,bOverride_LumenRayLightingMode=False,bOverride_LumenReflectionsScreenTraces=False,bOverride_LumenFrontLayerTranslucencyReflections=False,bOverride_LumenMaxRoughnessToTraceReflections=False,bOverride_LumenMaxReflectionBounces=False,bOverride_LumenMaxRefractionBounces=False,bOverride_LumenSurfaceCacheResolution=False,bOverride_RayTracingGI=False,bOverride_RayTracingGIMaxBounces=False,bOverride_RayTracingGISamplesPerPixel=False,bOverride_PathTracingMaxBounces=False,bOverride_PathTracingSamplesPerPixel=False,bOverride_PathTracingMaxPathIntensity=False,bOverride_PathTracingEnableEmissiveMaterials=False,bOverride_PathTracingEnableReferenceDOF=False,bOverride_PathTracingEnableReferenceAtmosphere=False,bOverride_PathTracingEnableDenoiser=False,bOverride_PathTracingIncludeEmissive=False,bOverride_PathTracingIncludeDiffuse=False,bOverride_PathTracingIncludeIndirectDiffuse=False,bOverride_PathTracingIncludeSpecular=False,bOverride_PathTracingIncludeIndirectSpecular=False,bOverride_PathTracingIncludeVolume=False,bOverride_PathTracingIncludeIndirectVolume=False,bMobileHQGaussian=False,BloomMethod=BM_SOG,AutoExposureMethod=AEM_Histogram,TemperatureType=TEMP_WhiteBalance,WhiteTemp=6500.000000,WhiteTint=0.000000,ColorSaturation=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorContrast=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorGamma=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorGain=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorOffset=(X=0.000000,Y=0.000000,Z=0.000000,W=0.000000),ColorSaturationShadows=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorContrastShadows=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorGammaShadows=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorGainShadows=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorOffsetShadows=(X=0.000000,Y=0.000000,Z=0.000000,W=0.000000),ColorSaturationMidtones=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorContrastMidtones=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorGammaMidtones=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorGainMidtones=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorOffsetMidtones=(X=0.000000,Y=0.000000,Z=0.000000,W=0.000000),ColorSaturationHighlights=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorContrastHighlights=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorGammaHighlights=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorGainHighlights=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorOffsetHighlights=(X=0.000000,Y=0.000000,Z=0.000000,W=0.000000),ColorCorrectionHighlightsMin=0.500000,ColorCorrectionHighlightsMax=1.000000,ColorCorrectionShadowsMax=0.090000,BlueCorrection=0.600000,ExpandGamut=1.000000,ToneCurveAmount=1.000000,FilmSlope=0.880000,FilmToe=0.550000,FilmShoulder=0.260000,FilmBlackClip=0.000000,FilmWhiteClip=0.040000,SceneColorTint=(R=1.000000,G=1.000000,B=1.000000,A=1.000000),SceneFringeIntensity=0.000000,ChromaticAberrationStartOffset=0.000000,BloomIntensity=0.675000,BloomThreshold=-1.000000,BloomSizeScale=4.000000,Bloom1Size=0.300000,Bloom2Size=1.000000,Bloom3Size=2.000000,Bloom4Size=10.000000,Bloom5Size=30.000000,Bloom6Size=64.000000,Bloom1Tint=(R=0.346500,G=0.346500,B=0.346500,A=1.000000),Bloom2Tint=(R=0.138000,G=0.138000,B=0.138000,A=1.000000),Bloom3Tint=(R=0.117600,G=0.117600,B=0.117600,A=1.000000),Bloom4Tint=(R=0.066000,G=0.066000,B=0.066000,A=1.000000),Bloom5Tint=(R=0.066000,G=0.066000,B=0.066000,A=1.000000),Bloom6Tint=(R=0.061000,G=0.061000,B=0.061000,A=1.000000),BloomConvolutionScatterDispersion=1.000000,BloomConvolutionSize=1.000000,BloomConvolutionTexture=None,BloomConvolutionCenterUV=(X=0.500000,Y=0.500000),BloomConvolutionPreFilterMin=7.000000,BloomConvolutionPreFilterMax=15000.000000,BloomConvolutionPreFilterMult=15.000000,BloomConvolutionBufferScale=0.133000,BloomDirtMask=None,BloomDirtMaskIntensity=0.000000,BloomDirtMaskTint=(R=0.500000,G=0.500000,B=0.500000,A=1.000000),DynamicGlobalIlluminationMethod=Lumen,IndirectLightingColor=(R=1.000000,G=1.000000,B=1.000000,A=1.000000),IndirectLightingIntensity=1.000000,LumenRayLightingMode=Default,LumenSceneLightingQuality=1.000000,LumenSceneDetail=1.000000,LumenSceneViewDistance=20000.000000,LumenSceneLightingUpdateSpeed=1.000000,LumenFinalGatherQuality=1.000000,LumenFinalGatherLightingUpdateSpeed=1.000000,LumenFinalGatherScreenTraces=True,LumenMaxTraceDistance=20000.000000,LumenDiffuseColorBoost=1.000000,LumenSkylightLeaking=0.000000,LumenFullSkylightLeakingDistance=1000.000000,LumenSurfaceCacheResolution=1.000000,ReflectionMethod=Lumen,LumenReflectionQuality=1.000000,LumenReflectionsScreenTraces=True,LumenFrontLayerTranslucencyReflections=False,LumenMaxRoughnessToTraceReflections=0.400000,LumenMaxReflectionBounces=1,LumenMaxRefractionBounces=0,ScreenSpaceReflectionIntensity=100.000000,ScreenSpaceReflectionQuality=50.000000,ScreenSpaceReflectionMaxRoughness=0.600000,bMegaLights=True,AmbientCubemapTint=(R=1.000000,G=1.000000,B=1.000000,A=1.000000),AmbientCubemapIntensity=1.000000,AmbientCubemap=None,CameraShutterSpeed=60.000000,CameraISO=100.000000,DepthOfFieldFstop=4.000000,DepthOfFieldMinFstop=1.200000,DepthOfFieldBladeCount=5,AutoExposureBias=1.000000,AutoExposureBiasBackup=0.000000,bOverride_AutoExposureBiasBackup=False,AutoExposureApplyPhysicalCameraExposure=True,AutoExposureBiasCurve=None,AutoExposureMeterMask=None,AutoExposureLowPercent=10.000000,AutoExposureHighPercent=90.000000,AutoExposureMinBrightness=-10.000000,AutoExposureMaxBrightness=20.000000,AutoExposureSpeedUp=3.000000,AutoExposureSpeedDown=1.000000,HistogramLogMin=-10.000000,HistogramLogMax=20.000000,LocalExposureMethod=Bilateral,LocalExposureHighlightContrastScale=1.000000,LocalExposureShadowContrastScale=1.000000,LocalExposureHighlightContrastCurve=None,LocalExposureShadowContrastCurve=None,LocalExposureHighlightThreshold=0.000000,LocalExposureShadowThreshold=0.000000,LocalExposureDetailStrength=1.000000,LocalExposureBlurredLuminanceBlend=0.600000,LocalExposureBlurredLuminanceKernelSizePercent=50.000000,LocalExposureMiddleGreyBias=0.000000,LensFlareIntensity=1.000000,LensFlareTint=(R=1.000000,G=1.000000,B=1.000000,A=1.000000),LensFlareBokehSize=3.000000,LensFlareThreshold=8.000000,LensFlareBokehShape=None,LensFlareTints[0]=(R=1.000000,G=0.800000,B=0.400000,A=0.600000),LensFlareTints[1]=(R=1.000000,G=1.000000,B=0.600000,A=0.530000),LensFlareTints[2]=(R=0.800000,G=0.800000,B=1.000000,A=0.460000),LensFlareTints[3]=(R=0.500000,G=1.000000,B=0.400000,A=0.390000),LensFlareTints[4]=(R=0.500000,G=0.800000,B=1.000000,A=0.310000),LensFlareTints[5]=(R=0.900000,G=1.000000,B=0.800000,A=0.270000),LensFlareTints[6]=(R=1.000000,G=0.800000,B=0.400000,A=0.220000),LensFlareTints[7]=(R=0.900000,G=0.700000,B=0.700000,A=0.150000),VignetteIntensity=0.400000,Sharpen=0.000000,FilmGrainIntensity=0.000000,FilmGrainIntensityShadows=1.000000,FilmGrainIntensityMidtones=1.000000,FilmGrainIntensityHighlights=1.000000,FilmGrainShadowsMax=0.090000,FilmGrainHighlightsMin=0.500000,FilmGrainHighlightsMax=1.000000,FilmGrainTexelSize=1.000000,FilmGrainTexture=None,AmbientOcclusionIntensity=0.500000,AmbientOcclusionStaticFraction=1.000000,AmbientOcclusionRadius=200.000000,AmbientOcclusionRadiusInWS=False,AmbientOcclusionFadeDistance=8000.000000,AmbientOcclusionFadeRadius=5000.000000,AmbientOcclusionPower=2.000000,AmbientOcclusionBias=3.000000,AmbientOcclusionQuality=50.000000,AmbientOcclusionMipBlend=0.600000,AmbientOcclusionMipScale=1.700000,AmbientOcclusionMipThreshold=0.010000,AmbientOcclusionTemporalBlendWeight=0.100000,RayTracingAO=False,RayTracingAOSamplesPerPixel=1,RayTracingAOIntensity=1.000000,RayTracingAORadius=200.000000,ColorGradingIntensity=1.000000,ColorGradingLUT=None,DepthOfFieldSensorWidth=24.576000,DepthOfFieldSqueezeFactor=1.000000,DepthOfFieldFocalDistance=0.000000,DepthOfFieldDepthBlurAmount=1.000000,DepthOfFieldDepthBlurRadius=0.000000,DepthOfFieldUseHairDepth=False,DepthOfFieldFocalRegion=0.000000,DepthOfFieldNearTransitionRegion=300.000000,DepthOfFieldFarTransitionRegion=500.000000,DepthOfFieldScale=0.000000,DepthOfFieldNearBlurSize=15.000000,DepthOfFieldFarBlurSize=15.000000,DepthOfFieldOcclusion=0.400000,DepthOfFieldSkyFocusDistance=0.000000,DepthOfFieldVignetteSize=200.000000,MotionBlurAmount=0.500000,MotionBlurMax=5.000000,MotionBlurTargetFPS=30,MotionBlurPerObjectSize=0.000000,TranslucencyType=Raster,RayTracingTranslucencyMaxRoughness=0.600000,RayTracingTranslucencyRefractionRays=3,RayTracingTranslucencySamplesPerPixel=1,RayTracingTranslucencyShadows=Hard_shadows,RayTracingTranslucencyRefraction=True,PathTracingMaxBounces=32,PathTracingSamplesPerPixel=2048,PathTracingMaxPathIntensity=24.000000,PathTracingEnableEmissiveMaterials=True,PathTracingEnableReferenceDOF=False,PathTracingEnableReferenceAtmosphere=False,PathTracingEnableDenoiser=True,PathTracingIncludeEmissive=True,PathTracingIncludeDiffuse=True,PathTracingIncludeIndirectDiffuse=True,PathTracingIncludeSpecular=True,PathTracingIncludeIndirectSpecular=True,PathTracingIncludeVolume=True,PathTracingIncludeIndirectVolume=True,UserFlags=0,WeightedBlendables=(Array=)),LightingRigRotation=0.000000,RotationSpeed=2.000000,DirectionalLightRotation=(Pitch=-40.000000,Yaw=-67.500000,Roll=0.000000),bEnableToneMapping=True,bShowMeshEdges=False) ++Profiles=(ProfileName="Grey Wireframe",bSharedProfile=True,bIsEngineDefaultProfile=True,bUseSkyLighting=True,DirectionalLightIntensity=1.000000,DirectionalLightColor=(R=1.000000,G=1.000000,B=1.000000,A=1.000000),SkyLightIntensity=1.000000,bRotateLightingRig=False,bShowEnvironment=False,bShowFloor=False,bShowGrid=True,EnvironmentColor=(R=0.039216,G=0.039216,B=0.039216,A=1.000000),EnvironmentIntensity=1.000000,EnvironmentCubeMapPath="/Engine/EditorMaterials/AssetViewer/EpicQuadPanorama_CC+EV1.EpicQuadPanorama_CC+EV1",bPostProcessingEnabled=False,PostProcessingSettings=(bOverride_TemperatureType=False,bOverride_WhiteTemp=False,bOverride_WhiteTint=False,bOverride_ColorSaturation=False,bOverride_ColorContrast=False,bOverride_ColorGamma=False,bOverride_ColorGain=False,bOverride_ColorOffset=False,bOverride_ColorSaturationShadows=False,bOverride_ColorContrastShadows=False,bOverride_ColorGammaShadows=False,bOverride_ColorGainShadows=False,bOverride_ColorOffsetShadows=False,bOverride_ColorSaturationMidtones=False,bOverride_ColorContrastMidtones=False,bOverride_ColorGammaMidtones=False,bOverride_ColorGainMidtones=False,bOverride_ColorOffsetMidtones=False,bOverride_ColorSaturationHighlights=False,bOverride_ColorContrastHighlights=False,bOverride_ColorGammaHighlights=False,bOverride_ColorGainHighlights=False,bOverride_ColorOffsetHighlights=False,bOverride_ColorCorrectionShadowsMax=False,bOverride_ColorCorrectionHighlightsMin=False,bOverride_ColorCorrectionHighlightsMax=False,bOverride_BlueCorrection=False,bOverride_ExpandGamut=False,bOverride_ToneCurveAmount=False,bOverride_FilmSlope=False,bOverride_FilmToe=False,bOverride_FilmShoulder=False,bOverride_FilmBlackClip=False,bOverride_FilmWhiteClip=False,bOverride_SceneColorTint=False,bOverride_SceneFringeIntensity=False,bOverride_ChromaticAberrationStartOffset=False,bOverride_bMegaLights=False,bOverride_AmbientCubemapTint=False,bOverride_AmbientCubemapIntensity=False,bOverride_BloomMethod=False,bOverride_BloomIntensity=False,bOverride_BloomThreshold=False,bOverride_Bloom1Tint=False,bOverride_Bloom1Size=False,bOverride_Bloom2Size=False,bOverride_Bloom2Tint=False,bOverride_Bloom3Tint=False,bOverride_Bloom3Size=False,bOverride_Bloom4Tint=False,bOverride_Bloom4Size=False,bOverride_Bloom5Tint=False,bOverride_Bloom5Size=False,bOverride_Bloom6Tint=False,bOverride_Bloom6Size=False,bOverride_BloomSizeScale=False,bOverride_BloomConvolutionTexture=False,bOverride_BloomConvolutionScatterDispersion=False,bOverride_BloomConvolutionSize=False,bOverride_BloomConvolutionCenterUV=False,bOverride_BloomConvolutionPreFilterMin=False,bOverride_BloomConvolutionPreFilterMax=False,bOverride_BloomConvolutionPreFilterMult=False,bOverride_BloomConvolutionBufferScale=False,bOverride_BloomDirtMaskIntensity=False,bOverride_BloomDirtMaskTint=False,bOverride_BloomDirtMask=False,bOverride_CameraShutterSpeed=False,bOverride_CameraISO=False,bOverride_AutoExposureMethod=False,bOverride_AutoExposureLowPercent=False,bOverride_AutoExposureHighPercent=False,bOverride_AutoExposureMinBrightness=False,bOverride_AutoExposureMaxBrightness=False,bOverride_AutoExposureSpeedUp=False,bOverride_AutoExposureSpeedDown=False,bOverride_AutoExposureBias=False,bOverride_AutoExposureBiasCurve=False,bOverride_AutoExposureMeterMask=False,bOverride_AutoExposureApplyPhysicalCameraExposure=False,bOverride_HistogramLogMin=False,bOverride_HistogramLogMax=False,bOverride_LocalExposureMethod=False,bOverride_LocalExposureHighlightContrastScale=False,bOverride_LocalExposureShadowContrastScale=False,bOverride_LocalExposureHighlightContrastCurve=False,bOverride_LocalExposureShadowContrastCurve=False,bOverride_LocalExposureHighlightThreshold=False,bOverride_LocalExposureShadowThreshold=False,bOverride_LocalExposureDetailStrength=False,bOverride_LocalExposureBlurredLuminanceBlend=False,bOverride_LocalExposureBlurredLuminanceKernelSizePercent=False,bOverride_LocalExposureMiddleGreyBias=False,bOverride_LensFlareIntensity=False,bOverride_LensFlareTint=False,bOverride_LensFlareTints=False,bOverride_LensFlareBokehSize=False,bOverride_LensFlareBokehShape=False,bOverride_LensFlareThreshold=False,bOverride_VignetteIntensity=False,bOverride_Sharpen=False,bOverride_FilmGrainIntensity=False,bOverride_FilmGrainIntensityShadows=False,bOverride_FilmGrainIntensityMidtones=False,bOverride_FilmGrainIntensityHighlights=False,bOverride_FilmGrainShadowsMax=False,bOverride_FilmGrainHighlightsMin=False,bOverride_FilmGrainHighlightsMax=False,bOverride_FilmGrainTexelSize=False,bOverride_FilmGrainTexture=False,bOverride_AmbientOcclusionIntensity=False,bOverride_AmbientOcclusionStaticFraction=False,bOverride_AmbientOcclusionRadius=False,bOverride_AmbientOcclusionFadeDistance=False,bOverride_AmbientOcclusionFadeRadius=False,bOverride_AmbientOcclusionRadiusInWS=False,bOverride_AmbientOcclusionPower=False,bOverride_AmbientOcclusionBias=False,bOverride_AmbientOcclusionQuality=False,bOverride_AmbientOcclusionMipBlend=False,bOverride_AmbientOcclusionMipScale=False,bOverride_AmbientOcclusionMipThreshold=False,bOverride_AmbientOcclusionTemporalBlendWeight=False,bOverride_RayTracingAO=False,bOverride_RayTracingAOSamplesPerPixel=False,bOverride_RayTracingAOIntensity=False,bOverride_RayTracingAORadius=False,bOverride_IndirectLightingColor=False,bOverride_IndirectLightingIntensity=False,bOverride_ColorGradingIntensity=False,bOverride_ColorGradingLUT=False,bOverride_DepthOfFieldFocalDistance=False,bOverride_DepthOfFieldFstop=False,bOverride_DepthOfFieldMinFstop=False,bOverride_DepthOfFieldBladeCount=False,bOverride_DepthOfFieldSensorWidth=False,bOverride_DepthOfFieldSqueezeFactor=False,bOverride_DepthOfFieldDepthBlurRadius=False,bOverride_DepthOfFieldUseHairDepth=False,bOverride_DepthOfFieldDepthBlurAmount=False,bOverride_DepthOfFieldFocalRegion=False,bOverride_DepthOfFieldNearTransitionRegion=False,bOverride_DepthOfFieldFarTransitionRegion=False,bOverride_DepthOfFieldScale=False,bOverride_DepthOfFieldNearBlurSize=False,bOverride_DepthOfFieldFarBlurSize=False,bOverride_MobileHQGaussian=False,bOverride_DepthOfFieldOcclusion=False,bOverride_DepthOfFieldSkyFocusDistance=False,bOverride_DepthOfFieldVignetteSize=False,bOverride_MotionBlurAmount=False,bOverride_MotionBlurMax=False,bOverride_MotionBlurTargetFPS=False,bOverride_MotionBlurPerObjectSize=False,bOverride_ReflectionMethod=False,bOverride_LumenReflectionQuality=False,bOverride_ScreenSpaceReflectionIntensity=False,bOverride_ScreenSpaceReflectionQuality=False,bOverride_ScreenSpaceReflectionMaxRoughness=False,bOverride_ScreenSpaceReflectionRoughnessScale=False,bOverride_UserFlags=False,bOverride_RayTracingReflectionsMaxRoughness=False,bOverride_RayTracingReflectionsMaxBounces=False,bOverride_RayTracingReflectionsSamplesPerPixel=False,bOverride_RayTracingReflectionsShadows=False,bOverride_RayTracingReflectionsTranslucency=False,bOverride_TranslucencyType=False,bOverride_RayTracingTranslucencyMaxRoughness=False,bOverride_RayTracingTranslucencyRefractionRays=False,bOverride_RayTracingTranslucencySamplesPerPixel=False,bOverride_RayTracingTranslucencyShadows=False,bOverride_RayTracingTranslucencyRefraction=False,bOverride_DynamicGlobalIlluminationMethod=False,bOverride_LumenSceneLightingQuality=False,bOverride_LumenSceneDetail=False,bOverride_LumenSceneViewDistance=False,bOverride_LumenSceneLightingUpdateSpeed=False,bOverride_LumenFinalGatherQuality=False,bOverride_LumenFinalGatherLightingUpdateSpeed=False,bOverride_LumenFinalGatherScreenTraces=False,bOverride_LumenMaxTraceDistance=False,bOverride_LumenDiffuseColorBoost=False,bOverride_LumenSkylightLeaking=False,bOverride_LumenFullSkylightLeakingDistance=False,bOverride_LumenRayLightingMode=False,bOverride_LumenReflectionsScreenTraces=False,bOverride_LumenFrontLayerTranslucencyReflections=False,bOverride_LumenMaxRoughnessToTraceReflections=False,bOverride_LumenMaxReflectionBounces=False,bOverride_LumenMaxRefractionBounces=False,bOverride_LumenSurfaceCacheResolution=False,bOverride_RayTracingGI=False,bOverride_RayTracingGIMaxBounces=False,bOverride_RayTracingGISamplesPerPixel=False,bOverride_PathTracingMaxBounces=False,bOverride_PathTracingSamplesPerPixel=False,bOverride_PathTracingMaxPathIntensity=False,bOverride_PathTracingEnableEmissiveMaterials=False,bOverride_PathTracingEnableReferenceDOF=False,bOverride_PathTracingEnableReferenceAtmosphere=False,bOverride_PathTracingEnableDenoiser=False,bOverride_PathTracingIncludeEmissive=False,bOverride_PathTracingIncludeDiffuse=False,bOverride_PathTracingIncludeIndirectDiffuse=False,bOverride_PathTracingIncludeSpecular=False,bOverride_PathTracingIncludeIndirectSpecular=False,bOverride_PathTracingIncludeVolume=False,bOverride_PathTracingIncludeIndirectVolume=False,bMobileHQGaussian=False,BloomMethod=BM_SOG,AutoExposureMethod=AEM_Histogram,TemperatureType=TEMP_WhiteBalance,WhiteTemp=6500.000000,WhiteTint=0.000000,ColorSaturation=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorContrast=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorGamma=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorGain=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorOffset=(X=0.000000,Y=0.000000,Z=0.000000,W=0.000000),ColorSaturationShadows=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorContrastShadows=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorGammaShadows=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorGainShadows=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorOffsetShadows=(X=0.000000,Y=0.000000,Z=0.000000,W=0.000000),ColorSaturationMidtones=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorContrastMidtones=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorGammaMidtones=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorGainMidtones=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorOffsetMidtones=(X=0.000000,Y=0.000000,Z=0.000000,W=0.000000),ColorSaturationHighlights=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorContrastHighlights=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorGammaHighlights=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorGainHighlights=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorOffsetHighlights=(X=0.000000,Y=0.000000,Z=0.000000,W=0.000000),ColorCorrectionHighlightsMin=0.500000,ColorCorrectionHighlightsMax=1.000000,ColorCorrectionShadowsMax=0.090000,BlueCorrection=0.600000,ExpandGamut=1.000000,ToneCurveAmount=1.000000,FilmSlope=0.880000,FilmToe=0.550000,FilmShoulder=0.260000,FilmBlackClip=0.000000,FilmWhiteClip=0.040000,SceneColorTint=(R=1.000000,G=1.000000,B=1.000000,A=1.000000),SceneFringeIntensity=0.000000,ChromaticAberrationStartOffset=0.000000,BloomIntensity=0.675000,BloomThreshold=-1.000000,BloomSizeScale=4.000000,Bloom1Size=0.300000,Bloom2Size=1.000000,Bloom3Size=2.000000,Bloom4Size=10.000000,Bloom5Size=30.000000,Bloom6Size=64.000000,Bloom1Tint=(R=0.346500,G=0.346500,B=0.346500,A=1.000000),Bloom2Tint=(R=0.138000,G=0.138000,B=0.138000,A=1.000000),Bloom3Tint=(R=0.117600,G=0.117600,B=0.117600,A=1.000000),Bloom4Tint=(R=0.066000,G=0.066000,B=0.066000,A=1.000000),Bloom5Tint=(R=0.066000,G=0.066000,B=0.066000,A=1.000000),Bloom6Tint=(R=0.061000,G=0.061000,B=0.061000,A=1.000000),BloomConvolutionScatterDispersion=1.000000,BloomConvolutionSize=1.000000,BloomConvolutionTexture=None,BloomConvolutionCenterUV=(X=0.500000,Y=0.500000),BloomConvolutionPreFilterMin=7.000000,BloomConvolutionPreFilterMax=15000.000000,BloomConvolutionPreFilterMult=15.000000,BloomConvolutionBufferScale=0.133000,BloomDirtMask=None,BloomDirtMaskIntensity=0.000000,BloomDirtMaskTint=(R=0.500000,G=0.500000,B=0.500000,A=1.000000),DynamicGlobalIlluminationMethod=Lumen,IndirectLightingColor=(R=1.000000,G=1.000000,B=1.000000,A=1.000000),IndirectLightingIntensity=1.000000,LumenRayLightingMode=Default,LumenSceneLightingQuality=1.000000,LumenSceneDetail=1.000000,LumenSceneViewDistance=20000.000000,LumenSceneLightingUpdateSpeed=1.000000,LumenFinalGatherQuality=1.000000,LumenFinalGatherLightingUpdateSpeed=1.000000,LumenFinalGatherScreenTraces=True,LumenMaxTraceDistance=20000.000000,LumenDiffuseColorBoost=1.000000,LumenSkylightLeaking=0.000000,LumenFullSkylightLeakingDistance=1000.000000,LumenSurfaceCacheResolution=1.000000,ReflectionMethod=Lumen,LumenReflectionQuality=1.000000,LumenReflectionsScreenTraces=True,LumenFrontLayerTranslucencyReflections=False,LumenMaxRoughnessToTraceReflections=0.400000,LumenMaxReflectionBounces=1,LumenMaxRefractionBounces=0,ScreenSpaceReflectionIntensity=100.000000,ScreenSpaceReflectionQuality=50.000000,ScreenSpaceReflectionMaxRoughness=0.600000,bMegaLights=True,AmbientCubemapTint=(R=1.000000,G=1.000000,B=1.000000,A=1.000000),AmbientCubemapIntensity=1.000000,AmbientCubemap=None,CameraShutterSpeed=60.000000,CameraISO=100.000000,DepthOfFieldFstop=4.000000,DepthOfFieldMinFstop=1.200000,DepthOfFieldBladeCount=5,AutoExposureBias=1.000000,AutoExposureBiasBackup=0.000000,bOverride_AutoExposureBiasBackup=False,AutoExposureApplyPhysicalCameraExposure=True,AutoExposureBiasCurve=None,AutoExposureMeterMask=None,AutoExposureLowPercent=10.000000,AutoExposureHighPercent=90.000000,AutoExposureMinBrightness=-10.000000,AutoExposureMaxBrightness=20.000000,AutoExposureSpeedUp=3.000000,AutoExposureSpeedDown=1.000000,HistogramLogMin=-10.000000,HistogramLogMax=20.000000,LocalExposureMethod=Bilateral,LocalExposureHighlightContrastScale=1.000000,LocalExposureShadowContrastScale=1.000000,LocalExposureHighlightContrastCurve=None,LocalExposureShadowContrastCurve=None,LocalExposureHighlightThreshold=0.000000,LocalExposureShadowThreshold=0.000000,LocalExposureDetailStrength=1.000000,LocalExposureBlurredLuminanceBlend=0.600000,LocalExposureBlurredLuminanceKernelSizePercent=50.000000,LocalExposureMiddleGreyBias=0.000000,LensFlareIntensity=1.000000,LensFlareTint=(R=1.000000,G=1.000000,B=1.000000,A=1.000000),LensFlareBokehSize=3.000000,LensFlareThreshold=8.000000,LensFlareBokehShape=None,LensFlareTints[0]=(R=1.000000,G=0.800000,B=0.400000,A=0.600000),LensFlareTints[1]=(R=1.000000,G=1.000000,B=0.600000,A=0.530000),LensFlareTints[2]=(R=0.800000,G=0.800000,B=1.000000,A=0.460000),LensFlareTints[3]=(R=0.500000,G=1.000000,B=0.400000,A=0.390000),LensFlareTints[4]=(R=0.500000,G=0.800000,B=1.000000,A=0.310000),LensFlareTints[5]=(R=0.900000,G=1.000000,B=0.800000,A=0.270000),LensFlareTints[6]=(R=1.000000,G=0.800000,B=0.400000,A=0.220000),LensFlareTints[7]=(R=0.900000,G=0.700000,B=0.700000,A=0.150000),VignetteIntensity=0.400000,Sharpen=0.000000,FilmGrainIntensity=0.000000,FilmGrainIntensityShadows=1.000000,FilmGrainIntensityMidtones=1.000000,FilmGrainIntensityHighlights=1.000000,FilmGrainShadowsMax=0.090000,FilmGrainHighlightsMin=0.500000,FilmGrainHighlightsMax=1.000000,FilmGrainTexelSize=1.000000,FilmGrainTexture=None,AmbientOcclusionIntensity=0.500000,AmbientOcclusionStaticFraction=1.000000,AmbientOcclusionRadius=200.000000,AmbientOcclusionRadiusInWS=False,AmbientOcclusionFadeDistance=8000.000000,AmbientOcclusionFadeRadius=5000.000000,AmbientOcclusionPower=2.000000,AmbientOcclusionBias=3.000000,AmbientOcclusionQuality=50.000000,AmbientOcclusionMipBlend=0.600000,AmbientOcclusionMipScale=1.700000,AmbientOcclusionMipThreshold=0.010000,AmbientOcclusionTemporalBlendWeight=0.100000,RayTracingAO=False,RayTracingAOSamplesPerPixel=1,RayTracingAOIntensity=1.000000,RayTracingAORadius=200.000000,ColorGradingIntensity=1.000000,ColorGradingLUT=None,DepthOfFieldSensorWidth=24.576000,DepthOfFieldSqueezeFactor=1.000000,DepthOfFieldFocalDistance=0.000000,DepthOfFieldDepthBlurAmount=1.000000,DepthOfFieldDepthBlurRadius=0.000000,DepthOfFieldUseHairDepth=False,DepthOfFieldFocalRegion=0.000000,DepthOfFieldNearTransitionRegion=300.000000,DepthOfFieldFarTransitionRegion=500.000000,DepthOfFieldScale=0.000000,DepthOfFieldNearBlurSize=15.000000,DepthOfFieldFarBlurSize=15.000000,DepthOfFieldOcclusion=0.400000,DepthOfFieldSkyFocusDistance=0.000000,DepthOfFieldVignetteSize=200.000000,MotionBlurAmount=0.500000,MotionBlurMax=5.000000,MotionBlurTargetFPS=30,MotionBlurPerObjectSize=0.000000,TranslucencyType=Raster,RayTracingTranslucencyMaxRoughness=0.600000,RayTracingTranslucencyRefractionRays=3,RayTracingTranslucencySamplesPerPixel=1,RayTracingTranslucencyShadows=Hard_shadows,RayTracingTranslucencyRefraction=True,PathTracingMaxBounces=32,PathTracingSamplesPerPixel=2048,PathTracingMaxPathIntensity=24.000000,PathTracingEnableEmissiveMaterials=True,PathTracingEnableReferenceDOF=False,PathTracingEnableReferenceAtmosphere=False,PathTracingEnableDenoiser=True,PathTracingIncludeEmissive=True,PathTracingIncludeDiffuse=True,PathTracingIncludeIndirectDiffuse=True,PathTracingIncludeSpecular=True,PathTracingIncludeIndirectSpecular=True,PathTracingIncludeVolume=True,PathTracingIncludeIndirectVolume=True,UserFlags=0,WeightedBlendables=(Array=)),LightingRigRotation=0.000000,RotationSpeed=2.000000,DirectionalLightRotation=(Pitch=-40.000000,Yaw=-67.500000,Roll=0.000000),bEnableToneMapping=False,bShowMeshEdges=True) diff --git a/Config/DefaultEngine.ini b/Config/DefaultEngine.ini index baf6d99..68ba984 100644 --- a/Config/DefaultEngine.ini +++ b/Config/DefaultEngine.ini @@ -1,6 +1,6 @@ [/Script/EngineSettings.GameMapsSettings] -GameDefaultMap=/Game/Maps/L_Default.L_Default -EditorStartupMap=/Game/Maps/L_Default.L_Default +GameDefaultMap=/Game/Maps/L_Level1.L_Level1 +EditorStartupMap=/Game/Maps/L_Level1.L_Level1 GlobalDefaultGameMode="/Script/CogSample.CogSampleGameMode" [/Script/Engine.RendererSettings] @@ -111,7 +111,7 @@ ManualIPAddress= +DefaultChannelResponses=(Channel=ECC_GameTraceChannel2,DefaultResponse=ECR_Ignore,bTraceType=False,bStaticObject=False,Name="Projectile") +DefaultChannelResponses=(Channel=ECC_GameTraceChannel3,DefaultResponse=ECR_Ignore,bTraceType=True,bStaticObject=False,Name="TraceCustom") +EditProfiles=(Name="Pawn",CustomResponses=((Channel="Camera",Response=ECR_Ignore),(Channel="Projectile",Response=ECR_Ignore),(Channel="TraceCustom"))) -+EditProfiles=(Name="CharacterMesh",CustomResponses=((Channel="Camera",Response=ECR_Ignore),(Channel="Projectile",Response=ECR_Overlap),(Channel="TraceCustom",Response=ECR_Ignore))) ++EditProfiles=(Name="CharacterMesh",CustomResponses=((Channel="Camera",Response=ECR_Ignore),(Channel="Projectile",Response=ECR_Overlap),(Channel="TraceCustom",Response=ECR_Ignore),(Channel="CharacterMesh",Response=ECR_Overlap))) +EditProfiles=(Name="BlockAll",CustomResponses=((Channel="Projectile"))) +EditProfiles=(Name="OverlapAll",CustomResponses=((Channel="Projectile",Response=ECR_Overlap))) +EditProfiles=(Name="BlockAllDynamic",CustomResponses=((Channel="Projectile"))) diff --git a/Config/DefaultGame.ini b/Config/DefaultGame.ini index fd1c507..fb5c7b4 100644 --- a/Config/DefaultGame.ini +++ b/Config/DefaultGame.ini @@ -15,11 +15,10 @@ bIgnoreMissingCookedAssetRegistryData=False [/Script/Engine.AssetManagerSettings] -PrimaryAssetTypesToScan=(PrimaryAssetType="Map",AssetBaseClass=/Script/Engine.World,bHasBlueprintClasses=False,bIsEditorOnly=True,Directories=((Path="/Game/Maps")),SpecificAssets=,Rules=(Priority=-1,ChunkId=-1,bApplyRecursively=True,CookRule=Unknown)) -PrimaryAssetTypesToScan=(PrimaryAssetType="PrimaryAssetLabel",AssetBaseClass=/Script/Engine.PrimaryAssetLabel,bHasBlueprintClasses=False,bIsEditorOnly=True,Directories=((Path="/Game")),SpecificAssets=,Rules=(Priority=-1,ChunkId=-1,bApplyRecursively=True,CookRule=Unknown)) -+PrimaryAssetTypesToScan=(PrimaryAssetType="Map",AssetBaseClass="/Script/Engine.World",bHasBlueprintClasses=False,bIsEditorOnly=True,Directories=((Path="/Game/Maps")),SpecificAssets=,Rules=(Priority=-1,ChunkId=-1,bApplyRecursively=True,CookRule=Unknown)) ++PrimaryAssetTypesToScan=(PrimaryAssetType="Map",AssetBaseClass="/Script/Engine.World",bHasBlueprintClasses=False,bIsEditorOnly=False,Directories=((Path="/Game/Maps")),SpecificAssets=,Rules=(Priority=-1,ChunkId=-1,bApplyRecursively=True,CookRule=AlwaysCook)) +PrimaryAssetTypesToScan=(PrimaryAssetType="PrimaryAssetLabel",AssetBaseClass="/Script/Engine.PrimaryAssetLabel",bHasBlueprintClasses=False,bIsEditorOnly=True,Directories=((Path="/Game")),SpecificAssets=,Rules=(Priority=-1,ChunkId=-1,bApplyRecursively=True,CookRule=Unknown)) -+PrimaryAssetTypesToScan=(PrimaryAssetType="CogAbilityDataAsset",AssetBaseClass="/Script/CogAbility.CogAbilityDataAsset",bHasBlueprintClasses=False,bIsEditorOnly=False,Directories=((Path="/Game/Core/Debug")),SpecificAssets=,Rules=(Priority=-1,ChunkId=-1,bApplyRecursively=True,CookRule=DevelopmentAlwaysCook)) -+PrimaryAssetTypesToScan=(PrimaryAssetType="CogEngineDataAsset",AssetBaseClass="/Script/CogEngine.CogEngineDataAsset",bHasBlueprintClasses=False,bIsEditorOnly=False,Directories=((Path="/Game/Core/Debug")),SpecificAssets=,Rules=(Priority=-1,ChunkId=-1,bApplyRecursively=True,CookRule=DevelopmentAlwaysCook)) -+PrimaryAssetTypesToScan=(PrimaryAssetType="CogInputDataAsset",AssetBaseClass="/Script/CogInput.CogInputDataAsset",bHasBlueprintClasses=False,bIsEditorOnly=False,Directories=((Path="/Game/Core/Debug")),SpecificAssets=,Rules=(Priority=-1,ChunkId=-1,bApplyRecursively=True,CookRule=DevelopmentAlwaysCook)) ++PrimaryAssetTypesToScan=(PrimaryAssetType="CogAbilityDataAsset",AssetBaseClass="/Script/CogAbility.CogAbilityDataAsset",bHasBlueprintClasses=False,bIsEditorOnly=False,Directories=((Path="/Game/Core/Debug")),SpecificAssets=,Rules=(Priority=-1,ChunkId=-1,bApplyRecursively=True,CookRule=DevelopmentAlwaysProductionNeverCook)) ++PrimaryAssetTypesToScan=(PrimaryAssetType="CogEngineDataAsset",AssetBaseClass="/Script/CogEngine.CogEngineDataAsset",bHasBlueprintClasses=False,bIsEditorOnly=False,Directories=((Path="/Game/Core/Debug")),SpecificAssets=,Rules=(Priority=-1,ChunkId=-1,bApplyRecursively=True,CookRule=DevelopmentAlwaysProductionNeverCook)) bOnlyCookProductionAssets=False bShouldManagerDetermineTypeAndName=False bShouldGuessTypeAndNameInEditor=True diff --git a/Config/DefaultGameplayTags.ini b/Config/DefaultGameplayTags.ini index 5189dd3..61b5988 100644 --- a/Config/DefaultGameplayTags.ini +++ b/Config/DefaultGameplayTags.ini @@ -1,3 +1,4 @@ +;METADATA=(Diff=true, UseCommands=true) [/Script/GameplayTags.GameplayTagsSettings] ImportTagsFromConfig=True WarnOnInvalidTags=True @@ -5,9 +6,12 @@ ClearInvalidTags=False AllowEditorTagUnloading=True AllowGameTagUnloading=False FastReplication=False +bDynamicReplication=False InvalidTagCharacters="\"\'," NumBitsForContainerSize=6 NetIndexFirstBitSegment=16 ++GameplayTagList=(Tag="Effect.Type.Damage.Magical",DevComment="") ++GameplayTagList=(Tag="Effect.Type.Damage.Physical",DevComment="") +GameplayTagList=(Tag="GameplayCue.Ability.Hero1.Poison",DevComment="") +GameplayTagList=(Tag="GameplayCue.Ability.Hero1.PuhBack",DevComment="") +GameplayTagList=(Tag="GameplayCue.Ability.Hero1.Shield",DevComment="") diff --git a/Content/Characters/Creature1/Abilities/Shield/AM_Creature1_Shield.uasset b/Content/Characters/Creature1/Abilities/Shield/AM_Creature1_Shield.uasset index 634aa8d..8f157d9 100644 Binary files a/Content/Characters/Creature1/Abilities/Shield/AM_Creature1_Shield.uasset and b/Content/Characters/Creature1/Abilities/Shield/AM_Creature1_Shield.uasset differ diff --git a/Content/Characters/Creature1/BP_Creature1.uasset b/Content/Characters/Creature1/BP_Creature1.uasset index 0cf3af8..c9d3254 100644 Binary files a/Content/Characters/Creature1/BP_Creature1.uasset and b/Content/Characters/Creature1/BP_Creature1.uasset differ diff --git a/Content/Characters/Creature2/BP_Creature2.uasset b/Content/Characters/Creature2/BP_Creature2.uasset index d04bb41..6864afa 100644 Binary files a/Content/Characters/Creature2/BP_Creature2.uasset and b/Content/Characters/Creature2/BP_Creature2.uasset differ diff --git a/Content/Characters/Hero1/Abilities/Area/AM_Hero1_Area.uasset b/Content/Characters/Hero1/Abilities/Area/AM_Hero1_Area.uasset index d0b76f5..aad4d17 100644 Binary files a/Content/Characters/Hero1/Abilities/Area/AM_Hero1_Area.uasset and b/Content/Characters/Hero1/Abilities/Area/AM_Hero1_Area.uasset differ diff --git a/Content/Characters/Hero1/Abilities/Blast/AM_Hero1_Blast.uasset b/Content/Characters/Hero1/Abilities/Blast/AM_Hero1_Blast.uasset index 7afb405..b860663 100644 Binary files a/Content/Characters/Hero1/Abilities/Blast/AM_Hero1_Blast.uasset and b/Content/Characters/Hero1/Abilities/Blast/AM_Hero1_Blast.uasset differ diff --git a/Content/Characters/Hero1/Abilities/Poison/AM_Hero1_Poison.uasset b/Content/Characters/Hero1/Abilities/Poison/AM_Hero1_Poison.uasset index af60af9..9ebf0a4 100644 Binary files a/Content/Characters/Hero1/Abilities/Poison/AM_Hero1_Poison.uasset and b/Content/Characters/Hero1/Abilities/Poison/AM_Hero1_Poison.uasset differ diff --git a/Content/Characters/Hero1/Abilities/Shield/AM_Hero1_Shield.uasset b/Content/Characters/Hero1/Abilities/Shield/AM_Hero1_Shield.uasset index b193287..bf2b69b 100644 Binary files a/Content/Characters/Hero1/Abilities/Shield/AM_Hero1_Shield.uasset and b/Content/Characters/Hero1/Abilities/Shield/AM_Hero1_Shield.uasset differ diff --git a/Content/Characters/Hero1/Abilities/Shield/GE_Hero1_Shield.uasset b/Content/Characters/Hero1/Abilities/Shield/GE_Hero1_Shield.uasset index 4e94d6f..bbf878f 100644 Binary files a/Content/Characters/Hero1/Abilities/Shield/GE_Hero1_Shield.uasset and b/Content/Characters/Hero1/Abilities/Shield/GE_Hero1_Shield.uasset differ diff --git a/Content/Characters/Hero1/Abilities/Shoot/AM_Hero1_Shoot.uasset b/Content/Characters/Hero1/Abilities/Shoot/AM_Hero1_Shoot.uasset index 9e6fd4f..9d44fbb 100644 Binary files a/Content/Characters/Hero1/Abilities/Shoot/AM_Hero1_Shoot.uasset and b/Content/Characters/Hero1/Abilities/Shoot/AM_Hero1_Shoot.uasset differ diff --git a/Content/Characters/_Shared_/Abilities/GA_Cast.uasset b/Content/Characters/_Shared_/Abilities/GA_Cast.uasset index fd57ced..05f3cf7 100644 Binary files a/Content/Characters/_Shared_/Abilities/GA_Cast.uasset and b/Content/Characters/_Shared_/Abilities/GA_Cast.uasset differ diff --git a/Content/Characters/_Shared_/BP_Character.uasset b/Content/Characters/_Shared_/BP_Character.uasset index 7291d0f..b5ec63b 100644 Binary files a/Content/Characters/_Shared_/BP_Character.uasset and b/Content/Characters/_Shared_/BP_Character.uasset differ diff --git a/Content/Characters/_Shared_/BP_Creature.uasset b/Content/Characters/_Shared_/BP_Creature.uasset index 14f5387..1d9c126 100644 Binary files a/Content/Characters/_Shared_/BP_Creature.uasset and b/Content/Characters/_Shared_/BP_Creature.uasset differ diff --git a/Content/Core/AnimNotify/AN_Cast.uasset b/Content/Core/AnimNotify/AN_Cast.uasset index 0e88021..3bf56f1 100644 Binary files a/Content/Core/AnimNotify/AN_Cast.uasset and b/Content/Core/AnimNotify/AN_Cast.uasset differ diff --git a/Content/Core/Debug/Cheats/AM_Cheat.uasset b/Content/Core/Debug/Cheats/AM_Cheat.uasset index df15630..eb1f7e3 100644 Binary files a/Content/Core/Debug/Cheats/AM_Cheat.uasset and b/Content/Core/Debug/Cheats/AM_Cheat.uasset differ diff --git a/Content/Core/Debug/Cheats/GE_Cheat_MoveSpeed.uasset b/Content/Core/Debug/Cheats/GE_Cheat_MoveSpeed.uasset new file mode 100644 index 0000000..511705b Binary files /dev/null and b/Content/Core/Debug/Cheats/GE_Cheat_MoveSpeed.uasset differ diff --git a/Content/Core/Debug/Cheats/GE_Cheat_Speed.uasset b/Content/Core/Debug/Cheats/GE_Cheat_Speed.uasset deleted file mode 100644 index a7f6476..0000000 Binary files a/Content/Core/Debug/Cheats/GE_Cheat_Speed.uasset and /dev/null differ diff --git a/Content/Core/Debug/DA_Debug_Ability.uasset b/Content/Core/Debug/DA_Debug_Ability.uasset index 4f0a77d..36ddae4 100644 Binary files a/Content/Core/Debug/DA_Debug_Ability.uasset and b/Content/Core/Debug/DA_Debug_Ability.uasset differ diff --git a/Content/Core/Debug/DA_Debug_Engine.uasset b/Content/Core/Debug/DA_Debug_Engine.uasset index a627828..cc7952c 100644 Binary files a/Content/Core/Debug/DA_Debug_Engine.uasset and b/Content/Core/Debug/DA_Debug_Engine.uasset differ diff --git a/Content/Core/Debug/DA_Debug_Input.uasset b/Content/Core/Debug/DA_Debug_Input.uasset deleted file mode 100644 index cba74ec..0000000 Binary files a/Content/Core/Debug/DA_Debug_Input.uasset and /dev/null differ diff --git a/Content/Core/GameModes/BP_PlayerController.uasset b/Content/Core/GameModes/BP_PlayerController.uasset index 67de134..0280b80 100644 Binary files a/Content/Core/GameModes/BP_PlayerController.uasset and b/Content/Core/GameModes/BP_PlayerController.uasset differ diff --git a/Content/Core/Hud/WBP_Menu.uasset b/Content/Core/Hud/WBP_Menu.uasset index 16a8795..d0ce32e 100644 Binary files a/Content/Core/Hud/WBP_Menu.uasset and b/Content/Core/Hud/WBP_Menu.uasset differ diff --git a/Content/Core/Input/Actions/IA_Menu.uasset b/Content/Core/Input/Actions/IA_Menu.uasset index 1d6e8f4..5798d69 100644 Binary files a/Content/Core/Input/Actions/IA_Menu.uasset and b/Content/Core/Input/Actions/IA_Menu.uasset differ diff --git a/Content/Core/Input/IMC_Default.uasset b/Content/Core/Input/IMC_Default.uasset index 809ad9f..a42de50 100644 Binary files a/Content/Core/Input/IMC_Default.uasset and b/Content/Core/Input/IMC_Default.uasset differ diff --git a/Content/Maps/L_Default.umap b/Content/Maps/L_Default.umap deleted file mode 100644 index d875dcb..0000000 Binary files a/Content/Maps/L_Default.umap and /dev/null differ diff --git a/Content/Maps/L_Level1.umap b/Content/Maps/L_Level1.umap new file mode 100644 index 0000000..bb6fd8c Binary files /dev/null and b/Content/Maps/L_Level1.umap differ diff --git a/Content/Maps/L_Level2.umap b/Content/Maps/L_Level2.umap new file mode 100644 index 0000000..428b8fd Binary files /dev/null and b/Content/Maps/L_Level2.umap differ diff --git a/Content/__ExternalActors__/Maps/L_Default/1/E8/AAU95ZYA4MAUHPOONF008W.uasset b/Content/__ExternalActors__/Maps/L_Default/1/E8/AAU95ZYA4MAUHPOONF008W.uasset deleted file mode 100644 index c9d1cc0..0000000 Binary files a/Content/__ExternalActors__/Maps/L_Default/1/E8/AAU95ZYA4MAUHPOONF008W.uasset and /dev/null differ diff --git a/Content/__ExternalActors__/Maps/L_Default/1/OB/2ESQZBC7083CHHIXUX8E3L.uasset b/Content/__ExternalActors__/Maps/L_Default/1/OB/2ESQZBC7083CHHIXUX8E3L.uasset deleted file mode 100644 index b7be7b7..0000000 Binary files a/Content/__ExternalActors__/Maps/L_Default/1/OB/2ESQZBC7083CHHIXUX8E3L.uasset and /dev/null differ diff --git a/Content/__ExternalActors__/Maps/L_Default/2/KZ/3Y4PAKEW3L97J087BUDMVI.uasset b/Content/__ExternalActors__/Maps/L_Default/2/KZ/3Y4PAKEW3L97J087BUDMVI.uasset deleted file mode 100644 index f5aa833..0000000 Binary files a/Content/__ExternalActors__/Maps/L_Default/2/KZ/3Y4PAKEW3L97J087BUDMVI.uasset and /dev/null differ diff --git a/Content/__ExternalActors__/Maps/L_Default/2/LS/FQYU6ZADUEDQR3NXV2VYUW.uasset b/Content/__ExternalActors__/Maps/L_Default/2/LS/FQYU6ZADUEDQR3NXV2VYUW.uasset deleted file mode 100644 index bcba985..0000000 Binary files a/Content/__ExternalActors__/Maps/L_Default/2/LS/FQYU6ZADUEDQR3NXV2VYUW.uasset and /dev/null differ diff --git a/Content/__ExternalActors__/Maps/L_Default/2/ZP/ZFTVD1X629VL0RB90NJ1OK.uasset b/Content/__ExternalActors__/Maps/L_Default/2/ZP/ZFTVD1X629VL0RB90NJ1OK.uasset deleted file mode 100644 index 6359990..0000000 Binary files a/Content/__ExternalActors__/Maps/L_Default/2/ZP/ZFTVD1X629VL0RB90NJ1OK.uasset and /dev/null differ diff --git a/Content/__ExternalActors__/Maps/L_Default/4/98/HCM4KXTG2Y2G1I0BTX2UNY.uasset b/Content/__ExternalActors__/Maps/L_Default/4/98/HCM4KXTG2Y2G1I0BTX2UNY.uasset deleted file mode 100644 index 97d15a9..0000000 Binary files a/Content/__ExternalActors__/Maps/L_Default/4/98/HCM4KXTG2Y2G1I0BTX2UNY.uasset and /dev/null differ diff --git a/Content/__ExternalActors__/Maps/L_Default/4/O6/EEDOC9EDKNLS020FIUS8UZ.uasset b/Content/__ExternalActors__/Maps/L_Default/4/O6/EEDOC9EDKNLS020FIUS8UZ.uasset deleted file mode 100644 index f5022c7..0000000 Binary files a/Content/__ExternalActors__/Maps/L_Default/4/O6/EEDOC9EDKNLS020FIUS8UZ.uasset and /dev/null differ diff --git a/Content/__ExternalActors__/Maps/L_Default/5/88/NDHUEK1ROBM2RCW7ZU51MM.uasset b/Content/__ExternalActors__/Maps/L_Default/5/88/NDHUEK1ROBM2RCW7ZU51MM.uasset deleted file mode 100644 index d4149b4..0000000 Binary files a/Content/__ExternalActors__/Maps/L_Default/5/88/NDHUEK1ROBM2RCW7ZU51MM.uasset and /dev/null differ diff --git a/Content/__ExternalActors__/Maps/L_Default/5/Z2/M3N1BNXNYQSVERTSDCQV0Q.uasset b/Content/__ExternalActors__/Maps/L_Default/5/Z2/M3N1BNXNYQSVERTSDCQV0Q.uasset deleted file mode 100644 index 16a32ff..0000000 Binary files a/Content/__ExternalActors__/Maps/L_Default/5/Z2/M3N1BNXNYQSVERTSDCQV0Q.uasset and /dev/null differ diff --git a/Content/__ExternalActors__/Maps/L_Default/6/C5/WYNS79L3C4G5BIBNA4TS4E.uasset b/Content/__ExternalActors__/Maps/L_Default/6/C5/WYNS79L3C4G5BIBNA4TS4E.uasset deleted file mode 100644 index 96b27e2..0000000 Binary files a/Content/__ExternalActors__/Maps/L_Default/6/C5/WYNS79L3C4G5BIBNA4TS4E.uasset and /dev/null differ diff --git a/Content/__ExternalActors__/Maps/L_Default/6/U3/6O7DJ03I0JB041XHH0L21L.uasset b/Content/__ExternalActors__/Maps/L_Default/6/U3/6O7DJ03I0JB041XHH0L21L.uasset deleted file mode 100644 index 39feb88..0000000 Binary files a/Content/__ExternalActors__/Maps/L_Default/6/U3/6O7DJ03I0JB041XHH0L21L.uasset and /dev/null differ diff --git a/Content/__ExternalActors__/Maps/L_Default/7/CY/NIXPTWLMTD4BF68QY853ZA.uasset b/Content/__ExternalActors__/Maps/L_Default/7/CY/NIXPTWLMTD4BF68QY853ZA.uasset deleted file mode 100644 index f1318a3..0000000 Binary files a/Content/__ExternalActors__/Maps/L_Default/7/CY/NIXPTWLMTD4BF68QY853ZA.uasset and /dev/null differ diff --git a/Content/__ExternalActors__/Maps/L_Default/7/GV/6CCF512KD41PF14VYB8AKJ.uasset b/Content/__ExternalActors__/Maps/L_Default/7/GV/6CCF512KD41PF14VYB8AKJ.uasset deleted file mode 100644 index 3387866..0000000 Binary files a/Content/__ExternalActors__/Maps/L_Default/7/GV/6CCF512KD41PF14VYB8AKJ.uasset and /dev/null differ diff --git a/Content/__ExternalActors__/Maps/L_Default/7/ZU/USA6BTRS1FQ12S60M283TF.uasset b/Content/__ExternalActors__/Maps/L_Default/7/ZU/USA6BTRS1FQ12S60M283TF.uasset deleted file mode 100644 index 8490eba..0000000 Binary files a/Content/__ExternalActors__/Maps/L_Default/7/ZU/USA6BTRS1FQ12S60M283TF.uasset and /dev/null differ diff --git a/Content/__ExternalActors__/Maps/L_Default/8/EO/J2O30Y8BP1IJGKNHYD8SUY.uasset b/Content/__ExternalActors__/Maps/L_Default/8/EO/J2O30Y8BP1IJGKNHYD8SUY.uasset deleted file mode 100644 index 39d336d..0000000 Binary files a/Content/__ExternalActors__/Maps/L_Default/8/EO/J2O30Y8BP1IJGKNHYD8SUY.uasset and /dev/null differ diff --git a/Content/__ExternalActors__/Maps/L_Default/9/9T/FCGBFHWX7CAR92DPH0V2G2.uasset b/Content/__ExternalActors__/Maps/L_Default/9/9T/FCGBFHWX7CAR92DPH0V2G2.uasset deleted file mode 100644 index 525beec..0000000 Binary files a/Content/__ExternalActors__/Maps/L_Default/9/9T/FCGBFHWX7CAR92DPH0V2G2.uasset and /dev/null differ diff --git a/Content/__ExternalActors__/Maps/L_Default/9/CI/AF9H3Z19RVVPEEQCVD0LH1.uasset b/Content/__ExternalActors__/Maps/L_Default/9/CI/AF9H3Z19RVVPEEQCVD0LH1.uasset deleted file mode 100644 index 6a20ddd..0000000 Binary files a/Content/__ExternalActors__/Maps/L_Default/9/CI/AF9H3Z19RVVPEEQCVD0LH1.uasset and /dev/null differ diff --git a/Content/__ExternalActors__/Maps/L_Default/A/PG/IL47CE5KTNDBK5U883KPVL.uasset b/Content/__ExternalActors__/Maps/L_Default/A/PG/IL47CE5KTNDBK5U883KPVL.uasset deleted file mode 100644 index a28ec3a..0000000 Binary files a/Content/__ExternalActors__/Maps/L_Default/A/PG/IL47CE5KTNDBK5U883KPVL.uasset and /dev/null differ diff --git a/Content/__ExternalActors__/Maps/L_Default/B/VG/ORCXCB1C1RR2JCZX4AT8D1.uasset b/Content/__ExternalActors__/Maps/L_Default/B/VG/ORCXCB1C1RR2JCZX4AT8D1.uasset deleted file mode 100644 index 5546698..0000000 Binary files a/Content/__ExternalActors__/Maps/L_Default/B/VG/ORCXCB1C1RR2JCZX4AT8D1.uasset and /dev/null differ diff --git a/Content/__ExternalActors__/Maps/L_Default/E/GE/FR0ZJ708CAOPGQ80MYRF9N.uasset b/Content/__ExternalActors__/Maps/L_Default/E/GE/FR0ZJ708CAOPGQ80MYRF9N.uasset deleted file mode 100644 index 710a83f..0000000 Binary files a/Content/__ExternalActors__/Maps/L_Default/E/GE/FR0ZJ708CAOPGQ80MYRF9N.uasset and /dev/null differ diff --git a/Content/__ExternalActors__/Maps/L_Default/E/HA/CXMK7W9FIGA0C2MR0GYXOO.uasset b/Content/__ExternalActors__/Maps/L_Default/E/HA/CXMK7W9FIGA0C2MR0GYXOO.uasset deleted file mode 100644 index f3d86f0..0000000 Binary files a/Content/__ExternalActors__/Maps/L_Default/E/HA/CXMK7W9FIGA0C2MR0GYXOO.uasset and /dev/null differ diff --git a/Content/__ExternalActors__/Maps/L_Default/E/J4/PC4HDG40BUJGTQ5N420GKK.uasset b/Content/__ExternalActors__/Maps/L_Default/E/J4/PC4HDG40BUJGTQ5N420GKK.uasset deleted file mode 100644 index 4b7979f..0000000 Binary files a/Content/__ExternalActors__/Maps/L_Default/E/J4/PC4HDG40BUJGTQ5N420GKK.uasset and /dev/null differ diff --git a/Content/__ExternalActors__/Maps/L_Default/E/MD/R8HUER247TNWDSI67EZY6X.uasset b/Content/__ExternalActors__/Maps/L_Default/E/MD/R8HUER247TNWDSI67EZY6X.uasset deleted file mode 100644 index 69b3eca..0000000 Binary files a/Content/__ExternalActors__/Maps/L_Default/E/MD/R8HUER247TNWDSI67EZY6X.uasset and /dev/null differ diff --git a/Content/__ExternalActors__/Maps/L_Default/F/2S/DP2YKKCSFH4URVADOOVRWD.uasset b/Content/__ExternalActors__/Maps/L_Default/F/2S/DP2YKKCSFH4URVADOOVRWD.uasset deleted file mode 100644 index 9ebe570..0000000 Binary files a/Content/__ExternalActors__/Maps/L_Default/F/2S/DP2YKKCSFH4URVADOOVRWD.uasset and /dev/null differ diff --git a/Content/__ExternalActors__/Maps/L_Level1/0/RB/EHVMYL6P2ZXUL0UI546DPN.uasset b/Content/__ExternalActors__/Maps/L_Level1/0/RB/EHVMYL6P2ZXUL0UI546DPN.uasset new file mode 100644 index 0000000..e6086fd Binary files /dev/null and b/Content/__ExternalActors__/Maps/L_Level1/0/RB/EHVMYL6P2ZXUL0UI546DPN.uasset differ diff --git a/Content/__ExternalActors__/Maps/L_Level1/1/8A/XAGPCCPJ3MPEPKLJL21LMW.uasset b/Content/__ExternalActors__/Maps/L_Level1/1/8A/XAGPCCPJ3MPEPKLJL21LMW.uasset new file mode 100644 index 0000000..5025293 Binary files /dev/null and b/Content/__ExternalActors__/Maps/L_Level1/1/8A/XAGPCCPJ3MPEPKLJL21LMW.uasset differ diff --git a/Content/__ExternalActors__/Maps/L_Level1/1/B7/YUXBMV0YSS1J3KB6JAEPE8.uasset b/Content/__ExternalActors__/Maps/L_Level1/1/B7/YUXBMV0YSS1J3KB6JAEPE8.uasset new file mode 100644 index 0000000..79634d7 Binary files /dev/null and b/Content/__ExternalActors__/Maps/L_Level1/1/B7/YUXBMV0YSS1J3KB6JAEPE8.uasset differ diff --git a/Content/__ExternalActors__/Maps/L_Level1/2/8K/SIGGD86NF2WES8K3SGKPXD.uasset b/Content/__ExternalActors__/Maps/L_Level1/2/8K/SIGGD86NF2WES8K3SGKPXD.uasset new file mode 100644 index 0000000..768175d Binary files /dev/null and b/Content/__ExternalActors__/Maps/L_Level1/2/8K/SIGGD86NF2WES8K3SGKPXD.uasset differ diff --git a/Content/__ExternalActors__/Maps/L_Level1/2/UD/0QSLN6P313IA1EAR1QKIBL.uasset b/Content/__ExternalActors__/Maps/L_Level1/2/UD/0QSLN6P313IA1EAR1QKIBL.uasset new file mode 100644 index 0000000..258bd14 Binary files /dev/null and b/Content/__ExternalActors__/Maps/L_Level1/2/UD/0QSLN6P313IA1EAR1QKIBL.uasset differ diff --git a/Content/__ExternalActors__/Maps/L_Level1/3/R9/FPG5WMFK3YXFYD9O8HJATR.uasset b/Content/__ExternalActors__/Maps/L_Level1/3/R9/FPG5WMFK3YXFYD9O8HJATR.uasset new file mode 100644 index 0000000..266a3cf Binary files /dev/null and b/Content/__ExternalActors__/Maps/L_Level1/3/R9/FPG5WMFK3YXFYD9O8HJATR.uasset differ diff --git a/Content/__ExternalActors__/Maps/L_Level1/3/UA/QKFZ22631P11PFZN69UDNR.uasset b/Content/__ExternalActors__/Maps/L_Level1/3/UA/QKFZ22631P11PFZN69UDNR.uasset new file mode 100644 index 0000000..a600967 Binary files /dev/null and b/Content/__ExternalActors__/Maps/L_Level1/3/UA/QKFZ22631P11PFZN69UDNR.uasset differ diff --git a/Content/__ExternalActors__/Maps/L_Level1/4/6U/R8ZHQIFLYQVLK5XRUJZI4F.uasset b/Content/__ExternalActors__/Maps/L_Level1/4/6U/R8ZHQIFLYQVLK5XRUJZI4F.uasset new file mode 100644 index 0000000..f5fb062 Binary files /dev/null and b/Content/__ExternalActors__/Maps/L_Level1/4/6U/R8ZHQIFLYQVLK5XRUJZI4F.uasset differ diff --git a/Content/__ExternalActors__/Maps/L_Level1/4/AZ/QYT9ON9Z3KNXW925HKYB44.uasset b/Content/__ExternalActors__/Maps/L_Level1/4/AZ/QYT9ON9Z3KNXW925HKYB44.uasset new file mode 100644 index 0000000..c691c72 Binary files /dev/null and b/Content/__ExternalActors__/Maps/L_Level1/4/AZ/QYT9ON9Z3KNXW925HKYB44.uasset differ diff --git a/Content/__ExternalActors__/Maps/L_Level1/4/CT/WC9YQSR9WS3DLCLHCGRI3D.uasset b/Content/__ExternalActors__/Maps/L_Level1/4/CT/WC9YQSR9WS3DLCLHCGRI3D.uasset new file mode 100644 index 0000000..9fc84a7 Binary files /dev/null and b/Content/__ExternalActors__/Maps/L_Level1/4/CT/WC9YQSR9WS3DLCLHCGRI3D.uasset differ diff --git a/Content/__ExternalActors__/Maps/L_Level1/5/YY/FZDL0QR3NO9IAFY56D12SP.uasset b/Content/__ExternalActors__/Maps/L_Level1/5/YY/FZDL0QR3NO9IAFY56D12SP.uasset new file mode 100644 index 0000000..b6a370a Binary files /dev/null and b/Content/__ExternalActors__/Maps/L_Level1/5/YY/FZDL0QR3NO9IAFY56D12SP.uasset differ diff --git a/Content/__ExternalActors__/Maps/L_Level1/6/DL/G9RQF1BM46P1MEATUZ1NDD.uasset b/Content/__ExternalActors__/Maps/L_Level1/6/DL/G9RQF1BM46P1MEATUZ1NDD.uasset new file mode 100644 index 0000000..b241bd8 Binary files /dev/null and b/Content/__ExternalActors__/Maps/L_Level1/6/DL/G9RQF1BM46P1MEATUZ1NDD.uasset differ diff --git a/Content/__ExternalActors__/Maps/L_Level1/6/HG/GAAOXN4H2TTS96C8J8X465.uasset b/Content/__ExternalActors__/Maps/L_Level1/6/HG/GAAOXN4H2TTS96C8J8X465.uasset new file mode 100644 index 0000000..aa38472 Binary files /dev/null and b/Content/__ExternalActors__/Maps/L_Level1/6/HG/GAAOXN4H2TTS96C8J8X465.uasset differ diff --git a/Content/__ExternalActors__/Maps/L_Level1/7/43/B813XY6J5JLWYBWGGXFHRF.uasset b/Content/__ExternalActors__/Maps/L_Level1/7/43/B813XY6J5JLWYBWGGXFHRF.uasset new file mode 100644 index 0000000..b04c21f Binary files /dev/null and b/Content/__ExternalActors__/Maps/L_Level1/7/43/B813XY6J5JLWYBWGGXFHRF.uasset differ diff --git a/Content/__ExternalActors__/Maps/L_Level1/7/L9/90XCJ4GRXY9X480B4LDNBM.uasset b/Content/__ExternalActors__/Maps/L_Level1/7/L9/90XCJ4GRXY9X480B4LDNBM.uasset new file mode 100644 index 0000000..8a84a89 Binary files /dev/null and b/Content/__ExternalActors__/Maps/L_Level1/7/L9/90XCJ4GRXY9X480B4LDNBM.uasset differ diff --git a/Content/__ExternalActors__/Maps/L_Level1/7/VA/EMVUW8KGQHD0UMKGMFK9I2.uasset b/Content/__ExternalActors__/Maps/L_Level1/7/VA/EMVUW8KGQHD0UMKGMFK9I2.uasset new file mode 100644 index 0000000..7b0d408 Binary files /dev/null and b/Content/__ExternalActors__/Maps/L_Level1/7/VA/EMVUW8KGQHD0UMKGMFK9I2.uasset differ diff --git a/Content/__ExternalActors__/Maps/L_Level1/A/24/G7LWLQDHYE0110C7G9GRWA.uasset b/Content/__ExternalActors__/Maps/L_Level1/A/24/G7LWLQDHYE0110C7G9GRWA.uasset new file mode 100644 index 0000000..074c8e5 Binary files /dev/null and b/Content/__ExternalActors__/Maps/L_Level1/A/24/G7LWLQDHYE0110C7G9GRWA.uasset differ diff --git a/Content/__ExternalActors__/Maps/L_Level1/A/6B/GYNOIBIJF1MG5SW3XBYX6N.uasset b/Content/__ExternalActors__/Maps/L_Level1/A/6B/GYNOIBIJF1MG5SW3XBYX6N.uasset new file mode 100644 index 0000000..b6e0d18 Binary files /dev/null and b/Content/__ExternalActors__/Maps/L_Level1/A/6B/GYNOIBIJF1MG5SW3XBYX6N.uasset differ diff --git a/Content/__ExternalActors__/Maps/L_Level1/B/6J/R8W4KPUWHG1XRKG5EN6W56.uasset b/Content/__ExternalActors__/Maps/L_Level1/B/6J/R8W4KPUWHG1XRKG5EN6W56.uasset new file mode 100644 index 0000000..14a1f04 Binary files /dev/null and b/Content/__ExternalActors__/Maps/L_Level1/B/6J/R8W4KPUWHG1XRKG5EN6W56.uasset differ diff --git a/Content/__ExternalActors__/Maps/L_Level1/C/XU/0H2LLMRLNC1KK9UZY01QMO.uasset b/Content/__ExternalActors__/Maps/L_Level1/C/XU/0H2LLMRLNC1KK9UZY01QMO.uasset new file mode 100644 index 0000000..cd16b92 Binary files /dev/null and b/Content/__ExternalActors__/Maps/L_Level1/C/XU/0H2LLMRLNC1KK9UZY01QMO.uasset differ diff --git a/Content/__ExternalActors__/Maps/L_Level1/D/Y2/EBVC7GZ2S4DLF8JG1OVE4D.uasset b/Content/__ExternalActors__/Maps/L_Level1/D/Y2/EBVC7GZ2S4DLF8JG1OVE4D.uasset new file mode 100644 index 0000000..b2d4056 Binary files /dev/null and b/Content/__ExternalActors__/Maps/L_Level1/D/Y2/EBVC7GZ2S4DLF8JG1OVE4D.uasset differ diff --git a/Content/__ExternalActors__/Maps/L_Level1/E/6U/YPVW6N5B4HA4VR47WLBKRA.uasset b/Content/__ExternalActors__/Maps/L_Level1/E/6U/YPVW6N5B4HA4VR47WLBKRA.uasset new file mode 100644 index 0000000..03546ac Binary files /dev/null and b/Content/__ExternalActors__/Maps/L_Level1/E/6U/YPVW6N5B4HA4VR47WLBKRA.uasset differ diff --git a/Content/__ExternalActors__/Maps/L_Level1/E/EI/WM2CUX1QTGF92BI5ZA0CGS.uasset b/Content/__ExternalActors__/Maps/L_Level1/E/EI/WM2CUX1QTGF92BI5ZA0CGS.uasset new file mode 100644 index 0000000..e85323e Binary files /dev/null and b/Content/__ExternalActors__/Maps/L_Level1/E/EI/WM2CUX1QTGF92BI5ZA0CGS.uasset differ diff --git a/Content/__ExternalActors__/Maps/L_Level1/E/SB/HEHNTUNSW3Z9JPULVMDUYC.uasset b/Content/__ExternalActors__/Maps/L_Level1/E/SB/HEHNTUNSW3Z9JPULVMDUYC.uasset new file mode 100644 index 0000000..0d88108 Binary files /dev/null and b/Content/__ExternalActors__/Maps/L_Level1/E/SB/HEHNTUNSW3Z9JPULVMDUYC.uasset differ diff --git a/Content/__ExternalActors__/Maps/L_Level2/3/1F/TXN4X67TTXAWD3ME2U6KH3.uasset b/Content/__ExternalActors__/Maps/L_Level2/3/1F/TXN4X67TTXAWD3ME2U6KH3.uasset new file mode 100644 index 0000000..654d5d5 Binary files /dev/null and b/Content/__ExternalActors__/Maps/L_Level2/3/1F/TXN4X67TTXAWD3ME2U6KH3.uasset differ diff --git a/Content/__ExternalActors__/Maps/L_Level2/3/JC/Q26NZFDMODS765HJOK9MJ4.uasset b/Content/__ExternalActors__/Maps/L_Level2/3/JC/Q26NZFDMODS765HJOK9MJ4.uasset new file mode 100644 index 0000000..54c01e7 Binary files /dev/null and b/Content/__ExternalActors__/Maps/L_Level2/3/JC/Q26NZFDMODS765HJOK9MJ4.uasset differ diff --git a/Content/__ExternalActors__/Maps/L_Level2/3/P0/QQEQRY10VTY9CIM4Q4ZEJ5.uasset b/Content/__ExternalActors__/Maps/L_Level2/3/P0/QQEQRY10VTY9CIM4Q4ZEJ5.uasset new file mode 100644 index 0000000..ab18037 Binary files /dev/null and b/Content/__ExternalActors__/Maps/L_Level2/3/P0/QQEQRY10VTY9CIM4Q4ZEJ5.uasset differ diff --git a/Content/__ExternalActors__/Maps/L_Level2/4/8L/OMQOIT9SH6RSCVXHFBHVC3.uasset b/Content/__ExternalActors__/Maps/L_Level2/4/8L/OMQOIT9SH6RSCVXHFBHVC3.uasset new file mode 100644 index 0000000..a8f5a4c Binary files /dev/null and b/Content/__ExternalActors__/Maps/L_Level2/4/8L/OMQOIT9SH6RSCVXHFBHVC3.uasset differ diff --git a/Content/__ExternalActors__/Maps/L_Level2/4/IL/CSFJYR5B7791EUYNZCBE49.uasset b/Content/__ExternalActors__/Maps/L_Level2/4/IL/CSFJYR5B7791EUYNZCBE49.uasset new file mode 100644 index 0000000..6d1a7ce Binary files /dev/null and b/Content/__ExternalActors__/Maps/L_Level2/4/IL/CSFJYR5B7791EUYNZCBE49.uasset differ diff --git a/Content/__ExternalActors__/Maps/L_Level2/4/KN/YBYPVWJKCRTYAPKJ8K5CPV.uasset b/Content/__ExternalActors__/Maps/L_Level2/4/KN/YBYPVWJKCRTYAPKJ8K5CPV.uasset new file mode 100644 index 0000000..e3d9033 Binary files /dev/null and b/Content/__ExternalActors__/Maps/L_Level2/4/KN/YBYPVWJKCRTYAPKJ8K5CPV.uasset differ diff --git a/Content/__ExternalActors__/Maps/L_Level2/4/UJ/0F9CLY0NE0CBIGVU4ZEU95.uasset b/Content/__ExternalActors__/Maps/L_Level2/4/UJ/0F9CLY0NE0CBIGVU4ZEU95.uasset new file mode 100644 index 0000000..59ae51e Binary files /dev/null and b/Content/__ExternalActors__/Maps/L_Level2/4/UJ/0F9CLY0NE0CBIGVU4ZEU95.uasset differ diff --git a/Content/__ExternalActors__/Maps/L_Level2/5/4F/71RMEL5NGK2ZC9VAZOUQIT.uasset b/Content/__ExternalActors__/Maps/L_Level2/5/4F/71RMEL5NGK2ZC9VAZOUQIT.uasset new file mode 100644 index 0000000..db04416 Binary files /dev/null and b/Content/__ExternalActors__/Maps/L_Level2/5/4F/71RMEL5NGK2ZC9VAZOUQIT.uasset differ diff --git a/Content/__ExternalActors__/Maps/L_Level2/5/T2/CZVI3XZ6WZS42TBG9FYELU.uasset b/Content/__ExternalActors__/Maps/L_Level2/5/T2/CZVI3XZ6WZS42TBG9FYELU.uasset new file mode 100644 index 0000000..a903860 Binary files /dev/null and b/Content/__ExternalActors__/Maps/L_Level2/5/T2/CZVI3XZ6WZS42TBG9FYELU.uasset differ diff --git a/Content/__ExternalActors__/Maps/L_Level2/7/OM/IGS9A1QIL5UB861IQ4220C.uasset b/Content/__ExternalActors__/Maps/L_Level2/7/OM/IGS9A1QIL5UB861IQ4220C.uasset new file mode 100644 index 0000000..d8ff0b1 Binary files /dev/null and b/Content/__ExternalActors__/Maps/L_Level2/7/OM/IGS9A1QIL5UB861IQ4220C.uasset differ diff --git a/Content/__ExternalActors__/Maps/L_Level2/7/WB/UPSQA3FG3J20EIR9JXHGCK.uasset b/Content/__ExternalActors__/Maps/L_Level2/7/WB/UPSQA3FG3J20EIR9JXHGCK.uasset new file mode 100644 index 0000000..63ba50c Binary files /dev/null and b/Content/__ExternalActors__/Maps/L_Level2/7/WB/UPSQA3FG3J20EIR9JXHGCK.uasset differ diff --git a/Content/__ExternalActors__/Maps/L_Level2/7/Y0/P8GNAMHAQ3WI4B9HOPU0NG.uasset b/Content/__ExternalActors__/Maps/L_Level2/7/Y0/P8GNAMHAQ3WI4B9HOPU0NG.uasset new file mode 100644 index 0000000..7bf5ca8 Binary files /dev/null and b/Content/__ExternalActors__/Maps/L_Level2/7/Y0/P8GNAMHAQ3WI4B9HOPU0NG.uasset differ diff --git a/Content/__ExternalActors__/Maps/L_Level2/C/CC/VUEPCMNI075L1P4GELJ1TI.uasset b/Content/__ExternalActors__/Maps/L_Level2/C/CC/VUEPCMNI075L1P4GELJ1TI.uasset new file mode 100644 index 0000000..6d4265f Binary files /dev/null and b/Content/__ExternalActors__/Maps/L_Level2/C/CC/VUEPCMNI075L1P4GELJ1TI.uasset differ diff --git a/Content/__ExternalActors__/Maps/L_Level2/C/RO/D7H2F19BKXJ2RT6T509JJ7.uasset b/Content/__ExternalActors__/Maps/L_Level2/C/RO/D7H2F19BKXJ2RT6T509JJ7.uasset new file mode 100644 index 0000000..f7f20b9 Binary files /dev/null and b/Content/__ExternalActors__/Maps/L_Level2/C/RO/D7H2F19BKXJ2RT6T509JJ7.uasset differ diff --git a/Content/__ExternalActors__/Maps/L_Level2/C/Y2/FF1AHQSWEZ0EKLIHP0I78L.uasset b/Content/__ExternalActors__/Maps/L_Level2/C/Y2/FF1AHQSWEZ0EKLIHP0I78L.uasset new file mode 100644 index 0000000..e30f230 Binary files /dev/null and b/Content/__ExternalActors__/Maps/L_Level2/C/Y2/FF1AHQSWEZ0EKLIHP0I78L.uasset differ diff --git a/Content/__ExternalActors__/Maps/L_Level2/D/LJ/NLSTOV7I4IGKU9ERSWXTHS.uasset b/Content/__ExternalActors__/Maps/L_Level2/D/LJ/NLSTOV7I4IGKU9ERSWXTHS.uasset new file mode 100644 index 0000000..43d4a7c Binary files /dev/null and b/Content/__ExternalActors__/Maps/L_Level2/D/LJ/NLSTOV7I4IGKU9ERSWXTHS.uasset differ diff --git a/Content/__ExternalActors__/Maps/L_Level2/D/XM/92ZF6XH9GFG7K0RHY3UMF1.uasset b/Content/__ExternalActors__/Maps/L_Level2/D/XM/92ZF6XH9GFG7K0RHY3UMF1.uasset new file mode 100644 index 0000000..8545344 Binary files /dev/null and b/Content/__ExternalActors__/Maps/L_Level2/D/XM/92ZF6XH9GFG7K0RHY3UMF1.uasset differ diff --git a/Content/__ExternalActors__/Maps/L_Level2/E/JR/VTYY1R30TG8FLYTS6AY0JA.uasset b/Content/__ExternalActors__/Maps/L_Level2/E/JR/VTYY1R30TG8FLYTS6AY0JA.uasset new file mode 100644 index 0000000..29bf1a2 Binary files /dev/null and b/Content/__ExternalActors__/Maps/L_Level2/E/JR/VTYY1R30TG8FLYTS6AY0JA.uasset differ diff --git a/Content/__ExternalObjects__/Maps/L_Default/0/7U/PQ1UCPQJZUI5PODRPKCDBV.uasset b/Content/__ExternalObjects__/Maps/L_Default/0/7U/PQ1UCPQJZUI5PODRPKCDBV.uasset deleted file mode 100644 index 97d7a2b..0000000 Binary files a/Content/__ExternalObjects__/Maps/L_Default/0/7U/PQ1UCPQJZUI5PODRPKCDBV.uasset and /dev/null differ diff --git a/Content/__ExternalObjects__/Maps/L_Default/8/LZ/Q1444EM3RZZ2WQ76J6HMTF.uasset b/Content/__ExternalObjects__/Maps/L_Default/8/LZ/Q1444EM3RZZ2WQ76J6HMTF.uasset deleted file mode 100644 index 6b38428..0000000 Binary files a/Content/__ExternalObjects__/Maps/L_Default/8/LZ/Q1444EM3RZZ2WQ76J6HMTF.uasset and /dev/null differ diff --git a/Content/__ExternalObjects__/Maps/L_Default/8/WD/YR82D11ZS7SFF4MIVAALB5.uasset b/Content/__ExternalObjects__/Maps/L_Default/8/WD/YR82D11ZS7SFF4MIVAALB5.uasset deleted file mode 100644 index 12f9ab8..0000000 Binary files a/Content/__ExternalObjects__/Maps/L_Default/8/WD/YR82D11ZS7SFF4MIVAALB5.uasset and /dev/null differ diff --git a/Content/__ExternalObjects__/Maps/L_Default/B/T4/MABZVDKRLP3FY16TB0EB3B.uasset b/Content/__ExternalObjects__/Maps/L_Default/B/T4/MABZVDKRLP3FY16TB0EB3B.uasset deleted file mode 100644 index d0e3e16..0000000 Binary files a/Content/__ExternalObjects__/Maps/L_Default/B/T4/MABZVDKRLP3FY16TB0EB3B.uasset and /dev/null differ diff --git a/Content/__ExternalObjects__/Maps/L_Default/C/L1/8QNSI3Q2UJ22GN0BXYDLOI.uasset b/Content/__ExternalObjects__/Maps/L_Default/C/L1/8QNSI3Q2UJ22GN0BXYDLOI.uasset deleted file mode 100644 index db6a04e..0000000 Binary files a/Content/__ExternalObjects__/Maps/L_Default/C/L1/8QNSI3Q2UJ22GN0BXYDLOI.uasset and /dev/null differ diff --git a/Content/__ExternalObjects__/Maps/L_Default/C/NA/VSQB15ATPLZGQPFNB5L5G9.uasset b/Content/__ExternalObjects__/Maps/L_Default/C/NA/VSQB15ATPLZGQPFNB5L5G9.uasset deleted file mode 100644 index 2f2fc97..0000000 Binary files a/Content/__ExternalObjects__/Maps/L_Default/C/NA/VSQB15ATPLZGQPFNB5L5G9.uasset and /dev/null differ diff --git a/Content/__ExternalObjects__/Maps/L_Level1/2/PW/5UZ9DG6GWQOB3PJI6ENN66.uasset b/Content/__ExternalObjects__/Maps/L_Level1/2/PW/5UZ9DG6GWQOB3PJI6ENN66.uasset new file mode 100644 index 0000000..afdd41e Binary files /dev/null and b/Content/__ExternalObjects__/Maps/L_Level1/2/PW/5UZ9DG6GWQOB3PJI6ENN66.uasset differ diff --git a/Content/__ExternalObjects__/Maps/L_Level1/8/D9/5MU1Q0Q272DKJN4NR9E4EI.uasset b/Content/__ExternalObjects__/Maps/L_Level1/8/D9/5MU1Q0Q272DKJN4NR9E4EI.uasset new file mode 100644 index 0000000..52a72a8 Binary files /dev/null and b/Content/__ExternalObjects__/Maps/L_Level1/8/D9/5MU1Q0Q272DKJN4NR9E4EI.uasset differ diff --git a/Content/__ExternalObjects__/Maps/L_Level1/9/ZH/QNMQC0KHQ6VY1QHIDE9M21.uasset b/Content/__ExternalObjects__/Maps/L_Level1/9/ZH/QNMQC0KHQ6VY1QHIDE9M21.uasset new file mode 100644 index 0000000..815181c Binary files /dev/null and b/Content/__ExternalObjects__/Maps/L_Level1/9/ZH/QNMQC0KHQ6VY1QHIDE9M21.uasset differ diff --git a/Content/__ExternalObjects__/Maps/L_Level1/B/I6/4CZ96YRVKKG6YQ05DBUZ4B.uasset b/Content/__ExternalObjects__/Maps/L_Level1/B/I6/4CZ96YRVKKG6YQ05DBUZ4B.uasset new file mode 100644 index 0000000..ae922a8 Binary files /dev/null and b/Content/__ExternalObjects__/Maps/L_Level1/B/I6/4CZ96YRVKKG6YQ05DBUZ4B.uasset differ diff --git a/Content/__ExternalObjects__/Maps/L_Level1/E/DK/Q67DM9MZR3GHQQXWQBHQVY.uasset b/Content/__ExternalObjects__/Maps/L_Level1/E/DK/Q67DM9MZR3GHQQXWQBHQVY.uasset new file mode 100644 index 0000000..1b11c25 Binary files /dev/null and b/Content/__ExternalObjects__/Maps/L_Level1/E/DK/Q67DM9MZR3GHQQXWQBHQVY.uasset differ diff --git a/Content/__ExternalObjects__/Maps/L_Level1/E/FW/J2SCV40EE0JMURIX9Q5LV2.uasset b/Content/__ExternalObjects__/Maps/L_Level1/E/FW/J2SCV40EE0JMURIX9Q5LV2.uasset new file mode 100644 index 0000000..891a254 Binary files /dev/null and b/Content/__ExternalObjects__/Maps/L_Level1/E/FW/J2SCV40EE0JMURIX9Q5LV2.uasset differ diff --git a/Content/__ExternalObjects__/Maps/L_Level2/1/AO/GNN5DLOEOYCH0Y0UNIXF41.uasset b/Content/__ExternalObjects__/Maps/L_Level2/1/AO/GNN5DLOEOYCH0Y0UNIXF41.uasset new file mode 100644 index 0000000..bd2a3ad Binary files /dev/null and b/Content/__ExternalObjects__/Maps/L_Level2/1/AO/GNN5DLOEOYCH0Y0UNIXF41.uasset differ diff --git a/Content/__ExternalObjects__/Maps/L_Level2/1/UF/XRLBPBQY40X6518UR4VOT2.uasset b/Content/__ExternalObjects__/Maps/L_Level2/1/UF/XRLBPBQY40X6518UR4VOT2.uasset new file mode 100644 index 0000000..a3049d9 Binary files /dev/null and b/Content/__ExternalObjects__/Maps/L_Level2/1/UF/XRLBPBQY40X6518UR4VOT2.uasset differ diff --git a/Content/__ExternalObjects__/Maps/L_Level2/2/N9/6CPJH83V91OKJDP2T3ARE3.uasset b/Content/__ExternalObjects__/Maps/L_Level2/2/N9/6CPJH83V91OKJDP2T3ARE3.uasset new file mode 100644 index 0000000..4bf7fdd Binary files /dev/null and b/Content/__ExternalObjects__/Maps/L_Level2/2/N9/6CPJH83V91OKJDP2T3ARE3.uasset differ diff --git a/Content/__ExternalObjects__/Maps/L_Level2/4/N1/XTUG6CLVCYSRXAWTM40H92.uasset b/Content/__ExternalObjects__/Maps/L_Level2/4/N1/XTUG6CLVCYSRXAWTM40H92.uasset new file mode 100644 index 0000000..ea87fa8 Binary files /dev/null and b/Content/__ExternalObjects__/Maps/L_Level2/4/N1/XTUG6CLVCYSRXAWTM40H92.uasset differ diff --git a/Content/__ExternalObjects__/Maps/L_Level2/6/87/ISL0IYLXYU545TS5SFTKAF.uasset b/Content/__ExternalObjects__/Maps/L_Level2/6/87/ISL0IYLXYU545TS5SFTKAF.uasset new file mode 100644 index 0000000..5ca8e85 Binary files /dev/null and b/Content/__ExternalObjects__/Maps/L_Level2/6/87/ISL0IYLXYU545TS5SFTKAF.uasset differ diff --git a/Content/__ExternalObjects__/Maps/L_Level2/8/ZK/IG4K4DTPXL1GXKWE7KPC3T.uasset b/Content/__ExternalObjects__/Maps/L_Level2/8/ZK/IG4K4DTPXL1GXKWE7KPC3T.uasset new file mode 100644 index 0000000..52272ba Binary files /dev/null and b/Content/__ExternalObjects__/Maps/L_Level2/8/ZK/IG4K4DTPXL1GXKWE7KPC3T.uasset differ diff --git a/Plugins/Cog/Source/CogDebug/Private/CogDebug.cpp b/Plugins/Cog/Source/CogDebug/Private/CogDebug.cpp index af48ab3..ca83704 100644 --- a/Plugins/Cog/Source/CogDebug/Private/CogDebug.cpp +++ b/Plugins/Cog/Source/CogDebug/Private/CogDebug.cpp @@ -3,13 +3,14 @@ #include "CogCommonDebugFilteredActorInterface.h" #include "CogDebugDrawHelper.h" #include "CogDebugReplicator.h" -#include "imgui.h" -#include "Engine/World.h" #include "Engine/Engine.h" +#include "Engine/World.h" +#include "imgui.h" #include "Kismet/KismetMathLibrary.h" +#include "Misc/EngineVersionComparison.h" //-------------------------------------------------------------------------------------------------------------------------- -TWeakObjectPtr FCogDebug::Selection; +TWeakObjectPtr FCogDebug::Selection[] = {}; FCogDebugSettings FCogDebug::Settings = FCogDebugSettings(); //-------------------------------------------------------------------------------------------------------------------------- @@ -32,7 +33,7 @@ bool FCogDebug::IsDebugActiveForObject(const UObject* WorldContextObject) return true; } - const bool Result = IsDebugActiveForObject_Internal(WorldContextObject, Selection.Get(), Settings.bIsFilteringBySelection); + const bool Result = IsDebugActiveForObject_Internal(WorldContextObject, Selection[GetPieSessionId()].Get(), Settings.bIsFilteringBySelection); return Result; } @@ -88,21 +89,52 @@ bool FCogDebug::IsDebugActiveForObject_Internal(const UObject* WorldContextObjec //-------------------------------------------------------------------------------------------------------------------------- AActor* FCogDebug::GetSelection() { - return Selection.Get(); + return Selection[GetPieSessionId()].Get(); } +//-------------------------------------------------------------------------------------------------------------------------- +int32 FCogDebug::GetPieSessionId() +{ +#if UE_EDITOR +#if UE_VERSION_OLDER_THAN(5, 5, 0) + return GPlayInEditorID; +#else + return UE::GetPlayInEditorID(); +#endif +#else + return 0; +#endif +} + + //-------------------------------------------------------------------------------------------------------------------------- void FCogDebug::SetSelection(const UWorld* World, AActor* Value) { - Selection = Value; + Selection[GetPieSessionId()] = Value; - if (World != nullptr && World->GetNetMode() == NM_Client) + ReplicateSelection(World, Value); +} + +//-------------------------------------------------------------------------------------------------------------------------- +void FCogDebug::ReplicateSelection(const UWorld* World, AActor* Value) +{ + if (World == nullptr) { - if (ACogDebugReplicator* Replicator = ACogDebugReplicator::GetLocalReplicator(*World)) - { - Replicator->Server_SetSelection(Value); - } + return; } + + ACogDebugReplicator* Replicator = ACogDebugReplicator::GetLocalReplicator(*World); + if (Replicator == nullptr) + { + return; + } + + if (Replicator->HasAuthority()) + { + return; + } + + Replicator->Server_SetSelection(Value, Settings.ReplicateSelection); } //-------------------------------------------------------------------------------------------------------------------------- @@ -306,7 +338,7 @@ void FCogDebug::GetDebugDrawOverlapSettings(FCogDebugDrawOverlapParams& Params) Params.NoHitColor = Settings.CollisionQueryNoHitColor; Params.DrawHitPrimitives = Settings.CollisionQueryDrawHitPrimitives; Params.DrawHitPrimitiveActorsName = Settings.CollisionQueryDrawHitPrimitiveActorsName; - Params.HitPrimitiveActorsNameShadow = Settings.CollisionQueryHitPrimitiveActorsNameShadow; + Params.DrawHitPrimitiveActorsNameShadow = Settings.CollisionQueryHitPrimitiveActorsNameShadow; Params.HitPrimitiveActorsNameSize = Settings.CollisionQueryHitPrimitiveActorsNameSize; Params.Persistent = false; Params.LifeTime = 0.0f; diff --git a/Plugins/Cog/Source/CogDebug/Private/CogDebugDraw.cpp b/Plugins/Cog/Source/CogDebug/Private/CogDebugDraw.cpp index 962a5de..1e32374 100644 --- a/Plugins/Cog/Source/CogDebug/Private/CogDebugDraw.cpp +++ b/Plugins/Cog/Source/CogDebug/Private/CogDebugDraw.cpp @@ -1,19 +1,20 @@ #include "CogDebugDraw.h" +#include "CogDebug.h" #include "CogDebugDrawHelper.h" #include "CogDebugDrawImGui.h" #include "CogDebugLog.h" #include "CogDebugReplicator.h" -#include "CogDebug.h" #include "CogDebugShape.h" #include "CogImguiHelper.h" +#include "Components/BoxComponent.h" +#include "Components/SkeletalMeshComponent.h" +#include "DrawDebugHelpers.h" #include "Engine/Engine.h" #include "Engine/SkeletalMesh.h" -#include "VisualLogger/VisualLogger.h" #include "Engine/World.h" -#include "DrawDebugHelpers.h" #include "ReferenceSkeleton.h" -#include "Components/SkeletalMeshComponent.h" +#include "VisualLogger/VisualLogger.h" #if ENABLE_COG @@ -638,6 +639,96 @@ void FCogDebugDraw::Skeleton(const FLogCategoryBase& LogCategory, const USkeleta } } +//-------------------------------------------------------------------------------------------------------------------------- +void FCogDebugDraw::LineTrace(const FLogCategoryBase& LogCategory, const UObject* WorldContextObject, const FVector& Start, const FVector& End, const bool HasHits, TArray& HitResults, const FCogDebugDrawLineTraceParams& Settings) +{ + if (FCogDebugLog::IsLogCategoryActive(LogCategory) == false) + { return; } + + const UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::LogAndReturnNull); + if (World == nullptr) + { return; } + + Settings.Persistent = FCogDebug::GetDebugPersistent(Settings.Persistent); + FCogDebugDrawHelper::DrawLineTrace(World, Start, End, HasHits, HitResults, Settings); + + ReplicateShape(WorldContextObject, + FCogDebugShape::MakeArrow(Start, + End, + FCogDebug::Settings.ArrowSize, + HasHits + ? Settings.HitColor + : Settings.NoHitColor, + FCogDebug::Settings.Thickness, + Settings.Persistent, + Settings.DepthPriority)); + + ReplicateHitResults(WorldContextObject, HitResults, Settings); +} + +//-------------------------------------------------------------------------------------------------------------------------- +void FCogDebugDraw::Sweep(const FLogCategoryBase& LogCategory, const UObject* WorldContextObject, const FCollisionShape& Shape, const FVector& Start, const FVector& End, const FQuat& Rotation, const bool HasHits, TArray& HitResults, const FCogDebugDrawSweepParams& Settings) +{ + if (FCogDebugLog::IsLogCategoryActive(LogCategory) == false) + { return; } + + const UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::LogAndReturnNull); + if (World == nullptr) + { return; } + + FCogDebugDrawHelper::DrawSweep(World, Shape, Start, End, Rotation, HasHits, HitResults, Settings); + + const FColor Color = HasHits + ? Settings.HitColor + : Settings.NoHitColor; + ReplicateShape(WorldContextObject, + FCogDebugShape::MakeCollisionShape(Shape, + Start, + Rotation, + Shape.GetExtent(), + Color, + FCogDebug::Settings.Thickness, + Settings.Persistent, + Settings.DepthPriority)); + ReplicateShape(WorldContextObject, + FCogDebugShape::MakeArrow(Start, + End, + FCogDebug::Settings.ArrowSize, + Color, + FCogDebug::Settings.Thickness, + Settings.Persistent, + Settings.DepthPriority)); + + ReplicateHitResults(WorldContextObject, HitResults, Settings); +} + +//-------------------------------------------------------------------------------------------------------------------------- +void FCogDebugDraw::Overlap(const FLogCategoryBase& LogCategory, const UObject* WorldContextObject, const FCollisionShape& Shape, const FVector& Location, const FQuat& Rotation, TArray& OverlapResults, const FCogDebugDrawOverlapParams& Settings) +{ + if (FCogDebugLog::IsLogCategoryActive(LogCategory) == false) + { return; } + + const UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::LogAndReturnNull); + if (World == nullptr) + { return; } + + FCogDebugDrawHelper::DrawOverlap(World, Shape, Location, Rotation, OverlapResults, Settings); + + const FColor Color = OverlapResults.Num() > 0 + ? Settings.HitColor + : Settings.NoHitColor; + ReplicateShape(WorldContextObject, + FCogDebugShape::MakeCollisionShape(Shape, + Location, + Rotation, + Shape.GetExtent(), + Color, + FCogDebug::Settings.Thickness, + Settings.Persistent, + Settings.DepthPriority)); + + // TODO: replicate overlap results +} //-------------------------------------------------------------------------------------------------------------------------- void FCogDebugDraw::ReplicateShape(const UObject* WorldContextObject, const FCogDebugShape& Shape) @@ -673,4 +764,112 @@ void FCogDebugDraw::ReplicateShape(const UObject* WorldContextObject, const FCog } } +//-------------------------------------------------------------------------------------------------------------------------- +void FCogDebugDraw::ReplicateHitResults(const UObject* WorldContextObject, const TArray& HitResults, const FCogDebugDrawLineTraceParams& Settings) +{ + TSet AlreadyDrawnPrimitives; + TSet AlreadyDrawnActors; + + for (const FHitResult& HitResult : HitResults) + { + const FColor& HitColor = Settings.HitColor; + + if (Settings.DrawHitLocation) + { + ReplicateShape(WorldContextObject, + FCogDebugShape::MakePoint(HitResult.Location, + Settings.HitPointSize, + HitColor, + Settings.Persistent, + Settings.DepthPriority)); + } + + if (Settings.DrawHitImpactPoints) + { + ReplicateShape(WorldContextObject, + FCogDebugShape::MakePoint(HitResult.ImpactPoint, + Settings.HitPointSize, + HitColor, + Settings.Persistent, + Settings.DepthPriority)); + } + + if (Settings.DrawHitNormals) + { + ReplicateShape(WorldContextObject, + FCogDebugShape::MakeArrow(HitResult.Location, + HitResult.Location + HitResult.Normal * 20.0f, + FCogDebug::Settings.ArrowSize, + HitColor, + Settings.Thickness, + Settings.Persistent, + Settings.DepthPriority)); + } + + if (Settings.DrawHitImpactNormals) + { + ReplicateShape(WorldContextObject, + FCogDebugShape::MakeArrow(HitResult.ImpactPoint, + HitResult.Location + HitResult.ImpactNormal * 20.0f, + FCogDebug::Settings.ArrowSize, + HitColor, + Settings.Thickness, + Settings.Persistent, + Settings.DepthPriority)); + } + + if (Settings.DrawHitPrimitives) + { + const UPrimitiveComponent* PrimitiveComponent = HitResult.GetComponent(); + if (PrimitiveComponent == nullptr) + { + continue; + } + + if (AlreadyDrawnPrimitives.Contains(PrimitiveComponent)) + { + continue; + } + + const UBoxComponent* BoxComponent = Cast(PrimitiveComponent); + const FCollisionShape Shape = PrimitiveComponent->GetCollisionShape(); + + AlreadyDrawnPrimitives.Add(PrimitiveComponent); + const ECollisionChannel CollisionObjectType = PrimitiveComponent->GetCollisionObjectType(); + const FColor PrimitiveColor = Settings.ChannelColors[CollisionObjectType]; + + if (Shape.ShapeType == ECollisionShape::Box && BoxComponent == nullptr) + { + FVector Location; + FVector Extent; + PrimitiveComponent->Bounds.GetBox().GetCenterAndExtents(Location, Extent); + + // TODO: this adds padding to prevent Z fight. Maybe add this as a parameter. + Extent += FVector::OneVector; + + ReplicateShape(WorldContextObject, + FCogDebugShape::MakeBox(Location, + FRotator::ZeroRotator, + Extent, + PrimitiveColor, + Settings.Thickness, + Settings.Persistent, + Settings.DepthPriority)); + } + else + { + ReplicateShape(WorldContextObject, + FCogDebugShape::MakeCollisionShape(Shape, + PrimitiveComponent->GetComponentLocation(), + PrimitiveComponent->GetComponentQuat(), + Shape.GetExtent(), + PrimitiveColor, + Settings.Thickness, + Settings.Persistent, + Settings.DepthPriority)); + } + } + } +} + #endif //ENABLE_COG diff --git a/Plugins/Cog/Source/CogDebug/Private/CogDebugDrawHelper.cpp b/Plugins/Cog/Source/CogDebug/Private/CogDebugDrawHelper.cpp index cf3be2c..56f4bb1 100644 --- a/Plugins/Cog/Source/CogDebug/Private/CogDebugDrawHelper.cpp +++ b/Plugins/Cog/Source/CogDebug/Private/CogDebugDrawHelper.cpp @@ -2,10 +2,14 @@ #include "CogDebug.h" #include "Components/LineBatchComponent.h" -#include "Engine/Engine.h" -#include "DrawDebugHelpers.h" #include "Components/BoxComponent.h" +#include "DrawDebugHelpers.h" +#include "Engine/Engine.h" #include "Engine/OverlapResult.h" +#include "PhysicsEngine/PhysicsAsset.h" +#include "PhysicsEngine/SkeletalBodySetup.h" +#include "PhysicsEngine/SphylElem.h" +#include "Runtime/Experimental/Chaos/Private/Chaos/PhysicsObjectInternal.h" namespace { @@ -307,9 +311,6 @@ void FCogDebugDrawHelper::DrawHitResults( const TArray& HitResults, const FCogDebugDrawLineTraceParams& Settings) { - TSet AlreadyDrawnPrimitives; - TSet AlreadyDrawnActors; - for (const FHitResult& HitResult : HitResults) { const FColor& HitColor = Settings.HitColor; @@ -374,33 +375,19 @@ void FCogDebugDrawHelper::DrawHitResults( continue; } - if (AlreadyDrawnPrimitives.Contains(PrimitiveComponent)) - { - continue; - } - - AlreadyDrawnPrimitives.Add(PrimitiveComponent); const ECollisionChannel CollisionObjectType = PrimitiveComponent->GetCollisionObjectType(); const FColor PrimitiveColor = Settings.ChannelColors[CollisionObjectType]; - DrawPrimitiveComponent(*PrimitiveComponent, PrimitiveColor, Settings.Persistent, Settings.LifeTime, Settings.DepthPriority, Settings.Thickness); - - if (Settings.DrawHitPrimitiveActorsName) - { - const AActor* Actor = PrimitiveComponent->GetOwner(); - if (Actor == nullptr) - { - continue; - } - - if (AlreadyDrawnActors.Contains(Actor)) - { - continue; - } - - AlreadyDrawnActors.Add(Actor); - const FColor TextColor = PrimitiveColor.WithAlpha(255); - DrawDebugString(World, Actor->GetActorLocation(), GetNameSafe(Actor->GetClass()), nullptr, TextColor, 0.0f, Settings.HitPrimitiveActorsNameShadow, Settings.HitPrimitiveActorsNameSize); - } + DrawPrimitiveComponent( + *PrimitiveComponent, + HitResult.PhysicsObject->GetBodyIndex(), + PrimitiveColor, + Settings.Persistent, + Settings.LifeTime, + Settings.DepthPriority, + Settings.Thickness, + Settings.DrawHitPrimitiveActorsName, + Settings.DrawHitPrimitiveActorsNameShadow, + Settings.HitPrimitiveActorsNameSize); } } } @@ -488,7 +475,17 @@ void FCogDebugDrawHelper::DrawOverlap( { const ECollisionChannel CollisionObjectType = PrimitiveComponent->GetCollisionObjectType(); const FColor PrimitiveColor = Settings.ChannelColors[CollisionObjectType]; - DrawPrimitiveComponent(*PrimitiveComponent, PrimitiveColor, Settings.Persistent, Settings.LifeTime, Settings.DepthPriority, Settings.Thickness); + DrawPrimitiveComponent( + *PrimitiveComponent, + OverlapResult.PhysicsObject->GetBodyIndex(), + PrimitiveColor, + Settings.Persistent, + Settings.LifeTime, + Settings.DepthPriority, + Settings.Thickness, + Settings.DrawHitPrimitiveActorsName, + Settings.DrawHitPrimitiveActorsNameShadow, + Settings.HitPrimitiveActorsNameSize); } } } @@ -496,12 +493,16 @@ void FCogDebugDrawHelper::DrawOverlap( //-------------------------------------------------------------------------------------------------------------------------- void FCogDebugDrawHelper::DrawPrimitiveComponent( - const UPrimitiveComponent& PrimitiveComponent, - const FColor& Color, - const bool Persistent, - const float LifeTime, - const uint8 DepthPriority, - const float Thickness) + const UPrimitiveComponent& PrimitiveComponent, + const int32 BodyIndex, + const FColor& Color, + const bool Persistent, + const float LifeTime, + const uint8 DepthPriority, + const float Thickness, + const bool DrawName, + const bool DrawNameShadow, + const float DrawNameSize) { const UWorld* World = PrimitiveComponent.GetWorld(); if (World == nullptr) @@ -509,46 +510,131 @@ void FCogDebugDrawHelper::DrawPrimitiveComponent( return; } - const UBoxComponent* BoxComponent = Cast(&PrimitiveComponent);; - const FCollisionShape Shape = PrimitiveComponent.GetCollisionShape(); - - if (Shape.ShapeType == ECollisionShape::Box && BoxComponent == nullptr) + if (const USkeletalMeshComponent* SkeletalMeshComponent = Cast(&PrimitiveComponent)) { - FVector Location; - FVector Extent; - PrimitiveComponent.Bounds.GetBox().GetCenterAndExtents(Location, Extent); + const UPhysicsAsset* PhysicsAsset = SkeletalMeshComponent->GetPhysicsAsset(); + if (PhysicsAsset->SkeletalBodySetups.IsValidIndex(BodyIndex) == false) + { + return; + } - // TODO: this adds padding to prevent Z fight. Maybe add this as a parameter. - Extent += FVector::OneVector; + const USkeletalBodySetup* BodySetup = PhysicsAsset->SkeletalBodySetups[BodyIndex]; + const int32 BoneIndex = SkeletalMeshComponent->GetBoneIndex(BodySetup->BoneName); + const FTransform BoneTransform = SkeletalMeshComponent->GetBoneTransform(BoneIndex); - DrawDebugSolidBox( - World, - Location, - Extent, - FQuat::Identity, - Color, - Persistent, - LifeTime, - DepthPriority); + if (DrawName) + { + DrawDebugString(World, BoneTransform.GetLocation(), BodySetup->BoneName.ToString(), nullptr, Color.WithAlpha(255), 0.0f, DrawNameShadow, DrawNameSize); + } - DrawDebugBox( - World, - Location, - Extent, - FQuat::Identity, - Color, - Persistent, - LifeTime, - DepthPriority, - Thickness); + for (const FKSphereElem& Sphere : BodySetup->AggGeom.SphereElems) + { + const FTransform transform = Sphere.GetTransform() * BoneTransform; + DrawSphere( + World, + transform.GetLocation(), + Sphere.Radius, + FCogDebug::GetDebugSegments(), + Color, + Persistent, + LifeTime, + DepthPriority, + Thickness); + } + + for (const FKBoxElem& Box : BodySetup->AggGeom.BoxElems) + { + const FTransform transform = Box.GetTransform() * BoneTransform; + + DrawDebugBox( + World, + transform.GetLocation(), + FVector(Box.X, Box.Y, Box.Z) * 0.5f, + transform.GetRotation(), + Color, + Persistent, + LifeTime, + DepthPriority, + Thickness); + } + + for (const FKSphylElem& Sphy : BodySetup->AggGeom.SphylElems) + { + const FTransform transform = Sphy.GetTransform() * BoneTransform; + + DrawDebugCapsule( + World, + transform.GetLocation(), + Sphy.Length * 0.5f, + Sphy.Radius, + transform.GetRotation(), + Color, + Persistent, + LifeTime, + DepthPriority, + Thickness); + } } else { - const FVector Location = PrimitiveComponent.GetComponentLocation(); - const FQuat Rotation = PrimitiveComponent.GetComponentQuat(); - const FVector Scale = PrimitiveComponent.GetComponentScale(); - DrawShape(World, Shape, Location, Rotation, Scale, Color, Persistent, LifeTime, DepthPriority, Thickness); + const AActor* Actor = PrimitiveComponent.GetOwner(); + + const UBoxComponent* BoxComponent = Cast(&PrimitiveComponent); + const FCollisionShape Shape = PrimitiveComponent.GetCollisionShape(); + + if (Shape.ShapeType == ECollisionShape::Box && BoxComponent == nullptr) + { + FVector Location; + FVector Extent; + PrimitiveComponent.Bounds.GetBox().GetCenterAndExtents(Location, Extent); + + if (DrawName) + { + DrawDebugString(World, Location, GetNameSafe(Actor), nullptr, Color.WithAlpha(255), 0.0f, DrawNameShadow, DrawNameSize); + } + + // TODO: this adds padding to prevent Z fight. Maybe add this as a parameter. + Extent += FVector::OneVector; + + DrawDebugSolidBox( + World, + Location, + Extent, + FQuat::Identity, + Color, + Persistent, + LifeTime, + DepthPriority); + + DrawDebugBox( + World, + Location, + Extent, + FQuat::Identity, + Color, + Persistent, + LifeTime, + DepthPriority, + Thickness); + + + } + else + { + const FVector Location = PrimitiveComponent.GetComponentLocation(); + const FQuat Rotation = PrimitiveComponent.GetComponentQuat(); + const FVector Scale = PrimitiveComponent.GetComponentScale(); + + if (DrawName) + { + DrawDebugString(World, Location, GetNameSafe(Actor), nullptr, Color.WithAlpha(255), 0.0f, DrawNameShadow, DrawNameSize); + } + + DrawShape(World, Shape, Location, Rotation, Scale, Color, Persistent, LifeTime, DepthPriority, Thickness); + } } + + } //-------------------------------------------------------------------------------------------------------------------------- diff --git a/Plugins/Cog/Source/CogDebug/Private/CogDebugLog.cpp b/Plugins/Cog/Source/CogDebug/Private/CogDebugLog.cpp index 6a9ae3a..8e2f424 100644 --- a/Plugins/Cog/Source/CogDebug/Private/CogDebugLog.cpp +++ b/Plugins/Cog/Source/CogDebug/Private/CogDebugLog.cpp @@ -130,6 +130,7 @@ FLogCategoryBase* FCogDebugLog::FindLogCategory(const FName CategoryName) { return LogCategoryInfo->LogCategory; } + return nullptr; } diff --git a/Plugins/Cog/Source/CogDebug/Private/CogDebugPlot.cpp b/Plugins/Cog/Source/CogDebug/Private/CogDebugPlot.cpp index 0cb8e73..fb34a22 100644 --- a/Plugins/Cog/Source/CogDebug/Private/CogDebugPlot.cpp +++ b/Plugins/Cog/Source/CogDebug/Private/CogDebugPlot.cpp @@ -1,7 +1,6 @@ #include "CogDebugPlot.h" #include "CogDebug.h" -#include "CogDebugDraw.h" #include "CogDebugHelper.h" #include "CogImguiHelper.h" #include "Engine/Engine.h" @@ -9,24 +8,28 @@ FCogDebugPlotEvent FCogDebugPlot::DefaultEvent; TArray FCogDebugPlot::Plots; +TArray FCogDebugPlot::Events; bool FCogDebugPlot::IsVisible = false; bool FCogDebugPlot::Pause = false; FName FCogDebugPlot::LastAddedEventPlotName = NAME_None; int32 FCogDebugPlot::LastAddedEventIndex = INDEX_NONE; +TMap> FCogDebugPlot::OccupationMap; //-------------------------------------------------------------------------------------------------------------------------- // FCogPlotEvent //-------------------------------------------------------------------------------------------------------------------------- float FCogDebugPlotEvent::GetActualEndTime(const FCogDebugPlotEntry& Plot) const { - const float ActualEndTime = EndTime == 0.0f ? Plot.Time : EndTime; + const UWorld* World = Plot.World.Get(); + const float WorldTime = World != nullptr ? World->GetTimeSeconds() : 0.0f; + const float ActualEndTime = EndTime != 0.0f ? EndTime : WorldTime; return ActualEndTime; } //-------------------------------------------------------------------------------------------------------------------------- uint64 FCogDebugPlotEvent::GetActualEndFrame(const FCogDebugPlotEntry& Plot) const { - const float ActualEndFame = EndFrame == 0.0f ? Plot.Frame : EndFrame; + const float ActualEndFame = EndFrame != 0.0f ? EndFrame : GFrameCounter; return ActualEndFame; } @@ -119,9 +122,8 @@ void FCogDebugPlotEntry::AddPoint(float X, float Y) //-------------------------------------------------------------------------------------------------------------------------- FCogDebugPlotEvent& FCogDebugPlotEntry::AddEvent( - const FCogDebugPlotEntry& OwnwePlot, - FString OwnerName, - bool IsInstant, + const FString& OwnerName, + const bool IsInstant, const FName EventId, const int32 Row, const FColor& Color) @@ -131,10 +133,9 @@ FCogDebugPlotEvent& FCogDebugPlotEntry::AddEvent( Events.Reserve(200); } - //----------------------------------------------------------------------- - // We currently having two events with the same name at the same time. - // So we stop the current one if any exist. - //----------------------------------------------------------------------- + //---------------------------- + // Stop if it already exist. + //---------------------------- StopEvent(EventId); FCogDebugPlotEvent* Event = nullptr; @@ -155,11 +156,16 @@ FCogDebugPlotEvent& FCogDebugPlotEntry::AddEvent( Event->Id = EventId; Event->OwnerName = OwnerName; Event->DisplayName = EventId.ToString(); - Event->StartTime = OwnwePlot.Time; - Event->EndTime = IsInstant ? OwnwePlot.Time : 0.0f; - Event->StartFrame = OwnwePlot.Frame; - Event->EndFrame = IsInstant ? OwnwePlot.Frame : 0.0f; - Event->Row = (Row == FCogDebugPlot::AutoRow) ? OwnwePlot.FindFreeRow() : Row; + Event->StartTime = Time; + Event->EndTime = IsInstant ? Time : 0.0f; + Event->StartFrame = Frame; + Event->EndFrame = IsInstant ? Frame : 0.0f; + Event->Row = (Row == FCogDebugPlot::AutoRow) ? FCogDebugPlot::FindFreeGraphRow(GraphIndex) : Row; + + if (IsInstant == false) + { + FCogDebugPlot::OccupyGraphRow(GraphIndex, Event->Row); + } MaxRow = FMath::Max(Event->Row, MaxRow); @@ -168,7 +174,7 @@ FCogDebugPlotEvent& FCogDebugPlotEntry::AddEvent( Event->BorderColor = FCogImguiHelper::ToImColor(BorderColor); Event->FillColor = FCogImguiHelper::ToImColor(FillColor); - FCogDebugPlot::LastAddedEventPlotName = OwnwePlot.Name; + FCogDebugPlot::LastAddedEventPlotName = Name; FCogDebugPlot::LastAddedEventIndex = AddedIndex; return *Event; @@ -187,18 +193,13 @@ FCogDebugPlotEvent& FCogDebugPlotEntry::StopEvent(const FName EventId) { Event->EndTime = Time; Event->EndFrame = Frame; + + FCogDebugPlot::FreeGraphRow(GraphIndex, Event->Row); } return *Event; } -//-------------------------------------------------------------------------------------------------------------------------- -void FCogDebugPlotEntry::UpdateTime(const UWorld* World) -{ - Time = World ? World->GetTimeSeconds() : 0.0; - Frame = GFrameCounter; -} - //-------------------------------------------------------------------------------------------------------------------------- FCogDebugPlotEvent* FCogDebugPlotEntry::GetLastEvent() { @@ -240,65 +241,17 @@ FCogDebugPlotEvent* FCogDebugPlotEntry::FindLastEventByName(FName EventId) } //-------------------------------------------------------------------------------------------------------------------------- -int32 FCogDebugPlotEntry::FindFreeRow() const +void FCogDebugPlotEntry::AssignGraphAndAxis(int32 InGraph, ImAxis InYAxis) { - static float InstantTimeThreshold = 1.0f; - static float TotalTimeThreshold = 10.0f; - TSet OccupiedRows; - - for (int32 i = Events.Num() - 1; i >= 0; --i) - { - int32 Index = i; - if (EventOffset != 0) - { - Index = (i + EventOffset) % Events.Num(); - } - const FCogDebugPlotEvent& Event = Events[Index]; - - if (Event.EndTime != 0.0f && Time > Event.EndTime + TotalTimeThreshold) - { - break; - } - - if (Event.StartTime == Event.EndTime && Time > Event.EndTime + InstantTimeThreshold) - { - continue; - } - - if (Event.EndTime != 0.0f) - { - continue; - } - - OccupiedRows.Add(Event.Row); - } - - int32 FreeRow = 0; - while (true) - { - if (OccupiedRows.Contains(FreeRow) == false) - { - break; - } - - FreeRow++; - } - - return FreeRow; + GraphIndex = InGraph; + YAxis = InYAxis; } //-------------------------------------------------------------------------------------------------------------------------- -void FCogDebugPlotEntry::AssignAxis(int32 Row, ImAxis YAxis) +void FCogDebugPlotEntry::ResetGraphAndAxis() { - CurrentRow = Row; - CurrentYAxis = YAxis; -} - -//-------------------------------------------------------------------------------------------------------------------------- -void FCogDebugPlotEntry::ResetAxis() -{ - CurrentRow = INDEX_NONE; - CurrentYAxis = ImAxis_COUNT; + GraphIndex = INDEX_NONE; + YAxis = ImAxis_COUNT; } //-------------------------------------------------------------------------------------------------------------------------- @@ -341,7 +294,7 @@ bool FCogDebugPlotEntry::FindValue(float x, float& y) const Index = (i + ValueOffset) % Values.size(); } - ImVec2 Point = Values[Index]; + const ImVec2 Point = Values[Index]; if (Point.x > x) { FoundAfter = true; @@ -368,6 +321,8 @@ bool FCogDebugPlotEntry::FindValue(float x, float& y) const void FCogDebugPlot::Reset() { Plots.Empty(); + Events.Empty(); + OccupationMap.Empty(); Pause = false; ResetLastAddedEvent(); } @@ -375,11 +330,17 @@ void FCogDebugPlot::Reset() //-------------------------------------------------------------------------------------------------------------------------- void FCogDebugPlot::Clear() { - for (FCogDebugPlotEntry& Entry : FCogDebugPlot::Plots) + for (FCogDebugPlotEntry& Entry : Plots) { Entry.Clear(); } + for (FCogDebugPlotEntry& Entry : Events) + { + Entry.Clear(); + } + + OccupationMap.Empty(); ResetLastAddedEvent(); } @@ -393,7 +354,7 @@ void FCogDebugPlot::ResetLastAddedEvent() //-------------------------------------------------------------------------------------------------------------------------- FCogDebugPlotEvent* FCogDebugPlot::GetLastAddedEvent() { - FCogDebugPlotEntry* Plot = FindPlot(LastAddedEventPlotName); + FCogDebugPlotEntry* Plot = FindEntry(true, LastAddedEventPlotName); if (Plot == nullptr) { return nullptr; @@ -403,10 +364,27 @@ FCogDebugPlotEvent* FCogDebugPlot::GetLastAddedEvent() } //-------------------------------------------------------------------------------------------------------------------------- -FCogDebugPlotEntry* FCogDebugPlot::FindPlot(const FName Name) +FCogDebugPlotEntry* FCogDebugPlot::FindEntry(const FName Name) { - FCogDebugPlotEntry* Plot = Plots.FindByPredicate([Name](const FCogDebugPlotEntry& P) { return P.Name == Name; }); - return Plot; + if (FCogDebugPlotEntry* Event = Events.FindByPredicate([Name](const FCogDebugPlotEntry& P) { return P.Name == Name; })) + { + return Event; + } + + if (FCogDebugPlotEntry* Plot = Plots.FindByPredicate([Name](const FCogDebugPlotEntry& P) { return P.Name == Name; })) + { + return Plot; + } + + return nullptr; +} + +//-------------------------------------------------------------------------------------------------------------------------- +FCogDebugPlotEntry* FCogDebugPlot::FindEntry(bool IsEvent, const FName Name) +{ + TArray* Entries = IsEvent ? &Events : &Plots; + FCogDebugPlotEntry* Entry = Entries->FindByPredicate([Name](const FCogDebugPlotEntry& P) { return P.Name == Name; }); + return Entry; } //-------------------------------------------------------------------------------------------------------------------------- @@ -431,19 +409,20 @@ FCogDebugPlotEntry* FCogDebugPlot::RegisterPlot(const UObject* WorldContextObjec return nullptr; } - FCogDebugPlotEntry* EntryPtr = FindPlot(PlotName); + FCogDebugPlotEntry* EntryPtr = FindEntry(IsEventPlot, PlotName); if (EntryPtr == nullptr) { - EntryPtr = &Plots.AddDefaulted_GetRef(); + TArray* Entries = IsEventPlot ? &Events : &Plots; + EntryPtr = &Entries->AddDefaulted_GetRef(); EntryPtr->Name = PlotName; EntryPtr->IsEventPlot = IsEventPlot; - Plots.Sort([](const FCogDebugPlotEntry& A, const FCogDebugPlotEntry& B) { return A.Name.ToString().Compare(B.Name.ToString()) < 0; }); + Entries->Sort([](const FCogDebugPlotEntry& A, const FCogDebugPlotEntry& B) { return A.Name.ToString().Compare(B.Name.ToString()) < 0; }); } - if (EntryPtr->CurrentYAxis == ImAxis_COUNT) - { - return nullptr; - } + //if (EntryPtr->YAxis == ImAxis_COUNT) + //{ + // return nullptr; + //} const float Time = World->GetTimeSeconds(); if (Time < EntryPtr->Time) @@ -451,6 +430,7 @@ FCogDebugPlotEntry* FCogDebugPlot::RegisterPlot(const UObject* WorldContextObjec EntryPtr->Clear(); } + EntryPtr->World = World; EntryPtr->Time = World->GetTimeSeconds(); EntryPtr->Frame = GFrameCounter; @@ -479,7 +459,7 @@ FCogDebugPlotEvent& FCogDebugPlot::PlotEvent(const UObject* WorldContextObject, return DefaultEvent; } - FCogDebugPlotEvent& Event = Plot->AddEvent(*Plot, GetNameSafe(WorldContextObject), IsInstant, EventId, Row, Color); + FCogDebugPlotEvent& Event = Plot->AddEvent(GetNameSafe(WorldContextObject), IsInstant, EventId, Row, Color); return Event; } @@ -522,3 +502,59 @@ FCogDebugPlotEvent& FCogDebugPlot::PlotEventToggle(const UObject* WorldContextOb return PlotEventStop(WorldContextObject, PlotName, EventId); } } + + +//-------------------------------------------------------------------------------------------------------------------------- +void FCogDebugPlot::OccupyGraphRow(const int32 InGraphIndex, const int32 InRow) +{ + TMap& GraphOccupation = OccupationMap.FindOrAdd(InGraphIndex); + + if (int32* RowOccupation = GraphOccupation.Find(InRow)) + { + (*RowOccupation)++; + } + else + { + GraphOccupation.Add(InRow, 1); + } +} + +//-------------------------------------------------------------------------------------------------------------------------- +void FCogDebugPlot::FreeGraphRow(const int32 InGraphIndex, const int32 Row) +{ + TMap* GraphOccupation = OccupationMap.Find(InGraphIndex); + if (GraphOccupation == nullptr) + { return; } + + int32* RowOccupation = GraphOccupation->Find(Row); + if (RowOccupation == nullptr) + { return; } + + (*RowOccupation)--; +} + +//-------------------------------------------------------------------------------------------------------------------------- +int32 FCogDebugPlot::FindFreeGraphRow(const int32 InGraphIndex) +{ + constexpr int32 MaxRows = 100; + + int32 FreeRow = 0; + + TMap* GraphOccupation = OccupationMap.Find(InGraphIndex); + if (GraphOccupation == nullptr) + { + return FreeRow; + } + + for (; FreeRow < MaxRows; ++FreeRow) + { + const int32* Occupation = GraphOccupation->Find(FreeRow); + if (Occupation == nullptr || *Occupation == 0) + { + break; + } + } + + return FreeRow; +} + diff --git a/Plugins/Cog/Source/CogDebug/Private/CogDebugReplicator.cpp b/Plugins/Cog/Source/CogDebug/Private/CogDebugReplicator.cpp index f0ea6a6..a2a95d2 100644 --- a/Plugins/Cog/Source/CogDebug/Private/CogDebugReplicator.cpp +++ b/Plugins/Cog/Source/CogDebug/Private/CogDebugReplicator.cpp @@ -82,7 +82,7 @@ void ACogDebugReplicator::BeginPlay() if (OwnerPlayerController != nullptr && OwnerPlayerController->IsLocalController()) { Server_RequestAllCategoriesVerbosity(); - Server_SetSelection(FCogDebug::GetSelection()); + Server_SetSelection(FCogDebug::GetSelection(), FCogDebug::Settings.ReplicateSelection); Server_SetIsFilteringBySelection(FCogDebug::GetIsFilteringBySelection()); } } @@ -210,12 +210,22 @@ void ACogDebugReplicator::Server_SetIsFilteringBySelection_Implementation(bool V } //-------------------------------------------------------------------------------------------------------------------------- -void ACogDebugReplicator::Server_SetSelection_Implementation(AActor* Value) +void ACogDebugReplicator::Server_SetSelection_Implementation(AActor* Value, bool ForceSelection) { #if !UE_BUILD_SHIPPING ServerSelection = Value; + if (ForceSelection) + { + FCogDebug::SetSelection(GetWorld(), Value); + } + else + { + FCogDebug::SetSelection(GetWorld(), nullptr); + } + + #endif // !UE_BUILD_SHIPPING } diff --git a/Plugins/Cog/Source/CogDebug/Private/CogDebugShape.cpp b/Plugins/Cog/Source/CogDebug/Private/CogDebugShape.cpp index a1ec759..768bafb 100644 --- a/Plugins/Cog/Source/CogDebug/Private/CogDebugShape.cpp +++ b/Plugins/Cog/Source/CogDebug/Private/CogDebugShape.cpp @@ -596,6 +596,22 @@ FCogDebugShape FCogDebugShape::MakePolygon(const TArray& Verts, const F return NewElement; } +//-------------------------------------------------------------------------------------------------------------------------- +FCogDebugShape FCogDebugShape::MakeCollisionShape(const FCollisionShape& Shape, const FVector& Location, const FQuat& Rotation, const FVector& Extent, const FColor& Color, const float Thickness, const bool bPersistent, const uint8 DepthPriority) +{ + switch (Shape.ShapeType) + { + case ECollisionShape::Box: + return MakeBox(Location, Rotation.Rotator(), Extent, Color, Thickness, bPersistent, DepthPriority); + case ECollisionShape::Capsule: + return MakeCapsule(Location, Rotation, Extent.X, Extent.Z, Color, Thickness, bPersistent, DepthPriority); + + default: + case ECollisionShape::Sphere: + return MakeCapsule(Location, Rotation, Extent.X, 0.0f, Color, Thickness, bPersistent, DepthPriority); + } +} + //-------------------------------------------------------------------------------------------------------------------------- void FCogDebugShape::DrawPolygon(const UWorld* World) const { diff --git a/Plugins/Cog/Source/CogDebug/Public/CogDebug.h b/Plugins/Cog/Source/CogDebug/Public/CogDebug.h index b6e95b2..7a4b517 100644 --- a/Plugins/Cog/Source/CogDebug/Public/CogDebug.h +++ b/Plugins/Cog/Source/CogDebug/Public/CogDebug.h @@ -13,7 +13,7 @@ struct FCogDebugDrawOverlapParams; struct FCogDebugDrawSweepParams; UENUM() -enum ECogDebugRecolorMode : uint8 +enum class ECogDebugRecolorMode : uint8 { None, Color, @@ -29,6 +29,9 @@ struct FCogDebugSettings UPROPERTY(Config) bool bIsFilteringBySelection = true; + UPROPERTY(Config) + bool ReplicateSelection = true; + UPROPERTY(Config) bool Persistent = false; @@ -63,7 +66,7 @@ struct FCogDebugSettings float AxesScale = 1.0f; UPROPERTY(Config) - TEnumAsByte RecolorMode = None; + ECogDebugRecolorMode RecolorMode = ECogDebugRecolorMode::None; UPROPERTY(Config) float RecolorIntensity = 0.0f; @@ -427,7 +430,13 @@ public: private: + static int32 GetPieSessionId(); + + static void ReplicateSelection(const UWorld* World, AActor* Value); + static bool IsDebugActiveForObject_Internal(const UObject* WorldContextObject, const AActor* InSelection, bool InIsFilteringBySelection); - static TWeakObjectPtr Selection; + static constexpr uint32 MaxPie = 16; + + static TWeakObjectPtr Selection[MaxPie]; }; diff --git a/Plugins/Cog/Source/CogDebug/Public/CogDebugDraw.h b/Plugins/Cog/Source/CogDebug/Public/CogDebugDraw.h index 351ca87..7ac28f5 100644 --- a/Plugins/Cog/Source/CogDebug/Public/CogDebugDraw.h +++ b/Plugins/Cog/Source/CogDebug/Public/CogDebugDraw.h @@ -5,6 +5,9 @@ class USkeletalMeshComponent; struct FCogDebugShape; +struct FCollisionShape; +struct FHitResult; +struct FOverlapResult; #if ENABLE_COG @@ -52,7 +55,15 @@ struct COGDEBUG_API FCogDebugDraw static void Skeleton(const FLogCategoryBase& LogCategory, const USkeletalMeshComponent* Skeleton, const FColor& Color, bool DrawSecondaryBones = false, const uint8 DepthPriority = 1); + static void LineTrace(const FLogCategoryBase& LogCategory, const UObject* WorldContextObject, const FVector& Start, const FVector& End, const bool HasHits, TArray& HitResults, const FCogDebugDrawLineTraceParams& Settings); + + static void Sweep(const FLogCategoryBase& LogCategory, const UObject* WorldContextObject, const FCollisionShape& Shape, const FVector& Start, const FVector& End, const FQuat& Rotation, const bool HasHits, TArray& HitResults, const FCogDebugDrawSweepParams& Settings); + + static void Overlap(const FLogCategoryBase& LogCategory, const UObject* WorldContextObject, const FCollisionShape& Shape, const FVector& Location, const FQuat& Rotation, TArray& OverlapResults, const FCogDebugDrawOverlapParams& Settings); + static void ReplicateShape(const UObject* WorldContextObject, const FCogDebugShape& Shape); + + static void ReplicateHitResults(const UObject* WorldContextObject, const TArray& HitResults, const FCogDebugDrawLineTraceParams& Settings); }; #endif //ENABLE_COG \ No newline at end of file diff --git a/Plugins/Cog/Source/CogDebug/Public/CogDebugDrawHelper.h b/Plugins/Cog/Source/CogDebug/Public/CogDebugDrawHelper.h index 710a66e..02c7e01 100644 --- a/Plugins/Cog/Source/CogDebug/Public/CogDebugDrawHelper.h +++ b/Plugins/Cog/Source/CogDebug/Public/CogDebugDrawHelper.h @@ -17,9 +17,9 @@ struct FCogDebugDrawOverlapParams FColor NoHitColor = FColor::Red; bool DrawHitPrimitives = true; bool DrawHitPrimitiveActorsName = false; - bool HitPrimitiveActorsNameShadow = true; + bool DrawHitPrimitiveActorsNameShadow = true; float HitPrimitiveActorsNameSize = 1.0f; - bool Persistent = false; + mutable bool Persistent = false; float LifeTime = 0.0f; uint8 DepthPriority = 0; float Thickness = 0.0f; @@ -62,7 +62,7 @@ public: static void DrawShape(const UWorld* World, const FCollisionShape& InShape, const FVector& Location, const FQuat& Rotation, const FVector& Scale, const FColor& Color, const bool Persistent, const float LifeTime, const uint8 DepthPriority, const float Thickness); - static void DrawPrimitiveComponent(const UPrimitiveComponent& PrimitiveComponent, const FColor& Color, const bool Persistent, const float LifeTime, const uint8 DepthPriority, const float Thickness); + static void DrawPrimitiveComponent(const UPrimitiveComponent& PrimitiveComponent, const int32 BodyIndex, const FColor& Color, const bool Persistent, const float LifeTime, const uint8 DepthPriority, const float Thickness, const bool DrawName = true, const bool DrawNameShadow = true, const float DrawNameSize = 1.0f); static void DrawOverlap(const UWorld* World, const FCollisionShape& Shape, const FVector& Location, const FQuat& Rotation, TArray& OverlapResults, const FCogDebugDrawOverlapParams& Settings); diff --git a/Plugins/Cog/Source/CogDebug/Public/CogDebugHelper.h b/Plugins/Cog/Source/CogDebug/Public/CogDebugHelper.h index 5c1faa4..2d48f29 100644 --- a/Plugins/Cog/Source/CogDebug/Public/CogDebugHelper.h +++ b/Plugins/Cog/Source/CogDebug/Public/CogDebugHelper.h @@ -2,7 +2,7 @@ #include "CoreMinimal.h" #include "Modules/ModuleManager.h" -#include "imgui.h" +#include "UObject/Class.h" class COGDEBUG_API FCogDebugHelper { diff --git a/Plugins/Cog/Source/CogDebug/Public/CogDebugPlot.h b/Plugins/Cog/Source/CogDebug/Public/CogDebugPlot.h index 71cfe80..40556ca 100644 --- a/Plugins/Cog/Source/CogDebug/Public/CogDebugPlot.h +++ b/Plugins/Cog/Source/CogDebug/Public/CogDebugPlot.h @@ -49,38 +49,56 @@ struct COGDEBUG_API FCogDebugPlotEvent //-------------------------------------------------------------------------------------------------------------------------- struct COGDEBUG_API FCogDebugPlotEntry { - void AssignAxis(int32 AssignedRow, ImAxis CurrentYAxis); - void AddPoint(float X, float Y); + void AssignGraphAndAxis(int32 AssignedRow, ImAxis CurrentYAxis); + + void AddPoint(float X, float Y); + bool FindValue(float Time, float& Value) const; - void ResetAxis(); - void Clear(); - FCogDebugPlotEvent& AddEvent(const FCogDebugPlotEntry& OwnwePlot, FString OwnerName, bool IsInstant, const FName EventId, const int32 Row, const FColor& Color); - FCogDebugPlotEvent& StopEvent(const FName EventId); - void UpdateTime(const UWorld* World); - int32 FindFreeRow() const; - FCogDebugPlotEvent* GetLastEvent(); - FCogDebugPlotEvent* FindLastEventByName(FName EventId); + + void ResetGraphAndAxis(); + + void Clear(); + + FCogDebugPlotEvent& AddEvent(const FString& OwnerName, bool IsInstant, const FName EventId, const int32 Row, const FColor& Color); + + FCogDebugPlotEvent& StopEvent(const FName EventId); + + FCogDebugPlotEvent* GetLastEvent(); + + FCogDebugPlotEvent* FindLastEventByName(FName EventId); FName Name; - bool IsEventPlot = false; - int32 CurrentRow = INDEX_NONE; - ImAxis CurrentYAxis = ImAxis_COUNT; - float Time = 0; - uint64 Frame = 0; + + bool IsEventPlot = false; + + int32 GraphIndex = INDEX_NONE; + + ImAxis YAxis = ImAxis_COUNT; + + float Time = 0; + + uint64 Frame = 0; + + TWeakObjectPtr World; //-------------------------- // Values //-------------------------- int32 ValueOffset = 0; - ImVector Values; - bool ShowValuesMarkers = false; + + ImVector Values; + + bool ShowValuesMarkers = false; //-------------------------- // Events //-------------------------- int32 EventOffset = 0; - TArray Events; - int32 MaxRow = 1; + + TArray Events; + + int32 MaxRow = 1; + }; //-------------------------------------------------------------------------------------------------------------------------- @@ -88,35 +106,59 @@ struct COGDEBUG_API FCogDebugPlotEntry class COGDEBUG_API FCogDebugPlot { public: - static const int32 AutoRow = -1; + static constexpr int32 AutoRow = -1; static void PlotValue(const UObject* WorldContextObject, const FName PlotName, const float Value); + static FCogDebugPlotEvent& PlotEvent(const UObject* WorldContextObject, const FName PlotName, const FName EventId, bool IsInstant, const int32 Row = AutoRow, const FColor& Color = FColor::Transparent); + static FCogDebugPlotEvent& PlotEventInstant(const UObject* WorldContextObject, const FName PlotName, const FName EventId, const int32 Row = AutoRow, const FColor& Color = FColor::Transparent); + static FCogDebugPlotEvent& PlotEventStart(const UObject* WorldContextObject, const FName PlotName, const FName EventId, const int32 Row = AutoRow, const FColor& Color = FColor::Transparent); + static FCogDebugPlotEvent& PlotEventStop(const UObject* WorldContextObject, const FName PlotName, const FName EventId); + static FCogDebugPlotEvent& PlotEventToggle(const UObject* WorldContextObject, const FName PlotName, const FName EventId, const bool ToggleValue, const int32 Row = AutoRow, const FColor& Color = FColor::Transparent); static void Reset(); + static void Clear(); - static FCogDebugPlotEntry* FindPlot(const FName Name); + + static FCogDebugPlotEntry* FindEntry(const FName Name); + + static FCogDebugPlotEntry* FindEntry(bool IsEvent, const FName Name); static TArray Plots; + + static TArray Events; + static bool IsVisible; + static bool Pause; private: friend struct FCogDebugPlotEntry; static void ResetLastAddedEvent(); - static FCogDebugPlotEntry* RegisterPlot(const UObject* Owner, const FName PlotName, bool IsEventPlot); - FCogDebugPlotEventParams* PlotEventAddParam(const FName Name); + + static FCogDebugPlotEntry* RegisterPlot(const UObject* Owner, const FName PlotName, bool IsEventPlot); + static FCogDebugPlotEvent* GetLastAddedEvent(); + static void OccupyGraphRow(const int32 InGraphIndex, const int32 InRow); + + static void FreeGraphRow(const int32 InGraphIndex, const int32 InRow); + + static int32 FindFreeGraphRow(const int32 InGraphIndex); + static FName LastAddedEventPlotName; - static int32 LastAddedEventIndex; + + static int32 LastAddedEventIndex; static FCogDebugPlotEvent DefaultEvent; + + // graph index to row index to number of objects occupying the row + static TMap> OccupationMap; }; #endif //ENABLE_COG diff --git a/Plugins/Cog/Source/CogDebug/Public/CogDebugReplicator.h b/Plugins/Cog/Source/CogDebug/Public/CogDebugReplicator.h index 0076af6..8ddcc1a 100644 --- a/Plugins/Cog/Source/CogDebug/Public/CogDebugReplicator.h +++ b/Plugins/Cog/Source/CogDebug/Public/CogDebugReplicator.h @@ -88,7 +88,7 @@ public: AActor* GetServerSelection() const { return ServerSelection.Get(); } UFUNCTION(Server, Reliable) - void Server_SetSelection(AActor* Value); + void Server_SetSelection(AActor* Value, bool ForceSelection); bool IsServerFilteringBySelection() const { return bIsServerFilteringBySelection; } diff --git a/Plugins/Cog/Source/CogDebug/Public/CogDebugShape.h b/Plugins/Cog/Source/CogDebug/Public/CogDebugShape.h index bb2742d..de3a1aa 100644 --- a/Plugins/Cog/Source/CogDebug/Public/CogDebugShape.h +++ b/Plugins/Cog/Source/CogDebug/Public/CogDebugShape.h @@ -4,6 +4,8 @@ DECLARE_LOG_CATEGORY_EXTERN(LogCogServerVLOG, Verbose, All); +struct FCollisionShape; + enum class ECogDebugShape : uint8 { Invalid, @@ -59,6 +61,7 @@ struct COGDEBUG_API FCogDebugShape static FCogDebugShape MakeCapsule(const FVector& Center, const FQuat& Rotation, const float Radius, const float HalfHeight, const FColor& Color, const float Thickness, const bool bPersistent, const uint8 DepthPriority); static FCogDebugShape MakeFlatCapsule(const FVector2D& Start, const FVector2D& End, const float Radius, const float Z, const FColor& Color, const float Thickness, const bool bPersistent, const uint8 DepthPriority); static FCogDebugShape MakePolygon(const TArray& Verts, const FColor& Color, const bool bPersistent, const uint8 DepthPriority); + static FCogDebugShape MakeCollisionShape(const FCollisionShape& Shape, const FVector& Location, const FQuat& Rotation, const FVector& Extent, const FColor& Color, const float Thickness, const bool bPersistent, const uint8 DepthPriority); void DrawPoint(const UWorld* World) const; void DrawSegment(const UWorld* World) const; diff --git a/Plugins/Cog/Source/CogDebugEditor/Private/CogDebugEditorModule.cpp b/Plugins/Cog/Source/CogDebugEditor/Private/CogDebugEditorModule.cpp index 6aa55a5..25a2e03 100644 --- a/Plugins/Cog/Source/CogDebugEditor/Private/CogDebugEditorModule.cpp +++ b/Plugins/Cog/Source/CogDebugEditor/Private/CogDebugEditorModule.cpp @@ -21,7 +21,7 @@ private: EAssetTypeCategories::Type AssetCategory; }; -IMPLEMENT_MODULE(FCogDebugEditorModule, CogEditor); +IMPLEMENT_MODULE(FCogDebugEditorModule, CogDebugEditor); //---------------------------------------------------------------------------------------------------------------------- void FCogDebugEditorModule::StartupModule() diff --git a/Plugins/Cog/Source/CogEngine/Private/CogEngineDataAsset.cpp b/Plugins/Cog/Source/CogEngine/Private/CogEngineDataAsset.cpp new file mode 100644 index 0000000..d5e3ecf --- /dev/null +++ b/Plugins/Cog/Source/CogEngine/Private/CogEngineDataAsset.cpp @@ -0,0 +1,18 @@ +#include "CogEngineDataAsset.h" + +//-------------------------------------------------------------------------------------------------------------------------- +void UCogEngineCheat_Execution::Execute_Implementation(const AActor* Instigator, const TArray& Targets) const +{ +} + +//-------------------------------------------------------------------------------------------------------------------------- +ECogEngineCheat_ActiveState UCogEngineCheat_Execution::IsActiveOnTargets_Implementation(const TArray& Targets) const +{ + return ECogEngineCheat_ActiveState::Inactive; +} + +//-------------------------------------------------------------------------------------------------------------------------- +bool UCogEngineCheat_Execution::GetColor(const FCogWindow& InCallingWindow, FLinearColor& OutColor) const +{ + return false; +} diff --git a/Plugins/Cog/Source/CogEngine/Private/CogEngineHelper.cpp b/Plugins/Cog/Source/CogEngine/Private/CogEngineHelper.cpp index 5d8dd9b..d663d48 100644 --- a/Plugins/Cog/Source/CogEngine/Private/CogEngineHelper.cpp +++ b/Plugins/Cog/Source/CogEngine/Private/CogEngineHelper.cpp @@ -18,19 +18,7 @@ void FCogEngineHelper::ActorContextMenu(AActor& Actor) FCogWindowWidgets::ThinSeparatorText("Object"); #if WITH_EDITOR - const UObject* DefaultObject = Actor.GetClass()->GetDefaultObject(); - if (DefaultObject == nullptr) - { - ImGui::BeginDisabled(); - } - if (ImGui::Button("Browse To Asset", ImVec2(-1, 0))) - { - IAssetTools::Get().SyncBrowserToAssets({ DefaultObject }); - } - if (DefaultObject == nullptr) - { - ImGui::EndDisabled(); - } + FCogWindowWidgets::OpenObjectAssetButton(&Actor, ImVec2(-1, 0)); #endif if (ImGui::Button("Delete", ImVec2(-1, 0))) diff --git a/Plugins/Cog/Source/CogEngine/Private/CogEngineReplicator.cpp b/Plugins/Cog/Source/CogEngine/Private/CogEngineReplicator.cpp index ef20cb5..404ff8f 100644 --- a/Plugins/Cog/Source/CogEngine/Private/CogEngineReplicator.cpp +++ b/Plugins/Cog/Source/CogEngine/Private/CogEngineReplicator.cpp @@ -220,3 +220,26 @@ void ACogEngineReplicator::Server_DeleteActor_Implementation(AActor* Actor) #endif // !UE_BUILD_SHIPPING } + + +//-------------------------------------------------------------------------------------------------------------------------- +void ACogEngineReplicator::Server_ApplyCheat_Implementation(const AActor* CheatInstigator, const TArray& Targets, const FCogEngineCheat& Cheat) const +{ + if (Cheat.Execution == nullptr) + { + return; + } + + Cheat.Execution->Execute(CheatInstigator, Targets); +} + +//-------------------------------------------------------------------------------------------------------------------------- +ECogEngineCheat_ActiveState ACogEngineReplicator::IsCheatActiveOnTargets(const TArray& Targets, const FCogEngineCheat& Cheat) +{ + if (Cheat.Execution == nullptr) + { + return ECogEngineCheat_ActiveState::Inactive; + } + + return Cheat.Execution->IsActiveOnTargets(Targets); +} diff --git a/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_Cheats.cpp b/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_Cheats.cpp new file mode 100644 index 0000000..2f00585 --- /dev/null +++ b/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_Cheats.cpp @@ -0,0 +1,467 @@ +#include "CogEngineWindow_Cheats.h" + +#include "CogEngineDataAsset.h" +#include "CogEngineReplicator.h" +#include "CogCommonAllegianceActorInterface.h" +#include "CogImguiHelper.h" +#include "CogWindowConsoleCommandManager.h" +#include "CogWindowWidgets.h" +#include "EngineUtils.h" +#include "GameFramework/Character.h" +#include "imgui.h" +#include "imgui_internal.h" + +//-------------------------------------------------------------------------------------------------------------------------- +void FCogEngineWindow_Cheats::RenderHelp() +{ + ImGui::Text( + "This window can be used to apply cheats to the selected actor (by default). " + "The cheats can be configured in the '%s' data asset. " + "When clicking a cheat button, press:\n" + " [CTRL] to apply the cheat to controlled actor\n" + " [ALT] to apply the cheat to the allies of the selected actor\n" + " [SHIFT] to apply the cheat to the enemies of the selected actor\n" + , TCHAR_TO_ANSI(*GetNameSafe(Asset.Get())) + ); +} + +//-------------------------------------------------------------------------------------------------------------------------- +void FCogEngineWindow_Cheats::Initialize() +{ + Super::Initialize(); + + bHasMenu = true; + + Asset = GetAsset(); + Config = GetConfig(); + + FCogWindowConsoleCommandManager::RegisterWorldConsoleCommand( + TEXT("Cog.Cheat"), + TEXT("Apply a cheat to the selection. Cog.Cheat -Allies -Enemies -Controlled"), + GetWorld(), + FCogWindowConsoleCommandDelegate::CreateLambda([this](const TArray& InArgs, UWorld* InWorld) + { + if (InArgs.Num() > 0) + { + if (const FCogEngineCheat* cheat = FindCheatByName(InArgs[0], false)) + { + const bool ApplyToEnemies = InArgs.Contains("-Enemies"); + const bool ApplyToAllies = InArgs.Contains("-Allies"); + const bool ApplyToControlled = InArgs.Contains("-Controlled"); + + RequestCheat(GetLocalPlayerPawn(), GetSelection(), *cheat, ApplyToEnemies, ApplyToAllies, ApplyToControlled); + } + else + { + UE_LOG(LogCogImGui, Warning, TEXT("Cog.Cheat %s | Cheat not found"), *InArgs[0]); + } + } + })); + + + if (Asset == nullptr) + { return; } + + for (const FCogEngineCheatCategory& CheatCategory : Asset->CheatCategories) + { + for (const FCogEngineCheat& Cheat : CheatCategory.PersistentEffects) + { + UpdateCheatColor(Cheat); + } + + for (const FCogEngineCheat& Cheat : CheatCategory.InstantEffects) + { + UpdateCheatColor(Cheat); + } + } +} + +//-------------------------------------------------------------------------------------------------------------------------- +void FCogEngineWindow_Cheats::UpdateCheatColor(const FCogEngineCheat& Cheat) const +{ + FLinearColor CustomColor; + if (Cheat.Execution != nullptr && Cheat.Execution->GetColor(*this, CustomColor)) + { + Cheat.CustomColor = CustomColor; + } + else + { + Cheat.CustomColor = Cheat.Color; + } +} + +//-------------------------------------------------------------------------------------------------------------------------- +void FCogEngineWindow_Cheats::ResetConfig() +{ + Super::ResetConfig(); + + Config->Reset(); +} + +//-------------------------------------------------------------------------------------------------------------------------- +void FCogEngineWindow_Cheats::GameTick(float DeltaTime) +{ + Super::GameTick(DeltaTime); + + TryReapplyCheats(); +} + +//-------------------------------------------------------------------------------------------------------------------------- +void FCogEngineWindow_Cheats::TryReapplyCheats() +{ + if (Config == nullptr) + { return; } + + if (bHasReappliedCheats) + { return; } + + if (Config->bReapplyCheatsBetweenPlays == false) + { return; } + + static int32 IsFirstLaunch = true; + if (IsFirstLaunch && Config->bReapplyCheatsBetweenLaunches == false) + { return; } + IsFirstLaunch = false; + + if (Asset == nullptr) + { return; } + + APawn* ControlledActor = GetLocalPlayerPawn(); + if (ControlledActor == nullptr) + { return; } + + const ACogEngineReplicator* Replicator = ACogEngineReplicator::GetLocalReplicator(*GetWorld()); + if (Replicator == nullptr) + { return; } + + TArray Targets { ControlledActor }; + + for (int32 i = Config->AppliedCheats.Num() - 1; i >= 0; i--) + { + if (const FCogEngineCheat* Cheat = FindCheatByName(Config->AppliedCheats[i], true)) + { + Replicator->Server_ApplyCheat(ControlledActor, Targets, *Cheat); + } + else + { + //----------------------------------------------------- + // This cheat doesn't exist anymore. We can remove it. + //----------------------------------------------------- + Config->AppliedCheats.RemoveAt(i); + } + } + + bHasReappliedCheats = true; +} + +//-------------------------------------------------------------------------------------------------------------------------- +bool FCogEngineWindow_Cheats::DrawTable() +{ + const bool Open = ImGui::BeginTable("Cheats", 2, ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Resizable | ImGuiTableFlags_NoBordersInBodyUntilResize); + ImGui::TableSetupColumn("Toggle", ImGuiTableColumnFlags_WidthStretch); + ImGui::TableSetupColumn("Instant", ImGuiTableColumnFlags_WidthStretch); + return Open; +} + +//-------------------------------------------------------------------------------------------------------------------------- +void FCogEngineWindow_Cheats::RenderContent() +{ + Super::RenderContent(); + + if (Config == nullptr) + { + ImGui::TextDisabled("Invalid Config"); + return; + } + + AActor* SelectedActor = GetSelection(); + if (SelectedActor == nullptr) + { + ImGui::TextDisabled("Invalid Selection"); + return; + } + + if (Asset == nullptr) + { + ImGui::TextDisabled("Invalid Asset"); + return; + } + + if (ImGui::BeginMenuBar()) + { + if (ImGui::BeginMenu("Options")) + { + ImGui::Checkbox("Group By Category", &Config->bGroupByCategories); + + ImGui::Checkbox("Use Two Columns", &Config->bUseTwoColumns); + + ImGui::Separator(); + + ImGui::Checkbox("Reapply Cheats Between Plays", &Config->bReapplyCheatsBetweenPlays); + if (Config->bReapplyCheatsBetweenPlays == false) + { + ImGui::BeginDisabled(); + } + + ImGui::Checkbox("Reapply Cheats Between Launches", &Config->bReapplyCheatsBetweenLaunches); + if (Config->bReapplyCheatsBetweenPlays == false) + { + ImGui::EndDisabled(); + } + + ImGui::Separator(); + if (ImGui::MenuItem("Reset Settings")) + { + ResetConfig(); + } + + ImGui::EndMenu(); + } + + ImGui::SameLine(); + + ImGui::SetNextItemWidth(ImGui::GetFontSize() * 7); + + if (ImGui::BeginMenu("Filters")) + { + for (const FCogEngineCheatCategory& CheatCategory : Asset->CheatCategories) + { + const auto CategoryStr = StringCast(*CheatCategory.Name); + bool IsSelected = Config->SelectedCategories.Contains(CheatCategory.Name); + if (ImGui::Checkbox(CategoryStr.Get(), &IsSelected)) + { + if (IsSelected) + { + Config->SelectedCategories.Add(CheatCategory.Name); + } + else + { + Config->SelectedCategories.Remove(CheatCategory.Name); + } + } + } + ImGui::EndMenu(); + } + + FCogWindowWidgets::SearchBar(Filter); + + ImGui::EndMenuBar(); + } + + APawn* ControlledActor = GetLocalPlayerPawn(); + + bool OpenTable = false; + if (Config->bGroupByCategories == false && Config->bUseTwoColumns) + { + OpenTable = DrawTable(); + } + + for (const FCogEngineCheatCategory& CheatCategory : Asset->CheatCategories) + { + const auto CategoryStr = StringCast(*CheatCategory.Name); + + if (Config->SelectedCategories.Num() != 0 && Config->SelectedCategories.Contains(CheatCategory.Name) == false) + { continue; } + + bool Open = true; + if (Config->bGroupByCategories) + { + Open = FCogWindowWidgets::DarkCollapsingHeader(CategoryStr.Get(), ImGuiTreeNodeFlags_DefaultOpen); + + if (Open && Config->bUseTwoColumns) + { + DrawTable(); + } + } + + + if (Open) + { + if (Config->bUseTwoColumns) + { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + } + + int Index = 0; + for (const FCogEngineCheat& Cheat : CheatCategory.PersistentEffects) + { + AddCheat(Index, ControlledActor, SelectedActor, Cheat, true); + Index++; + } + + //---------------------------------------------------------------------------- + // Update the config of applied cheat to reapply them on the next launch. + // We do not update them only when the user input is pressed because + // the state of the cheat is lagging when connected to a server. + // So we check if the array should be updated all the time. + //---------------------------------------------------------------------------- + if (SelectedActor == ControlledActor) + { + for (const FCogEngineCheat& Cheat : CheatCategory.PersistentEffects) + { + TArray Targets = { SelectedActor }; + if (ACogEngineReplicator::IsCheatActiveOnTargets(Targets, Cheat) == ECogEngineCheat_ActiveState::Active) + { + Config->AppliedCheats.AddUnique(Cheat.Name); + } + else + { + Config->AppliedCheats.Remove(Cheat.Name); + } + } + } + + ImGui::TableNextColumn(); + + Index = 0; + for (const FCogEngineCheat& Cheat : CheatCategory.InstantEffects) + { + AddCheat(Index, ControlledActor, SelectedActor, Cheat, false); + Index++; + } + + if (Config->bGroupByCategories && Config->bUseTwoColumns) + { + ImGui::EndTable(); + } + } + } + + if (OpenTable) + { + ImGui::EndTable(); + } +} + +//-------------------------------------------------------------------------------------------------------------------------- +bool FCogEngineWindow_Cheats::AddCheat(const int32 Index, AActor* ControlledActor, AActor* SelectedActor, const FCogEngineCheat& Cheat, bool IsPersistent) +{ + const auto CheatName = StringCast(*Cheat.Name); + + if (Filter.PassFilter(CheatName.Get()) == false) + { return false; } + + ImGui::PushID(Index); + + FCogWindowWidgets::PushBackColor(FCogImguiHelper::ToImVec4(Cheat.CustomColor)); + + const bool IsShiftDown = (ImGui::GetCurrentContext()->IO.KeyMods & ImGuiMod_Shift) != 0; + const bool IsAltDown = (ImGui::GetCurrentContext()->IO.KeyMods & ImGuiMod_Alt) != 0; + const bool IsControlDown = (ImGui::GetCurrentContext()->IO.KeyMods & ImGuiMod_Ctrl) != 0; + + bool bIsPressed = false; + if (IsPersistent) + { + TArray Targets = { SelectedActor }; + bool isEnabled = ACogEngineReplicator::IsCheatActiveOnTargets(Targets, Cheat) == ECogEngineCheat_ActiveState::Active; + if (ImGui::Checkbox(CheatName.Get(), &isEnabled)) + { + RequestCheat(ControlledActor, SelectedActor, Cheat, IsShiftDown, IsAltDown, IsControlDown); + bIsPressed = true; + } + } + else + { + if (ImGui::Button(CheatName.Get(), ImVec2(-1, 0))) + { + RequestCheat(ControlledActor, SelectedActor, Cheat, IsShiftDown, IsAltDown, IsControlDown); + bIsPressed = true; + } + } + + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::TextColored(ImVec4(1.0f, 1.0f, 1.0f, IsShiftDown || IsAltDown || IsControlDown ? 0.5f : 1.0f), "On Selection"); + ImGui::TextColored(ImVec4(1.0f, 1.0f, 1.0f, IsShiftDown ? 1.0f : 0.5f), "On Enemies [SHIFT]"); + ImGui::TextColored(ImVec4(1.0f, 1.0f, 1.0f, IsAltDown ? 1.0f : 0.5f), "On Allies [ALT]"); + ImGui::TextColored(ImVec4(1.0f, 1.0f, 1.0f, IsControlDown ? 1.0f : 0.5f), "On Controlled [CTRL]"); + ImGui::EndTooltip(); + } + + FCogWindowWidgets::PopBackColor(); + + ImGui::PopID(); + + return bIsPressed; +} + +//-------------------------------------------------------------------------------------------------------------------------- +void FCogEngineWindow_Cheats::RequestCheat(AActor* ControlledActor, AActor* SelectedActor, const FCogEngineCheat& Cheat, bool ApplyToEnemies, bool ApplyToAllies, bool ApplyToControlled) +{ + TArray Actors; + + if (ApplyToControlled) + { + Actors.Add(ControlledActor); + } + + if (ApplyToEnemies || ApplyToAllies) + { + for (TActorIterator It(GetWorld(), ACharacter::StaticClass()); It; ++It) + { + if (AActor* OtherActor = *It) + { + ECogCommonAllegiance Allegiance = ECogCommonAllegiance::Enemy; + + if (ICogCommonAllegianceActorInterface* AllegianceInterface = Cast(OtherActor)) + { + Allegiance = AllegianceInterface->GetAllegianceWithOtherActor(ControlledActor); + } + + if ((ApplyToEnemies && (Allegiance == ECogCommonAllegiance::Enemy)) + || (ApplyToAllies && (Allegiance == ECogCommonAllegiance::Friendly))) + { + Actors.Add(OtherActor); + } + } + } + } + + if ((ApplyToControlled || ApplyToEnemies || ApplyToAllies) == false) + { + Actors.Add(SelectedActor); + } + + if (ACogEngineReplicator* Replicator = ACogEngineReplicator::GetLocalReplicator(*GetWorld())) + { + Replicator->Server_ApplyCheat(ControlledActor, Actors, Cheat); + } + else + { + UE_LOG(LogCogImGui, Warning, TEXT("FCogAbilityWindow_Cheats::RequestCheat | Replicator not found")); + } +} + +//-------------------------------------------------------------------------------------------------------------------------- +const FCogEngineCheat* FCogEngineWindow_Cheats::FindCheatByName(const FString& CheatName, const bool OnlyPersistentCheats) +{ + for (const FCogEngineCheatCategory& CheatCategory : Asset->CheatCategories) + { + for (const FCogEngineCheat& Cheat : CheatCategory.PersistentEffects) + { + if (Cheat.Name == CheatName) + { + return &Cheat; + } + } + + if (OnlyPersistentCheats) + { + continue; + } + + for (const FCogEngineCheat& Cheat : CheatCategory.InstantEffects) + { + if (Cheat.Name == CheatName) + { + return &Cheat; + } + } + + + } + + return nullptr; +} diff --git a/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_CollisionTester.cpp b/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_CollisionTester.cpp index 497909e..d4abc26 100644 --- a/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_CollisionTester.cpp +++ b/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_CollisionTester.cpp @@ -84,7 +84,11 @@ void FCogEngineWindow_CollisionTester::RenderContent() } ImGui::SetNextItemWidth(-1); - FCogWindowWidgets::MenuActorsCombo("CollisionTesters", *GetWorld(), ACogEngineCollisionTester::StaticClass()); + AActor* NewSelection = nullptr; + if (FCogWindowWidgets::MenuActorsCombo("CollisionTesters", NewSelection, *GetWorld(), ACogEngineCollisionTester::StaticClass())) + { + FCogDebug::SetSelection(GetWorld(), NewSelection); + } ImGui::EndMenuBar(); } diff --git a/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_DebugSettings.cpp b/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_DebugSettings.cpp index 0bdc107..d612c10 100644 --- a/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_DebugSettings.cpp +++ b/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_DebugSettings.cpp @@ -80,98 +80,56 @@ void FCogEngineWindow_DebugSettings::RenderContent() { FCogDebug::SetIsFilteringBySelection(GetWorld(), Config->Data.bIsFilteringBySelection); } - if (ImGui::IsItemHovered(ImGuiHoveredFlags_Stationary)) - { - ImGui::SetTooltip("If checked, only show the debug of the currently selected actor. Otherwise show the debug of all actors."); - } + ImGui::SetItemTooltip("If checked, only show the debug of the currently selected actor. Otherwise show the debug of all actors."); - ImGui::Checkbox("Persistent", &Settings.Persistent); - if (ImGui::IsItemHovered(ImGuiHoveredFlags_Stationary)) - { - ImGui::SetTooltip("Make debug draw always persist"); - } + ImGui::Checkbox("Persistent", &Settings.Persistent); + ImGui::SetItemTooltip("Make debug draw always persist"); - ImGui::Checkbox("Actor Name Use Label", &Settings.ActorNameUseLabel); - if (ImGui::IsItemHovered(ImGuiHoveredFlags_Stationary)) - { - ImGui::SetTooltip("Use the actor label when displaying the actor name."); - } + ImGui::Checkbox("Actor Name Use Label", &Settings.ActorNameUseLabel); + ImGui::SetItemTooltip("Use the actor label when displaying the actor name."); - ImGui::Checkbox("Text Shadow", &Settings.TextShadow); - if (ImGui::IsItemHovered(ImGuiHoveredFlags_Stationary)) - { - ImGui::SetTooltip("Show a shadow below debug text."); - } + ImGui::Checkbox("Text Shadow", &Settings.TextShadow); + ImGui::SetItemTooltip("Show a shadow below debug text."); - FCogWindowWidgets::SetNextItemToShortWidth(); - ImGui::Checkbox("Fade 2D", &Settings.Fade2D); - if (ImGui::IsItemHovered(ImGuiHoveredFlags_Stationary)) - { - ImGui::SetTooltip("Does the 2D debug is fading out."); - } + FCogWindowWidgets::SetNextItemToShortWidth(); + ImGui::Checkbox("Fade 2D", &Settings.Fade2D); + ImGui::SetItemTooltip("Does the 2D debug is fading out."); - FCogWindowWidgets::SetNextItemToShortWidth(); - ImGui::DragFloat("Duration", &Settings.Duration, 0.01f, 0.0f, 100.0f, "%.1f"); - if (ImGui::IsItemHovered(ImGuiHoveredFlags_Stationary)) - { - ImGui::SetTooltip("The duration of debug elements."); - } + FCogWindowWidgets::SetNextItemToShortWidth(); + ImGui::DragFloat("Duration", &Settings.Duration, 0.01f, 0.0f, 100.0f, "%.1f"); + ImGui::SetItemTooltip("The duration of debug elements."); - FCogWindowWidgets::SetNextItemToShortWidth(); - ImGui::DragFloat("Thickness", &Settings.Thickness, 0.05f, 0.0f, 5.0f, "%.1f"); - if (ImGui::IsItemHovered(ImGuiHoveredFlags_Stationary)) - { - ImGui::SetTooltip("The thickness of debug lines."); - } + FCogWindowWidgets::SetNextItemToShortWidth(); + ImGui::DragFloat("Thickness", &Settings.Thickness, 0.05f, 0.0f, 5.0f, "%.1f"); + ImGui::SetItemTooltip("The thickness of debug lines."); - FCogWindowWidgets::SetNextItemToShortWidth(); - ImGui::DragFloat("Server Thickness", &Settings.ServerThickness, 0.05f, 0.0f, 5.0f, "%.1f"); - if (ImGui::IsItemHovered(ImGuiHoveredFlags_Stationary)) - { - ImGui::SetTooltip("The thickness the server debug lines."); - } + FCogWindowWidgets::SetNextItemToShortWidth(); + ImGui::DragFloat("Server Thickness", &Settings.ServerThickness, 0.05f, 0.0f, 5.0f, "%.1f"); + ImGui::SetItemTooltip("The thickness the server debug lines."); - FCogWindowWidgets::SetNextItemToShortWidth(); - ImGui::DragFloat("Server Color Mult", &Settings.ServerColorMultiplier, 0.01f, 0.0f, 1.0f, "%.1f"); - if (ImGui::IsItemHovered(ImGuiHoveredFlags_Stationary)) - { - ImGui::SetTooltip("The color multiplier applied to the server debug lines."); - } + FCogWindowWidgets::SetNextItemToShortWidth(); + ImGui::DragFloat("Server Color Mult", &Settings.ServerColorMultiplier, 0.01f, 0.0f, 1.0f, "%.1f"); + ImGui::SetItemTooltip("The color multiplier applied to the server debug lines."); - FCogWindowWidgets::SetNextItemToShortWidth(); - ImGui::DragInt("Depth Priority", &Settings.DepthPriority, 0.1f, 0, 100); - if (ImGui::IsItemHovered(ImGuiHoveredFlags_Stationary)) - { - ImGui::SetTooltip("The depth priority of debug elements."); - } + FCogWindowWidgets::SetNextItemToShortWidth(); + ImGui::DragInt("Depth Priority", &Settings.DepthPriority, 0.1f, 0, 100); + ImGui::SetItemTooltip("The depth priority of debug elements."); - FCogWindowWidgets::SetNextItemToShortWidth(); - ImGui::DragInt("Segments", &Settings.Segments, 0.1f, 4, 20.0f); - if (ImGui::IsItemHovered(ImGuiHoveredFlags_Stationary)) - { - ImGui::SetTooltip("The number of segments used for circular shapes."); - } + FCogWindowWidgets::SetNextItemToShortWidth(); + ImGui::DragInt("Segments", &Settings.Segments, 0.1f, 4, 20.0f); + ImGui::SetItemTooltip("The number of segments used for circular shapes."); - FCogWindowWidgets::SetNextItemToShortWidth(); - ImGui::DragFloat("Axes Scale", &Settings.AxesScale, 0.1f, 0, 10.0f, "%.1f"); - if (ImGui::IsItemHovered(ImGuiHoveredFlags_Stationary)) - { - ImGui::SetTooltip("The scaling debug axis."); - } + FCogWindowWidgets::SetNextItemToShortWidth(); + ImGui::DragFloat("Axes Scale", &Settings.AxesScale, 0.1f, 0, 10.0f, "%.1f"); + ImGui::SetItemTooltip("The scaling debug axis."); - FCogWindowWidgets::SetNextItemToShortWidth(); - ImGui::DragFloat("Arrow Size", &Settings.ArrowSize, 1.0f, 0.0f, 200.0f, "%.0f"); - if (ImGui::IsItemHovered(ImGuiHoveredFlags_Stationary)) - { - ImGui::SetTooltip("The size of debug arrows."); - } + FCogWindowWidgets::SetNextItemToShortWidth(); + ImGui::DragFloat("Arrow Size", &Settings.ArrowSize, 1.0f, 0.0f, 200.0f, "%.0f"); + ImGui::SetItemTooltip("The size of debug arrows."); - FCogWindowWidgets::SetNextItemToShortWidth(); - ImGui::DragFloat("Text Size", &Settings.TextSize, 0.1f, 0.1f, 5.0f, "%.1f"); - if (ImGui::IsItemHovered(ImGuiHoveredFlags_Stationary)) - { - ImGui::SetTooltip("The size of the debug texts."); - } + FCogWindowWidgets::SetNextItemToShortWidth(); + ImGui::DragFloat("Text Size", &Settings.TextSize, 0.1f, 0.1f, 5.0f, "%.1f"); + ImGui::SetItemTooltip("The size of the debug texts."); } if (ImGui::CollapsingHeader("Recolor", ImGuiTreeNodeFlags_DefaultOpen)) @@ -183,42 +141,30 @@ void FCogEngineWindow_DebugSettings::RenderContent() { Settings.RecolorMode = Mode; } - if (ImGui::IsItemHovered(ImGuiHoveredFlags_Stationary)) - { - ImGui::SetTooltip("How the debug element should be recolored."); - } + ImGui::SetItemTooltip("How the debug element should be recolored."); if (Settings.RecolorMode != ECogDebugRecolorMode::None) { FCogWindowWidgets::SetNextItemToShortWidth(); ImGui::DragFloat("Recolor Intensity", &Settings.RecolorIntensity, 0.01f, 0.0f, 1.0f, "%.2f"); - if (ImGui::IsItemHovered(ImGuiHoveredFlags_Stationary)) - { - ImGui::SetTooltip("How much the debug elements color should be changed."); - } + ImGui::SetItemTooltip("How much the debug elements color should be changed."); } if (Settings.RecolorMode == ECogDebugRecolorMode::Color) { FCogImguiHelper::ColorEdit4("Recolor Color", Settings.RecolorColor, ColorEditFlags); } - else if (Settings.RecolorMode == HueOverTime) + else if (Settings.RecolorMode == ECogDebugRecolorMode::HueOverTime) { FCogWindowWidgets::SetNextItemToShortWidth(); ImGui::DragFloat("Recolor Speed", &Settings.RecolorTimeSpeed, 0.1f, 0.0f, 10.0f, "%.1f"); - if (ImGui::IsItemHovered(ImGuiHoveredFlags_Stationary)) - { - ImGui::SetTooltip("The speed of the recolor."); - } + ImGui::SetItemTooltip("The speed of the recolor."); } else if (Settings.RecolorMode == ECogDebugRecolorMode::HueOverFrames) { FCogWindowWidgets::SetNextItemToShortWidth(); ImGui::DragInt("Recolor Cycle", &Settings.RecolorFrameCycle, 1, 2, 100); - if (ImGui::IsItemHovered(ImGuiHoveredFlags_Stationary)) - { - ImGui::SetTooltip("How many frames are used to perform a full hue cycle."); - } + ImGui::SetItemTooltip("How many frames are used to perform a full hue cycle."); } } @@ -230,10 +176,7 @@ void FCogEngineWindow_DebugSettings::RenderContent() FCogWindowWidgets::SetNextItemToShortWidth(); ImGui::DragFloat("Gizmo Scale", &Settings.GizmoScale, 0.1f, 0.1f, 10.0f, "%.1f"); - if (ImGui::IsItemHovered(ImGuiHoveredFlags_Stationary)) - { - ImGui::SetTooltip("The scale of the gizmo."); - } + ImGui::SetItemTooltip("The scale of the gizmo."); FCogWindowWidgets::SetNextItemToShortWidth(); ImGui::DragInt("Z Low", &Settings.GizmoZLow, 0.5f, 0, 1000); @@ -384,23 +327,47 @@ void FCogEngineWindow_DebugSettings::RenderContent() if (ImGui::CollapsingHeader("Collision Query")) { ImGui::Checkbox("Draw Hit Primitives", &Settings.CollisionQueryDrawHitPrimitives); - ImGui::Checkbox("Draw Hit Primitive Actors Name", &Settings.CollisionQueryDrawHitPrimitiveActorsName); - ImGui::Checkbox("Prim Hit Primitive Actors Name Shadow", &Settings.CollisionQueryHitPrimitiveActorsNameShadow); - ImGui::Checkbox("Draw Hit Shapes", &Settings.CollisionQueryDrawHitShapes); + ImGui::SetItemTooltip("Draw the shape of the primitives that have been hit."); + + ImGui::Checkbox("Draw Hit Primitive Actors Name", &Settings.CollisionQueryDrawHitPrimitiveActorsName); + ImGui::SetItemTooltip("Draw the actor name of the primitives that have been hit."); + + ImGui::Checkbox("Prim Hit Primitive Actors Name Shadow", &Settings.CollisionQueryHitPrimitiveActorsNameShadow); + ImGui::SetItemTooltip("Draw the actor name shadow of the primitives that have been hit."); + + ImGui::Checkbox("Draw Hit Shapes", &Settings.CollisionQueryDrawHitShapes); + ImGui::SetItemTooltip("Draw the sweep shape at every impact location."); + ImGui::Checkbox("Draw Hit Location", &Settings.CollisionQueryDrawHitLocation); + ImGui::SetItemTooltip("Draw the location of hit results."); + ImGui::Checkbox("Draw Hit Impact Points", &Settings.CollisionQueryDrawHitImpactPoints); + ImGui::SetItemTooltip("Draw the impact point of hit results."); + ImGui::Checkbox("Draw Hit Normals", &Settings.CollisionQueryDrawHitNormals); + ImGui::SetItemTooltip("Draw the hit normal of hit results."); + ImGui::Checkbox("Draw Hit Impact Normals", &Settings.CollisionQueryDrawHitImpactNormals); + ImGui::SetItemTooltip("Draw the hit impact normal of hit results."); FCogWindowWidgets::SetNextItemToShortWidth(); - ImGui::DragFloat("Primitive Actors Name Size", &Settings.CollisionQueryHitPrimitiveActorsNameSize); + ImGui::DragFloat("Primitive Actors Name Size", &Settings.CollisionQueryHitPrimitiveActorsNameSize, 0.1f, 0.5f, 10.0f, "%0.1f"); + ImGui::SetItemTooltip("Size of the actor name of the primitives that have been hit."); FCogWindowWidgets::SetNextItemToShortWidth(); - ImGui::DragFloat("Hit Point Size", &Settings.CollisionQueryHitPointSize); + ImGui::DragFloat("Hit Point Size", &Settings.CollisionQueryHitPointSize, 0.5f, 0.0f, 100.0f, "%0.1f"); + ImGui::SetItemTooltip("Size of the hit result location and impact point."); FCogImguiHelper::ColorEdit4("Hit Color", Settings.CollisionQueryHitColor, ColorEditFlags); + ImGui::SetItemTooltip("Color of the collision query when the query has hit."); + FCogImguiHelper::ColorEdit4("No Hit Color", Settings.CollisionQueryNoHitColor, ColorEditFlags); + ImGui::SetItemTooltip("Color of the collision query when the query has not hit."); + FCogImguiHelper::ColorEdit4("Normal Color", Settings.CollisionQueryNormalColor, ColorEditFlags); + ImGui::SetItemTooltip("Color of the hit result normal color."); + FCogImguiHelper::ColorEdit4("Impact Normal Color", Settings.CollisionQueryImpactNormalColor, ColorEditFlags); + ImGui::SetItemTooltip("Color of the hit result impact normal color."); } } diff --git a/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_Inspector.cpp b/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_Inspector.cpp index 4844206..1faacd0 100644 --- a/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_Inspector.cpp +++ b/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_Inspector.cpp @@ -205,6 +205,7 @@ void FCogEngineWindow_Inspector::RenderMenu() ImGui::CloseCurrentPopup(); } + ImGui::PushID("Favorites"); for (Favorite& Favorite : Favorites) { const TWeakObjectPtr& Object = Favorite.Object; @@ -214,21 +215,26 @@ void FCogEngineWindow_Inspector::RenderMenu() ImGui::CloseCurrentPopup(); } } + ImGui::PopID(); //----------------------------------- // HISTORY //----------------------------------- ImGui::Spacing(); ImGui::SeparatorText("HISTORY"); + ImGui::PushID("History"); for (int32 i = History.Num() - 1; i >= 0; i--) { + ImGui::PushID(i); const TWeakObjectPtr& Object = History[i]; if (ImGui::MenuItem(TCHAR_TO_ANSI(*GetNameSafe(Object.Get())), nullptr, i == HistoryIndex)) { NewHistoryIndex = i; ImGui::CloseCurrentPopup(); } + ImGui::PopID(); } + ImGui::PopID(); ImGui::EndChild(); ImGui::EndPopup(); @@ -954,12 +960,8 @@ bool FCogEngineWindow_Inspector::HasPropertyAnyChildren(const FProperty* Propert { if (const FStructProperty* StructProperty = CastField(Property)) { - for (TFieldIterator It(StructProperty->Struct); It; ++It) - { - return true; - } - - return false; + const TFieldIterator It(StructProperty->Struct); + return It ? true : false; } else if (const FArrayProperty* ArrayProperty = CastField(Property)) { diff --git a/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_NetImGui.cpp b/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_NetImGui.cpp new file mode 100644 index 0000000..225d22d --- /dev/null +++ b/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_NetImGui.cpp @@ -0,0 +1,402 @@ +#include "CogEngineWindow_NetImGui.h" + +#include "CogImguiContext.h" +#include "CogImguiHelper.h" +#include "CogWindowConsoleCommandManager.h" +#include "CogWindowManager.h" +#include "CogWindowWidgets.h" +#include "Engine/EngineBaseTypes.h" +#include "Engine/World.h" +#include "imgui.h" +#include "Misc/CoreMisc.h" +#include "Misc/Paths.h" +#include "NetImgui_Api.h" + +//-------------------------------------------------------------------------------------------------------------------------- +void FCogEngineWindow_NetImgui::Initialize() +{ + Super::Initialize(); + + Config = GetConfig(); + + FCogWindowConsoleCommandManager::RegisterWorldConsoleCommand( + TEXT("Cog.NetImgui.Connect"), + TEXT("Connect to NetImgui server"), + GetWorld(), + FCogWindowConsoleCommandDelegate::CreateLambda([this](const TArray& InArgs, UWorld* InWorld) + { + ConnectTo(); + })); + + FCogWindowConsoleCommandManager::RegisterWorldConsoleCommand( + TEXT("Cog.NetImgui.Listen"), + TEXT("Listen for NetImgui server connection"), + GetWorld(), + FCogWindowConsoleCommandDelegate::CreateLambda([this](const TArray& InArgs, UWorld* InWorld) + { + ConnectFrom(); + })); + + FCogWindowConsoleCommandManager::RegisterWorldConsoleCommand( + TEXT("Cog.NetImgui.Disconnect"), + TEXT("Disconnect from NetImgui server"), + GetWorld(), + FCogWindowConsoleCommandDelegate::CreateLambda([this](const TArray& InArgs, UWorld* InWorld) + { + Disconnect(); + })); + + FCogWindowConsoleCommandManager::RegisterWorldConsoleCommand( + TEXT("Cog.NetImgui.RunServer"), + TEXT("Run NetImgui server application"), + GetWorld(), + FCogWindowConsoleCommandDelegate::CreateLambda([this](const TArray& InArgs, UWorld* InWorld) + { + RunServer(); + })); + + FCogWindowConsoleCommandManager::RegisterWorldConsoleCommand( + TEXT("Cog.NetImgui.CloseServer"), + TEXT("Close NetImgui server application"), + GetWorld(), + FCogWindowConsoleCommandDelegate::CreateLambda([this](const TArray& InArgs, UWorld* InWorld) + { + CloseServer(); + })); +} + +//-------------------------------------------------------------------------------------------------------------------------- +void FCogEngineWindow_NetImgui::Shutdown() +{ + if (NetImgui::IsConnected() || NetImgui::IsConnectionPending()) + { + NetImgui::Disconnect(); + } + + CloseServer(); +} + +//-------------------------------------------------------------------------------------------------------------------------- +void FCogEngineWindow_NetImgui::ResetConfig() +{ + Super::ResetConfig(); + Config->Reset(); +} + +//-------------------------------------------------------------------------------------------------------------------------- +void FCogEngineWindow_NetImgui::RenderHelp() +{ + ImGui::Text("This window manage the connection to the NetImgui server." + "See https://github.com/sammyfreg/netImgui for more info."); +} + +//-------------------------------------------------------------------------------------------------------------------------- +void FCogEngineWindow_NetImgui::RenderTick(float DeltaTime) +{ + //------------------------------------------------------ + // Before auto connecting, wait for NetImgui startup, + // which require imgui context to be initialized + //------------------------------------------------------ + + if (HasStartedAutoConnection == false && FCogImguiContext::GetIsNetImguiInitialized()) + { + HasStartedAutoConnection = true; + + if (Config->AutoRunServer && GetWorld()->IsPlayInEditor()) + { + RunServer(); + } + + ECogNetImguiAutoConnectionMode AutoConnectMode = ECogNetImguiAutoConnectionMode::NoAutoConnect; + switch (GetWorld()->GetNetMode()) + { + case NM_Client: AutoConnectMode = Config->AutoConnectOnClient; break; + case NM_ListenServer: AutoConnectMode = Config->AutoConnectOnListenServer; break; + case NM_Standalone: AutoConnectMode = Config->AutoConnectOnStandalone; break; + case NM_DedicatedServer: AutoConnectMode = Config->AutoConnectOnDedicatedServer; break; + default: AutoConnectMode = ECogNetImguiAutoConnectionMode::NoAutoConnect; + } + + if (AutoConnectMode == ECogNetImguiAutoConnectionMode::AutoListen) + { + ConnectFrom(); + } + else if (AutoConnectMode == ECogNetImguiAutoConnectionMode::AutoConnect) + { + ConnectTo(); + } + } +} + +//-------------------------------------------------------------------------------------------------------------------------- +void FCogEngineWindow_NetImgui::RenderContent() +{ + Super::RenderContent(); + +#if NETIMGUI_ENABLED + + //---------------------------------------- + // Status + //---------------------------------------- + if (NetImgui::IsConnected()) + { + ImGui::TextColored(ImVec4(0.5f, 1.0f, 0.6f, 1.0f), "Connected"); + } + else if (NetImgui::IsConnectionPending()) + { + ImGui::TextColored(ImVec4(0.7f, 0.7f, 0.7f, 1.0f), "Waiting Server"); + } + else + { + ImGui::TextColored(ImVec4(1.0f, 0.4f, 0.3f, 1.0f), "Not Connected"); + } + + //---------------------------------------- + // Connection buttons + //---------------------------------------- + if (NetImgui::IsConnected()) + { + if (ImGui::Button("Disconnect", ImVec2(ImGui::GetContentRegionAvail().x, 0))) + { + NetImgui::Disconnect(); + } + } + else if (NetImgui::IsConnectionPending()) + { + if (ImGui::Button("Cancel Connection", ImVec2(ImGui::GetContentRegionAvail().x, 0))) + { + NetImgui::Disconnect(); + } + } + else + { + if (ImGui::Button("Connect", ImVec2(ImGui::GetContentRegionAvail().x, 0))) + { + ConnectTo(); + } + ImGui::SetItemTooltip("Attempt a connection to a remote netImgui server at the provided address."); + + if (ImGui::Button("Listen", ImVec2(ImGui::GetContentRegionAvail().x, 0))) + { + ConnectFrom(); + } + ImGui::SetItemTooltip("Start listening for a connection request by a remote netImgui server, on the provided Port."); + } + + //---------------------------------------- + // Run/Close server button + //---------------------------------------- + if (FPlatformProcess::IsProcRunning(ServerProcess)) + { + if (ImGui::Button("Close Server", ImVec2(ImGui::GetContentRegionAvail().x, 0))) + { + CloseServer(); + } + if (ImGui::IsItemHovered()) + { + ImGui::SetTooltip("Close the NetImgui server executable."); + } + } + else + { + if (NetImgui::IsConnected() == false) + { + if (ImGui::Button("Run Server", ImVec2(ImGui::GetContentRegionAvail().x, 0))) + { + RunServer(); + } + if (ImGui::IsItemHovered()) + { + ImGui::SetTooltip("Run the NetImgui server executable."); + } + } + } + + ImGui::Spacing(); + + //---------------------------------------- + // Settings + //---------------------------------------- + if (ImGui::CollapsingHeader("Settings")) + { + ImGui::SeparatorText("Connection"); + + FCogWindowWidgets::SetNextItemToShortWidth(); + FCogWindowWidgets::InputText("Server Address", Config->ServerAddress); + ImGui::SetItemTooltip("NetImgui server application address."); + + FCogWindowWidgets::SetNextItemToShortWidth(); + ImGui::InputInt("Server Port", &Config->ServerPort); + ImGui::SetItemTooltip("Port of the NetImgui Server application to connect to."); + + FCogWindowWidgets::SetNextItemToShortWidth(); + FCogWindowWidgets::InputText("Client Name", Config->ClientName); + ImGui::SetItemTooltip("Client name displayed in the server's clients list."); + + FCogWindowWidgets::SetNextItemToShortWidth(); + ImGui::InputInt("Client Port", &Config->ClientPort); + ImGui::SetItemTooltip("Port this client should wait for connection from server application."); + + ImGui::SeparatorText("Auto-Connect"); + + FCogWindowWidgets::SetNextItemToShortWidth(); + FCogWindowWidgets::ComboboxEnum("Dedicated Server", Config->AutoConnectOnDedicatedServer); + ImGui::SetItemTooltip("Auto-connect mode to the NetImgui server when launching on dedicated server mode."); + + FCogWindowWidgets::SetNextItemToShortWidth(); + FCogWindowWidgets::ComboboxEnum("Listen Server", Config->AutoConnectOnListenServer); + ImGui::SetItemTooltip("Auto-connect mode to the NetImgui server when launching on listen server mode."); + + FCogWindowWidgets::SetNextItemToShortWidth(); + FCogWindowWidgets::ComboboxEnum("Client", Config->AutoConnectOnClient); + ImGui::SetItemTooltip("Auto-connect mode to the NetImgui server when launching on client mode."); + + FCogWindowWidgets::SetNextItemToShortWidth(); + FCogWindowWidgets::ComboboxEnum("Standalone", Config->AutoConnectOnStandalone); + ImGui::SetItemTooltip("Auto-connect mode to the NetImgui server when launching on standalone mode."); + + ImGui::SeparatorText("Server App"); + + ImGui::Checkbox("Auto Run Server", &Config->AutoRunServer); + ImGui::SetItemTooltip("Automatically run the NetImgui server executable at startup."); + + FCogWindowWidgets::SetNextItemToShortWidth(); + FCogWindowWidgets::InputText("Server Executable", Config->ServerExecutable); + ImGui::SetItemTooltip("Filename of the NetImgui server executable."); + + FCogWindowWidgets::SetNextItemToShortWidth(); + FCogWindowWidgets::InputText("Server Directory", Config->ServerDirectory); + ImGui::SetItemTooltip("Directory of the NetImgui server executable."); + + FCogWindowWidgets::SetNextItemToShortWidth(); + FCogWindowWidgets::InputText("Server Arguments", Config->ServerArguments); + ImGui::SetItemTooltip("Argument used when launching the NetImgui server executable."); + } +#endif // #if NETIMGUI_ENABLED +} + +//-------------------------------------------------------------------------------------------------------------------------- +FString FCogEngineWindow_NetImgui::GetClientName() const +{ + switch (GetWorld()->GetNetMode()) + { + case NM_Standalone: return FString::Printf(TEXT("%s_%s"), *Config->ClientName, TEXT("Standalone")); + case NM_DedicatedServer: return FString::Printf(TEXT("%s_%s"), *Config->ClientName, TEXT("DedicatedServer")); + case NM_ListenServer: return FString::Printf(TEXT("%s_%s"), *Config->ClientName, TEXT("ListenServer")); + case NM_Client: return FString::Printf(TEXT("%s_%s"), *Config->ClientName, TEXT("Client")); + default:; + } + + return Config->ClientName; +} + + +//-------------------------------------------------------------------------------------------------------------------------- +void FCogEngineWindow_NetImgui::ConnectTo() +{ + FCogImGuiContextScope ImGuiContextScope(GetOwner()->GetContext()); + + const FString ClientName = GetClientName(); + + UE_LOG(LogCogImGui, Verbose, TEXT("FCogEngineWindow_NetImgui::ConnectTo | ClientName:%s | ServerAddress:%s | ServerPort:%d"), + *ClientName, + *Config->ServerAddress, + Config->ServerPort); + + const auto clientName = StringCast(*ClientName); + const auto serverAddress = StringCast(*Config->ServerAddress); + NetImgui::ConnectToApp(clientName.Get(), serverAddress.Get(), Config->ServerPort, nullptr, nullptr); +} + +//-------------------------------------------------------------------------------------------------------------------------- +void FCogEngineWindow_NetImgui::ConnectFrom() +{ + FCogImGuiContextScope ImGuiContextScope(GetOwner()->GetContext()); + + const FString ClientName = GetClientName(); + + UE_LOG(LogCogImGui, Verbose, TEXT("FCogEngineWindow_NetImgui::ConnectFrom | ClientName:%s | ClientPort:%d"), + *ClientName, + Config->ClientPort); + + const auto clientName = StringCast(*ClientName); + NetImgui::ConnectFromApp(clientName.Get(), Config->ClientPort, nullptr, nullptr); + +} + +//-------------------------------------------------------------------------------------------------------------------------- +void FCogEngineWindow_NetImgui::Disconnect() +{ + FCogImGuiContextScope ImGuiContextScope(GetOwner()->GetContext()); + + UE_LOG(LogCogImGui, Verbose, TEXT("FCogEngineWindow_NetImgui::Disconnect")); + NetImgui::Disconnect(); +} + +//-------------------------------------------------------------------------------------------------------------------------- +void FCogEngineWindow_NetImgui::RunServer() +{ + if (FPlatformProcess::IsProcRunning(ServerProcess)) + { + UE_LOG(LogCogImGui, Verbose, TEXT("FCogEngineWindow_NetImgui::RunServer | Already running")); + return; + } + + const FString ServerPath = FPaths::Combine(Config->ServerDirectory, Config->ServerExecutable); + if (IPlatformFile::GetPlatformPhysical().FileExists(*ServerPath) == false) + { + UE_LOG(LogCogImGui, Verbose, TEXT("FCogEngineWindow_NetImgui::RunServer | Invalid Server Path:%s"), *ServerPath); + return; + } + + UE_LOG(LogCogImGui, Verbose, TEXT("FCogEngineWindow_NetImgui::RunServer | Server Path:%s"), *ServerPath); + + ServerProcess = FPlatformProcess::CreateProc( + *ServerPath, + *Config->ServerArguments, + false, + false, + false, + nullptr, + 0, + *Config->ServerDirectory, + nullptr + ); +} + +//-------------------------------------------------------------------------------------------------------------------------- +void FCogEngineWindow_NetImgui::CloseServer() +{ + if (FPlatformProcess::IsProcRunning(ServerProcess) == false) + { + return; + } + + FPlatformProcess::TerminateProc(ServerProcess); +} + +//-------------------------------------------------------------------------------------------------------------------------- +// Config +//-------------------------------------------------------------------------------------------------------------------------- +void UCogEngineWindowConfig_NetImgui::Reset() +{ + Super::Reset(); + +#if NETIMGUI_ENABLED + + ClientName = FString("Cog"); + ClientPort = NetImgui::kDefaultClientPort; + AutoConnectOnDedicatedServer = ECogNetImguiAutoConnectionMode::AutoConnect; + AutoConnectOnListenServer = ECogNetImguiAutoConnectionMode::NoAutoConnect; + AutoConnectOnClient = ECogNetImguiAutoConnectionMode::NoAutoConnect; + AutoConnectOnStandalone = ECogNetImguiAutoConnectionMode::NoAutoConnect; + + ServerAddress = FString("127.0.0.1"); + ServerPort = NetImgui::kDefaultServerPort; + ServerDirectory = FString("C:\\NetImgui\\Server_Exe"); + ServerExecutable = FString("NetImguiServer.exe"); + ServerArguments = FString(""); + AutoRunServer = false; + +#endif +} diff --git a/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_Plots.cpp b/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_Plots.cpp index 4fc8332..0399111 100644 --- a/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_Plots.cpp +++ b/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_Plots.cpp @@ -1,6 +1,7 @@ #include "CogEngineWindow_Plots.h" #include "CogDebugPlot.h" +#include "CogImguiHelper.h" #include "CogWindowWidgets.h" #include "Engine/World.h" #include "imgui.h" @@ -15,6 +16,8 @@ void FCogEngineWindow_Plots::Initialize() bNoPadding = true; Config = GetConfig(); + + FCogDebugPlot::Clear(); } //-------------------------------------------------------------------------------------------------------------------------- @@ -46,28 +49,52 @@ void FCogEngineWindow_Plots::RenderContent() { Super::RenderContent(); + TArray VisiblePlots; + for (FCogDebugPlotEntry& Plot : FCogDebugPlot::Plots) + { + if (Plot.YAxis != ImAxis_COUNT && Plot.GraphIndex != INDEX_NONE) + { + VisiblePlots.Add(&Plot); + } + } + + for (FCogDebugPlotEntry& Event : FCogDebugPlot::Events) + { + if (Event.YAxis != ImAxis_COUNT && Event.GraphIndex != INDEX_NONE) + { + VisiblePlots.Add(&Event); + } + } + RenderMenu(); - if (ImGui::BeginTable("PlotTable", 2, ImGuiTableFlags_RowBg - | ImGuiTableFlags_Resizable - | ImGuiTableFlags_BordersV - | ImGuiTableFlags_NoPadInnerX - | ImGuiTableFlags_NoPadOuterX)) + if (Config->DockEntries) { + if (ImGui::BeginTable("PlotTable", 2, ImGuiTableFlags_RowBg + | ImGuiTableFlags_Resizable + | ImGuiTableFlags_BordersV + | ImGuiTableFlags_NoPadInnerX + | ImGuiTableFlags_NoPadOuterX)) + { - ImGui::TableSetupColumn("PlotsList", ImGuiTableColumnFlags_WidthFixed, FCogWindowWidgets::GetFontWidth() * 20.0f); - ImGui::TableSetupColumn("Plots", ImGuiTableColumnFlags_WidthStretch, 0.0f); - ImGui::TableNextRow(); + ImGui::TableSetupColumn("PlotsList", ImGuiTableColumnFlags_WidthFixed, FCogWindowWidgets::GetFontWidth() * 20.0f); + ImGui::TableSetupColumn("Plots", ImGuiTableColumnFlags_WidthStretch, 0.0f); + ImGui::TableNextRow(); - TArray VisiblePlots; - ImGui::TableNextColumn(); - RenderPlotsList(VisiblePlots); + ImGui::TableNextColumn(); + RenderAllEntriesNames(ImVec2(0, -1)); - ImGui::TableNextColumn(); + ImGui::TableNextColumn(); + RenderPlots(VisiblePlots); + + ImGui::EndTable(); + } + + } + else + { RenderPlots(VisiblePlots); - - ImGui::EndTable(); } bApplyTimeScale = false; @@ -78,13 +105,17 @@ void FCogEngineWindow_Plots::RenderMenu() { if (ImGui::BeginMenuBar()) { + if (Config->DockEntries == false) + { + if (ImGui::BeginMenu("Entries")) + { + RenderAllEntriesNames(ImVec2(ImGui::GetFontSize() * 15, ImGui::GetFontSize() * 20)); + ImGui::EndMenu(); + } + } + if (ImGui::BeginMenu("Options")) { - if (ImGui::MenuItem("Clear Data")) - { - FCogDebugPlot::Clear(); - } - if (ImGui::MenuItem("Reset")) { FCogDebugPlot::Pause = false; @@ -95,20 +126,47 @@ void FCogEngineWindow_Plots::RenderMenu() ImGui::Separator(); FCogWindowWidgets::SetNextItemToShortWidth(); - if (ImGui::SliderInt("Rows", &Config->Rows, 1, 5)) + if (ImGui::SliderInt("Num Graphs", &Config->NumGraphs, 1, 5)) { bApplyTimeScale = true; } - + FCogWindowWidgets::SetNextItemToShortWidth(); - if (ImGui::SliderFloat("Time Range", &Config->TimeRange, 1.0f, 30.0f, "%0.1f")) + ImGui::SliderInt("Num YAxis", &Config->NumYAxis, 0, 3); + + FCogWindowWidgets::SetNextItemToShortWidth(); + if (ImGui::SliderFloat("Time range", &Config->TimeRange, 1.0f, 100.0f, "%0.1f")) { bApplyTimeScale = true; } - + + FCogWindowWidgets::SetNextItemToShortWidth(); + ImGui::SliderFloat("Drag pause sensitivity", &Config->DragPauseSensitivity, 1.0f, 50.0f, "%0.0f"); + + FCogWindowWidgets::SetNextItemToShortWidth(); + ImGui::Checkbox("Show time bar at game time", &Config->ShowTimeBarAtGameTime); + + FCogWindowWidgets::SetNextItemToShortWidth(); + ImGui::Checkbox("Show time bar at cursor", &Config->ShowTimeBarAtCursor); + + FCogWindowWidgets::SetNextItemToShortWidth(); + ImGui::Checkbox("Show value at cursor", &Config->ShowValueAtCursor); + + FCogWindowWidgets::SetNextItemToShortWidth(); + ImGui::Checkbox("Dock entries", &Config->DockEntries); + + constexpr ImGuiColorEditFlags ColorEditFlags = ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_AlphaPreviewHalf; + FCogImguiHelper::ColorEdit4("Pause background color", Config->PauseBackgroundColor, ColorEditFlags); + ImGui::SetItemTooltip("Background color of the plot when paused."); + ImGui::EndMenu(); } + if (ImGui::MenuItem("Clear")) + { + FCogDebugPlot::Clear(); + } + FCogWindowWidgets::ToggleMenuButton(&FCogDebugPlot::Pause, "Pause", ImVec4(1.0f, 0.0f, 0.0f, 1.0f)); ImGui::EndMenuBar(); @@ -116,40 +174,82 @@ void FCogEngineWindow_Plots::RenderMenu() } //-------------------------------------------------------------------------------------------------------------------------- -void FCogEngineWindow_Plots::RenderPlotsList(TArray& VisiblePlots) +void FCogEngineWindow_Plots::RenderEntryName(const int Index, FCogDebugPlotEntry& Entry) { - if (ImGui::BeginChild("Plots", ImVec2(0, -1))) + ImGui::PushID(Index); + + const bool IsAssignedToRow = Entry.GraphIndex != INDEX_NONE; + if (ImGui::Selectable(TCHAR_TO_ANSI(*Entry.Name.ToString()), IsAssignedToRow, ImGuiSelectableFlags_AllowDoubleClick)) { - int Index = 0; - - ImGui::Indent(6); - - for (FCogDebugPlotEntry& Entry : FCogDebugPlot::Plots) + if (IsAssignedToRow) { - if (Entry.CurrentYAxis != ImAxis_COUNT && Entry.CurrentRow != INDEX_NONE) - { - VisiblePlots.Add(&Entry); - } + Entry.ResetGraphAndAxis(); + } + else + { + Entry.AssignGraphAndAxis(0, ImAxis_Y1); + } + } - ImGui::PushID(Index); + if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None)) + { + const auto EntryName = StringCast(*Entry.Name.ToString()); + ImGui::SetDragDropPayload("DragAndDrop", EntryName.Get(), EntryName.Length() + 1); + ImGui::Text("%s", EntryName.Get()); + ImGui::EndDragDropSource(); + } - ImGui::PushStyleColor(ImGuiCol_Text, Entry.IsEventPlot ? IM_COL32(128, 128, 255, 255) : IM_COL32(255, 255, 255, 255)); - ImGui::Selectable(TCHAR_TO_ANSI(*Entry.Name.ToString()), false, 0); - ImGui::PopStyleColor(); + ImGui::PopID(); +} - if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None)) - { - const auto EntryName = StringCast(*Entry.Name.ToString()); - ImGui::SetDragDropPayload("DragAndDrop", EntryName.Get(), EntryName.Length() + 1); - ImGui::Text("%s", EntryName.Get()); - ImGui::EndDragDropSource(); - } - - ImGui::PopID(); - Index++; +//-------------------------------------------------------------------------------------------------------------------------- +void FCogEngineWindow_Plots::RenderAllEntriesNames(const ImVec2& InSize) +{ + if (ImGui::BeginChild("Entries", InSize)) + { + if (Config->DockEntries) + { + ImGui::Indent(6); } - ImGui::Unindent(); + int Index = 0; + + if (FCogWindowWidgets::DarkCollapsingHeader("Events", ImGuiTreeNodeFlags_DefaultOpen)) + { + if (FCogDebugPlot::Events.IsEmpty()) + { + ImGui::TextDisabled("No event added yet"); + } + else + { + for (FCogDebugPlotEntry& Event : FCogDebugPlot::Events) + { + RenderEntryName(Index, Event); + Index++; + } + } + } + + if (FCogWindowWidgets::DarkCollapsingHeader("Plots", ImGuiTreeNodeFlags_DefaultOpen)) + { + if (FCogDebugPlot::Plots.IsEmpty()) + { + ImGui::TextDisabled("No plot added yet"); + } + else + { + for (FCogDebugPlotEntry& Plot : FCogDebugPlot::Plots) + { + RenderEntryName(Index, Plot); + Index++; + } + } + } + + if (Config->DockEntries) + { + ImGui::Unindent(); + } } ImGui::EndChild(); @@ -157,9 +257,9 @@ void FCogEngineWindow_Plots::RenderPlotsList(TArray& Visibl { if (const ImGuiPayload* Payload = ImGui::AcceptDragDropPayload("DragAndDrop")) { - if (FCogDebugPlotEntry* Plot = FCogDebugPlot::FindPlot(FName((const char*)Payload->Data))) + if (FCogDebugPlotEntry* Plot = FCogDebugPlot::FindEntry(FName((const char*)Payload->Data))) { - Plot->ResetAxis(); + Plot->ResetGraphAndAxis(); } } ImGui::EndDragDropTarget(); @@ -174,9 +274,16 @@ void FCogEngineWindow_Plots::RenderPlots(const TArray& Visi static float RowRatios[] = { 1, 1, 1, 1, 1, 1 }; static float ColRatios[] = { 1 }; static ImPlotSubplotFlags SubplotsFlags = ImPlotSubplotFlags_LinkCols; - if (ImPlot::BeginSubplots("", Config->Rows, 1, ImVec2(-1, -1), SubplotsFlags, RowRatios, ColRatios)) + + const bool PushPlotBgStyle = FCogDebugPlot::Pause; + if (PushPlotBgStyle) { - for (int PlotIndex = 0; PlotIndex < Config->Rows; ++PlotIndex) + ImPlot::PushStyleColor(ImPlotCol_PlotBg, FCogImguiHelper::ToImVec4(Config->PauseBackgroundColor)); + } + + if (ImPlot::BeginSubplots("", Config->NumGraphs, 1, ImVec2(-1, -1), SubplotsFlags, RowRatios, ColRatios)) + { + for (int PlotIndex = 0; PlotIndex < Config->NumGraphs; ++PlotIndex) { if (ImPlot::BeginPlot("##Plot", ImVec2(-1, 250))) { @@ -186,15 +293,27 @@ void FCogEngineWindow_Plots::RenderPlots(const TArray& Visi for (const FCogDebugPlotEntry* PlotPtr : VisiblePlots) { - HasPlotOnAxisY1 |= PlotPtr->CurrentYAxis == ImAxis_Y1 && PlotPtr->CurrentRow == PlotIndex; - HasPlotOnAxisY2 |= PlotPtr->CurrentYAxis == ImAxis_Y2 && PlotPtr->CurrentRow == PlotIndex; - HasPlotOnAxisY3 |= PlotPtr->CurrentYAxis == ImAxis_Y3 && PlotPtr->CurrentRow == PlotIndex; + HasPlotOnAxisY1 |= PlotPtr->YAxis == ImAxis_Y1 && PlotPtr->GraphIndex == PlotIndex; + HasPlotOnAxisY2 |= PlotPtr->YAxis == ImAxis_Y2 && PlotPtr->GraphIndex == PlotIndex; + HasPlotOnAxisY3 |= PlotPtr->YAxis == ImAxis_Y3 && PlotPtr->GraphIndex == PlotIndex; } ImPlot::SetupAxis(ImAxis_X1, nullptr, ImPlotAxisFlags_NoTickLabels | ImPlotAxisFlags_NoGridLines); - ImPlot::SetupAxis(ImAxis_Y1, HasPlotOnAxisY1 ? "" : "[drop here]", (HasPlotOnAxisY1 ? ImPlotAxisFlags_None : (ImPlotAxisFlags_NoTickLabels | ImPlotAxisFlags_NoGridLines)) | ImPlotAxisFlags_AutoFit); - ImPlot::SetupAxis(ImAxis_Y2, HasPlotOnAxisY2 ? "" : "[drop here]", (HasPlotOnAxisY2 ? ImPlotAxisFlags_None : (ImPlotAxisFlags_NoTickLabels | ImPlotAxisFlags_NoGridLines)) | ImPlotAxisFlags_AutoFit | ImPlotAxisFlags_Opposite); - ImPlot::SetupAxis(ImAxis_Y3, HasPlotOnAxisY3 ? "" : "[drop here]", (HasPlotOnAxisY3 ? ImPlotAxisFlags_None : (ImPlotAxisFlags_NoTickLabels | ImPlotAxisFlags_NoGridLines)) | ImPlotAxisFlags_AutoFit | ImPlotAxisFlags_Opposite); + + if (Config->NumYAxis > 0) + { + ImPlot::SetupAxis(ImAxis_Y1, HasPlotOnAxisY1 ? "" : "[drop here]", (HasPlotOnAxisY1 ? ImPlotAxisFlags_None : (ImPlotAxisFlags_NoTickLabels | ImPlotAxisFlags_NoGridLines)) | ImPlotAxisFlags_AutoFit); + } + + if (Config->NumYAxis > 1) + { + ImPlot::SetupAxis(ImAxis_Y2, HasPlotOnAxisY2 ? "" : "[drop here]", (HasPlotOnAxisY2 ? ImPlotAxisFlags_None : (ImPlotAxisFlags_NoTickLabels | ImPlotAxisFlags_NoGridLines)) | ImPlotAxisFlags_AutoFit | ImPlotAxisFlags_Opposite); + } + + if (Config->NumYAxis > 2) + { + ImPlot::SetupAxis(ImAxis_Y3, HasPlotOnAxisY3 ? "" : "[drop here]", (HasPlotOnAxisY3 ? ImPlotAxisFlags_None : (ImPlotAxisFlags_NoTickLabels | ImPlotAxisFlags_NoGridLines)) | ImPlotAxisFlags_AutoFit | ImPlotAxisFlags_Opposite); + } //-------------------------------------------------------------------------------------------------- // Set the initial X axis range. After, it is automatically updated to move with the current time. @@ -209,94 +328,136 @@ void FCogEngineWindow_Plots::RenderPlots(const TArray& Visi Config->TimeRange = TimeRange; } + const float Time = GetWorld() ? GetWorld()->GetTimeSeconds() : 0.0; + + //------------------------------------------------------------------ + // Setup all the Z and Y axis limits. Must be done before calling + // ImPlot::GetPlotPos or ImPlot::GetPlotSize as it calls SetupLock() + //------------------------------------------------------------------ + { + //-------------------------------------------------------------------------------- + // Make the time axis move forward automatically, unless the user pauses or zoom. + //-------------------------------------------------------------------------------- + if (FCogDebugPlot::Pause == false && ImGui::GetIO().MouseWheel == 0) + { + ImPlot::SetupAxisLimits(ImAxis_X1, Time - TimeRange, Time, ImGuiCond_Always); + } + + if (bApplyTimeScale) + { + ImPlot::SetupAxisLimits(ImAxis_X1, Time - Config->TimeRange, Time, ImGuiCond_Always); + } + + //-------------------------------------------------------------------------------- + // Set the Y axis limit for Events. + //-------------------------------------------------------------------------------- + for (const FCogDebugPlotEntry* PlotPtr : VisiblePlots) + { + if (PlotPtr == nullptr) + { continue; } + + if (PlotPtr->GraphIndex != PlotIndex) + { continue; } + + if (PlotPtr->IsEventPlot) + { + ImPlot::SetupAxisLimits(PlotPtr->YAxis, 0, PlotPtr->MaxRow + 2, ImGuiCond_Always); + } + } + } + const ImVec2 PlotMin = ImPlot::GetPlotPos(); const ImVec2 PlotSize = ImPlot::GetPlotSize(); const ImVec2 PlotMax = PlotMin + PlotSize; //---------------------------------------------------------------- - // Draw a vertical lines representing the current time and the mouse time + // Pause the scrolling if the user drag inside //---------------------------------------------------------------- - RenderTimeMarker(); + const ImVec2 Mouse = ImGui::GetMousePos(); + if (Mouse.x > PlotMin.x + && Mouse.y > PlotMin.y + && Mouse.x < PlotMax.x + && Mouse.y < PlotMax.y + && ImGui::GetDragDropPayload() == nullptr) + { + const ImVec2 Drag = ImGui::GetMouseDragDelta(0); + if (FMath::Abs(Drag.x) > Config->DragPauseSensitivity) + { + FCogDebugPlot::Pause = true; + } + } + if (ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) + { + FCogDebugPlot::Pause = false; + } + + //--------------------------------------------------------------------------- + // Draw a vertical lines representing the current time and the mouse time + //--------------------------------------------------------------------------- + if (Config->ShowTimeBarAtGameTime || Config->ShowTimeBarAtGameTime) + { + ImDrawList* PlotDrawList = ImPlot::GetPlotDrawList(); + + const float PlotTop = PlotMin.y; + const float TimeBarBottom = PlotTop + PlotSize.y; + + ImPlot::PushPlotClipRect(); + if (Config->ShowTimeBarAtCursor) + { + PlotDrawList->AddLine(ImVec2(ImGui::GetMousePos().x, PlotTop), ImVec2(ImGui::GetMousePos().x, TimeBarBottom), IM_COL32(128, 128, 128, 64)); + } + + if (Config->ShowTimeBarAtGameTime && FCogDebugPlot::Pause) + { + const float TimeBarX = ImPlot::PlotToPixels(Time, 0.0f).x; + PlotDrawList->AddLine(ImVec2(TimeBarX, PlotTop), ImVec2(TimeBarX, TimeBarBottom), IM_COL32(255, 255, 255, 64)); + } + ImPlot::PopPlotClipRect(); + } + + //----------------------------------------------------------- + // Draw all the plots assigned to this row + //----------------------------------------------------------- for (FCogDebugPlotEntry* PlotPtr : VisiblePlots) { if (PlotPtr == nullptr) + { continue; } + + FCogDebugPlotEntry& Plot = *PlotPtr; + if (Plot.GraphIndex != PlotIndex) + { continue; } + + ImPlot::SetAxis(Plot.YAxis); + + ImPlot::SetNextLineStyle(IMPLOT_AUTO_COL); + const auto Label = StringCast(*Plot.Name.ToString()); + + //------------------------------------------------------- + // Plot Events + //------------------------------------------------------- + if (Plot.IsEventPlot) { - continue; + RenderEvents(Plot, Label.Get(), PlotMin, PlotMax); + } + //------------------------------------------------------- + // Plot Values + //------------------------------------------------------- + else if (Plot.Values.empty() == false) + { + RenderValues(Plot, Label.Get()); } - FCogDebugPlotEntry& Entry = *PlotPtr; - - if (Entry.Values.empty()) + //------------------------------------------------------- + // Allow legend item labels to be drag and drop sources + //------------------------------------------------------- + if (ImPlot::BeginDragDropSourceItem(Label.Get())) { - continue; + const auto EntryName = StringCast(*Plot.Name.ToString()); + ImGui::SetDragDropPayload("DragAndDrop", EntryName.Get(), EntryName.Length() + 1); + ImGui::TextUnformatted(EntryName.Get()); + ImPlot::EndDragDropSource(); } - - if (Entry.CurrentRow == PlotIndex) - { - //-------------------------------------------------------------------------------- - // Make the time axis move forward automatically, unless the user pauses or zoom. - //-------------------------------------------------------------------------------- - if (FCogDebugPlot::Pause == false && ImGui::GetIO().MouseWheel == 0) - { - ImPlot::SetupAxisLimits(ImAxis_X1, Entry.Time - TimeRange, Entry.Time, ImGuiCond_Always); - } - - if (bApplyTimeScale) - { - ImPlot::SetupAxisLimits(ImAxis_X1, Entry.Time - Config->TimeRange, Entry.Time, ImGuiCond_Always); - } - - ImPlot::SetAxis(Entry.CurrentYAxis); - - ImPlot::SetNextLineStyle(IMPLOT_AUTO_COL); - const auto Label = StringCast(*Entry.Name.ToString()); - - //---------------------------------------------------------------- - // Pause the scrolling if the user drag inside - //---------------------------------------------------------------- - const ImVec2 Mouse = ImGui::GetMousePos(); - if (Mouse.x > PlotMin.x - && Mouse.y > PlotMin.y - && Mouse.x < PlotMax.x - && Mouse.y < PlotMax.y - && ImGui::GetDragDropPayload() == nullptr) - { - const ImVec2 Drag = ImGui::GetMouseDragDelta(0); - if (FMath::Abs(Drag.x) > 10) - { - FCogDebugPlot::Pause = true; - } - } - - //------------------------------------------------------- - // Plot Events - //------------------------------------------------------- - const bool IsEventPlot = Entry.Events.Num() > 0; - if (IsEventPlot) - { - RenderEvents(Entry, Label.Get(), PlotMin, PlotMax); - } - //------------------------------------------------------- - // Plot Values - //------------------------------------------------------- - else - { - RenderValues(Entry, Label.Get()); - } - - //------------------------------------------------------- - // Allow legend item labels to be drag and drop sources - //------------------------------------------------------- - if (ImPlot::BeginDragDropSourceItem(Label.Get())) - { - const auto EntryName = StringCast(*Entry.Name.ToString()); - ImGui::SetDragDropPayload("DragAndDrop", EntryName.Get(), EntryName.Length() + 1); - ImGui::TextUnformatted(EntryName.Get()); - ImPlot::EndDragDropSource(); - } - } - } //------------------------------------------------------- @@ -306,9 +467,9 @@ void FCogEngineWindow_Plots::RenderPlots(const TArray& Visi { if (const ImGuiPayload* Payload = ImGui::AcceptDragDropPayload("DragAndDrop")) { - if (FCogDebugPlotEntry* Plot = FCogDebugPlot::FindPlot(FName((const char*)Payload->Data))) + if (FCogDebugPlotEntry* Plot = FCogDebugPlot::FindEntry(FName((const char*)Payload->Data))) { - Plot->AssignAxis(PlotIndex, ImAxis_Y1); + Plot->AssignGraphAndAxis(PlotIndex, ImAxis_Y1); } } ImPlot::EndDragDropTarget(); @@ -323,9 +484,9 @@ void FCogEngineWindow_Plots::RenderPlots(const TArray& Visi { if (const ImGuiPayload* Payload = ImGui::AcceptDragDropPayload("DragAndDrop")) { - if (FCogDebugPlotEntry* Plot = FCogDebugPlot::FindPlot(FName((const char*)Payload->Data))) + if (FCogDebugPlotEntry* Plot = FCogDebugPlot::FindEntry(FName((const char*)Payload->Data))) { - Plot->AssignAxis(PlotIndex, y); + Plot->AssignGraphAndAxis(PlotIndex, y); } } ImPlot::EndDragDropTarget(); @@ -339,9 +500,9 @@ void FCogEngineWindow_Plots::RenderPlots(const TArray& Visi { if (const ImGuiPayload* Payload = ImGui::AcceptDragDropPayload("DragAndDrop")) { - if (FCogDebugPlotEntry* Plot = FCogDebugPlot::FindPlot(FName((const char*)Payload->Data))) + if (FCogDebugPlotEntry* Plot = FCogDebugPlot::FindEntry(FName((const char*)Payload->Data))) { - Plot->AssignAxis(PlotIndex, ImAxis_Y1); + Plot->AssignGraphAndAxis(PlotIndex, ImAxis_Y1); } } ImPlot::EndDragDropTarget(); @@ -352,45 +513,39 @@ void FCogEngineWindow_Plots::RenderPlots(const TArray& Visi } ImPlot::EndSubplots(); } + + if (PushPlotBgStyle) + { + ImPlot::PopStyleColor(); + } } ImGui::EndChild(); } //-------------------------------------------------------------------------------------------------------------------------- -void FCogEngineWindow_Plots::RenderTimeMarker() const -{ - const ImVec2 PlotMin = ImPlot::GetPlotPos(); - const ImVec2 PlotSize = ImPlot::GetPlotSize(); - ImDrawList* PlotDrawList = ImPlot::GetPlotDrawList(); - - const float PlotTop = PlotMin.y; - const float TimeBarBottom = PlotTop + PlotSize.y; - - ImPlot::PushPlotClipRect(); - PlotDrawList->AddLine(ImVec2(ImGui::GetMousePos().x, PlotTop), ImVec2(ImGui::GetMousePos().x, TimeBarBottom), IM_COL32(128, 128, 128, 64)); - if (FCogDebugPlot::Pause) - { - const float Time = GetWorld() ? GetWorld()->GetTimeSeconds() : 0.0; - const float TimeBarX = ImPlot::PlotToPixels(Time, 0.0f).x; - PlotDrawList->AddLine(ImVec2(TimeBarX, PlotTop), ImVec2(TimeBarX, TimeBarBottom), IM_COL32(255, 255, 255, 64)); - } - ImPlot::PopPlotClipRect(); -} - -//-------------------------------------------------------------------------------------------------------------------------- -void FCogEngineWindow_Plots::RenderValues(FCogDebugPlotEntry& Entry, const char* Label) +void FCogEngineWindow_Plots::RenderValues(FCogDebugPlotEntry& Entry, const char* Label) const { //---------------------------------------------------------------- - // Custom tooltip + // Value at cursor tooltip //---------------------------------------------------------------- - if (ImPlot::IsPlotHovered()) + if (Config->ShowValueAtCursor && ImPlot::IsPlotHovered()) { float Value; if (Entry.FindValue(ImPlot::GetPlotMousePos().x, Value)) { - ImGui::BeginTooltip(); - ImGui::Text("%s: %0.2f", Label, Value); - ImGui::EndTooltip(); + if (FCogWindowWidgets::BeginTableTooltip()) + { + if (ImGui::BeginTable("Params", 2, ImGuiTableFlags_Borders)) + { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("%s", Label); + ImGui::TableNextColumn(); + ImGui::Text("%0.2f", Value); + ImGui::EndTable(); + } + FCogWindowWidgets::EndTableTooltip(); + } } } @@ -418,16 +573,8 @@ void FCogEngineWindow_Plots::RenderEvents(FCogDebugPlotEntry& Entry, const char* const ImVec2 Mouse = ImGui::GetMousePos(); ImDrawList* PlotDrawList = ImPlot::GetPlotDrawList(); - //-------------------------------------------------------------------- - // Update plot time for events as events are not pushed every frames - //-------------------------------------------------------------------- - Entry.UpdateTime(GetWorld()); - - ImPlot::SetupAxisLimits(Entry.CurrentYAxis, 0, Entry.MaxRow + 2, ImGuiCond_Always); - ImPlot::PushPlotClipRect(); - //---------------------------------------------------------------- // Plot line only to make the plotter move in time and auto scale //---------------------------------------------------------------- @@ -447,7 +594,7 @@ void FCogEngineWindow_Plots::RenderEvents(FCogDebugPlotEntry& Entry, const char* const bool IsInstant = Event.StartTime == Event.EndTime; if (IsInstant) { - constexpr float Radius = 10.0f; + constexpr float Radius = 10.0f; PlotDrawList->AddNgon(PosMid, 10, Event.BorderColor, 4); PlotDrawList->AddNgonFilled(PosMid, 10, Event.FillColor, 4); PlotDrawList->AddText(ImVec2(PosMid.x + 15, PosMid.y - 6), IM_COL32(255, 255, 255, 255), TCHAR_TO_ANSI(*Event.DisplayName)); @@ -494,76 +641,78 @@ void FCogEngineWindow_Plots::RenderEvents(FCogDebugPlotEntry& Entry, const char* } //-------------------------------------------------------------------------------------------------------------------------- -void FCogEngineWindow_Plots::RenderEventTooltip(const FCogDebugPlotEvent* HoveredEvent, FCogDebugPlotEntry& Entry) +void FCogEngineWindow_Plots::RenderEventTooltip(const FCogDebugPlotEvent* HoveredEvent, const FCogDebugPlotEntry& Entry) { if (ImPlot::IsPlotHovered() && HoveredEvent != nullptr) { - FCogWindowWidgets::BeginTableTooltip(); - if (ImGui::BeginTable("Params", 2, ImGuiTableFlags_Borders)) + if (FCogWindowWidgets::BeginTableTooltip()) { - //------------------------ - // Event Name - //------------------------ - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::Text("Name"); - ImGui::TableNextColumn(); - ImGui::Text("%s", TCHAR_TO_ANSI(*HoveredEvent->DisplayName)); - - //------------------------ - // Owner Name - //------------------------ - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::Text("Owner"); - ImGui::TableNextColumn(); - ImGui::Text("%s", TCHAR_TO_ANSI(*HoveredEvent->OwnerName)); - - //------------------------ - // Times - //------------------------ - if (HoveredEvent->EndTime != HoveredEvent->StartTime) + if (ImGui::BeginTable("Params", 2, ImGuiTableFlags_Borders)) { - const float ActualEndTime = HoveredEvent->GetActualEndTime(Entry); - const uint64 ActualEndFrame = HoveredEvent->GetActualEndFrame(Entry); + //------------------------ + // Event Name + //------------------------ + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("Name"); + ImGui::TableNextColumn(); + ImGui::Text("%s", TCHAR_TO_ANSI(*HoveredEvent->DisplayName)); + //------------------------ + // Owner Name + //------------------------ ImGui::TableNextRow(); ImGui::TableNextColumn(); - ImGui::Text("Duration"); + ImGui::Text("Owner"); ImGui::TableNextColumn(); - ImGui::Text("%0.2fs", ActualEndTime - HoveredEvent->StartTime); + ImGui::Text("%s", TCHAR_TO_ANSI(*HoveredEvent->OwnerName)); - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::Text("Frames"); - ImGui::TableNextColumn(); - ImGui::Text("%d [%d-%d]", - (int32)(ActualEndFrame - HoveredEvent->StartFrame), - (int32)(HoveredEvent->StartFrame % 1000), - (int32)(ActualEndFrame % 1000)); - } - else - { - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::Text("Frame"); - ImGui::TableNextColumn(); - ImGui::Text("%d", (int32)(HoveredEvent->StartFrame % 1000)); - } + //------------------------ + // Times + //------------------------ + if (HoveredEvent->EndTime != HoveredEvent->StartTime) + { + const float ActualEndTime = HoveredEvent->GetActualEndTime(Entry); + const uint64 ActualEndFrame = HoveredEvent->GetActualEndFrame(Entry); - //------------------------ - // Params - //------------------------ - for (FCogDebugPlotEventParams Param : HoveredEvent->Params) - { - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::Text("%s", TCHAR_TO_ANSI(*Param.Name.ToString())); - ImGui::TableNextColumn(); - ImGui::Text("%s", TCHAR_TO_ANSI(*Param.Value)); + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("Duration"); + ImGui::TableNextColumn(); + ImGui::Text("%0.2fs", ActualEndTime - HoveredEvent->StartTime); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("Frames"); + ImGui::TableNextColumn(); + ImGui::Text("%d [%d-%d]", + (int32)(ActualEndFrame - HoveredEvent->StartFrame), + (int32)(HoveredEvent->StartFrame % 1000), + (int32)(ActualEndFrame % 1000)); + } + else + { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("Frame"); + ImGui::TableNextColumn(); + ImGui::Text("%d", (int32)(HoveredEvent->StartFrame % 1000)); + } + + //------------------------ + // Params + //------------------------ + for (FCogDebugPlotEventParams Param : HoveredEvent->Params) + { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("%s", TCHAR_TO_ANSI(*Param.Name.ToString())); + ImGui::TableNextColumn(); + ImGui::Text("%s", TCHAR_TO_ANSI(*Param.Value)); + } + ImGui::EndTable(); } - ImGui::EndTable(); + FCogWindowWidgets::EndTableTooltip(); } - FCogWindowWidgets::EndTableTooltip(); } } diff --git a/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_Selection.cpp b/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_Selection.cpp index dbe97d1..710ede4 100644 --- a/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_Selection.cpp +++ b/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_Selection.cpp @@ -2,9 +2,11 @@ #include "CogDebug.h" #include "CogEngineHelper.h" +#include "CogEngineReplicator.h" #include "CogEngineWindow_ImGui.h" #include "CogImguiHelper.h" #include "CogImguiInputHelper.h" +#include "CogWindowConsoleCommandManager.h" #include "CogWindowManager.h" #include "CogWindowWidgets.h" #include "Components/PrimitiveComponent.h" @@ -27,11 +29,14 @@ void FCogEngineWindow_Selection::Initialize() Config = GetConfig(); - ConsoleCommands.Add(IConsoleManager::Get().RegisterConsoleCommand( + FCogWindowConsoleCommandManager::RegisterWorldConsoleCommand( *ToggleSelectionModeCommand, TEXT("Toggle the actor selection mode"), - FConsoleCommandWithArgsDelegate::CreateLambda([this](const TArray& Args) { ToggleSelectionMode(); }), - ECVF_Cheat)); + GetWorld(), + FCogWindowConsoleCommandDelegate::CreateLambda([this](const TArray& InArgs, UWorld* InWorld) + { + ToggleSelectionMode(); + })); TryReapplySelection(); } @@ -50,10 +55,6 @@ void FCogEngineWindow_Selection::RenderHelp() //-------------------------------------------------------------------------------------------------------------------------- void FCogEngineWindow_Selection::Shutdown() { - for (IConsoleObject* ConsoleCommand : ConsoleCommands) - { - IConsoleManager::Get().UnregisterConsoleObject(ConsoleCommand); - } } //-------------------------------------------------------------------------------------------------------------------------- @@ -75,7 +76,7 @@ void FCogEngineWindow_Selection::PreSaveConfig() //-------------------------------------------------------------------------------------------------------------------------- void FCogEngineWindow_Selection::TryReapplySelection() const { - const UWorld* World = GetWorld(); + const UWorld* World = GetWorld(); if (World == nullptr) { return; @@ -139,7 +140,7 @@ void FCogEngineWindow_Selection::ActivateSelectionMode() bSelectionModeActive = true; bIsInputEnabledBeforeEnteringSelectionMode = GetOwner()->GetContext().GetEnableInput(); GetOwner()->GetContext().SetEnableInput(true); - GetOwner()->SetHideAllWindows(true); + GetOwner()->SetActivateSelectionMode(true); } //-------------------------------------------------------------------------------------------------------------------------- @@ -161,7 +162,7 @@ void FCogEngineWindow_Selection::DeactivateSelectionMode() //-------------------------------------------------------------------------------------------- GetOwner()->GetContext().SetEnableInput(bIsInputEnabledBeforeEnteringSelectionMode); - GetOwner()->SetHideAllWindows(false); + GetOwner()->SetActivateSelectionMode(false); } //-------------------------------------------------------------------------------------------------------------------------- @@ -204,7 +205,14 @@ void FCogEngineWindow_Selection::RenderContent() if (ImGui::BeginMenu("Options")) { ImGui::Checkbox("Save selection", &Config->bReapplySelection); + ImGui::SetItemTooltip("Should the last selection be saved and reapplied on startup."); + ImGui::Checkbox("Actor Name Use Label", &FCogDebug::Settings.ActorNameUseLabel); + ImGui::SetItemTooltip("Should actor names be displayed using their label. Labels are more readable."); + + ImGui::Checkbox("Replicate Selection", &FCogDebug::Settings.ReplicateSelection); + ImGui::SetItemTooltip("Should the client replicate its actor selection to the server."); + ImGui::EndMenu(); } @@ -219,7 +227,14 @@ void FCogEngineWindow_Selection::RenderContent() //-------------------------------------------------------------------------------------------------------------------------- bool FCogEngineWindow_Selection::DrawSelectionCombo() { - return FCogWindowWidgets::ActorsListWithFilters(*GetWorld(), ActorClasses, Config->SelectedClassIndex, &Filter, GetLocalPlayerPawn()); + AActor* NewSelection = nullptr; + const bool result = FCogWindowWidgets::ActorsListWithFilters(NewSelection, *GetWorld(), ActorClasses, Config->SelectedClassIndex, &Filter, GetLocalPlayerPawn()); + if (result) + { + SetGlobalSelection(NewSelection); + } + + return result; } //-------------------------------------------------------------------------------------------------------------------------- @@ -254,7 +269,15 @@ void FCogEngineWindow_Selection::TickSelectionMode() AActor* HoveredActor = nullptr; FVector WorldOrigin, WorldDirection; - if (UGameplayStatics::DeprojectScreenToWorld(PlayerController, FCogImguiHelper::ToFVector2D(ImGui::GetMousePos() - ViewportPos), WorldOrigin, WorldDirection)) + + //----------------------------------------------------------------------------------------------- + // Do not use imgui mouse pos because when connected to NetImgui, the mouse position is invalid. + // See https://github.com/sammyfreg/netImgui/issues/61 + //----------------------------------------------------------------------------------------------- + //ImVec2 mousePos = ImGui::GetMousePos(); + ImVec2 mousePos = GetOwner()->GetContext().GetImguiMousePos(); + + if (UGameplayStatics::DeprojectScreenToWorld(PlayerController, FCogImguiHelper::ToFVector2D(mousePos - ViewportPos), WorldOrigin, WorldDirection)) { //-------------------------------------------------------------------------------------------------------- // Prioritize another actor than the selected actor unless we only touch the selected actor. @@ -345,7 +368,19 @@ void FCogEngineWindow_Selection::RenderMainMenuWidget(int32 SubWidgetIndex, floa else if (SubWidgetIndex == 1) { ImGui::SetNextItemWidth(Width); - FCogWindowWidgets::MenuActorsCombo("MenuActorSelection", *GetWorld(), ActorClasses, Config->SelectedClassIndex, &Filter, GetLocalPlayerPawn(), [this](AActor& Actor) { RenderActorContextMenu(Actor); }); + AActor* NewSelection = nullptr; + if (FCogWindowWidgets::MenuActorsCombo( + "MenuActorSelection", + NewSelection, + *GetWorld(), + ActorClasses, + Config->SelectedClassIndex, + &Filter, + GetLocalPlayerPawn(), + [this](AActor& Actor) { RenderActorContextMenu(Actor); })) + { + SetGlobalSelection(NewSelection); + } } else if (SubWidgetIndex == 2) { diff --git a/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_Skeleton.cpp b/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_Skeleton.cpp index 83341bd..9519c92 100644 --- a/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_Skeleton.cpp +++ b/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_Skeleton.cpp @@ -161,11 +161,11 @@ void FCogEngineWindow_Skeleton::RenderBoneEntry(int32 BoneIndex, bool OpenAllChi //------------------------ if (BoneInfo.Children.Num() > 0 && Filter.IsActive() == false) { - OpenChildren = ImGui::TreeNodeEx("##Bone", ImGuiSelectableFlags_AllowOverlap | ImGuiTreeNodeFlags_SpanFullWidth); + OpenChildren = ImGui::TreeNodeEx("##Bone", ImGuiTreeNodeFlags_AllowOverlap | ImGuiTreeNodeFlags_SpanFullWidth); } else { - ImGui::TreeNodeEx("##Bone", ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiSelectableFlags_AllowOverlap | ImGuiTreeNodeFlags_SpanFullWidth); + ImGui::TreeNodeEx("##Bone", ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_AllowOverlap | ImGuiTreeNodeFlags_SpanFullWidth); } const bool IsControlDown = ImGui::GetCurrentContext()->IO.KeyCtrl; diff --git a/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_Spawns.cpp b/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_Spawns.cpp index d318013..258d04f 100644 --- a/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_Spawns.cpp +++ b/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_Spawns.cpp @@ -56,14 +56,10 @@ void FCogEngineWindow_Spawns::RenderContent() //-------------------------------------------------------------------------------------------------------------------------- void FCogEngineWindow_Spawns::RenderSpawnGroup(ACogEngineReplicator& Replicator, const FCogEngineSpawnGroup& SpawnGroup) { - ImGui::PushStyleColor(ImGuiCol_Header, IM_COL32(66, 66, 66, 79)); - ImGui::PushStyleColor(ImGuiCol_HeaderHovered, IM_COL32(62, 62, 62, 204)); - ImGui::PushStyleColor(ImGuiCol_HeaderActive, IM_COL32(86, 86, 86, 255)); - - if (ImGui::CollapsingHeader(TCHAR_TO_ANSI(*SpawnGroup.Name), ImGuiTreeNodeFlags_DefaultOpen)) + if (FCogWindowWidgets::DarkCollapsingHeader(TCHAR_TO_ANSI(*SpawnGroup.Name), ImGuiTreeNodeFlags_DefaultOpen)) { - int32 GroupIndex = 0; - ImGui::PushID(GroupIndex); + int32 GroupIndex = 0; + ImGui::PushID(GroupIndex); const bool PushColor = (SpawnGroup.Color != FColor::Transparent); if (PushColor) @@ -92,8 +88,6 @@ void FCogEngineWindow_Spawns::RenderSpawnGroup(ACogEngineReplicator& Replicator, ImGui::PopID(); GroupIndex++; } - - ImGui::PopStyleColor(3); } //-------------------------------------------------------------------------------------------------------------------------- @@ -117,7 +111,7 @@ bool FCogEngineWindow_Spawns::RenderSpawnAsset(ACogEngineReplicator& Replicator, if (ImGui::Button(TCHAR_TO_ANSI(*EntryName), ImVec2(-1, 0))) { IsPressed = true; - Replicator.Server_Spawn(SpawnEntry); + Replicator.Server_Spawn(SpawnEntry); } ImGui::PopStyleVar(1); diff --git a/Plugins/Cog/Source/CogEngine/Public/CogEngineDataAsset.h b/Plugins/Cog/Source/CogEngine/Public/CogEngineDataAsset.h index 142a505..86a43b0 100644 --- a/Plugins/Cog/Source/CogEngine/Public/CogEngineDataAsset.h +++ b/Plugins/Cog/Source/CogEngine/Public/CogEngineDataAsset.h @@ -5,6 +5,68 @@ #include "Engine/EngineTypes.h" #include "CogEngineDataAsset.generated.h" +class FCogWindow; +//-------------------------------------------------------------------------------------------------------------------------- +UENUM(BlueprintType) +enum class ECogEngineCheat_ActiveState : uint8 +{ + Inactive, + Partial, + Active, +}; + +//-------------------------------------------------------------------------------------------------------------------------- +UCLASS(BlueprintType, Abstract, Const, DefaultToInstanced, EditInlineNew, CollapseCategories) +class COGENGINE_API UCogEngineCheat_Execution + : public UObject +{ + GENERATED_BODY() + +public: + + UFUNCTION(BlueprintNativeEvent) + void Execute(const AActor* Instigator, const TArray& Targets) const; + + UFUNCTION(BlueprintNativeEvent) + ECogEngineCheat_ActiveState IsActiveOnTargets(const TArray& Targets) const; + + virtual bool GetColor(const FCogWindow& InCallingWindow, FLinearColor& OutColor) const; +}; + +//-------------------------------------------------------------------------------------------------------------------------- +USTRUCT() +struct COGENGINE_API FCogEngineCheat +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere) + FString Name; + + UPROPERTY(EditAnywhere, Instanced) + TObjectPtr Execution; + + UPROPERTY(EditAnywhere) + FLinearColor Color = FLinearColor::White; + + mutable FLinearColor CustomColor = FLinearColor::White; +}; + +//-------------------------------------------------------------------------------------------------------------------------- +USTRUCT() +struct COGENGINE_API FCogEngineCheatCategory +{ + GENERATED_BODY() + + UPROPERTY(Category = "Cheats", EditAnywhere) + FString Name; + + UPROPERTY(Category = "Cheats", EditAnywhere, meta = (TitleProperty = "Name")) + TArray PersistentEffects; + + UPROPERTY(Category = "Cheats", EditAnywhere, meta = (TitleProperty = "Name")) + TArray InstantEffects; +}; + //-------------------------------------------------------------------------------------------------------------------------- USTRUCT() struct COGENGINE_API FCogEngineSpawnEntry @@ -44,6 +106,9 @@ public: UCogEngineDataAsset() {} + UPROPERTY(Category = "Cheats", EditAnywhere, meta = (TitleProperty = "Name")) + TArray CheatCategories; + UPROPERTY(Category = "Spawns", EditAnywhere, meta = (TitleProperty = "Name")) TArray SpawnGroups; }; diff --git a/Plugins/Cog/Source/CogEngine/Public/CogEngineReplicator.h b/Plugins/Cog/Source/CogEngine/Public/CogEngineReplicator.h index 953712a..be13be5 100644 --- a/Plugins/Cog/Source/CogEngine/Public/CogEngineReplicator.h +++ b/Plugins/Cog/Source/CogEngine/Public/CogEngineReplicator.h @@ -1,6 +1,7 @@ #pragma once #include "CoreMinimal.h" +#include "CogEngineDataAsset.h" #include "GameFramework/Actor.h" #include "UObject/Class.h" #include "UObject/ObjectMacros.h" @@ -50,6 +51,11 @@ public: UFUNCTION(Server, Reliable) void Server_DeleteActor(AActor* Actor); + UFUNCTION(Reliable, Server) + void Server_ApplyCheat(const AActor* CheatInstigator, const TArray& TargetActors, const FCogEngineCheat& Cheat) const; + + static ECogEngineCheat_ActiveState IsCheatActiveOnTargets(const TArray& Targets, const FCogEngineCheat& Cheat); + protected: UFUNCTION(Server, Reliable) diff --git a/Plugins/Cog/Source/CogEngine/Public/CogEngineWindow_Cheats.h b/Plugins/Cog/Source/CogEngine/Public/CogEngineWindow_Cheats.h new file mode 100644 index 0000000..712c04d --- /dev/null +++ b/Plugins/Cog/Source/CogEngine/Public/CogEngineWindow_Cheats.h @@ -0,0 +1,90 @@ +#pragma once + +#include "CoreMinimal.h" +#include "CogCommonConfig.h" +#include "CogWindow.h" +#include "CogEngineWindow_Cheats.generated.h" + +class AActor; +class UCogEngineConfig_Cheats; +class UCogEngineDataAsset; +struct FCogEngineCheat; + +//-------------------------------------------------------------------------------------------------------------------------- +class COGENGINE_API FCogEngineWindow_Cheats : public FCogWindow +{ + typedef FCogWindow Super; + +public: + + virtual void Initialize() override; + +protected: + + virtual void GameTick(float DeltaTime) override; + + virtual void ResetConfig() override; + + virtual void RenderHelp() override; + + virtual void RenderContent() override; + + virtual void TryReapplyCheats(); + + virtual bool AddCheat(const int32 Index, AActor* ControlledActor, AActor* TargetActor, const FCogEngineCheat& CheatEffect, bool IsPersistent); + + virtual void RequestCheat(AActor* ControlledActor, AActor* SelectedActor, const FCogEngineCheat& Cheat, bool ApplyToEnemies, bool ApplyToAllies, bool ApplyToControlled); + + virtual const FCogEngineCheat* FindCheatByName(const FString& CheatName, const bool OnlyPersistentCheats); + + static bool DrawTable(); + + void UpdateCheatColor(const FCogEngineCheat& Cheat) const; + + TObjectPtr Asset = nullptr; + + TObjectPtr Config = nullptr; + + bool bHasReappliedCheats = false; + + ImGuiTextFilter Filter; + + TArray AllCheats; +}; + +//-------------------------------------------------------------------------------------------------------------------------- +UCLASS(Config = Cog) +class UCogEngineConfig_Cheats : public UCogCommonConfig +{ + GENERATED_BODY() + +public: + + UPROPERTY(Config) + bool bGroupByCategories = true; + + UPROPERTY(Config) + bool bReapplyCheatsBetweenPlays = true; + + UPROPERTY(Config) + bool bReapplyCheatsBetweenLaunches = true; + + UPROPERTY(Config) + bool bUseTwoColumns = true; + + UPROPERTY(Config) + TArray AppliedCheats; + + UPROPERTY(Config) + TSet SelectedCategories; + + virtual void Reset() override + { + Super::Reset(); + + bReapplyCheatsBetweenPlays = true; + bReapplyCheatsBetweenLaunches = true; + AppliedCheats.Empty(); + SelectedCategories.Empty(); + } +}; diff --git a/Plugins/Cog/Source/CogEngine/Public/CogEngineWindow_NetImGui.h b/Plugins/Cog/Source/CogEngine/Public/CogEngineWindow_NetImGui.h new file mode 100644 index 0000000..07e7db7 --- /dev/null +++ b/Plugins/Cog/Source/CogEngine/Public/CogEngineWindow_NetImGui.h @@ -0,0 +1,106 @@ +#pragma once + +#include "CoreMinimal.h" +#include "CogCommonConfig.h" +#include "CogWindow.h" +#include "CogEngineWindow_NetImgui.generated.h" + +class UCogEngineWindowConfig_NetImgui; + +UENUM() +enum class ECogNetImguiAutoConnectionMode : uint8 +{ + NoAutoConnect, + AutoConnect, + AutoListen, +}; + +class COGENGINE_API FCogEngineWindow_NetImgui : public FCogWindow +{ + typedef FCogWindow Super; + +public: + + virtual void Initialize() override; + + virtual void Shutdown() override; + +protected: + + virtual void ResetConfig() override; + + virtual void RenderHelp() override; + + virtual void RenderContent() override; + + virtual void RenderTick(float DeltaTime); + + void ConnectTo(); + + void ConnectFrom(); + + void Disconnect(); + + void TryStartup(); + + void RunServer(); + + void CloseServer(); + +private: + + FString GetClientName() const; + + TObjectPtr Config = nullptr; + + bool HasStartedAutoConnection = false; + + FProcHandle ServerProcess; +}; + +//-------------------------------------------------------------------------------------------------------------------------- +UCLASS(Config = Cog) +class UCogEngineWindowConfig_NetImgui : public UCogCommonConfig +{ + GENERATED_BODY() + +public: + + virtual void Reset() override; + + UPROPERTY(Config) + FString ClientName = FString("Cog"); + + UPROPERTY(Config) + int32 ClientPort = 8889; + + UPROPERTY(Config) + ECogNetImguiAutoConnectionMode AutoConnectOnDedicatedServer = ECogNetImguiAutoConnectionMode::AutoConnect; + + UPROPERTY(Config) + ECogNetImguiAutoConnectionMode AutoConnectOnListenServer = ECogNetImguiAutoConnectionMode::NoAutoConnect; + + UPROPERTY(Config) + ECogNetImguiAutoConnectionMode AutoConnectOnClient = ECogNetImguiAutoConnectionMode::NoAutoConnect; + + UPROPERTY(Config) + ECogNetImguiAutoConnectionMode AutoConnectOnStandalone = ECogNetImguiAutoConnectionMode::NoAutoConnect; + + UPROPERTY(Config) + FString ServerAddress = FString("127.0.0.1"); + + UPROPERTY(Config) + int32 ServerPort = 8888; + + UPROPERTY(Config) + FString ServerDirectory = FString("C:\\NetImgui\\Server_Exe"); + + UPROPERTY(Config) + FString ServerExecutable = FString("NetImguiServer.exe"); + + UPROPERTY(Config) + FString ServerArguments = FString(""); + + UPROPERTY(Config) + bool AutoRunServer = false; +}; \ No newline at end of file diff --git a/Plugins/Cog/Source/CogEngine/Public/CogEngineWindow_Plots.h b/Plugins/Cog/Source/CogEngine/Public/CogEngineWindow_Plots.h index 377bec3..f337506 100644 --- a/Plugins/Cog/Source/CogEngine/Public/CogEngineWindow_Plots.h +++ b/Plugins/Cog/Source/CogEngine/Public/CogEngineWindow_Plots.h @@ -26,19 +26,19 @@ protected: virtual void RenderContent() override; - static void RenderPlotsList(TArray& VisiblePlots); + virtual void RenderAllEntriesNames(const ImVec2& InSize); - void RenderPlots(const TArray& VisiblePlots) const; + virtual void RenderEntryName(const int Index, FCogDebugPlotEntry& Entry); - void RenderMenu(); + virtual void RenderPlots(const TArray& VisiblePlots) const; - void RenderTimeMarker() const; + virtual void RenderMenu(); - static void RenderValues(FCogDebugPlotEntry& Entry, const char* Label); + virtual void RenderValues(FCogDebugPlotEntry& Entry, const char* Label) const; - void RenderEvents(FCogDebugPlotEntry& Entry, const char* Label, const ImVec2& PlotMin, const ImVec2& PlotMax) const; + virtual void RenderEvents(FCogDebugPlotEntry& Entry, const char* Label, const ImVec2& PlotMin, const ImVec2& PlotMax) const; - static void RenderEventTooltip(const FCogDebugPlotEvent* HoveredEvent, FCogDebugPlotEntry& Entry); + static void RenderEventTooltip(const FCogDebugPlotEvent* HoveredEvent, const FCogDebugPlotEntry& Entry); TObjectPtr Config = nullptr; @@ -57,14 +57,41 @@ class UCogEngineConfig_Plots : public UCogCommonConfig public: UPROPERTY(Config) - int Rows = 1; + int NumGraphs = 1; UPROPERTY(Config) - float TimeRange = 10.0f; + int NumYAxis = 1; + + UPROPERTY(Config) + float TimeRange = 20.0f; + + UPROPERTY(Config) + bool ShowTimeBarAtGameTime = true; + + UPROPERTY(Config) + bool ShowTimeBarAtCursor = true; + + UPROPERTY(Config) + bool ShowValueAtCursor = true; + + UPROPERTY(Config) + float DragPauseSensitivity = 10.0f; + + UPROPERTY(Config) + FColor PauseBackgroundColor = FColor(10, 0, 0, 255); + + UPROPERTY(Config) + bool DockEntries = false; virtual void Reset() override { - Rows = 1; - TimeRange = 10.0f; + NumGraphs = 1; + TimeRange = 20.0f; + ShowTimeBarAtGameTime = true; + ShowTimeBarAtCursor = true; + ShowValueAtCursor = true; + DragPauseSensitivity = 10.0f; + PauseBackgroundColor = FColor(10, 0, 0, 255); + DockEntries = false; } }; \ No newline at end of file diff --git a/Plugins/Cog/Source/CogEngine/Public/CogEngineWindow_Selection.h b/Plugins/Cog/Source/CogEngine/Public/CogEngineWindow_Selection.h index 2235a5b..d40fc94 100644 --- a/Plugins/Cog/Source/CogEngine/Public/CogEngineWindow_Selection.h +++ b/Plugins/Cog/Source/CogEngine/Public/CogEngineWindow_Selection.h @@ -75,7 +75,7 @@ protected: bool bSelectionModeActive = false; - bool bIsInputEnabledBeforeEnteringSelectionMode; + bool bIsInputEnabledBeforeEnteringSelectionMode = false; int32 WaitInputReleased = 0; @@ -83,8 +83,6 @@ protected: ETraceTypeQuery TraceType = TraceTypeQuery1; - TArray ConsoleCommands; - TObjectPtr Config; ImGuiTextFilter Filter; diff --git a/Plugins/Cog/Source/CogImgui/CogImgui.Build.cs b/Plugins/Cog/Source/CogImgui/CogImgui.Build.cs index e1d0f31..4638f22 100644 --- a/Plugins/Cog/Source/CogImgui/CogImgui.Build.cs +++ b/Plugins/Cog/Source/CogImgui/CogImgui.Build.cs @@ -12,6 +12,7 @@ public class CogImgui : ModuleRules "Core", "ImGui", "ImPlot", + "NetImgui", }); PrivateDependencyModuleNames.AddRange(new[] @@ -21,7 +22,8 @@ public class CogImgui : ModuleRules "Engine", "InputCore", "Slate", - "SlateCore" + "SlateCore", + "Sockets" }); if (Target.bBuildEditor) diff --git a/Plugins/Cog/Source/CogImgui/Private/CogImguiConfig.cpp b/Plugins/Cog/Source/CogImgui/Private/CogImguiConfig.cpp index 50167d8..2dd03d5 100644 --- a/Plugins/Cog/Source/CogImgui/Private/CogImguiConfig.cpp +++ b/Plugins/Cog/Source/CogImgui/Private/CogImguiConfig.cpp @@ -1,12 +1,22 @@ #include "CogImguiConfig.h" THIRD_PARTY_INCLUDES_START + #include #include #include #include #include + #include #include #include + +#include "Private/NetImgui_Api.cpp" +#include "Private/NetImgui_Client.cpp" +#include "Private/NetImgui_CmdPackets_DrawFrame.cpp" +#include "Private/NetImgui_NetworkPosix.cpp" +#include "Private/NetImgui_NetworkUE4.cpp" +#include "Private/NetImgui_NetworkWin32.cpp" + THIRD_PARTY_INCLUDES_END \ No newline at end of file diff --git a/Plugins/Cog/Source/CogImgui/Private/CogImguiContext.cpp b/Plugins/Cog/Source/CogImgui/Private/CogImguiContext.cpp index 5c8be05..80ad99b 100644 --- a/Plugins/Cog/Source/CogImgui/Private/CogImguiContext.cpp +++ b/Plugins/Cog/Source/CogImgui/Private/CogImguiContext.cpp @@ -17,43 +17,72 @@ #include "imgui.h" #include "imgui_internal.h" #include "implot.h" +#include "Misc/EngineVersionComparison.h" +#include "NetImgui_Api.h" #include "TextureResource.h" #include "Widgets/SViewport.h" #include "Widgets/SWindow.h" static UPlayerInput* GetPlayerInput(const UWorld* World); +FCogImGuiContextScope:: +FCogImGuiContextScope(FCogImguiContext& CogImguiContext) +{ + PrevContext = ImGui::GetCurrentContext(); + PrevPlotContext = ImPlot::GetCurrentContext(); + + ImGui::SetCurrentContext(CogImguiContext.ImGuiContext); + ImPlot::SetCurrentContext(CogImguiContext.PlotContext); +} + +FCogImGuiContextScope:: +FCogImGuiContextScope(ImGuiContext* GuiCtx, ImPlotContext* PlotCtx) +{ + PrevContext = ImGui::GetCurrentContext(); + PrevPlotContext = ImPlot::GetCurrentContext(); + + ImGui::SetCurrentContext(GuiCtx); + ImPlot::SetCurrentContext(PlotCtx); +} + +FCogImGuiContextScope:: +~FCogImGuiContextScope() +{ + ImGui::SetCurrentContext(PrevContext); + ImPlot::SetCurrentContext(PrevPlotContext); +} + +//-------------------------------------------------------------------------------------------------------------------------- +bool FCogImguiContext::bIsNetImguiInitialized = false; + //-------------------------------------------------------------------------------------------------------------------------- void FCogImguiContext::Initialize() { IMGUI_CHECKVERSION(); - if (FSlateApplication::IsInitialized() == false) - { - return; - } - - FSlateApplication& SlateApp = FSlateApplication::Get(); - GameViewport = GEngine->GameViewport; - SAssignNew(MainWidget, SCogImguiWidget).Context(this); - GameViewport->AddViewportWidgetContent(MainWidget.ToSharedRef(), TNumericLimits::Max()); + if (GameViewport != nullptr) + { + SAssignNew(MainWidget, SCogImguiWidget).Context(this); + GameViewport->AddViewportWidgetContent(MainWidget.ToSharedRef(), TNumericLimits::Max()); - SAssignNew(InputCatcherWidget, SCogImguiInputCatcherWidget).Context(this); - GameViewport->AddViewportWidgetContent(InputCatcherWidget.ToSharedRef(), -TNumericLimits::Max()); + SAssignNew(InputCatcherWidget, SCogImguiInputCatcherWidget).Context(this); + GameViewport->AddViewportWidgetContent(InputCatcherWidget.ToSharedRef(), -TNumericLimits::Max()); + } ImGuiContext = ImGui::CreateContext(); PlotContext = ImPlot::CreateContext(); + ImGui::SetCurrentContext(ImGuiContext); ImPlot::SetImGuiContext(ImGuiContext); + ImPlot::SetCurrentContext(PlotContext); ImGuiIO& IO = ImGui::GetIO(); IO.UserData = this; + IO.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; IO.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; - IO.ConfigFlags |= ImGuiConfigFlags_NavNoCaptureKeyboard; - IO.ConfigFlags |= ImGuiConfigFlags_NavEnableSetMousePos; IO.ConfigFlags |= ImGuiConfigFlags_DockingEnable; IO.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; @@ -70,7 +99,7 @@ void FCogImguiContext::Initialize() ImGuiViewport* MainViewport = ImGui::GetMainViewport(); FCogImGuiViewportData* ViewportData = new FCogImGuiViewportData(); MainViewport->PlatformUserData = ViewportData; - ViewportData->Window = SlateApp.GetActiveTopLevelWindow(); + ViewportData->Window = FSlateApplication::IsInitialized() ? FSlateApplication::Get().GetActiveTopLevelWindow() : nullptr; ViewportData->Context = this; ViewportData->Widget = MainWidget; @@ -93,35 +122,73 @@ void FCogImguiContext::Initialize() PlatformIO.Platform_SetWindowAlpha = ImGui_SetWindowAlpha; PlatformIO.Platform_RenderWindow = ImGui_RenderWindow; - if (const TSharedPtr PlatformApplication = SlateApp.GetPlatformApplication()) + if (FSlateApplication::IsInitialized()) { + if (const TSharedPtr PlatformApplication = FSlateApplication::Get().GetPlatformApplication()) + { + FDisplayMetrics DisplayMetrics; + PlatformApplication->GetInitialDisplayMetrics(DisplayMetrics); + PlatformApplication->OnDisplayMetricsChanged().AddRaw(this, &FCogImguiContext::OnDisplayMetricsChanged); + OnDisplayMetricsChanged(DisplayMetrics); + } + } + else + { + FMonitorInfo monitorInfo; + monitorInfo.bIsPrimary = true; + monitorInfo.DisplayRect = FPlatformRect(0, 0, 1080, 720); FDisplayMetrics DisplayMetrics; - PlatformApplication->GetInitialDisplayMetrics(DisplayMetrics); - PlatformApplication->OnDisplayMetricsChanged().AddRaw(this, &FCogImguiContext::OnDisplayMetricsChanged); + DisplayMetrics.MonitorInfo.Add(monitorInfo); OnDisplayMetricsChanged(DisplayMetrics); } + +#if NETIMGUI_ENABLED + if (bIsNetImguiInitialized == false) + { + NetImgui::Startup(); + bIsNetImguiInitialized = true; + } +#endif } //-------------------------------------------------------------------------------------------------------------------------- void FCogImguiContext::Shutdown() { - ImGuiViewport* MainViewport = ImGui::GetMainViewport(); - if (const FCogImGuiViewportData* ViewportData = static_cast(MainViewport->PlatformUserData)) + FCogImGuiContextScope ImGuiContextScope(ImGuiContext, PlotContext); + + //------------------------------------------------------------------ + // NetImgui must be shutdown before imgui as it uses context hooks + //------------------------------------------------------------------ +#if NETIMGUI_ENABLED + if (bIsNetImguiInitialized) { - delete ViewportData; - MainViewport->PlatformUserData = nullptr; + NetImgui::Shutdown(); + bIsNetImguiInitialized = false; + } +#endif + + if (ImGuiViewport* MainViewport = ImGui::GetMainViewport()) + { + if (const FCogImGuiViewportData* ViewportData = static_cast(MainViewport->PlatformUserData)) + { + delete ViewportData; + MainViewport->PlatformUserData = nullptr; + } } if (FSlateApplication::IsInitialized()) { - FSlateApplication& SlateApp = FSlateApplication::Get(); - if (const TSharedPtr PlatformApplication = SlateApp.GetPlatformApplication()) + if (const TSharedPtr PlatformApplication = FSlateApplication::Get().GetPlatformApplication()) { PlatformApplication->OnDisplayMetricsChanged().RemoveAll(this); } } - GameViewport->RemoveViewportWidgetContent(MainWidget.ToSharedRef()); + if (GameViewport != nullptr) + { + GameViewport->RemoveViewportWidgetContent(MainWidget.ToSharedRef()); + GameViewport->RemoveViewportWidgetContent(InputCatcherWidget.ToSharedRef()); + } if (PlotContext) { @@ -139,6 +206,8 @@ void FCogImguiContext::Shutdown() //-------------------------------------------------------------------------------------------------------------------------- void FCogImguiContext::OnDisplayMetricsChanged(const FDisplayMetrics& DisplayMetrics) const { + FCogImGuiContextScope ImGuiContextScope(ImGuiContext, PlotContext); + ImGuiPlatformIO& PlatformIO = ImGui::GetPlatformIO(); PlatformIO.Monitors.resize(0); @@ -149,7 +218,7 @@ void FCogImguiContext::OnDisplayMetricsChanged(const FDisplayMetrics& DisplayMet ImGuiMonitor.MainSize = ImVec2(Monitor.DisplayRect.Right - Monitor.DisplayRect.Left, Monitor.DisplayRect.Bottom - Monitor.DisplayRect.Top); ImGuiMonitor.WorkPos = ImVec2(Monitor.WorkArea.Left, Monitor.WorkArea.Top); ImGuiMonitor.WorkSize = ImVec2(Monitor.WorkArea.Right - Monitor.WorkArea.Left, Monitor.WorkArea.Bottom - Monitor.WorkArea.Top); - ImGuiMonitor.DpiScale = Monitor.DPI; + ImGuiMonitor.DpiScale = 1.0f; if (Monitor.bIsPrimary) { @@ -165,6 +234,8 @@ void FCogImguiContext::OnDisplayMetricsChanged(const FDisplayMetrics& DisplayMet //-------------------------------------------------------------------------------------------------------------------------- bool FCogImguiContext::BeginFrame(float InDeltaTime) { + FCogImGuiContextScope ImGuiContextScope(ImGuiContext, PlotContext); + //------------------------------------------------------------------------------------------------------- // Skip the first frame, to let the main widget update its TickSpaceGeometry which is returned by the // plateform callback ImGui_GetWindowPos. When using viewports Imgui needs to know the main viewport @@ -176,13 +247,17 @@ bool FCogImguiContext::BeginFrame(float InDeltaTime) return false; } - ImGui::SetCurrentContext(ImGuiContext); - ImPlot::SetImGuiContext(ImGuiContext); - ImPlot::SetCurrentContext(PlotContext); - ImGuiIO& IO = ImGui::GetIO(); IO.DeltaTime = InDeltaTime; - IO.DisplaySize = FCogImguiHelper::ToImVec2(MainWidget->GetTickSpaceGeometry().GetAbsoluteSize()); + + if (MainWidget != nullptr) + { + IO.DisplaySize = FCogImguiHelper::ToImVec2(MainWidget->GetTickSpaceGeometry().GetAbsoluteSize()); + } + else + { + IO.DisplaySize = ImVec2(1080, 720); + } //------------------------------------------------------------------------------------------------------- // Build font @@ -195,40 +270,45 @@ bool FCogImguiContext::BeginFrame(float InDeltaTime) //------------------------------------------------------------------------------------------------------- // Update which viewport is under the mouse //------------------------------------------------------------------------------------------------------- - ImGuiID MouseViewportId = 0; - - FSlateApplication& SlateApp = FSlateApplication::Get(); - FWidgetPath WidgetsUnderCursor = SlateApp.LocateWindowUnderMouse(SlateApp.GetCursorPos(), SlateApp.GetInteractiveTopLevelWindows()); - if (WidgetsUnderCursor.IsValid()) + if (FSlateApplication::IsInitialized()) { - TSharedRef Window = WidgetsUnderCursor.GetWindow(); - ImGuiID* ViewportId = WindowToViewportMap.Find(Window); + ImGuiID MouseViewportId = 0; - if (ViewportId != nullptr) + FWidgetPath WidgetsUnderCursor = FSlateApplication::Get().LocateWindowUnderMouse( + FSlateApplication::Get().GetCursorPos(), + FSlateApplication::Get().GetInteractiveTopLevelWindows()); + + if (WidgetsUnderCursor.IsValid()) { - MouseViewportId = *ViewportId; - } - else - { - MouseViewportId = ImGui::GetMainViewport()->ID; + TSharedRef Window = WidgetsUnderCursor.GetWindow(); + ImGuiID* ViewportId = WindowToViewportMap.Find(Window); + + if (ViewportId != nullptr) + { + MouseViewportId = *ViewportId; + } + else + { + MouseViewportId = ImGui::GetMainViewport()->ID; + } } + + IO.AddMouseViewportEvent(MouseViewportId); + + //------------------------------------------------------------------------------------------------------- + // Refresh modifiers otherwise, when pressing ALT-TAB, the Alt modifier is always true + //------------------------------------------------------------------------------------------------------- + FModifierKeysState ModifierKeys = FSlateApplication::Get().GetModifierKeys(); + if (ModifierKeys.IsControlDown() != IO.KeyCtrl) { IO.AddKeyEvent(ImGuiMod_Ctrl, ModifierKeys.IsControlDown()); } + if (ModifierKeys.IsShiftDown() != IO.KeyShift) { IO.AddKeyEvent(ImGuiMod_Shift, ModifierKeys.IsShiftDown()); } + if (ModifierKeys.IsAltDown() != IO.KeyAlt) { IO.AddKeyEvent(ImGuiMod_Alt, ModifierKeys.IsAltDown()); } + if (ModifierKeys.IsCommandDown() != IO.KeySuper) { IO.AddKeyEvent(ImGuiMod_Super, ModifierKeys.IsCommandDown()); } } - IO.AddMouseViewportEvent(MouseViewportId); - - //------------------------------------------------------------------------------------------------------- - // Refresh modifiers otherwise, when pressing ALT-TAB, the Alt modifier is always true - //------------------------------------------------------------------------------------------------------- - FModifierKeysState ModifierKeys = FSlateApplication::Get().GetModifierKeys(); - if (ModifierKeys.IsControlDown() != IO.KeyCtrl) { IO.AddKeyEvent(ImGuiMod_Ctrl, ModifierKeys.IsControlDown()); } - if (ModifierKeys.IsShiftDown() != IO.KeyShift) { IO.AddKeyEvent(ImGuiMod_Shift, ModifierKeys.IsShiftDown()); } - if (ModifierKeys.IsAltDown() != IO.KeyAlt) { IO.AddKeyEvent(ImGuiMod_Alt, ModifierKeys.IsAltDown()); } - if (ModifierKeys.IsCommandDown() != IO.KeySuper) { IO.AddKeyEvent(ImGuiMod_Super, ModifierKeys.IsCommandDown()); } - //------------------------------------------------------------------------------------------------------- // //------------------------------------------------------------------------------------------------------- - if (bEnableInput) + if (bEnableInput || NetImgui::IsConnected()) { IO.ConfigFlags &= ~ImGuiConfigFlags_NoMouse; } @@ -237,35 +317,24 @@ bool FCogImguiContext::BeginFrame(float InDeltaTime) IO.ConfigFlags |= ImGuiConfigFlags_NoMouse; } - //------------------------------------------------------------------------------------------------------- - // - //------------------------------------------------------------------------------------------------------- - const bool bHasMouse = (IO.ConfigFlags & ImGuiConfigFlags_NoMouse) == 0; - const bool bUpdateMouseMouseCursor = (IO.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) == 0; - if (bHasMouse && bUpdateMouseMouseCursor) + if (MainWidget != nullptr && FSlateApplication::IsInitialized()) { - MainWidget->SetCursor(FCogImguiInputHelper::ToSlateMouseCursor(ImGui::GetMouseCursor())); - } + const bool bHasMouse = (IO.ConfigFlags & ImGuiConfigFlags_NoMouse) == 0; + const bool bUpdateMouseMouseCursor = (IO.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) == 0; + if (bHasMouse && bUpdateMouseMouseCursor) + { + MainWidget->SetCursor(FCogImguiInputHelper::ToSlateMouseCursor(ImGui::GetMouseCursor())); + } - //------------------------------------------------------------------------------------------------------- - // - //------------------------------------------------------------------------------------------------------- - const FVector2D& MousePosition = SlateApp.GetCursorPos(); - if (IO.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) - { - IO.AddMousePosEvent(MousePosition.X, MousePosition.Y); - } - else - { - const FVector2D TransformedMousePosition = MousePosition - MainWidget->GetTickSpaceGeometry().GetAbsolutePosition(); - IO.AddMousePosEvent(TransformedMousePosition.X, TransformedMousePosition.Y); + if (bEnableInput) + { + const ImVec2 mousePos = GetImguiMousePos(); + IO.AddMousePosEvent(mousePos.x, mousePos.y); + } } bWantCaptureMouse = ImGui::GetIO().WantCaptureMouse; - //------------------------------------------------------------------------------------------------------- - // - //------------------------------------------------------------------------------------------------------- if (bRefreshDPIScale) { bRefreshDPIScale = false; @@ -278,16 +347,37 @@ bool FCogImguiContext::BeginFrame(float InDeltaTime) } ImGui::NewFrame(); + //if (NetImgui::NewFrame(true) == false) + //{ + // return false; + //} //DrawDebug(); return true; } +//-------------------------------------------------------------------------------------------------------------------------- +ImVec2 FCogImguiContext::GetImguiMousePos() +{ + const FVector2D& MousePosition = FSlateApplication::Get().GetCursorPos(); + if (ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_ViewportsEnable) + { + return ImVec2(MousePosition.X, MousePosition.Y); + } + + const FVector2D TransformedMousePosition = MousePosition - MainWidget->GetTickSpaceGeometry().GetAbsolutePosition(); + return ImVec2(TransformedMousePosition.X, TransformedMousePosition.Y); +} + //-------------------------------------------------------------------------------------------------------------------------- void FCogImguiContext::EndFrame() { + FCogImGuiContextScope ImGuiContextScope(ImGuiContext, PlotContext); + ImGui::Render(); + //NetImgui::EndFrame(); + ImGui_RenderWindow(ImGui::GetMainViewport(), nullptr); ImGui::UpdatePlatformWindows(); @@ -297,6 +387,11 @@ void FCogImguiContext::EndFrame() //-------------------------------------------------------------------------------------------------------------------------- void FCogImguiContext::ImGui_CreateWindow(ImGuiViewport* Viewport) { + if (FSlateApplication::IsInitialized() == false) + { + return; + } + if (Viewport->ParentViewportId == 0) { return; @@ -592,13 +687,16 @@ void FCogImguiContext::SetEnableInput(bool Value) { bEnableInput = Value; + if (FSlateApplication::IsInitialized() == false) + { + return; + } + if (bEnableInput) { FSlateThrottleManager::Get().DisableThrottle(true); bIsThrottleDisabled = true; - FSlateApplication& SlateApp = FSlateApplication::Get(); - if (ULocalPlayer* LocalPlayer = GetLocalPlayer()) { LocalPlayer->GetSlateOperations() @@ -612,7 +710,7 @@ void FCogImguiContext::SetEnableInput(bool Value) { FSlateThrottleManager::Get().DisableThrottle(false); } - + if (ULocalPlayer* LocalPlayer = GetLocalPlayer()) { LocalPlayer->GetSlateOperations().CaptureMouse(GameViewport->GetGameViewportWidget().ToSharedRef()); @@ -639,6 +737,11 @@ void FCogImguiContext::SetShareMouseWithGameplay(bool Value) //-------------------------------------------------------------------------------------------------------------------------- void FCogImguiContext::RefreshMouseCursor() { + if (FSlateApplication::IsInitialized() == false) + { + return; + } + //------------------------------------------------------------------------------------------- // Focus the main widget when enabling input otherwise the mouse can still be hidden because // the gameplay might have the focus and might hide the cursor. @@ -652,21 +755,24 @@ void FCogImguiContext::RefreshMouseCursor() //------------------------------------------------------------------------------------------- // Force to show the cursor when sharing mouse with gameplay for games that hide the cursor //------------------------------------------------------------------------------------------- - if (APlayerController* PlayerController = GetLocalPlayerController(GameViewport->GetWorld())) + if (GameViewport != nullptr) { - if (bHasSavedInitialCursorVisibility == false) + if (APlayerController* PlayerController = GetLocalPlayerController(GameViewport->GetWorld())) { - bIsCursorInitiallyVisible = PlayerController->ShouldShowMouseCursor(); - bHasSavedInitialCursorVisibility = true; - } + if (bHasSavedInitialCursorVisibility == false) + { + bIsCursorInitiallyVisible = PlayerController->ShouldShowMouseCursor(); + bHasSavedInitialCursorVisibility = true; + } - if (bEnableInput && bShareMouse && bShareMouseWithGameplay) - { - PlayerController->SetShowMouseCursor(true); - } - else - { - PlayerController->SetShowMouseCursor(bIsCursorInitiallyVisible); + if (bEnableInput && bShareMouse && bShareMouseWithGameplay) + { + PlayerController->SetShowMouseCursor(true); + } + else + { + PlayerController->SetShowMouseCursor(bIsCursorInitiallyVisible); + } } } } @@ -686,6 +792,8 @@ void FCogImguiContext::SetDPIScale(float Value) //-------------------------------------------------------------------------------------------------------------------------- void FCogImguiContext::BuildFont() { + FCogImGuiContextScope ImGuiContextScope(ImGuiContext, PlotContext); + if (FontAtlasTexture != nullptr) { FontAtlasTexture->RemoveFromRoot(); @@ -703,7 +811,15 @@ void FCogImguiContext::BuildFont() int32 TextureWidth, TextureHeight, BytesPerPixel; IO.Fonts->GetTexDataAsRGBA32(&TextureDataRaw, &TextureWidth, &TextureHeight, &BytesPerPixel); - FontAtlasTexture = UTexture2D::CreateTransient(TextureWidth, TextureHeight, PF_R8G8B8A8, TEXT("ImGuiFontAtlas")); +#if UE_VERSION_OLDER_THAN(5, 5, 0) + const int32 PieSessionId = GPlayInEditorID; +#else + const int32 PieSessionId = UE::GetPlayInEditorID(); +#endif + + FString TextureName = FString::Format(TEXT("ImGuiFontAtlas{0}"), { PieSessionId }); + + FontAtlasTexture = UTexture2D::CreateTransient(TextureWidth, TextureHeight, PF_R8G8B8A8, *TextureName); FontAtlasTexture->Filter = TF_Bilinear; FontAtlasTexture->AddressX = TA_Wrap; FontAtlasTexture->AddressY = TA_Wrap; @@ -720,7 +836,9 @@ void FCogImguiContext::BuildFont() //-------------------------------------------------------------------------------------------------------------------------- bool FCogImguiContext::IsConsoleOpened() const { - return GameViewport->ViewportConsole && GameViewport->ViewportConsole->ConsoleState != NAME_None; + return GameViewport != nullptr + && GameViewport->ViewportConsole + && GameViewport->ViewportConsole->ConsoleState != NAME_None; } //-------------------------------------------------------------------------------------------------------------------------- @@ -739,15 +857,14 @@ void FCogImguiContext::DrawDebug() ImVec2 LocalSize = FCogImguiHelper::ToImVec2(MainWidget->GetTickSpaceGeometry().GetLocalSize()); ImGui::InputFloat2("Widget Local Size", &LocalSize.x, "%0.1f"); - FSlateApplication& SlateApp = FSlateApplication::Get(); - ImVec2 MousePosition = FCogImguiHelper::ToImVec2(SlateApp.GetCursorPos()); + ImVec2 MousePosition = FCogImguiHelper::ToImVec2(FSlateApplication::Get().GetCursorPos()); ImGui::InputFloat2("Mouse", &MousePosition.x, "%0.1f"); ImGuiIO& IO = ImGui::GetIO(); ImGui::InputFloat2("ImGui Mouse", &IO.MousePos.x, "%0.1f"); FString Focus = "None"; - if (TSharedPtr KeyboardFocusedWidget = SlateApp.GetKeyboardFocusedWidget()) + if (TSharedPtr KeyboardFocusedWidget = FSlateApplication::Get().GetKeyboardFocusedWidget()) { Focus = KeyboardFocusedWidget->ToString(); } @@ -777,3 +894,16 @@ ULocalPlayer* FCogImguiContext::GetLocalPlayer() const ULocalPlayer* LocalPlayer = World->GetFirstLocalPlayerFromController(); return LocalPlayer; } + +//-------------------------------------------------------------------------------------------------------------------------- +bool FCogImguiContext::GetSkipRendering() const +{ + return bSkipRendering; +} + +//-------------------------------------------------------------------------------------------------------------------------- +void FCogImguiContext::SetSkipRendering(bool Value) +{ + bSkipRendering = Value; +} + diff --git a/Plugins/Cog/Source/CogImgui/Private/CogImguiHelper.cpp b/Plugins/Cog/Source/CogImgui/Private/CogImguiHelper.cpp index 25df74b..956bef6 100644 --- a/Plugins/Cog/Source/CogImgui/Private/CogImguiHelper.cpp +++ b/Plugins/Cog/Source/CogImgui/Private/CogImguiHelper.cpp @@ -38,7 +38,7 @@ float FCogImguiHelper::GetNextItemWidth() { float Width; const ImGuiContext& g = *GImGui; - if (g.NextItemData.Flags & ImGuiNextItemDataFlags_HasWidth) + if (g.NextItemData.HasFlags & ImGuiNextItemDataFlags_HasWidth) { Width = g.NextItemData.Width; } diff --git a/Plugins/Cog/Source/CogImgui/Private/CogImguiInputCatcherWidget.cpp b/Plugins/Cog/Source/CogImgui/Private/CogImguiInputCatcherWidget.cpp index b3bf534..ec99bca 100644 --- a/Plugins/Cog/Source/CogImgui/Private/CogImguiInputCatcherWidget.cpp +++ b/Plugins/Cog/Source/CogImgui/Private/CogImguiInputCatcherWidget.cpp @@ -93,6 +93,8 @@ FReply SCogImguiInputCatcherWidget::OnMouseButtonUp(const FGeometry& MyGeometry, //-------------------------------------------------------------------------------------------------------------------------- FReply SCogImguiInputCatcherWidget::HandleMouseButtonEvent(const FPointerEvent& MouseEvent, bool Down) { + FCogImGuiContextScope ImGuiContextScope(*Context); + if (Context->GetEnableInput() == false) { UE_LOG(LogCogImGui, VeryVerbose, TEXT("SCogImguiInputCatcherWidget::HandleMouseButtonEvent | Window:%s | Unhandled | EnableInput == false | Down:%d"), Window.IsValid() ? *Window->GetTitle().ToString() : *FString("None"), Down); @@ -110,6 +112,8 @@ FReply SCogImguiInputCatcherWidget::HandleMouseButtonEvent(const FPointerEvent& //-------------------------------------------------------------------------------------------------------------------------- FReply SCogImguiInputCatcherWidget::OnMouseWheel(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) { + FCogImGuiContextScope ImGuiContextScope(*Context); + if (Context->GetEnableInput() == false) { return FReply::Unhandled(); diff --git a/Plugins/Cog/Source/CogImgui/Private/CogImguiModule.cpp b/Plugins/Cog/Source/CogImgui/Private/CogImguiModule.cpp index adf113f..8caa5dd 100644 --- a/Plugins/Cog/Source/CogImgui/Private/CogImguiModule.cpp +++ b/Plugins/Cog/Source/CogImgui/Private/CogImguiModule.cpp @@ -33,4 +33,4 @@ void FCogImguiModule::ShutdownModule() //-------------------------------------------------------------------------------------------------------------------------- #undef LOCTEXT_NAMESPACE -IMPLEMENT_MODULE(FCogImguiModule, CogImGui) \ No newline at end of file +IMPLEMENT_MODULE(FCogImguiModule, CogImgui) \ No newline at end of file diff --git a/Plugins/Cog/Source/CogImgui/Private/CogImguiWidget.cpp b/Plugins/Cog/Source/CogImgui/Private/CogImguiWidget.cpp index dd736e4..dd32365 100644 --- a/Plugins/Cog/Source/CogImgui/Private/CogImguiWidget.cpp +++ b/Plugins/Cog/Source/CogImgui/Private/CogImguiWidget.cpp @@ -45,6 +45,10 @@ int32 SCogImguiWidget::OnPaint( const FWidgetStyle& WidgetStyle, bool bParentEnabled) const { + if (Context == nullptr || Context->GetSkipRendering()) + { + return LayerId; + } const FSlateRenderTransform Transform(FCogImguiHelper::RoundTranslation(AllottedGeometry.GetAccumulatedRenderTransform().GetTranslation() - FVector2d(DrawData.DisplayPos))); @@ -71,7 +75,7 @@ int32 SCogImguiWidget::OnPaint( TArray VerticesSlice(Vertices.GetData() + DrawCmd.VtxOffset, Vertices.Num() - DrawCmd.VtxOffset); TArray IndicesSlice(Indices.GetData() + DrawCmd.IdxOffset, DrawCmd.ElemCount); - UTexture2D* Texture = DrawCmd.GetTexID(); + UTexture2D* Texture = Cast(DrawCmd.GetTexID()); if (TextureBrush.GetResourceObject() != Texture) { TextureBrush.SetResourceObject(Texture); @@ -112,6 +116,8 @@ FVector2D SCogImguiWidget::ComputeDesiredSize(float Scale) const //-------------------------------------------------------------------------------------------------------------------------- FReply SCogImguiWidget::OnKeyChar(const FGeometry& MyGeometry, const FCharacterEvent& CharacterEvent) { + FCogImGuiContextScope ImGuiContextScope(*Context); + ImGuiIO& IO = ImGui::GetIO(); IO.AddInputCharacter(FCogImguiInputHelper::CastInputChar(CharacterEvent.GetCharacter())); @@ -134,6 +140,8 @@ FReply SCogImguiWidget::OnKeyUp(const FGeometry& MyGeometry, const FKeyEvent& Ke //-------------------------------------------------------------------------------------------------------------------------- FReply SCogImguiWidget::HandleKeyEvent(const FKeyEvent& KeyEvent, bool Down) { + FCogImGuiContextScope ImGuiContextScope(*Context); + if (Context->GetEnableInput() == false) { return FReply::Unhandled(); @@ -196,6 +204,8 @@ FReply SCogImguiWidget::OnMouseButtonUp(const FGeometry& MyGeometry, const FPoin //-------------------------------------------------------------------------------------------------------------------------- FReply SCogImguiWidget::HandleMouseButtonEvent(const FPointerEvent& MouseEvent, bool Down) { + FCogImGuiContextScope ImGuiContextScope(*Context); + if (Context->GetEnableInput() == false) { UE_LOG(LogCogImGui, VeryVerbose, TEXT("SCogImguiWidget::HandleMouseButtonEvent | %s | Unhandled | EnableInput == false | Down:%d"), Window.IsValid() ? *Window->GetTitle().ToString() : *FString("None"), Down); @@ -212,6 +222,8 @@ FReply SCogImguiWidget::HandleMouseButtonEvent(const FPointerEvent& MouseEvent, //-------------------------------------------------------------------------------------------------------------------------- FReply SCogImguiWidget::OnMouseWheel(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) { + FCogImGuiContextScope ImGuiContextScope(*Context); + if (Context->GetEnableInput() == false) { return FReply::Unhandled(); @@ -224,6 +236,8 @@ FReply SCogImguiWidget::OnMouseWheel(const FGeometry& MyGeometry, const FPointer //-------------------------------------------------------------------------------------------------------------------------- FReply SCogImguiWidget::OnMouseMove(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) { + FCogImGuiContextScope ImGuiContextScope(*Context); + if (Context->GetEnableInput() == false) { //UE_LOG(LogCogImGui, VeryVerbose, TEXT("SCogImguiWidget::OnMouseMove | Window:%s | Unhandled | EnableInput == false"), Window.IsValid() ? *Window->GetTitle().ToString() : *FString("None")); diff --git a/Plugins/Cog/Source/CogImgui/Public/CogImguiContext.h b/Plugins/Cog/Source/CogImgui/Public/CogImguiContext.h index c8d7b85..66a9d1b 100644 --- a/Plugins/Cog/Source/CogImgui/Public/CogImguiContext.h +++ b/Plugins/Cog/Source/CogImgui/Public/CogImguiContext.h @@ -25,6 +25,18 @@ struct COGIMGUI_API FCogImGuiViewportData TWeakPtr Widget = nullptr; }; + +struct COGIMGUI_API FCogImGuiContextScope +{ + UE_NODISCARD_CTOR explicit FCogImGuiContextScope(FCogImguiContext& CogImguiContext); + UE_NODISCARD_CTOR explicit FCogImGuiContextScope(ImGuiContext* GuiCtx, ImPlotContext* PlotCtx); + ~FCogImGuiContextScope(); + +private: + ImGuiContext* PrevContext = nullptr; + ImPlotContext* PrevPlotContext = nullptr; +}; + class COGIMGUI_API FCogImguiContext : public TSharedFromThis { public: @@ -53,18 +65,30 @@ public: bool BeginFrame(float InDeltaTime); + void GetCursorPos(ImGuiIO& IO); + void EndFrame(); float GetDpiScale() const { return DpiScale; } void SetDPIScale(float Value); + bool GetSkipRendering() const; + + void SetSkipRendering(bool Value); + + ImVec2 GetImguiMousePos(); + TObjectPtr GetGameViewport() const { return GameViewport; } TSharedPtr GetMainWidget() const { return MainWidget; } + static bool GetIsNetImguiInitialized() { return bIsNetImguiInitialized; } + private: + friend struct FCogImGuiContextScope; + void OnDisplayMetricsChanged(const FDisplayMetrics& DisplayMetrics) const; bool IsConsoleOpened() const; @@ -147,4 +171,9 @@ private: bool bWantCaptureMouse = false; float DpiScale = 1.f; + + bool bSkipRendering = false; + + static bool bIsNetImguiInitialized; + }; diff --git a/Plugins/Cog/Source/CogImgui/Public/CogImguiHelper.h b/Plugins/Cog/Source/CogImgui/Public/CogImguiHelper.h index a40f9be..e1d7cf6 100644 --- a/Plugins/Cog/Source/CogImgui/Public/CogImguiHelper.h +++ b/Plugins/Cog/Source/CogImgui/Public/CogImguiHelper.h @@ -5,7 +5,7 @@ #include "Layout/SlateRect.h" #include "Rendering/SlateRenderTransform.h" -COGIMGUI_API DECLARE_LOG_CATEGORY_EXTERN(LogCogImGui, Warning, All); +COGIMGUI_API DECLARE_LOG_CATEGORY_EXTERN(LogCogImGui, Verbose, All); struct ImGuiWindow; diff --git a/Plugins/Cog/Source/CogWindow/CogWindow.Build.cs b/Plugins/Cog/Source/CogWindow/CogWindow.Build.cs index 52db039..6f990d5 100644 --- a/Plugins/Cog/Source/CogWindow/CogWindow.Build.cs +++ b/Plugins/Cog/Source/CogWindow/CogWindow.Build.cs @@ -40,9 +40,18 @@ public class CogWindow : ModuleRules "NetCore", } ); - - - DynamicallyLoadedModuleNames.AddRange( + + if (Target.bBuildEditor) + { + PrivateDependencyModuleNames.AddRange(new string[] + { + "UnrealEd", + "AssetTools" + }); + } + + + DynamicallyLoadedModuleNames.AddRange( new string[] { } diff --git a/Plugins/Cog/Source/CogWindow/Private/CogWindow.cpp b/Plugins/Cog/Source/CogWindow/Private/CogWindow.cpp index e1461a5..045f886 100644 --- a/Plugins/Cog/Source/CogWindow/Private/CogWindow.cpp +++ b/Plugins/Cog/Source/CogWindow/Private/CogWindow.cpp @@ -60,7 +60,7 @@ void FCogWindow::Render(float DeltaTime) const FString WindowTitle = GetTitle() + "##" + Name; - if (bHasMenu && bHideMenu == false) + if (bHasMenu && bShowMenu) { WindowFlags |= ImGuiWindowFlags_MenuBar; } @@ -81,10 +81,10 @@ void FCogWindow::Render(float DeltaTime) { if (bHasMenu) { - ImGui::Checkbox("Hide Menu", &bHideMenu); + ImGui::Checkbox("Show Menu", &bShowMenu); } - if (ImGui::Button("Reset")) + if (ImGui::Button("Reset Settings")) { ResetConfig(); } @@ -138,6 +138,17 @@ void FCogWindow::SetSelection(AActor* NewSelection) OnSelectionChanged(OldActor, NewSelection); } +//-------------------------------------------------------------------------------------------------------------------------- + +void FCogWindow::SetIsVisible(const bool Value) +{ + if (bIsVisible == Value) + { return; } + + bIsVisible = Value; + OnWindowVisibilityChanged(Value); +} + //-------------------------------------------------------------------------------------------------------------------------- APawn* FCogWindow::GetLocalPlayerPawn() const { diff --git a/Plugins/Cog/Source/CogWindow/Private/CogWindowConsoleCommandManager.cpp b/Plugins/Cog/Source/CogWindow/Private/CogWindowConsoleCommandManager.cpp new file mode 100644 index 0000000..0db517a --- /dev/null +++ b/Plugins/Cog/Source/CogWindow/Private/CogWindowConsoleCommandManager.cpp @@ -0,0 +1,66 @@ +#include "CogWindowConsoleCommandManager.h" + +#include "Engine/World.h" + +TMap FCogWindowConsoleCommandManager::CommandMap; + +//-------------------------------------------------------------------------------------------------------------------------- +void FCogWindowConsoleCommandManager::RegisterWorldConsoleCommand(const TCHAR* InName, const TCHAR* InHelp, UWorld* InWorld, const FCogWindowConsoleCommandDelegate& InDelegate) +{ + FCogCommandInfo& commandInfo = CommandMap.FindOrAdd(InName); + + if (commandInfo.Receivers.Num() == 0) + { + commandInfo.ConsoleObject = IConsoleManager::Get().RegisterConsoleCommand + ( + InName, + InHelp, + FConsoleCommandWithWorldAndArgsDelegate::CreateLambda( + [InName](const TArray& Args, UWorld* InCommandWorld) + { + FCogCommandInfo* commandInfo = CommandMap.Find(InName); + if (commandInfo == nullptr) + { + return; + } + + for (auto& receiver : commandInfo->Receivers) + { + if (receiver.World == InCommandWorld) + { + receiver.Delegate.ExecuteIfBound(Args, InCommandWorld); + break; + } + } + }), + ECVF_Cheat + ); + } + + FCogCommandReceiver& receiver = commandInfo.Receivers.AddDefaulted_GetRef(); + receiver.World = InWorld; + receiver.Delegate = InDelegate; +} + +//-------------------------------------------------------------------------------------------------------------------------- +void FCogWindowConsoleCommandManager::UnregisterAllWorldConsoleCommands(const UWorld* InWorld) +{ + for (auto& kv : CommandMap) + { + FCogCommandInfo& commandInfo = kv.Value; + + for (int32 i = commandInfo.Receivers.Num() - 1; i >= 0; --i) + { + if (commandInfo.Receivers[i].World == InWorld) + { + commandInfo.Receivers.RemoveAt(i); + } + } + + if (commandInfo.Receivers.Num() == 0 && commandInfo.ConsoleObject != nullptr) + { + IConsoleManager::Get().UnregisterConsoleObject(commandInfo.ConsoleObject); + commandInfo.ConsoleObject = nullptr; + } + } +} \ No newline at end of file diff --git a/Plugins/Cog/Source/CogWindow/Private/CogWindowManager.cpp b/Plugins/Cog/Source/CogWindow/Private/CogWindowManager.cpp index c76eb1b..c7b7e54 100644 --- a/Plugins/Cog/Source/CogWindow/Private/CogWindowManager.cpp +++ b/Plugins/Cog/Source/CogWindow/Private/CogWindowManager.cpp @@ -6,14 +6,18 @@ #include "CogWindow_Layouts.h" #include "CogWindow_Settings.h" #include "CogWindow_Spacing.h" +#include "CogWindowConsoleCommandManager.h" #include "CogWindowHelper.h" #include "CogWindowWidgets.h" #include "Engine/Engine.h" #include "GameFramework/PlayerInput.h" #include "HAL/IConsoleManager.h" #include "imgui_internal.h" +#include "Misc/CoreMisc.h" +#include "NetImgui_Api.h" FString UCogWindowManager::ToggleInputCommand = TEXT("Cog.ToggleInput"); +FString UCogWindowManager::DisableInputCommand = TEXT("Cog.DisableInput"); FString UCogWindowManager::LoadLayoutCommand = TEXT("Cog.LoadLayout"); FString UCogWindowManager::SaveLayoutCommand = TEXT("Cog.SaveLayout"); FString UCogWindowManager::ResetLayoutCommand = TEXT("Cog.ResetLayout"); @@ -28,13 +32,21 @@ void UCogWindowManager::PostInitProperties() { Super::PostInitProperties(); - if (bRegisterDefaultCommands) - { - if (RegisterDefaultCommandBindings()) - { - bRegisterDefaultCommands = false; - } - } + //if (bRegisterDefaultCommands) + //{ + // if (RegisterDefaultCommandBindings()) + // { + // bRegisterDefaultCommands = false; + // } + //} + + //------------------------------------------------------------------------------- + // Currently always register default commands. + // Since UE5.4, the ini files must have this to be saved: + // [SectionsToSave] + // bCanSaveAllSections = True + //------------------------------------------------------------------------------- + RegisterDefaultCommandBindings(); } //-------------------------------------------------------------------------------------------------------------------------- @@ -42,6 +54,8 @@ void UCogWindowManager::InitializeInternal() { Context.Initialize(); + FCogImGuiContextScope ImGuiContextScope(Context); + ImGuiSettingsHandler IniHandler; IniHandler.TypeName = "Cog"; IniHandler.TypeHash = ImHashStr("Cog"); @@ -61,50 +75,86 @@ void UCogWindowManager::InitializeInternal() LayoutsWindow = AddWindow("Window.Layouts", false); SettingsWindow = AddWindow("Window.Settings", false); - ConsoleCommands.Add(IConsoleManager::Get().RegisterConsoleCommand( - *ToggleInputCommand, + FCogWindowConsoleCommandManager::RegisterWorldConsoleCommand( + *ToggleInputCommand, TEXT("Toggle the input focus between the Game and ImGui"), - FConsoleCommandWithArgsDelegate::CreateLambda([this](const TArray& Args) { ToggleInputMode(); }), - ECVF_Cheat)); + GetWorld(), + FCogWindowConsoleCommandDelegate::CreateLambda([this](const TArray& InArgs, UWorld* InWorld) + { + ToggleInputMode(); + })); - ConsoleCommands.Add(IConsoleManager::Get().RegisterConsoleCommand( + FCogWindowConsoleCommandManager::RegisterWorldConsoleCommand( + *DisableInputCommand, + TEXT("Disable ImGui input"), + GetWorld(), + FCogWindowConsoleCommandDelegate::CreateLambda([this](const TArray& InArgs, UWorld* InWorld) + { + DisableInputMode(); + })); + + FCogWindowConsoleCommandManager::RegisterWorldConsoleCommand( *ResetLayoutCommand, TEXT("Reset the layout."), - FConsoleCommandWithArgsDelegate::CreateLambda([this](const TArray& Args) { if (Args.Num() > 0) { ResetLayout(); }}), - ECVF_Cheat)); + GetWorld(), + FCogWindowConsoleCommandDelegate::CreateLambda([this](const TArray& InArgs, UWorld* InWorld) + { + if (InArgs.Num() > 0) + { + ResetLayout(); + } + })); - ConsoleCommands.Add(IConsoleManager::Get().RegisterConsoleCommand( + FCogWindowConsoleCommandManager::RegisterWorldConsoleCommand( *LoadLayoutCommand, TEXT("Load the layout. Cog.LoadLayout "), - FConsoleCommandWithArgsDelegate::CreateLambda([this](const TArray& Args) { if (Args.Num() > 0) { LoadLayout(FCString::Atoi(*Args[0])); }}), - ECVF_Cheat)); + GetWorld(), + FCogWindowConsoleCommandDelegate::CreateLambda([this](const TArray& InArgs, UWorld* InWorld) + { + if (InArgs.Num() > 0) + { + LoadLayout(FCString::Atoi(*InArgs[0])); + } + })); - ConsoleCommands.Add(IConsoleManager::Get().RegisterConsoleCommand( - *SaveLayoutCommand, + FCogWindowConsoleCommandManager::RegisterWorldConsoleCommand( + *SaveLayoutCommand, TEXT("Save the layout. Cog.SaveLayout "), - FConsoleCommandWithArgsDelegate::CreateLambda([this](const TArray& Args) { if (Args.Num() > 0) { SaveLayout(FCString::Atoi(*Args[0])); }}), - ECVF_Cheat)); + GetWorld(), + FCogWindowConsoleCommandDelegate::CreateLambda([this](const TArray& InArgs, UWorld* InWorld) + { + if (InArgs.Num() > 0) + { + SaveLayout(FCString::Atoi(*InArgs[0])); + } + })); IsInitialized = true; + } //-------------------------------------------------------------------------------------------------------------------------- void UCogWindowManager::Shutdown() { - //------------------------------------------------------------ + FCogImGuiContextScope ImGuiContextScope(Context); + + //------------------------------------------------------------------ // Call PreSaveConfig before destroying imgui context // if PreSaveConfig needs to read ImGui IO for example - //------------------------------------------------------------ + //------------------------------------------------------------------ for (FCogWindow* Window : Windows) { Window->PreSaveConfig(); } - //------------------------------------------------------------ + //------------------------------------------------------------------ // Destroy ImGui before destroying the windows to make sure // imgui serialize their visibility state in imgui.ini - //------------------------------------------------------------ - Context.Shutdown(); + //------------------------------------------------------------------ + if (IsInitialized == true) + { + Context.Shutdown(); + } SaveConfig(); @@ -120,16 +170,15 @@ void UCogWindowManager::Shutdown() Config->SaveConfig(); } - for (IConsoleObject* ConsoleCommand : ConsoleCommands) - { - IConsoleManager::Get().UnregisterConsoleObject(ConsoleCommand); - } + FCogWindowConsoleCommandManager::UnregisterAllWorldConsoleCommands(GetWorld()); } //-------------------------------------------------------------------------------------------------------------------------- void UCogWindowManager::Tick(float DeltaTime) { - if (GEngine->GameViewport == nullptr) + FCogImGuiContextScope ImGuiContextScope(Context); + + if (GEngine->GameViewport == nullptr && IsRunningDedicatedServer() == false) { return; } @@ -151,6 +200,9 @@ void UCogWindowManager::Tick(float DeltaTime) Window->GameTick(DeltaTime); } + const bool shouldSkipRendering = NetImgui::IsConnected() && bIsSelectionModeActive == false; + Context.SetSkipRendering(shouldSkipRendering); + if (Context.BeginFrame(DeltaTime)) { Render(DeltaTime); @@ -161,8 +213,10 @@ void UCogWindowManager::Tick(float DeltaTime) //-------------------------------------------------------------------------------------------------------------------------- void UCogWindowManager::Render(float DeltaTime) { + FCogImGuiContextScope ImGuiContextScope(Context); + ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0, 0, 0, 0)); - ImGui::DockSpaceOverViewport(0, ImGui::GetWindowViewport(), ImGuiDockNodeFlags_PassthruCentralNode | ImGuiDockNodeFlags_NoDockingOverCentralNode | ImGuiDockNodeFlags_AutoHideTabBar); + ImGui::DockSpaceOverViewport(0, nullptr, ImGuiDockNodeFlags_PassthruCentralNode | ImGuiDockNodeFlags_NoDockingOverCentralNode | ImGuiDockNodeFlags_AutoHideTabBar); ImGui::PopStyleColor(1); @@ -172,19 +226,25 @@ void UCogWindowManager::Render(float DeltaTime) FCogWindowWidgets::PushStyleCompact(); } - if (bHideAllWindows == false) + //---------------------------------------------------------------------- + // There is no need to have Imgui input enabled if the imgui rendering + // is only done on the NetImgui server. So we disable imgui input. + //---------------------------------------------------------------------- + if (Context.GetEnableInput() && NetImgui::IsConnected() && bIsSelectionModeActive == false) { - if (Context.GetEnableInput()) - { - RenderMainMenu(); - } + Context.SetEnableInput(false); + } + + if ((Context.GetEnableInput() || NetImgui::IsConnected()) && bIsSelectionModeActive == false) + { + RenderMainMenu(); } for (FCogWindow* Window : Windows) { Window->RenderTick(DeltaTime); - if (Window->GetIsVisible() && bHideAllWindows == false) + if (Window->GetIsVisible() && bIsSelectionModeActive == false) { if (SettingsWindow->GetSettingsConfig()->bTransparentMode) { @@ -240,15 +300,22 @@ FCogWindow* UCogWindowManager::FindWindowByID(const ImGuiID ID) } //-------------------------------------------------------------------------------------------------------------------------- -void UCogWindowManager::SetHideAllWindows(const bool Value) +void UCogWindowManager::SetActivateSelectionMode(const bool Value) { - HideAllWindowsCounter = FMath::Max(HideAllWindowsCounter + (Value ? +1 : -1), 0); - bHideAllWindows = HideAllWindowsCounter > 0; + SelectionModeActiveCounter = FMath::Max(SelectionModeActiveCounter + (Value ? 1 : -1), 0); + bIsSelectionModeActive = SelectionModeActiveCounter > 0; + + if (bIsSelectionModeActive) + { + Context.SetEnableInput(true); + } } //-------------------------------------------------------------------------------------------------------------------------- void UCogWindowManager::ResetLayout() { + FCogImGuiContextScope ImGuiContextScope(Context); + for (const FCogWindow* Window : Windows) { ImGui::SetWindowPos(TCHAR_TO_ANSI(*Window->GetName()), ImVec2(10, 10), ImGuiCond_Always); @@ -280,6 +347,8 @@ void UCogWindowManager::LoadLayout(const int32 LayoutIndex) //-------------------------------------------------------------------------------------------------------------------------- void UCogWindowManager::SaveLayout(const int32 LayoutIndex) { + FCogImGuiContextScope ImGuiContextScope(Context); + const FString Filename = *FCogImguiHelper::GetIniFilePath(FString::Printf(TEXT("imgui_layout_%d"), LayoutIndex)); ImGui::SaveIniSettingsToDisk(TCHAR_TO_ANSI(*Filename)); } @@ -351,7 +420,6 @@ void UCogWindowManager::RenderMainMenu() ImGui::Separator(); RenderMenuItem(*LayoutsWindow, "Layouts"); - RenderMenuItem(*SettingsWindow, "Settings"); if (ImGui::BeginMenu("Spacing")) @@ -602,11 +670,15 @@ void* UCogWindowManager::SettingsHandler_ReadOpen(ImGuiContext* Context, ImGuiSe //-------------------------------------------------------------------------------------------------------------------------- void UCogWindowManager::SettingsHandler_ReadLine(ImGuiContext* Context, ImGuiSettingsHandler* Handler, void* Entry, const char* Line) { + //----------------------------------------------------------------------------------- + // Load the visibility of windows. + //----------------------------------------------------------------------------------- if (Entry == (void*)1) { ImGuiID Id; + int32 ShowMenu; #if PLATFORM_WINDOWS || PLATFORM_MICROSOFT - if (sscanf_s(Line, "0x%08X", &Id) == 1) + if (sscanf_s(Line, "0x%08X %d", &Id, &ShowMenu) == 2) #else if (sscanf(Line, "0x%08X", &Id) == 1) #endif @@ -615,9 +687,13 @@ void UCogWindowManager::SettingsHandler_ReadLine(ImGuiContext* Context, ImGuiSet if (FCogWindow* Window = Manager->FindWindowByID(Id)) { Window->SetIsVisible(true); + Window->bShowMenu = (ShowMenu > 0); } } } + //----------------------------------------------------------------------------------- + // Load which widgets are present in the main menu bar and with what order. + //----------------------------------------------------------------------------------- else if (Entry == (void*)2) { ImGuiID Id; @@ -645,16 +721,28 @@ void UCogWindowManager::SettingsHandler_WriteAll(ImGuiContext* Context, ImGuiSet { const UCogWindowManager* Manager = (UCogWindowManager*)Handler->UserData; + //----------------------------------------------------------------------------------- + // Save the visibility of windows. Example: + // [Cog][Windows] + // 0xB5D96693 + // 0xBF3390B5 + //----------------------------------------------------------------------------------- Buffer->appendf("[%s][Windows]\n", Handler->TypeName); for (const FCogWindow* Window : Manager->Windows) { if (Window->GetIsVisible()) { - Buffer->appendf("0x%08X\n", Window->GetID()); + Buffer->appendf("0x%08X %d\n", Window->GetID(), (int32)Window->bShowMenu); } } Buffer->append("\n"); + //----------------------------------------------------------------------------------- + // Save which widgets are present in the main menu bar and with what order. Example: + // [Cog][Widgets] + // 0x639F1181 1 + // 0x52BDE3E0 1 + //----------------------------------------------------------------------------------- Buffer->appendf("[%s][Widgets]\n", Handler->TypeName); for (const FCogWindow* Window : Manager->Widgets) { @@ -681,6 +769,10 @@ bool UCogWindowManager::RegisterDefaultCommandBindings() } UPlayerInput* PlayerInput = FCogImguiInputHelper::GetPlayerInput(*GetWorld()); + if (PlayerInput == nullptr) + { + return false; + } AddCommand(PlayerInput, "Cog.ToggleInput", EKeys::F1); AddCommand(PlayerInput, "Cog.LoadLayout 1", EKeys::F2); @@ -690,13 +782,17 @@ bool UCogWindowManager::RegisterDefaultCommandBindings() SortCommands(PlayerInput); PlayerInput->SaveConfig(); - return true; } //-------------------------------------------------------------------------------------------------------------------------- void UCogWindowManager::AddCommand(UPlayerInput* PlayerInput, const FString& Command, const FKey& Key) { + if (PlayerInput == nullptr) + { + return; + } + //--------------------------------------------------- // Reassign conflicting commands //--------------------------------------------------- @@ -788,3 +884,9 @@ void UCogWindowManager::ToggleInputMode() Context.SetEnableInput(!Context.GetEnableInput()); } +//-------------------------------------------------------------------------------------------------------------------------- +void UCogWindowManager::DisableInputMode() +{ + UE_LOG(LogCogImGui, Verbose, TEXT("UCogWindowManager::DisableInputMode")); + Context.SetEnableInput(false); +} diff --git a/Plugins/Cog/Source/CogWindow/Private/CogWindowWidgets.cpp b/Plugins/Cog/Source/CogWindow/Private/CogWindowWidgets.cpp index 1fd1d4b..991df58 100644 --- a/Plugins/Cog/Source/CogWindow/Private/CogWindowWidgets.cpp +++ b/Plugins/Cog/Source/CogWindow/Private/CogWindowWidgets.cpp @@ -13,13 +13,23 @@ #include "imgui_internal.h" #include "InputCoreTypes.h" +#if WITH_EDITOR +#include "IAssetTools.h" +#include "Subsystems/AssetEditorSubsystem.h" +#endif + //-------------------------------------------------------------------------------------------------------------------------- -void FCogWindowWidgets::BeginTableTooltip() +bool FCogWindowWidgets::BeginTableTooltip() { ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2(4, 4)); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); ImGui::PushStyleColor(ImGuiCol_PopupBg, IM_COL32(29, 42, 62, 240)); - ImGui::BeginTooltip(); + if (ImGui::BeginTooltip() == false) + { + EndTableTooltip(); + return false; + } + return true; } //-------------------------------------------------------------------------------------------------------------------------- @@ -30,16 +40,42 @@ void FCogWindowWidgets::EndTableTooltip() ImGui::PopStyleVar(2); } +//-------------------------------------------------------------------------------------------------------------------------- +bool FCogWindowWidgets::BeginItemTableTooltip() +{ + if (ImGui::IsItemHovered(ImGuiHoveredFlags_Stationary | ImGuiHoveredFlags_DelayShort) == false) + { return false; } + + return BeginTableTooltip(); +} + +//-------------------------------------------------------------------------------------------------------------------------- +void FCogWindowWidgets::EndItemTableTooltip() +{ + return EndTableTooltip(); +} + //-------------------------------------------------------------------------------------------------------------------------- void FCogWindowWidgets::ThinSeparatorText(const char* Label) { - ImGui::PushStyleVar(ImGuiStyleVar_SeparatorTextBorderSize, 2); - ImGui::PushStyleColor(ImGuiCol_Text, IM_COL32(100, 100, 100, 255)); + ImGui::PushStyleVar(ImGuiStyleVar_SeparatorTextBorderSize, 2); + ImGui::PushStyleColor(ImGuiCol_Text, IM_COL32(100, 100, 100, 255)); - ImGui::SeparatorText(Label); + ImGui::SeparatorText(Label); ImGui::PopStyleColor(); - ImGui::PopStyleVar(); + ImGui::PopStyleVar(); +} + +//-------------------------------------------------------------------------------------------------------------------------- +bool FCogWindowWidgets::DarkCollapsingHeader(const char* InLabel, ImGuiTreeNodeFlags InFlags) +{ + ImGui::PushStyleColor(ImGuiCol_Header, IM_COL32(66, 66, 66, 79)); + ImGui::PushStyleColor(ImGuiCol_HeaderHovered, IM_COL32(62, 62, 62, 204)); + ImGui::PushStyleColor(ImGuiCol_HeaderActive, IM_COL32(86, 86, 86, 255)); + const bool open = ImGui::CollapsingHeader(InLabel, InFlags); + ImGui::PopStyleColor(3); + return open; } //-------------------------------------------------------------------------------------------------------------------------- @@ -226,10 +262,10 @@ void FCogWindowWidgets::AddTextWithShadow(ImDrawList* DrawList, const ImVec2& Po //-------------------------------------------------------------------------------------------------------------------------- void FCogWindowWidgets::SearchBar(ImGuiTextFilter& Filter, float Width /*= -1*/) { - const ImGuiWindow* Window = FCogImguiHelper::GetCurrentWindow(); - const ImVec2 Pos1 = Window->DC.CursorPos; + const ImGuiWindow* Window = FCogImguiHelper::GetCurrentWindow(); + const ImVec2 Pos1 = Window->DC.CursorPos; Filter.Draw("##Filter", Width); - const ImVec2 Pos2 = Window->DC.CursorPosPrevLine; + const ImVec2 Pos2 = Window->DC.CursorPosPrevLine; if (ImGui::IsItemActive() == false && Filter.Filters.empty()) { @@ -355,7 +391,7 @@ bool FCogWindowWidgets::ComboboxEnum(const char* Label, UEnum* Enum, int64 Curre } //-------------------------------------------------------------------------------------------------------------------------- -bool FCogWindowWidgets::CheckBoxState(const char* Label, ECheckBoxState& State) +bool FCogWindowWidgets::CheckBoxState(const char* Label, ECheckBoxState& State, bool ShowTooltip) { const char* TooltipText = "Invalid"; @@ -399,14 +435,14 @@ bool FCogWindowWidgets::CheckBoxState(const char* Label, ECheckBoxState& State) ImGui::PopStyleColor(5); - if (ImGui::IsItemHovered(ImGuiHoveredFlags_Stationary)) + if (ShowTooltip) { - ImGui::SetTooltip("%s", TooltipText); + ImGui::SetItemTooltip("%s", TooltipText); } - if (IsPressed) + if (IsPressed) { - switch (State) + switch (State) { case ECheckBoxState::Checked: State = ECheckBoxState::Unchecked; break; case ECheckBoxState::Unchecked: State = ECheckBoxState::Undetermined; break; @@ -682,7 +718,7 @@ bool FCogWindowWidgets::CollisionProfileChannel(const UCollisionProfile& Collisi bool Result = false; FCogImguiHelper::ColorEdit4("Color", ChannelColor, ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel); - ImGui::SameLine(); + ImGui::SameLine(); bool IsCollisionActive = (Channels & ECC_TO_BITFIELD(ChannelIndex)) > 0; const FName ChannelName = CollisionProfile.ReturnChannelNameFromContainerIndex(ChannelIndex); @@ -700,7 +736,7 @@ bool FCogWindowWidgets::CollisionProfileChannel(const UCollisionProfile& Collisi } } - return Result; + return Result; } //-------------------------------------------------------------------------------------------------------------------------- @@ -734,7 +770,7 @@ bool FCogWindowWidgets::CollisionProfileChannels(int32& Channels) } //-------------------------------------------------------------------------------------------------------------------------- -bool FCogWindowWidgets::ActorsListWithFilters(const UWorld& World, const TArray>& ActorClasses, int32& SelectedActorClassIndex, ImGuiTextFilter* Filter, const APawn* LocalPlayerPawn, const FCogWindowActorContextMenuFunction& ContextMenuFunction) +bool FCogWindowWidgets::ActorsListWithFilters(AActor*& NewSelection, const UWorld& World, const TArray>& ActorClasses, int32& SelectedActorClassIndex, ImGuiTextFilter* Filter, const APawn* LocalPlayerPawn, const FCogWindowActorContextMenuFunction& ContextMenuFunction) { TSubclassOf SelectedClass = AActor::StaticClass(); if (ActorClasses.IsValidIndex(SelectedActorClassIndex)) @@ -783,14 +819,14 @@ bool FCogWindowWidgets::ActorsListWithFilters(const UWorld& World, const TArray< // Actor List //------------------------ ImGui::BeginChild("ActorsList", ImVec2(-1, -1), false); - const bool SelectionChanged = ActorsList(World, SelectedClass, Filter, LocalPlayerPawn, ContextMenuFunction); + const bool SelectionChanged = ActorsList(NewSelection, World, SelectedClass, Filter, LocalPlayerPawn, ContextMenuFunction); ImGui::EndChild(); return SelectionChanged; } //-------------------------------------------------------------------------------------------------------------------------- -bool FCogWindowWidgets::ActorsList(const UWorld& World, const TSubclassOf ActorClass, const ImGuiTextFilter* Filter, const APawn* LocalPlayerPawn, const FCogWindowActorContextMenuFunction& ContextMenuFunction) +bool FCogWindowWidgets::ActorsList(AActor*& NewSelection, const UWorld& World, const TSubclassOf ActorClass, const ImGuiTextFilter* Filter, const APawn* LocalPlayerPawn, const FCogWindowActorContextMenuFunction& ContextMenuFunction) { TArray Actors; for (TActorIterator It(&World, ActorClass); It; ++It) @@ -813,8 +849,8 @@ bool FCogWindowWidgets::ActorsList(const UWorld& World, const TSubclassOf ActorClass, const FCogWindowActorContextMenuFunction& ContextMenuFunction) +bool FCogWindowWidgets::MenuActorsCombo(const char* StrID, AActor*& NewSelection, const UWorld& World, TSubclassOf ActorClass, const FCogWindowActorContextMenuFunction& ContextMenuFunction) { int32 SelectedActorClassIndex = 0; const TArray ActorClasses = { ActorClass }; AActor* Actor = nullptr; - return MenuActorsCombo(StrID, World, ActorClasses, SelectedActorClassIndex, nullptr, nullptr, ContextMenuFunction); + return MenuActorsCombo(StrID, NewSelection, World, ActorClasses, SelectedActorClassIndex, nullptr, nullptr, ContextMenuFunction); } //-------------------------------------------------------------------------------------------------------------------------- -bool FCogWindowWidgets::MenuActorsCombo(const char* StrID, const UWorld& World, const TArray>& ActorClasses, int32& SelectedActorClassIndex, ImGuiTextFilter* Filter, const APawn* LocalPlayerPawn, const FCogWindowActorContextMenuFunction& ContextMenuFunction) +bool FCogWindowWidgets::MenuActorsCombo(const char* StrID, AActor*& NewSelection, const UWorld& World, const TArray>& ActorClasses, int32& SelectedActorClassIndex, ImGuiTextFilter* Filter, const APawn* LocalPlayerPawn, const FCogWindowActorContextMenuFunction& ContextMenuFunction) { bool Result = false; ImGui::PushID(StrID); @@ -880,9 +916,9 @@ bool FCogWindowWidgets::MenuActorsCombo(const char* StrID, const UWorld& World, const ImVec2 Pos1 = ImGui::GetCursorScreenPos(); const float Width = FCogImguiHelper::GetNextItemWidth(); - //----------------------------------- - // Combo button - //----------------------------------- + //----------------------------------- + // Combo button + //----------------------------------- { ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 0.0f)); ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0.0f, 0.5f)); @@ -920,15 +956,15 @@ bool FCogWindowWidgets::MenuActorsCombo(const char* StrID, const UWorld& World, } //----------------------------------- - // Popup - //----------------------------------- + // Popup + //----------------------------------- const ImVec2 Pos2 = ImGui::GetCursorScreenPos(); ImGui::SetNextWindowPos(ImVec2(Pos1.x, Pos1.y + ImGui::GetFrameHeight())); if (ImGui::BeginPopup("ActorListPopup")) { ImGui::BeginChild("Child", ImVec2(Pos2.x - Pos1.x, GetFontWidth() * 40), false); - Result = ActorsListWithFilters(World, ActorClasses, SelectedActorClassIndex, Filter, LocalPlayerPawn, ContextMenuFunction); + Result = ActorsListWithFilters(NewSelection, World, ActorClasses, SelectedActorClassIndex, Filter, LocalPlayerPawn, ContextMenuFunction); if (Result) { ImGui::CloseCurrentPopup(); @@ -946,10 +982,10 @@ bool FCogWindowWidgets::MenuActorsCombo(const char* StrID, const UWorld& World, //-------------------------------------------------------------------------------------------------------------------------- void FCogWindowWidgets::ActorContextMenu(AActor& Selection, const FCogWindowActorContextMenuFunction& ContextMenuFunction) { - if (ContextMenuFunction == nullptr) - { + if (ContextMenuFunction == nullptr) + { return; - } + } ImGui::SetNextWindowSize(ImVec2(GetFontWidth() * 30, 0)); if (ImGui::BeginPopupContextItem()) @@ -962,7 +998,7 @@ void FCogWindowWidgets::ActorContextMenu(AActor& Selection, const FCogWindowActo //-------------------------------------------------------------------------------------------------------------------------- void FCogWindowWidgets::ActorFrame(const AActor& Actor) { - const APlayerController* PlayerController = Actor.GetWorld()->GetFirstPlayerController(); + const APlayerController* PlayerController = Actor.GetWorld()->GetFirstPlayerController(); if (PlayerController == nullptr) { return; @@ -1029,4 +1065,155 @@ void FCogWindowWidgets::SmallButton(const char* Text, const ImVec4& Color) ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(Color.x, Color.y, Color.z, Color.w * 1.0f)); ImGui::SmallButton(Text); ImGui::PopStyleColor(3); -} \ No newline at end of file +} + +//-------------------------------------------------------------------------------------------------------------------------- +bool FCogWindowWidgets::InputText(const char* Text, FString& Value) +{ + static char Buffer[256] = ""; + ImStrncpy(Buffer, TCHAR_TO_ANSI(*Value), IM_ARRAYSIZE(Buffer)); + + bool result = ImGui::InputText(Text, Buffer, IM_ARRAYSIZE(Buffer)); + if (result) + { + Value = FString(Buffer); + } + + return result; +} + +//-------------------------------------------------------------------------------------------------------------------------- +bool FCogWindowWidgets::BeginRightAlign(const char* Id) +{ + if (ImGui::BeginTable(Id, 2, ImGuiTableFlags_SizingFixedFit, ImVec2(-1, 0))) + { + ImGui::TableSetupColumn("a", ImGuiTableColumnFlags_WidthStretch); + + ImGui::TableNextColumn(); + ImGui::TableNextColumn(); + return true; + } + return false; +} + +//-------------------------------------------------------------------------------------------------------------------------- +void FCogWindowWidgets::EndRightAlign() +{ + ImGui::EndTable(); +} + +//-------------------------------------------------------------------------------------------------------------------------- +void FCogWindowWidgets::MenuItemShortcut(const char* Id, const FString& Text) +{ + ImGui::SameLine(); + if (BeginRightAlign(Id)) + { + ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyle().Colors[ImGuiCol_TextDisabled]); + const auto TextStr = StringCast(*Text); + ImGui::Text("%s", TextStr.Get()); + ImGui::PopStyleColor(); + + EndRightAlign(); + } +} + +//-------------------------------------------------------------------------------------------------------------------------- +bool FCogWindowWidgets::BrowseToAssetButton(const UObject* InAsset, const ImVec2& InSize) +{ +#if WITH_EDITOR + + if (InAsset == nullptr) + { + ImGui::BeginDisabled(); + } + + const bool result = ImGui::Button("Browse To Asset", InSize); + if (result) + { + IAssetTools::Get().SyncBrowserToAssets({ InAsset }); + } + + if (InAsset == nullptr) + { + ImGui::EndDisabled(); + } + return result; + +#else + return false; +#endif +} + +//-------------------------------------------------------------------------------------------------------------------------- +bool FCogWindowWidgets::BrowseToObjectAssetButton(const UObject* InObject, const ImVec2& InSize) +{ +#if WITH_EDITOR + + const UObject* ObjectAsset = nullptr; + if (InObject != nullptr && InObject->GetClass() != nullptr) + { + ObjectAsset = InObject->GetClass()->ClassGeneratedBy; + } + + return BrowseToAssetButton(ObjectAsset, InSize); + +#else + return false; +#endif + +} + +//-------------------------------------------------------------------------------------------------------------------------- +bool FCogWindowWidgets::OpenAssetButton(const UObject* InAsset, const ImVec2& InSize) +{ +#if WITH_EDITOR + + UAssetEditorSubsystem* editorSubsystem = GEditor->GetEditorSubsystem(); + if (InAsset == nullptr || editorSubsystem == nullptr) + { + ImGui::BeginDisabled(); + } + + const bool result = ImGui::Button("Open Asset", InSize); + if (result) + { + if (editorSubsystem != nullptr) + { + editorSubsystem->OpenEditorForAsset(InAsset); + } + } + + if (InAsset == nullptr) + { + ImGui::EndDisabled(); + } + return result; + +#else + return false; +#endif +} + +//-------------------------------------------------------------------------------------------------------------------------- +bool FCogWindowWidgets::OpenObjectAssetButton(const UObject* InObject, const ImVec2& InSize) +{ +#if WITH_EDITOR + + const UObject* ObjectAsset = nullptr; + if (InObject != nullptr && InObject->GetClass() != nullptr) + { + ObjectAsset = InObject->GetClass()->ClassGeneratedBy; + } + + return OpenAssetButton(ObjectAsset, InSize); + +#else + return false; +#endif + +} + + + + + diff --git a/Plugins/Cog/Source/CogWindow/Private/CogWindow_Settings.cpp b/Plugins/Cog/Source/CogWindow/Private/CogWindow_Settings.cpp index 123ab8e..10ee950 100644 --- a/Plugins/Cog/Source/CogWindow/Private/CogWindow_Settings.cpp +++ b/Plugins/Cog/Source/CogWindow/Private/CogWindow_Settings.cpp @@ -5,6 +5,7 @@ #include "CogWindowManager.h" #include "CogWindowWidgets.h" #include "imgui.h" +#include "imgui.h" #include "InputCoreTypes.h" //-------------------------------------------------------------------------------------------------------------------------- @@ -77,17 +78,7 @@ void FCogWindow_Settings::RenderContent() Context.SetEnableInput(bEnableInput); } ImGui::SetItemTooltip("Enable ImGui inputs. When enabled the ImGui menu is shown and inputs are forwarded to ImGui."); - - const auto ShortcutText = StringCast(*FCogImguiInputHelper::CommandToString(PlayerInput, UCogWindowManager::ToggleInputCommand)); - const float ShortcutWidth = (ShortcutText.Get() != nullptr && ShortcutText.Get()[0]) ? ImGui::CalcTextSize(ShortcutText.Get(), NULL).x : 0.0f; - if (ShortcutWidth > 0.0f) - { - ImGui::SameLine(); - ImGui::SetCursorPosX(ImGui::GetContentRegionAvail().x); // https://github.com/ocornut/imgui/issues/7838 - ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyle().Colors[ImGuiCol_TextDisabled]); - ImGui::Text("%s", ShortcutText.Get()); - ImGui::PopStyleColor(); - } + FCogWindowWidgets::MenuItemShortcut("EnableInputShortcut", FCogImguiInputHelper::CommandToString(PlayerInput, UCogWindowManager::ToggleInputCommand)); //------------------------------------------------------------------------------------------- bool bShareKeyboard = Context.GetShareKeyboard(); diff --git a/Plugins/Cog/Source/CogWindow/Public/CogWindow.h b/Plugins/Cog/Source/CogWindow/Public/CogWindow.h index fda5de3..78b0611 100644 --- a/Plugins/Cog/Source/CogWindow/Public/CogWindow.h +++ b/Plugins/Cog/Source/CogWindow/Public/CogWindow.h @@ -53,13 +53,13 @@ public: /** The short name of the window. "Effect" if the window full name is "Gameplay.Character.Effect" */ const FString& GetName() const { return Name; } - AActor* GetSelection() { return CurrentSelection.Get(); } + AActor* GetSelection() const { return CurrentSelection.Get(); } void SetSelection(AActor* Actor); bool GetIsVisible() const { return bIsVisible; } - void SetIsVisible(bool Value) { bIsVisible = Value; } + void SetIsVisible(bool Value); bool HasWidget() const { return bHasWidget; } @@ -76,12 +76,12 @@ public: UCogWindowManager* GetOwner() const { return Owner; } template - T* GetConfig() { return Cast(GetConfig(T::StaticClass())); } + T* GetConfig() const { return Cast(GetConfig(T::StaticClass())); } UCogCommonConfig* GetConfig(const TSubclassOf ConfigClass) const; template - const T* GetAsset() { return Cast(GetAsset(T::StaticClass())); } + const T* GetAsset() const { return Cast(GetAsset(T::StaticClass())); } const UObject* GetAsset(const TSubclassOf AssetClass) const; @@ -103,6 +103,8 @@ protected: virtual bool CheckEditorVisibility(); + virtual void OnWindowVisibilityChanged(bool NewVisibility) { } + virtual void OnSelectionChanged(AActor* OldSelection, AActor* NewSelection) {} APawn* GetLocalPlayerPawn() const; @@ -113,7 +115,7 @@ protected: protected: - bool bHideMenu = false; + bool bShowMenu = true; bool bNoPadding = false; diff --git a/Plugins/Cog/Source/CogWindow/Public/CogWindowConsoleCommandManager.h b/Plugins/Cog/Source/CogWindow/Public/CogWindowConsoleCommandManager.h new file mode 100644 index 0000000..c15a759 --- /dev/null +++ b/Plugins/Cog/Source/CogWindow/Public/CogWindowConsoleCommandManager.h @@ -0,0 +1,39 @@ +#pragma once + +#include "CoreMinimal.h" +#include "HAL/IConsoleManager.h" +#include "Templates/Function.h" + +class UWorld; + +DECLARE_DELEGATE_TwoParams(FCogWindowConsoleCommandDelegate, const TArray&, UWorld*); + +//-------------------------------------------------------------------------------------------------------------------------- +struct FCogCommandReceiver +{ + UWorld* World = nullptr; + + FCogWindowConsoleCommandDelegate Delegate; +}; + +//-------------------------------------------------------------------------------------------------------------------------- +struct FCogCommandInfo +{ + IConsoleObject* ConsoleObject = nullptr; + + TArray Receivers; +}; + +//-------------------------------------------------------------------------------------------------------------------------- +struct COGWINDOW_API FCogWindowConsoleCommandManager +{ +public: + + static void RegisterWorldConsoleCommand(const TCHAR* InName, const TCHAR* InHelp, UWorld* InWorld, const FCogWindowConsoleCommandDelegate& InDelegate); + + static void UnregisterAllWorldConsoleCommands(const UWorld* InWorld); + +protected: + + static TMap CommandMap; +}; diff --git a/Plugins/Cog/Source/CogWindow/Public/CogWindowManager.h b/Plugins/Cog/Source/CogWindow/Public/CogWindowManager.h index 3f120d6..a0695e1 100644 --- a/Plugins/Cog/Source/CogWindow/Public/CogWindowManager.h +++ b/Plugins/Cog/Source/CogWindow/Public/CogWindowManager.h @@ -36,6 +36,7 @@ public: virtual void Tick(float DeltaTime); + virtual void AddWindow(FCogWindow* Window, const FString& Name, bool AddToMainMenu = true); template @@ -51,9 +52,9 @@ public: virtual void SaveLayout(int32 LayoutIndex); - virtual bool GetHideAllWindows() const { return bHideAllWindows; } + virtual bool GetHideAllWindows() const { return bIsSelectionModeActive; } - virtual void SetHideAllWindows(bool Value); + virtual void SetActivateSelectionMode(bool Value); virtual void ResetAllWindowsConfig(); @@ -101,10 +102,12 @@ protected: virtual void RenderMenuItem(FCogWindow& Window, const char* MenuItemName); - void RenderMenuItemHelp(FCogWindow& Window); + virtual void RenderMenuItemHelp(FCogWindow& Window); virtual void ToggleInputMode(); + virtual void DisableInputMode(); + static void SettingsHandler_ClearAll(ImGuiContext* ctx, ImGuiSettingsHandler*); static void SettingsHandler_ApplyAll(ImGuiContext* ctx, ImGuiSettingsHandler*); @@ -116,6 +119,8 @@ protected: static void SettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* buf); static FString ToggleInputCommand; + + static FString DisableInputCommand; static FString LoadLayoutCommand; @@ -150,13 +155,11 @@ protected: int32 LayoutToLoad = -1; - int32 HideAllWindowsCounter = 0; + int32 SelectionModeActiveCounter = 0; - bool bHideAllWindows = false; + bool bIsSelectionModeActive = false; bool IsInitialized = false; - - TArray ConsoleCommands; }; //-------------------------------------------------------------------------------------------------------------------------- diff --git a/Plugins/Cog/Source/CogWindow/Public/CogWindowWidgets.h b/Plugins/Cog/Source/CogWindow/Public/CogWindowWidgets.h index e576f0e..408984b 100644 --- a/Plugins/Cog/Source/CogWindow/Public/CogWindowWidgets.h +++ b/Plugins/Cog/Source/CogWindow/Public/CogWindowWidgets.h @@ -4,6 +4,10 @@ #include "imgui.h" #include "UObject/ReflectedTypeAccessors.h" +#include + +class AActor; +class APawn; class FEnumProperty; class UCollisionProfile; class UEnum; @@ -19,12 +23,18 @@ class COGWINDOW_API FCogWindowWidgets { public: - static void BeginTableTooltip(); + static bool BeginTableTooltip(); static void EndTableTooltip(); + static bool BeginItemTableTooltip(); + + static void EndItemTableTooltip(); + static void ThinSeparatorText(const char* Label); + static bool DarkCollapsingHeader(const char* InLabel, ImGuiTreeNodeFlags InFlags); + static void ProgressBarCentered(float Fraction, const ImVec2& Size, const char* Overlay); static bool ToggleMenuButton(bool* Value, const char* Text, const ImVec4& TrueColor); @@ -73,7 +83,7 @@ public: static bool ComboboxEnum(const char* Label, const FEnumProperty* EnumProperty, uint8* PointerToEnumValue); - static bool CheckBoxState(const char* Label, ECheckBoxState& State); + static bool CheckBoxState(const char* Label, ECheckBoxState& State, bool ShowTooltip = true); static bool InputKey(const char* Label, FCogImGuiKeyInfo& KeyInfo); @@ -91,19 +101,36 @@ public: static bool CollisionProfileChannels(int32& Channels); - static bool MenuActorsCombo(const char* StrID, const UWorld& World, TSubclassOf ActorClass, const FCogWindowActorContextMenuFunction& ContextMenuFunction = nullptr); + static bool MenuActorsCombo(const char* StrID, AActor*& NewSelection, const UWorld& World, TSubclassOf ActorClass, const FCogWindowActorContextMenuFunction& ContextMenuFunction = nullptr); - static bool MenuActorsCombo(const char* StrID, const UWorld& World, const TArray>& ActorClasses, int32& SelectedActorClassIndex, ImGuiTextFilter* Filter, const APawn* LocalPlayerPawn, const FCogWindowActorContextMenuFunction& ContextMenuFunction = nullptr); + static bool MenuActorsCombo(const char* StrID, AActor*& NewSelection, const UWorld& World, const TArray>& ActorClasses, int32& SelectedActorClassIndex, ImGuiTextFilter* Filter, const APawn* LocalPlayerPawn, const FCogWindowActorContextMenuFunction& ContextMenuFunction = nullptr); - static bool ActorsListWithFilters(const UWorld& World, const TArray>& ActorClasses, int32& SelectedActorClassIndex, ImGuiTextFilter* Filter, const APawn* LocalPlayerPawn, const FCogWindowActorContextMenuFunction& ContextMenuFunction = nullptr); + static bool ActorsListWithFilters(AActor*& NewSelection, const UWorld& World, const TArray>& ActorClasses, int32& SelectedActorClassIndex, ImGuiTextFilter* Filter, const APawn* LocalPlayerPawn, const FCogWindowActorContextMenuFunction& ContextMenuFunction = nullptr); - static bool ActorsList(const UWorld& World, const TSubclassOf ActorClass, const ImGuiTextFilter* Filter = nullptr, const APawn* LocalPlayerPawn = nullptr, const FCogWindowActorContextMenuFunction& ContextMenuFunction = nullptr); + static bool ActorsList(AActor*& NewSelection, const UWorld& World, const TSubclassOf ActorClass, const ImGuiTextFilter* Filter = nullptr, const APawn* LocalPlayerPawn = nullptr, const FCogWindowActorContextMenuFunction& ContextMenuFunction = nullptr); static void ActorContextMenu(AActor& Selection, const FCogWindowActorContextMenuFunction& ContextMenuFunction); static void ActorFrame(const AActor& Actor); static void SmallButton(const char* Text, const ImVec4& Color); + + static bool InputText(const char* Text, FString& Value); + + static bool BeginRightAlign(const char* Id); + + static void EndRightAlign(); + + static void MenuItemShortcut(const char* Id, const FString& Text); + + static bool BrowseToAssetButton(const UObject* InAsset, const ImVec2& InSize = ImVec2(0, 0)); + + static bool BrowseToObjectAssetButton(const UObject* InObject, const ImVec2& InSize = ImVec2(0, 0)); + + static bool OpenAssetButton(const UObject* InAsset, const ImVec2& InSize = ImVec2(0, 0)); + + static bool OpenObjectAssetButton(const UObject* InObject, const ImVec2& InSize = ImVec2(0, 0)); + }; template diff --git a/Plugins/Cog/Source/ThirdParty/ImGui/LICENSE.txt b/Plugins/Cog/Source/ThirdParty/ImGui/LICENSE.txt new file mode 100644 index 0000000..00ae473 --- /dev/null +++ b/Plugins/Cog/Source/ThirdParty/ImGui/LICENSE.txt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014-2025 Omar Cornut + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Plugins/Cog/Source/ThirdParty/NetImgui/NetImgui.Build.cs b/Plugins/Cog/Source/ThirdParty/NetImgui/NetImgui.Build.cs new file mode 100644 index 0000000..ed3997e --- /dev/null +++ b/Plugins/Cog/Source/ThirdParty/NetImgui/NetImgui.Build.cs @@ -0,0 +1,11 @@ +using UnrealBuildTool; +using System.IO; + +public class NetImgui : ModuleRules +{ + public NetImgui(ReadOnlyTargetRules Target) : base(Target) + { + Type = ModuleType.External; + PublicSystemIncludePaths.Add(ModuleDirectory); + } +} diff --git a/Plugins/Cog/Source/ThirdParty/NetImgui/NetImgui_Api.h b/Plugins/Cog/Source/ThirdParty/NetImgui/NetImgui_Api.h new file mode 100644 index 0000000..6815ab5 --- /dev/null +++ b/Plugins/Cog/Source/ThirdParty/NetImgui/NetImgui_Api.h @@ -0,0 +1,285 @@ +#pragma once + +//================================================================================================= +//! @Name : NetImgui +//================================================================================================= +//! @author : Sammy Fatnassi +//! @date : 2024/12/10 +//! @version : v1.12.1 +//! @Details : For integration info : https://github.com/sammyfreg/netImgui/wiki +//================================================================================================= +#define NETIMGUI_VERSION "1.12.1" // Fixed disconnect thread contention and clipboard command +#define NETIMGUI_VERSION_NUM 11201 + + + + +//------------------------------------------------------------------------------------------------- +// Deactivate a few warnings to allow Imgui header include +// without generating warnings in maximum level '-Wall' +//------------------------------------------------------------------------------------------------- +#if defined (__clang__) + #pragma clang diagnostic push + // ImGui.h warnings(s) + #pragma clang diagnostic ignored "-Wunknown-warning-option" + #pragma clang diagnostic ignored "-Wc++98-compat-pedantic" + #pragma clang diagnostic ignored "-Wreserved-identifier" // Enum values using '__' or member starting with '_' in imgui.h + // NetImgui_Api.h Warning(s) + #pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // Not using nullptr in case this file is used in pre C++11 +#elif defined(_MSC_VER) + #pragma warning (push) + // ImGui.h warnings(s) + #pragma warning (disable: 4514) // 'xxx': unreferenced inline function has been removed + #pragma warning (disable: 4710) // 'xxx': function not inlined + #pragma warning (disable: 4820) // 'xxx': 'yyy' bytes padding added after data member 'zzz' + #pragma warning (disable: 5045) // Compiler will insert Spectre mitigation for memory load if /Qspectre switch specified +#endif + +//================================================================================================= +// Include the user config file. It should contain the include for : +// 'imgui.h' : always +// 'imgui_internal.h' when 'NETIMGUI_INTERNAL_INCLUDE' is defined +//================================================================================================= +#ifdef NETIMGUI_IMPLEMENTATION + #define NETIMGUI_INTERNAL_INCLUDE + #include "NetImgui_Config.h" + #undef NETIMGUI_INTERNAL_INCLUDE +#else + #include "NetImgui_Config.h" +#endif + +//------------------------------------------------------------------------------------------------- +// If 'NETIMGUI_ENABLED' hasn't been defined yet (in project settings or NetImgui_Config.h') +// we define this library as 'Disabled' +//------------------------------------------------------------------------------------------------- +#ifndef NETIMGUI_ENABLED + #define NETIMGUI_ENABLED 0 +#endif + +//------------------------------------------------------------------------------------------------- +// NetImgui needs to detect Dear ImGui to be active, otherwise we disable it +// When including this header, make sure imgui.h is included first +// (either always included in NetImgui_config.h or have it included after Imgui.h in your cpp) +//------------------------------------------------------------------------------------------------- +#if !defined(IMGUI_VERSION) + #undef NETIMGUI_ENABLED + #define NETIMGUI_ENABLED 0 +#endif + +#if NETIMGUI_ENABLED + +#include + +//================================================================================================= +// Default Build settings defines values +// Assign default values when not set in user NetImgui_Config.h +//================================================================================================= + +//------------------------------------------------------------------------------------------------- +// Prepended to functions signature, for dll export/import +//------------------------------------------------------------------------------------------------- +#ifndef NETIMGUI_API + #define NETIMGUI_API IMGUI_API // Use same value as defined by Dear ImGui by default +#endif + +//------------------------------------------------------------------------------------------------- +// Enable TCP socket 'reuse port' option when opening it as a 'listener'. +// Note: Can help when unable to open a socket because it wasn't properly released after a crash. +//------------------------------------------------------------------------------------------------- +#ifndef NETIMGUI_FORCE_TCP_LISTEN_BINDING + #define NETIMGUI_FORCE_TCP_LISTEN_BINDING 0 // Doesn't seem to be needed on Window/Linux +#endif + +//------------------------------------------------------------------------------------------------- +// Enable Dear ImGui Callbacks support for BeginFrame/Render automatic interception. +// Note: Avoid having to replace ImGui::BeginFrame/ImGui::Render with in library user code, by +// 'NetImgui::NewFrame/NetImgui::EndFrame'. But prevent benefit of skipping frame draw +// when unneeded, that 'NetImgui::NewFrame' can provide. +// For more info, consult 'SampleNewFrame.cpp'. +// Needs Dear ImGui 1.81+ +//------------------------------------------------------------------------------------------------- +#ifndef NETIMGUI_IMGUI_CALLBACK_ENABLED + #define NETIMGUI_IMGUI_CALLBACK_ENABLED (IMGUI_VERSION_NUM >= 18100) // Not supported pre Dear ImGui 1.81 +#endif + + +namespace NetImgui +{ + +//================================================================================================= +// List of texture format supported +//================================================================================================= +enum eTexFormat { + kTexFmtA8, + kTexFmtRGBA8, + + // Support of 'user defined' texture format. + // Implementation must be added on both client and Server code. + // Search for TEXTURE_CUSTOM_SAMPLE for example implementation. + kTexFmtCustom, + + // + kTexFmt_Count, + kTexFmt_Invalid=kTexFmt_Count +}; + +//================================================================================================= +// Data Compression wanted status +//================================================================================================= +enum eCompressionMode { + kForceDisable, // Disable data compression for communications + kForceEnable, // Enable data compression for communications + kUseServerSetting // Use Server setting for compression (default) +}; + +//------------------------------------------------------------------------------------------------- +// Function typedefs +//------------------------------------------------------------------------------------------------- +typedef void (*ThreadFunctPtr)(void threadedFunction(void* pClientInfo), void* pClientInfo); +typedef void (*FontCreateFuncPtr)(float PreviousDPIScale, float NewDPIScale); + +//================================================================================================= +// Initialize the Network Library +//================================================================================================= +NETIMGUI_API bool Startup(void); + +//================================================================================================= +// Free Resources +// Wait until all communication threads have terminated before returning +//================================================================================================= +NETIMGUI_API void Shutdown(); + +//================================================================================================= +// Establish a connection between the NetImgui server application and this client. +// +// Can connect with NetImgui Server application by either reaching it directly +// using 'ConnectToApp' or waiting for Server to reach us after Client called 'ConnectFromApp'. +// +// Note: Start a new communication thread using std::Thread by default, but can receive custom +// thread start function instead (Look at ClientExample 'CustomCommunicationThread'). +//------------------------------------------------------------------------------------------------- +// clientName : Client name displayed in the Server's clients list +// serverHost : NetImgui Server Application address (Ex1: 127.0.0.2, Ex2: localhost) +// serverPort : PortID of the NetImgui Server application to connect to +// clientPort : PortID this Client should wait for connection from Server application +// threadFunction : User provided function to launch new networking thread. +// Use 'DefaultStartCommunicationThread' by default (uses 'std::thread'). +// fontCreateFunction : User provided function to call when the Server expect an update of +// the font atlas, because of a monitor DPI change. When left to nullptr, +// uses 'ImGuiIO.FontGlobalScale' instead to increase text size, +// with blurier results. +//================================================================================================= +NETIMGUI_API bool ConnectToApp(const char* clientName, const char* serverHost, uint32_t serverPort=kDefaultServerPort, ThreadFunctPtr threadFunction=0, FontCreateFuncPtr FontCreateFunction=0); +NETIMGUI_API bool ConnectFromApp(const char* clientName, uint32_t clientPort=kDefaultClientPort, ThreadFunctPtr threadFunction=0, FontCreateFuncPtr fontCreateFunction=0); + +//================================================================================================= +// Request a disconnect from the NetImguiServer application +//================================================================================================= +NETIMGUI_API void Disconnect(void); + +//================================================================================================= +// True if connected to the NetImguiServer application +//================================================================================================= +NETIMGUI_API bool IsConnected(void); + +//================================================================================================= +// True if connection request is waiting to be completed. For example, while waiting for +// Server to reach ud after having called 'ConnectFromApp()' +//================================================================================================= +NETIMGUI_API bool IsConnectionPending(void); + +//================================================================================================= +// True when Dear ImGui is currently expecting draw commands +// This means that we are between NewFrame() and EndFrame() +//================================================================================================= +NETIMGUI_API bool IsDrawing(void); + +//================================================================================================= +// True when we are currently drawing on the NetImguiServer application +// Means that we are between NewFrame() and EndFrame() of drawing for remote application +//================================================================================================= +NETIMGUI_API bool IsDrawingRemote(void); + +//================================================================================================= +// Send an updated texture used by imgui, to the NetImguiServer application +// Note: To remove a texture, set pData to nullptr +// Note: User needs to provide a valid 'dataSize' when using format 'kTexFmtCustom', +// can be ignored otherwise +//================================================================================================= +NETIMGUI_API void SendDataTexture(ImTextureID textureId, void* pData, uint16_t width, uint16_t height, eTexFormat format, uint32_t dataSize=0); + +//================================================================================================= +// Start a new Imgui Frame and wait for Draws commands, using ImContext that was active on connect. +// Returns true if we are awaiting a new ImGui frame. +// +// All ImGui drawing should be skipped when return is false. +// +// Note: This code can be used instead, to know if you should be drawing or not : +// 'if( !NetImgui::IsDrawing() )' +// +// Note: If your code cannot handle skipping a ImGui frame, leave 'bSupportFrameSkip=false', +// and this function will always call 'ImGui::NewFrame()' internally and return true +// +// Note: With Dear ImGui 1.81+, you can keep using the ImGui::BeginFrame()/Imgui::Render() +// without having to use NetImgui::NewFrame()/NetImgui::EndFrame() +// (unless wanting to support frame skip) +//================================================================================================= +NETIMGUI_API bool NewFrame(bool bSupportFrameSkip=false); + +//================================================================================================= +// Process all receives draws, send them to remote connection and restore the ImGui Context +//================================================================================================= +NETIMGUI_API void EndFrame(void); + +//================================================================================================= +// Return the context associated to this remote connection. Null when not connected. +//================================================================================================= +NETIMGUI_API ImGuiContext* GetContext(); + +//================================================================================================= +// Set the remote client background color and texture +// Note: If no TextureID is specified, will use the default server texture +//================================================================================================= +NETIMGUI_API void SetBackground(const ImVec4& bgColor); +NETIMGUI_API void SetBackground(const ImVec4& bgColor, const ImVec4& textureTint ); +NETIMGUI_API void SetBackground(const ImVec4& bgColor, const ImVec4& textureTint, ImTextureID bgTextureID); + +//================================================================================================= +// Control the data compression for communications between Client/Server +//================================================================================================= +NETIMGUI_API void SetCompressionMode(eCompressionMode eMode); +NETIMGUI_API eCompressionMode GetCompressionMode(); + +//================================================================================================= +// Helper functions +//================================================================================================= +NETIMGUI_API uint8_t GetTexture_BitsPerPixel (eTexFormat eFormat); +NETIMGUI_API uint32_t GetTexture_BytePerLine (eTexFormat eFormat, uint32_t pixelWidth); +NETIMGUI_API uint32_t GetTexture_BytePerImage (eTexFormat eFormat, uint32_t pixelWidth, uint32_t pixelHeight); +} + +//================================================================================================= +// Optional single include compiling option +// Note: User wanting to avoid adding the few NetImgui sources files to their project, +// can instead define 'NETIMGUI_IMPLEMENTATION' *once* before including 'NetImgui_Api.h' +// to pull all the needed cpp files alongside for compilation +//================================================================================================= +#if defined(NETIMGUI_IMPLEMENTATION) + #include "Private/NetImgui_Api.cpp" + #include "Private/NetImgui_Client.cpp" + #include "Private/NetImgui_CmdPackets_DrawFrame.cpp" + #include "Private/NetImgui_NetworkPosix.cpp" + #include "Private/NetImgui_NetworkUE4.cpp" + #include "Private/NetImgui_NetworkWin32.cpp" +#endif + +#endif // NETIMGUI_ENABLED + +//------------------------------------------------------------------------------------------------- +// Re-Enable the Deactivated warnings +//------------------------------------------------------------------------------------------------- +#if defined (__clang__) + #pragma clang diagnostic pop +#elif defined(_MSC_VER) + #pragma warning (pop) +#endif diff --git a/Plugins/Cog/Source/ThirdParty/NetImgui/NetImgui_Config.h b/Plugins/Cog/Source/ThirdParty/NetImgui/NetImgui_Config.h new file mode 100644 index 0000000..25ade93 --- /dev/null +++ b/Plugins/Cog/Source/ThirdParty/NetImgui/NetImgui_Config.h @@ -0,0 +1,62 @@ +#pragma once + +//================================================================================================= +// Enable code compilation for this library +// Note: Useful to disable 'netImgui' on unsupported builds while keeping functions declared +//================================================================================================= +#ifndef NETIMGUI_ENABLED + #define NETIMGUI_ENABLED 1 +#endif + +#if NETIMGUI_ENABLED + +#include + +#ifdef NETIMGUI_INTERNAL_INCLUDE +#include "Private/NetImgui_WarningDisableImgui.h" // Disable some extra warning generated by imgui_internal in '-Wall' +#include // Only needed when compiling NetImgui, not when using the NetImgui Api +#include "Private/NetImgui_WarningReenable.h" +#endif + +#endif // NETIMGUI_ENABLED + +//================================================================================================= +// Default Ports used to reach the Server or the Client (listen port for incoming connection) +//================================================================================================= +namespace NetImgui +{ + enum Constants{ + kDefaultServerPort = 8888, //!< Default port Server waits for a connection + kDefaultClientPort = 8889 //!< Default port Client waits for a connection + }; +} + +//================================================================================================= +// Enable default Win32/Posix networking code +// Note: By default, netImgui uses Winsock on Windows and Posix sockets on other platforms +// +// The use your own code, turn off both NETIMGUI_WINSOCKET_ENABLED, +// NETIMGUI_POSIX_SOCKETS_ENABLED and provide your own implementation of the functions +// declared in 'NetImgui_Network.h'. +// +// As an example, 'SampleCompression' disable default com implementation and use its own +//================================================================================================= +#if !defined(NETIMGUI_WINSOCKET_ENABLED) && !defined(__UNREAL__) + #ifdef _WIN32 + #define NETIMGUI_WINSOCKET_ENABLED 1 // Project needs 'ws2_32.lib' added to input libraries + #else + #define NETIMGUI_WINSOCKET_ENABLED 0 + #endif +#endif + +#if !defined(NETIMGUI_POSIX_SOCKETS_ENABLED) && !defined(__UNREAL__) + #define NETIMGUI_POSIX_SOCKETS_ENABLED !(NETIMGUI_WINSOCKET_ENABLED) +#endif + +//================================================================================================= +// Various build settings define +// Note: for more information, please look in 'NetImgui_Api.h' for description and default values +//================================================================================================= +//#define NETIMGUI_IMGUI_CALLBACK_ENABLED (IMGUI_VERSION_NUM >= 18100) // Not supported pre Dear ImGui 1.81 +//#define NETIMGUI_FORCE_TCP_LISTEN_BINDING 0 // Doesn't seem to be needed on Window/Linux +//#define NETIMGUI_API IMGUI_API // Use same value as defined by Dear ImGui by default diff --git a/Plugins/Cog/Source/ThirdParty/NetImgui/Private/NetImgui_Api.cpp b/Plugins/Cog/Source/ThirdParty/NetImgui/Private/NetImgui_Api.cpp new file mode 100644 index 0000000..c998218 --- /dev/null +++ b/Plugins/Cog/Source/ThirdParty/NetImgui/Private/NetImgui_Api.cpp @@ -0,0 +1,795 @@ +#include "NetImgui_Shared.h" +#include "NetImgui_WarningDisable.h" + +#if NETIMGUI_ENABLED +#include +#include +#include "NetImgui_Client.h" +#include "NetImgui_Network.h" +#include "NetImgui_CmdPackets.h" + +using namespace NetImgui::Internal; + +namespace NetImgui { + +static Client::ClientInfo* gpClientInfo = nullptr; + +bool ProcessInputData(Client::ClientInfo& client); + +//================================================================================================= +void DefaultStartCommunicationThread(void ComFunctPtr(void*), void* pClient) +//================================================================================================= +{ +// Visual Studio 2017 generate this warning on std::thread, avoid the warning preventing build +#if defined(_MSC_VER) && (_MSC_VER < 1920) + #pragma warning (push) + #pragma warning (disable: 4625) // 'std::_LaunchPad<_Target>' : copy constructor was implicitly defined as deleted + #pragma warning (disable: 4626) // 'std::_LaunchPad<_Target>' : assignment operator was implicitly defined as deleted +#endif + + std::thread(ComFunctPtr, pClient).detach(); + +#if defined(_MSC_VER) && (_MSC_VER < 1920) + #pragma warning (pop) +#endif +} + + +//================================================================================================= +bool ConnectToApp(const char* clientName, const char* ServerHost, uint32_t serverPort, ThreadFunctPtr threadFunction, FontCreateFuncPtr FontCreateFunction) +//================================================================================================= +{ + if (!gpClientInfo) return false; + + Client::ClientInfo& client = *gpClientInfo; + Disconnect(); + + while (client.IsActive()) + std::this_thread::yield(); + + client.ContextRestore(); // Restore context setting override, after a disconnect + client.ContextRemoveHooks(); // Remove hooks callback only when completely disconnected + + StringCopy(client.mName, (clientName == nullptr || clientName[0] == 0 ? "Unnamed" : clientName)); + client.mpSocketPending = Network::Connect(ServerHost, serverPort); + client.mFontCreationFunction = FontCreateFunction; + if (client.mpSocketPending.load() != nullptr) + { + client.ContextInitialize(); + threadFunction = threadFunction == nullptr ? DefaultStartCommunicationThread : threadFunction; + threadFunction(Client::CommunicationsConnect, &client); + } + + return client.IsActive(); +} + +//================================================================================================= +bool ConnectFromApp(const char* clientName, uint32_t serverPort, ThreadFunctPtr threadFunction, FontCreateFuncPtr FontCreateFunction) +//================================================================================================= +{ + if (!gpClientInfo) return false; + + Client::ClientInfo& client = *gpClientInfo; + Disconnect(); + + while (client.IsActive()) + std::this_thread::yield(); + + client.ContextRestore(); // Restore context setting override, after a disconnect + client.ContextRemoveHooks(); // Remove hooks callback only when completly disconnected + + StringCopy(client.mName, (clientName == nullptr || clientName[0] == 0 ? "Unnamed" : clientName)); + client.mpSocketPending = Network::ListenStart(serverPort); + client.mFontCreationFunction = FontCreateFunction; + client.mThreadFunction = (threadFunction == nullptr) ? DefaultStartCommunicationThread : threadFunction; + if (client.mpSocketPending.load() != nullptr) + { + client.ContextInitialize(); + client.mSocketListenPort = serverPort; + client.mThreadFunction(Client::CommunicationsHost, &client); + } + + return client.IsActive(); +} + +//================================================================================================= +void Disconnect(void) +//================================================================================================= +{ + if (!gpClientInfo) return; + + // Attempt fake connection on local socket waiting for a Server connection, + // so the blocking operation can terminate and release the communication thread + Client::ClientInfo& client = *gpClientInfo; + client.mbDisconnectPending = true; + client.mbDisconnectListen = true; + if( client.mpSocketListen.load() != nullptr && client.mSocketListenPort != 0 ) + { + Network::SocketInfo* pFakeSocket = Network::Connect("127.0.0.1", client.mSocketListenPort); + client.mSocketListenPort = 0; + client.mbDisconnectPending = true; + + if(pFakeSocket){ + Network::Disconnect(pFakeSocket); + } + } + + // Wait for connection attempt to complete and fail + while( client.mbComInitActive || client.mbClientThreadActive ); + + // If fake connection to exit Listening failed, force disconnect socket directly + // even though it might potentially cause a race condition + Network::SocketInfo* pListenSocket = client.mpSocketListen.exchange(nullptr); + if( pListenSocket ){ + Network::Disconnect(pListenSocket); + } + + Network::SocketInfo* pPendingSocket = client.mpSocketPending.exchange(nullptr); + if( pPendingSocket ){ + Network::Disconnect(pPendingSocket); + } +} + +//================================================================================================= +bool IsConnected(void) +//================================================================================================= +{ + if (!gpClientInfo) return false; + + Client::ClientInfo& client = *gpClientInfo; + + // If disconnected in middle of a remote frame drawing, + // want to behave like it is still connected to finish frame properly + return client.IsConnected() || IsDrawingRemote(); +} + +//================================================================================================= +bool IsConnectionPending(void) +//================================================================================================= +{ + if (!gpClientInfo) return false; + + Client::ClientInfo& client = *gpClientInfo; + return client.IsConnectPending(); +} + +//================================================================================================= +bool IsDrawing(void) +//================================================================================================= +{ + if (!gpClientInfo) return false; + + Client::ClientInfo& client = *gpClientInfo; + return client.mbIsDrawing; +} + +//================================================================================================= +bool IsDrawingRemote(void) +//================================================================================================= +{ + if (!gpClientInfo) return false; + + Client::ClientInfo& client = *gpClientInfo; + return IsDrawing() && client.mbIsRemoteDrawing; +} + +//================================================================================================= +bool NewFrame(bool bSupportFrameSkip) +//================================================================================================= +{ + if (!gpClientInfo || gpClientInfo->mbIsDrawing) return false; + + Client::ClientInfo& client = *gpClientInfo; + ScopedBool scopedInside(client.mbInsideNewEnd, true); + + // ImGui Newframe handled by remote connection settings + if( NetImgui::IsConnected() ) + { + ImGui::SetCurrentContext(client.mpContext); + + // Save current context settings and override settings to fit our netImgui usage + if (!client.IsContextOverriden() ) + { + client.ContextOverride(); + } + + auto elapsedCheck = std::chrono::steady_clock::now() - client.mLastOutgoingDrawCheckTime; + auto elapsedDraw = std::chrono::steady_clock::now() - client.mLastOutgoingDrawTime; + auto elapsedCheckMs = static_cast(std::chrono::duration_cast(elapsedCheck).count()) / 1000.f; + auto elapsedDrawMs = static_cast(std::chrono::duration_cast(elapsedDraw).count()) / 1000.f; + client.mLastOutgoingDrawCheckTime = std::chrono::steady_clock::now(); + + // Update input and see if remote netImgui expect a new frame + client.mSavedDisplaySize = ImGui::GetIO().DisplaySize; + client.mbValidDrawFrame = false; + + // Take into account delay until next method call, for more precise fps + if( client.mDesiredFps > 0.f && (elapsedDrawMs + elapsedCheckMs/2.f) > (1000.f/client.mDesiredFps) ) + { + client.mLastOutgoingDrawTime = std::chrono::steady_clock::now(); + client.mbValidDrawFrame = true; + } + + ProcessInputData(client); + + // We are about to start drawing for remote context, check for font data update + const ImFontAtlas* pFonts = ImGui::GetIO().Fonts; + if( pFonts->TexPixelsAlpha8 && + (pFonts->TexPixelsAlpha8 != client.mpFontTextureData || client.mFontTextureID != pFonts->TexID )) + { + uint8_t* pPixelData(nullptr); int width(0), height(0); + ImGui::GetIO().Fonts->GetTexDataAsAlpha8(&pPixelData, &width, &height); + SendDataTexture(pFonts->TexID, pPixelData, static_cast(width), static_cast(height), eTexFormat::kTexFmtA8); + } + + // No font texture has been sent to the netImgui server, you can either + // 1. Leave font data available in ImGui (not call ImGui::ClearTexData) for netImgui to auto send it + // 2. Manually call 'NetImgui::SendDataTexture' with font texture data + assert(client.mbFontUploaded); + + // Update current active content with our time + ImGui::GetIO().DeltaTime = std::max(1.f / 1000.f, elapsedCheckMs/1000.f); + + // NetImgui isn't waiting for a new frame, try to skip drawing when caller supports it + if( !client.mbValidDrawFrame && bSupportFrameSkip ) + { + return false; + } + } + // Regular Imgui NewFrame + else + { + // Restore context setting override, after a disconnect + client.ContextRestore(); + + // Remove hooks callback only when completly disconnected + if (!client.IsConnectPending()) + { + client.ContextRemoveHooks(); + } + } + + // A new frame is expected, update the current time of the drawing context, and let Imgui know to prepare a new drawing frame + client.mbIsRemoteDrawing = NetImgui::IsConnected(); + client.mbIsDrawing = true; + + // This function can be called from a 'NewFrame' ImGui hook, we should not start a new frame again + if (!client.mbInsideHook) + { + ImGui::NewFrame(); + } + + return true; +} + +//================================================================================================= +void EndFrame(void) +//================================================================================================= +{ + if (!gpClientInfo) return; + + Client::ClientInfo& client = *gpClientInfo; + ScopedBool scopedInside(client.mbInsideNewEnd, true); + + if ( client.mbIsDrawing ) + { + // Must be fetched before 'Render' + ImGuiMouseCursor Cursor = ImGui::GetMouseCursor(); + + // This function can be called from a 'NewFrame' ImGui hook, in which case no need to call this again + if( !client.mbInsideHook ){ + ImGui::Render(); + } + + // Prepare the Dear Imgui DrawData for later tranmission to Server + client.ProcessDrawData(ImGui::GetDrawData(), Cursor); + + // Detect change to background settings by user, and forward them to server + if( client.mBGSetting != client.mBGSettingSent ) + { + CmdBackground* pCmdBackground = netImguiNew(); + *pCmdBackground = client.mBGSetting; + client.mBGSettingSent = client.mBGSetting; + client.mPendingBackgroundOut.Assign(pCmdBackground); + } + + // Restore display size, so we never lose original setting that may get updated after initial connection + if( client.mbIsRemoteDrawing ) { + ImGui::GetIO().DisplaySize = client.mSavedDisplaySize; + } + } + + client.mbIsRemoteDrawing = false; + client.mbIsDrawing = false; + client.mbValidDrawFrame = false; +} + +//================================================================================================= +ImGuiContext* GetContext() +//================================================================================================= +{ + if (!gpClientInfo) return nullptr; + + Client::ClientInfo& client = *gpClientInfo; + return client.mpContext; +} + +//================================================================================================= +void SendDataTexture(ImTextureID textureId, void* pData, uint16_t width, uint16_t height, eTexFormat format, uint32_t dataSize) +//================================================================================================= +{ + if (!gpClientInfo) return; + + Client::ClientInfo& client = *gpClientInfo; + CmdTexture* pCmdTexture = nullptr; + + // Makes sure even 32bits ImTextureID value are received properly as 64bits + uint64_t texId64(0); + static_assert(sizeof(uint64_t) >= sizeof(textureId), "ImTextureID is bigger than 64bits, CmdTexture::mTextureId needs to be updated to support it"); + reinterpret_cast(&texId64)[0] = textureId; + + // Add/Update a texture + if( pData != nullptr ) + { + if( format != eTexFormat::kTexFmtCustom ){ + dataSize = GetTexture_BytePerImage(format, width, height); + } + uint32_t SizeNeeded = dataSize + sizeof(CmdTexture); + pCmdTexture = netImguiSizedNew(SizeNeeded); + + pCmdTexture->mpTextureData.SetPtr(reinterpret_cast(&pCmdTexture[1])); + memcpy(pCmdTexture->mpTextureData.Get(), pData, dataSize); + + pCmdTexture->mSize = SizeNeeded; + pCmdTexture->mWidth = width; + pCmdTexture->mHeight = height; + pCmdTexture->mTextureId = texId64; + pCmdTexture->mFormat = static_cast(format); + pCmdTexture->mpTextureData.ToOffset(); + + // Detects when user is sending the font texture + ScopedImguiContext scopedCtx(client.mpContext ? client.mpContext : ImGui::GetCurrentContext()); + if( ImGui::GetIO().Fonts && ImGui::GetIO().Fonts->TexID == textureId ) + { + client.mbFontUploaded |= true; + client.mpFontTextureData = ImGui::GetIO().Fonts->TexPixelsAlpha8; + client.mFontTextureID = textureId; + } + } + // Texture to remove + else + { + pCmdTexture = netImguiNew(); + pCmdTexture->mTextureId = texId64; + pCmdTexture->mWidth = 0; + pCmdTexture->mHeight = 0; + pCmdTexture->mFormat = eTexFormat::kTexFmt_Invalid; + pCmdTexture->mpTextureData.SetOff(0); + } + + // In unlikely event of too many textures, wait for them to be processed + // (if connected) or Process them now (if not) + while( (client.mTexturesPendingCreated - client.mTexturesPendingSent) >= static_cast(ArrayCount(client.mTexturesPending)) ) + { + if( IsConnected() ) + std::this_thread::yield(); + else + client.ProcessTexturePending(); + } + uint32_t idx = client.mTexturesPendingCreated.fetch_add(1) % static_cast(ArrayCount(client.mTexturesPending)); + client.mTexturesPending[idx] = pCmdTexture; + + // If not connected to server yet, update all pending textures + if( !IsConnected() ) + client.ProcessTexturePending(); +} + +//================================================================================================= +void SetBackground(const ImVec4& bgColor) +//================================================================================================= +{ + if (!gpClientInfo) return; + + Client::ClientInfo& client = *gpClientInfo; + client.mBGSetting = NetImgui::Internal::CmdBackground(); + client.mBGSetting.mClearColor[0] = bgColor.x; + client.mBGSetting.mClearColor[1] = bgColor.y; + client.mBGSetting.mClearColor[2] = bgColor.z; + client.mBGSetting.mClearColor[3] = bgColor.w; +} + +//================================================================================================= +void SetBackground(const ImVec4& bgColor, const ImVec4& textureTint ) +//================================================================================================= +{ + if (!gpClientInfo) return; + + Client::ClientInfo& client = *gpClientInfo; + client.mBGSetting.mClearColor[0] = bgColor.x; + client.mBGSetting.mClearColor[1] = bgColor.y; + client.mBGSetting.mClearColor[2] = bgColor.z; + client.mBGSetting.mClearColor[3] = bgColor.w; + client.mBGSetting.mTextureTint[0] = textureTint.x; + client.mBGSetting.mTextureTint[1] = textureTint.y; + client.mBGSetting.mTextureTint[2] = textureTint.z; + client.mBGSetting.mTextureTint[3] = textureTint.w; + client.mBGSetting.mTextureId = NetImgui::Internal::CmdBackground::kDefaultTexture; +} + +//================================================================================================= +void SetBackground(const ImVec4& bgColor, const ImVec4& textureTint, ImTextureID bgTextureID) +//================================================================================================= +{ + if (!gpClientInfo) return; + + Client::ClientInfo& client = *gpClientInfo; + client.mBGSetting.mClearColor[0] = bgColor.x; + client.mBGSetting.mClearColor[1] = bgColor.y; + client.mBGSetting.mClearColor[2] = bgColor.z; + client.mBGSetting.mClearColor[3] = bgColor.w; + client.mBGSetting.mTextureTint[0] = textureTint.x; + client.mBGSetting.mTextureTint[1] = textureTint.y; + client.mBGSetting.mTextureTint[2] = textureTint.z; + client.mBGSetting.mTextureTint[3] = textureTint.w; + + uint64_t texId64(0); + reinterpret_cast(&texId64)[0] = bgTextureID; + client.mBGSetting.mTextureId = texId64; +} + +//================================================================================================= +void SetCompressionMode(eCompressionMode eMode) +//================================================================================================= +{ + if (!gpClientInfo) return; + + Client::ClientInfo& client = *gpClientInfo; + client.mClientCompressionMode = static_cast(eMode); +} +//================================================================================================= +eCompressionMode GetCompressionMode() +//================================================================================================= +{ + if (!gpClientInfo) return eCompressionMode::kUseServerSetting; + + Client::ClientInfo& client = *gpClientInfo; + return static_cast(client.mClientCompressionMode); +} + +//================================================================================================= +bool Startup(void) +//================================================================================================= +{ + if (!gpClientInfo) + { + gpClientInfo = netImguiNew(); + } + + return Network::Startup(); +} + +//================================================================================================= +void Shutdown() +//================================================================================================= +{ + if (!gpClientInfo) return; + + Disconnect(); + while( gpClientInfo->IsActive() ) + std::this_thread::yield(); + Network::Shutdown(); + + netImguiDeleteSafe(gpClientInfo); +} + + +//================================================================================================= +ImGuiContext* CloneContext(ImGuiContext* pSourceContext) +//================================================================================================= +{ + // Create a context duplicate + ScopedImguiContext scopedSourceCtx(pSourceContext); + ImGuiContext* pContextClone = ImGui::CreateContext(ImGui::GetIO().Fonts); + ImGuiIO& sourceIO = ImGui::GetIO(); + ImGuiStyle& sourceStyle = ImGui::GetStyle(); + { + ScopedImguiContext scopedCloneCtx(pContextClone); + ImGuiIO& newIO = ImGui::GetIO(); + ImGuiStyle& newStyle = ImGui::GetStyle(); + + // Import the style/options settings of current context, into this one + memcpy(&newStyle, &sourceStyle, sizeof(newStyle)); + memcpy(&newIO, &sourceIO, sizeof(newIO)); + //memcpy(newIO.KeyMap, sourceIO.KeyMap, sizeof(newIO.KeyMap)); + newIO.InputQueueCharacters.Data = nullptr; + newIO.InputQueueCharacters.Size = 0; + newIO.InputQueueCharacters.Capacity = 0; + } + return pContextClone; +} + +//================================================================================================= +uint8_t GetTexture_BitsPerPixel(eTexFormat eFormat) +//================================================================================================= +{ + switch(eFormat) + { + case eTexFormat::kTexFmtA8: return 8*1; + case eTexFormat::kTexFmtRGBA8: return 8*4; + case eTexFormat::kTexFmtCustom: return 0; + case eTexFormat::kTexFmt_Invalid: return 0; + } + return 0; +} + +//================================================================================================= +uint32_t GetTexture_BytePerLine(eTexFormat eFormat, uint32_t pixelWidth) +//================================================================================================= +{ + uint32_t bitsPerPixel = static_cast(GetTexture_BitsPerPixel(eFormat)); + return pixelWidth * bitsPerPixel / 8; + //Note: If adding support to BC compression format, have to take into account 4x4 size alignment +} + +//================================================================================================= +uint32_t GetTexture_BytePerImage(eTexFormat eFormat, uint32_t pixelWidth, uint32_t pixelHeight) +//================================================================================================= +{ + return GetTexture_BytePerLine(eFormat, pixelWidth) * pixelHeight; + //Note: If adding support to BC compression format, have to take into account 4x4 size alignement +} + +static inline void AddKeyEvent(const Client::ClientInfo& client, const CmdInput* pCmdInput, CmdInput::NetImguiKeys netimguiKey, ImGuiKey imguiKey) +{ + uint32_t valIndex = netimguiKey/64; + uint64_t valMask = 0x0000000000000001ull << (netimguiKey%64); +#if IMGUI_VERSION_NUM < 18700 + IM_UNUSED(client); + ImGui::GetIO().KeysDown[imguiKey] = (pCmdInput->mInputDownMask[valIndex] & valMask) != 0; +#else + bool bChanged = (pCmdInput->mInputDownMask[valIndex] ^ client.mPreviousInputState.mInputDownMask[valIndex]) & valMask; + if( bChanged ){ + ImGui::GetIO().AddKeyEvent(imguiKey, pCmdInput->mInputDownMask[valIndex] & valMask ); + } +#endif +} + +static inline void AddKeyAnalogEvent(const Client::ClientInfo& client, const CmdInput* pCmdInput, CmdInput::NetImguiKeys netimguiKey, ImGuiKey imguiKey) +{ + uint32_t valIndex = netimguiKey/64; + uint64_t valMask = 0x0000000000000001ull << (netimguiKey%64); + assert(CmdInput::kAnalog_First <= static_cast(netimguiKey) && static_cast(netimguiKey) <= CmdInput::kAnalog_Last); +#if IMGUI_VERSION_NUM < 18700 + IM_UNUSED(client); IM_UNUSED(pCmdInput); IM_UNUSED(netimguiKey); IM_UNUSED(imguiKey); +#else + int indexAnalog = netimguiKey - CmdInput::kAnalog_First; + indexAnalog = indexAnalog >= static_cast(CmdInput::kAnalog_Count) ? CmdInput::kAnalog_Count - 1 : indexAnalog; + float analogValue = pCmdInput->mInputAnalog[indexAnalog]; + bool bChanged = (pCmdInput->mInputDownMask[valIndex] ^ client.mPreviousInputState.mInputDownMask[valIndex]) & valMask; + bChanged |= abs(client.mPreviousInputState.mInputAnalog[indexAnalog] - analogValue) > 0.001f; + if(bChanged){ + ImGui::GetIO().AddKeyAnalogEvent(imguiKey, pCmdInput->mInputDownMask[valIndex] & valMask, analogValue); + } +#endif +} + +//================================================================================================= +bool ProcessInputData(Client::ClientInfo& client) +//================================================================================================= +{ + // Update the current clipboard data received from Server + CmdClipboard* pCmdClipboardNew = client.mPendingClipboardIn.Release(); + if( pCmdClipboardNew ){ + netImguiDeleteSafe(client.mpCmdClipboard); + client.mpCmdClipboard = pCmdClipboardNew; + } + + // Update the keyboard/mouse/gamepad inputs + CmdInput* pCmdInputNew = client.mPendingInputIn.Release(); + bool hasNewInput = pCmdInputNew != nullptr; + CmdInput* pCmdInput = hasNewInput ? pCmdInputNew : client.mpCmdInputPending; + ImGuiIO& io = ImGui::GetIO(); + + if (pCmdInput) + { + const float wheelY = pCmdInput->mMouseWheelVert - client.mPreviousInputState.mMouseWheelVertPrev; + const float wheelX = pCmdInput->mMouseWheelHoriz - client.mPreviousInputState.mMouseWheelHorizPrev; + io.DisplaySize = ImVec2(pCmdInput->mScreenSize[0], pCmdInput->mScreenSize[1]); + + // User assigned a function callback handling FontScaling, + // use it to request a Font update on DPI scaling change on the server + if (gpClientInfo->mFontCreationFunction != nullptr) + { + if(abs(gpClientInfo->mFontCreationScaling - pCmdInput->mFontDPIScaling) > 0.01f) + { + gpClientInfo->mFontCreationFunction(gpClientInfo->mFontCreationScaling, pCmdInput->mFontDPIScaling); + gpClientInfo->mFontCreationScaling = pCmdInput->mFontDPIScaling; + } + } + // Client doesn't support regenerating the font at new DPI + // Use FontGlobalScale to affect rendering size, resulting in blurrier result + else + { + io.FontGlobalScale = pCmdInput->mFontDPIScaling; + } + +#if IMGUI_VERSION_NUM < 18700 + io.MousePos = ImVec2(pCmdInput->mMousePos[0], pCmdInput->mMousePos[1]); + io.MouseWheel = wheelY; + io.MouseWheelH = wheelX; + for (uint32_t i(0); i < CmdInput::NetImguiMouseButton::ImGuiMouseButton_COUNT; ++i) { + io.MouseDown[i] = (pCmdInput->mMouseDownMask & (0x0000000000000001ull << i)) != 0; + } + + #define AddInputDown(KEYNAME) AddKeyEvent(client, pCmdInput, CmdInput::KEYNAME, ImGuiKey_::KEYNAME); + AddInputDown(ImGuiKey_Tab) + AddInputDown(ImGuiKey_LeftArrow) + AddInputDown(ImGuiKey_RightArrow) + AddInputDown(ImGuiKey_UpArrow) + AddInputDown(ImGuiKey_DownArrow) + AddInputDown(ImGuiKey_PageUp) + AddInputDown(ImGuiKey_PageDown) + AddInputDown(ImGuiKey_Home) + AddInputDown(ImGuiKey_End) + AddInputDown(ImGuiKey_Insert) + AddInputDown(ImGuiKey_Delete) + AddInputDown(ImGuiKey_Backspace) + AddInputDown(ImGuiKey_Space) + AddInputDown(ImGuiKey_Enter) + AddInputDown(ImGuiKey_Escape) + AddInputDown(ImGuiKey_A) // for text edit CTRL+A: select all + AddInputDown(ImGuiKey_C) // for text edit CTRL+C: copy + AddInputDown(ImGuiKey_V) // for text edit CTRL+V: paste + AddInputDown(ImGuiKey_X) // for text edit CTRL+X: cut + AddInputDown(ImGuiKey_Y) // for text edit CTRL+Y: redo + AddInputDown(ImGuiKey_Z) // for text edit CTRL+Z: undo + + io.KeyShift = pCmdInput->IsKeyDown(CmdInput::NetImguiKeys::ImGuiKey_ReservedForModShift); + io.KeyCtrl = pCmdInput->IsKeyDown(CmdInput::NetImguiKeys::ImGuiKey_ReservedForModCtrl); + io.KeyAlt = pCmdInput->IsKeyDown(CmdInput::NetImguiKeys::ImGuiKey_ReservedForModAlt); + io.KeySuper = pCmdInput->IsKeyDown(CmdInput::NetImguiKeys::ImGuiKey_ReservedForModSuper); +#else + #if IMGUI_VERSION_NUM < 18837 + #define ImGuiKey ImGuiKey_ + #endif + // At the moment All Dear Imgui version share the same ImGuiKey_ enum (with a 512 value offset), + // but could change in the future, so convert from our own enum version, to Dear ImGui. + #define AddInputDown(KEYNAME) AddKeyEvent(client, pCmdInput, CmdInput::KEYNAME, ImGuiKey::KEYNAME); + #define AddAnalogInputDown(KEYNAME) AddKeyAnalogEvent(client, pCmdInput, CmdInput::KEYNAME, ImGuiKey::KEYNAME); + AddInputDown(ImGuiKey_Tab) + AddInputDown(ImGuiKey_LeftArrow) + AddInputDown(ImGuiKey_RightArrow) + AddInputDown(ImGuiKey_UpArrow) + AddInputDown(ImGuiKey_DownArrow) + AddInputDown(ImGuiKey_PageUp) + AddInputDown(ImGuiKey_PageDown) + AddInputDown(ImGuiKey_Home) + AddInputDown(ImGuiKey_End) + AddInputDown(ImGuiKey_Insert) + AddInputDown(ImGuiKey_Delete) + AddInputDown(ImGuiKey_Backspace) + AddInputDown(ImGuiKey_Space) + AddInputDown(ImGuiKey_Enter) + AddInputDown(ImGuiKey_Escape) + + AddInputDown(ImGuiKey_LeftCtrl) AddInputDown(ImGuiKey_LeftShift) AddInputDown(ImGuiKey_LeftAlt) AddInputDown(ImGuiKey_LeftSuper) + AddInputDown(ImGuiKey_RightCtrl) AddInputDown(ImGuiKey_RightShift) AddInputDown(ImGuiKey_RightAlt) AddInputDown(ImGuiKey_RightSuper) + AddInputDown(ImGuiKey_Menu) + AddInputDown(ImGuiKey_0) AddInputDown(ImGuiKey_1) AddInputDown(ImGuiKey_2) AddInputDown(ImGuiKey_3) AddInputDown(ImGuiKey_4) AddInputDown(ImGuiKey_5) AddInputDown(ImGuiKey_6) AddInputDown(ImGuiKey_7) AddInputDown(ImGuiKey_8) AddInputDown(ImGuiKey_9) + AddInputDown(ImGuiKey_A) AddInputDown(ImGuiKey_B) AddInputDown(ImGuiKey_C) AddInputDown(ImGuiKey_D) AddInputDown(ImGuiKey_E) AddInputDown(ImGuiKey_F) AddInputDown(ImGuiKey_G) AddInputDown(ImGuiKey_H) AddInputDown(ImGuiKey_I) AddInputDown(ImGuiKey_J) + AddInputDown(ImGuiKey_K) AddInputDown(ImGuiKey_L) AddInputDown(ImGuiKey_M) AddInputDown(ImGuiKey_N) AddInputDown(ImGuiKey_O) AddInputDown(ImGuiKey_P) AddInputDown(ImGuiKey_Q) AddInputDown(ImGuiKey_R) AddInputDown(ImGuiKey_S) AddInputDown(ImGuiKey_T) + AddInputDown(ImGuiKey_U) AddInputDown(ImGuiKey_V) AddInputDown(ImGuiKey_W) AddInputDown(ImGuiKey_X) AddInputDown(ImGuiKey_Y) AddInputDown(ImGuiKey_Z) + AddInputDown(ImGuiKey_F1) AddInputDown(ImGuiKey_F2) AddInputDown(ImGuiKey_F3) AddInputDown(ImGuiKey_F4) AddInputDown(ImGuiKey_F5) AddInputDown(ImGuiKey_F6) + AddInputDown(ImGuiKey_F7) AddInputDown(ImGuiKey_F8) AddInputDown(ImGuiKey_F9) AddInputDown(ImGuiKey_F10) AddInputDown(ImGuiKey_F11) AddInputDown(ImGuiKey_F12) + + AddInputDown(ImGuiKey_Apostrophe) + AddInputDown(ImGuiKey_Comma) + AddInputDown(ImGuiKey_Minus) + AddInputDown(ImGuiKey_Period) + AddInputDown(ImGuiKey_Slash) + AddInputDown(ImGuiKey_Semicolon) + AddInputDown(ImGuiKey_Equal) + AddInputDown(ImGuiKey_LeftBracket) + AddInputDown(ImGuiKey_Backslash) + AddInputDown(ImGuiKey_RightBracket) + AddInputDown(ImGuiKey_GraveAccent) + AddInputDown(ImGuiKey_CapsLock) + AddInputDown(ImGuiKey_ScrollLock) + AddInputDown(ImGuiKey_NumLock) + AddInputDown(ImGuiKey_PrintScreen) + AddInputDown(ImGuiKey_Pause) + AddInputDown(ImGuiKey_Keypad0) AddInputDown(ImGuiKey_Keypad1) AddInputDown(ImGuiKey_Keypad2) AddInputDown(ImGuiKey_Keypad3) AddInputDown(ImGuiKey_Keypad4) + AddInputDown(ImGuiKey_Keypad5) AddInputDown(ImGuiKey_Keypad6) AddInputDown(ImGuiKey_Keypad7) AddInputDown(ImGuiKey_Keypad8) AddInputDown(ImGuiKey_Keypad9) + AddInputDown(ImGuiKey_KeypadDecimal) AddInputDown(ImGuiKey_KeypadDivide) AddInputDown(ImGuiKey_KeypadMultiply) + AddInputDown(ImGuiKey_KeypadSubtract) AddInputDown(ImGuiKey_KeypadAdd) AddInputDown(ImGuiKey_KeypadEnter) + AddInputDown(ImGuiKey_KeypadEqual) + +#if IMGUI_VERSION_NUM >= 19000 + AddInputDown(ImGuiKey_F13) AddInputDown(ImGuiKey_F14) AddInputDown(ImGuiKey_F15) AddInputDown(ImGuiKey_F16) AddInputDown(ImGuiKey_F17) AddInputDown(ImGuiKey_F18) + AddInputDown(ImGuiKey_F19) AddInputDown(ImGuiKey_F20) AddInputDown(ImGuiKey_F21) AddInputDown(ImGuiKey_F22) AddInputDown(ImGuiKey_F23) AddInputDown(ImGuiKey_F24) + AddInputDown(ImGuiKey_AppBack) + AddInputDown(ImGuiKey_AppForward) +#endif + // Gamepad + AddInputDown(ImGuiKey_GamepadStart) + AddInputDown(ImGuiKey_GamepadBack) + AddInputDown(ImGuiKey_GamepadFaceUp) + AddInputDown(ImGuiKey_GamepadFaceDown) + AddInputDown(ImGuiKey_GamepadFaceLeft) + AddInputDown(ImGuiKey_GamepadFaceRight) + AddInputDown(ImGuiKey_GamepadDpadUp) + AddInputDown(ImGuiKey_GamepadDpadDown) + AddInputDown(ImGuiKey_GamepadDpadLeft) + AddInputDown(ImGuiKey_GamepadDpadRight) + AddInputDown(ImGuiKey_GamepadL1) + AddInputDown(ImGuiKey_GamepadR1) + AddInputDown(ImGuiKey_GamepadL2) + AddInputDown(ImGuiKey_GamepadR2) + AddInputDown(ImGuiKey_GamepadL3) + AddInputDown(ImGuiKey_GamepadR3) + AddAnalogInputDown(ImGuiKey_GamepadLStickUp) + AddAnalogInputDown(ImGuiKey_GamepadLStickDown) + AddAnalogInputDown(ImGuiKey_GamepadLStickLeft) + AddAnalogInputDown(ImGuiKey_GamepadLStickRight) + AddAnalogInputDown(ImGuiKey_GamepadRStickUp) + AddAnalogInputDown(ImGuiKey_GamepadRStickDown) + AddAnalogInputDown(ImGuiKey_GamepadRStickLeft) + AddAnalogInputDown(ImGuiKey_GamepadRStickRight) + + #undef AddInputDown + #undef AddAnalogInputDown + #if IMGUI_VERSION_NUM < 18837 + #undef ImGuiKey + #endif + + #if IMGUI_VERSION_NUM < 18837 + #define ImGuiMod_Ctrl ImGuiKey_ModCtrl + #define ImGuiMod_Shift ImGuiKey_ModShift + #define ImGuiMod_Alt ImGuiKey_ModAlt + #define ImGuiMod_Super ImGuiKey_ModSuper + #endif + io.AddKeyEvent(ImGuiMod_Ctrl, pCmdInput->IsKeyDown(CmdInput::NetImguiKeys::ImGuiKey_ReservedForModCtrl)); + io.AddKeyEvent(ImGuiMod_Shift, pCmdInput->IsKeyDown(CmdInput::NetImguiKeys::ImGuiKey_ReservedForModShift)); + io.AddKeyEvent(ImGuiMod_Alt, pCmdInput->IsKeyDown(CmdInput::NetImguiKeys::ImGuiKey_ReservedForModAlt)); + io.AddKeyEvent(ImGuiMod_Super, pCmdInput->IsKeyDown(CmdInput::NetImguiKeys::ImGuiKey_ReservedForModSuper)); + + // Mouse + io.AddMouseWheelEvent(wheelX, wheelY); + io.AddMousePosEvent(pCmdInput->mMousePos[0], pCmdInput->mMousePos[1]); + for(int i(0); imMouseDownMask ^ client.mPreviousInputState.mMouseDownMask) & valMask){ + io.AddMouseButtonEvent(i, pCmdInput->mMouseDownMask & valMask); + } + } +#endif + uint16_t character; + io.InputQueueCharacters.resize(0); + while (client.mPendingKeyIn.ReadData(&character)){ + ImWchar ConvertedKey = static_cast(character); + io.AddInputCharacter(ConvertedKey); + } + + static_assert(sizeof(client.mPreviousInputState.mInputDownMask) == sizeof(pCmdInput->mInputDownMask), "Array size should match"); + static_assert(sizeof(client.mPreviousInputState.mInputAnalog) == sizeof(pCmdInput->mInputAnalog), "Array size should match"); + memcpy(client.mPreviousInputState.mInputDownMask, pCmdInput->mInputDownMask, sizeof(client.mPreviousInputState.mInputDownMask)); + memcpy(client.mPreviousInputState.mInputAnalog, pCmdInput->mInputAnalog, sizeof(client.mPreviousInputState.mInputAnalog)); + client.mPreviousInputState.mMouseDownMask = pCmdInput->mMouseDownMask; + client.mPreviousInputState.mMouseWheelVertPrev = pCmdInput->mMouseWheelVert; + client.mPreviousInputState.mMouseWheelHorizPrev = pCmdInput->mMouseWheelHoriz; + client.mServerCompressionEnabled = pCmdInput->mCompressionUse; + client.mServerCompressionSkip |= pCmdInput->mCompressionSkip; + } + + if( hasNewInput ){ + netImguiDeleteSafe(client.mpCmdInputPending); + client.mpCmdInputPending = pCmdInputNew; + } + return hasNewInput; +} + +} // namespace NetImgui + +#endif //NETIMGUI_ENABLED + +#include "NetImgui_WarningReenable.h" diff --git a/Plugins/Cog/Source/ThirdParty/NetImgui/Private/NetImgui_Client.cpp b/Plugins/Cog/Source/ThirdParty/NetImgui/Private/NetImgui_Client.cpp new file mode 100644 index 0000000..6cdde43 --- /dev/null +++ b/Plugins/Cog/Source/ThirdParty/NetImgui/Private/NetImgui_Client.cpp @@ -0,0 +1,725 @@ +#include "NetImgui_Shared.h" + +#if NETIMGUI_ENABLED +#include "NetImgui_WarningDisable.h" +#include "NetImgui_Client.h" +#include "NetImgui_Network.h" +#include "NetImgui_CmdPackets.h" + +namespace NetImgui { namespace Internal { namespace Client +{ + +//================================================================================================= +// SAVED IMGUI CONTEXT +// Because we overwrite some Imgui context IO values, we save them before makign any change +// and restore them after detecting a disconnection +//================================================================================================= +void SavedImguiContext::Save(ImGuiContext* copyFrom) +{ + ScopedImguiContext scopedContext(copyFrom); + ImGuiIO& sourceIO = ImGui::GetIO(); + mSavedContext = true; + mConfigFlags = sourceIO.ConfigFlags; + mBackendFlags = sourceIO.BackendFlags; + mBackendPlatformName = sourceIO.BackendPlatformName; + mBackendRendererName = sourceIO.BackendRendererName; + mDrawMouse = sourceIO.MouseDrawCursor; + mFontGlobalScale = sourceIO.FontGlobalScale; + mFontGeneratedSize = sourceIO.Fonts->Fonts.Size > 0 ? sourceIO.Fonts->Fonts[0]->FontSize : 13.f; // Save size to restore the font to original size +#if IMGUI_VERSION_NUM < 18700 + memcpy(mKeyMap, sourceIO.KeyMap, sizeof(mKeyMap)); +#endif +#if IMGUI_VERSION_NUM < 19110 + mGetClipboardTextFn = sourceIO.GetClipboardTextFn; + mSetClipboardTextFn = sourceIO.SetClipboardTextFn; + mClipboardUserData = sourceIO.ClipboardUserData; +#else + ImGuiPlatformIO& plaformIO = ImGui::GetPlatformIO(); + mGetClipboardTextFn = plaformIO.Platform_GetClipboardTextFn; + mSetClipboardTextFn = plaformIO.Platform_SetClipboardTextFn; + mClipboardUserData = plaformIO.Platform_ClipboardUserData; +#endif +} + +void SavedImguiContext::Restore(ImGuiContext* copyTo) +{ + ScopedImguiContext scopedContext(copyTo); + ImGuiIO& destIO = ImGui::GetIO(); + mSavedContext = false; + destIO.ConfigFlags = mConfigFlags; + destIO.BackendFlags = mBackendFlags; + destIO.BackendPlatformName = mBackendPlatformName; + destIO.BackendRendererName = mBackendRendererName; + destIO.MouseDrawCursor = mDrawMouse; + destIO.FontGlobalScale = mFontGlobalScale; +#if IMGUI_VERSION_NUM < 18700 + memcpy(destIO.KeyMap, mKeyMap, sizeof(destIO.KeyMap)); +#endif +#if IMGUI_VERSION_NUM < 19110 + destIO.GetClipboardTextFn = mGetClipboardTextFn; + destIO.SetClipboardTextFn = mSetClipboardTextFn; + destIO.ClipboardUserData = mClipboardUserData; +#else + ImGuiPlatformIO& plaformIO = ImGui::GetPlatformIO(); + plaformIO.Platform_GetClipboardTextFn = mGetClipboardTextFn; + plaformIO.Platform_SetClipboardTextFn = mSetClipboardTextFn; + plaformIO.Platform_ClipboardUserData = mClipboardUserData; +#endif +} + +//================================================================================================= +// GET CLIPBOARD +// Content received from the Server +//================================================================================================= +#if IMGUI_VERSION_NUM < 19110 +static const char* GetClipboardTextFn_NetImguiImpl(void* user_data_ctx) +{ + const ClientInfo* pClient = reinterpret_cast(user_data_ctx); + return pClient && pClient->mpCmdClipboard ? pClient->mpCmdClipboard->mContentUTF8.Get() : nullptr; +} +#else +static const char* GetClipboardTextFn_NetImguiImpl(ImGuiContext* ctx) +{ + ScopedImguiContext scopedContext(ctx); + const ClientInfo* pClient = reinterpret_cast(ImGui::GetPlatformIO().Platform_ClipboardUserData); + return pClient && pClient->mpCmdClipboard ? pClient->mpCmdClipboard->mContentUTF8.Get() : nullptr; +} +#endif + + +//================================================================================================= +// SET CLIPBOARD +//================================================================================================= +#if IMGUI_VERSION_NUM < 19110 +static void SetClipboardTextFn_NetImguiImpl(void* user_data_ctx, const char* text) +{ + if(user_data_ctx){ + ClientInfo* pClient = reinterpret_cast(user_data_ctx); + CmdClipboard* pClipboardOut = CmdClipboard::Create(text); + pClient->mPendingClipboardOut.Assign(pClipboardOut); + } +} +#else +static void SetClipboardTextFn_NetImguiImpl(ImGuiContext* ctx, const char* text) +{ + ScopedImguiContext scopedContext(ctx); + ClientInfo* pClient = reinterpret_cast(ImGui::GetPlatformIO().Platform_ClipboardUserData); + CmdClipboard* pClipboardOut = CmdClipboard::Create(text); + pClient->mPendingClipboardOut.Assign(pClipboardOut); +} +#endif + +//================================================================================================= +// INCOM: INPUT +// Receive new keyboard/mouse/screen resolution input to pass on to dearImgui +//================================================================================================= +void Communications_Incoming_Input(ClientInfo& client) +{ + auto pCmdInput = static_cast(client.mPendingRcv.pCommand); + client.mPendingRcv.bAutoFree = false; // Taking ownership of the data + client.mDesiredFps = pCmdInput->mDesiredFps > 0.f ? pCmdInput->mDesiredFps : 0.f; + size_t keyCount(pCmdInput->mKeyCharCount); + client.mPendingKeyIn.AddData(pCmdInput->mKeyChars, keyCount); + client.mPendingInputIn.Assign(pCmdInput); +} + +//================================================================================================= +// INCOM: CLIPBOARD +// Receive server new clipboard content, updating internal cache +//================================================================================================= +void Communications_Incoming_Clipboard(ClientInfo& client) +{ + auto pCmdClipboard = static_cast(client.mPendingRcv.pCommand); + client.mPendingRcv.bAutoFree = false; // Taking ownership of the data + pCmdClipboard->ToPointers(); + client.mPendingClipboardIn.Assign(pCmdClipboard); +} + +//================================================================================================= +// OUTCOM: TEXTURE +// Transmit all pending new/updated texture +//================================================================================================= +void Communications_Outgoing_Textures(ClientInfo& client) +{ + client.ProcessTexturePending(); + if( client.mbHasTextureUpdate ) + { + for(auto& cmdTexture : client.mTextures) + { + if( !cmdTexture.mbSent && cmdTexture.mpCmdTexture ) + { + client.mPendingSend.pCommand = cmdTexture.mpCmdTexture; + client.mPendingSend.bAutoFree = cmdTexture.mpCmdTexture->mFormat == eTexFormat::kTexFmt_Invalid; // Texture as been marked for deletion, can now free memory allocated for this + cmdTexture.mbSent = true; + return; // Exit as soon as we find a texture to send, so thread can proceed with transmitting it + } + } + client.mbHasTextureUpdate = false; // No pending texture detected, mark as 'all sent' + } +} + +//================================================================================================= +// OUTCOM: BACKGROUND +// Transmit the current client background settings +//================================================================================================= +void Communications_Outgoing_Background(ClientInfo& client) +{ + CmdBackground* pPendingBackground = client.mPendingBackgroundOut.Release(); + if( pPendingBackground ) + { + client.mPendingSend.pCommand = pPendingBackground; + client.mPendingSend.bAutoFree = false; + } +} + +//================================================================================================= +// OUTCOM: FRAME +// Transmit a new dearImgui frame to render +//================================================================================================= +void Communications_Outgoing_Frame(ClientInfo& client) +{ + CmdDrawFrame* pPendingDraw = client.mPendingFrameOut.Release(); + if( pPendingDraw ) + { + pPendingDraw->mFrameIndex = client.mFrameIndex++; + //--------------------------------------------------------------------- + // Apply delta compression to DrawCommand, when requested + if( pPendingDraw->mCompressed ) + { + // Create a new Compressed DrawFrame Command + if( client.mpCmdDrawLast && !client.mServerCompressionSkip ){ + client.mpCmdDrawLast->ToPointers(); + CmdDrawFrame* pDrawCompressed = CompressCmdDrawFrame(client.mpCmdDrawLast, pPendingDraw); + netImguiDeleteSafe(client.mpCmdDrawLast); + client.mpCmdDrawLast = pPendingDraw; // Keep original new command for next frame delta compression + pPendingDraw = pDrawCompressed; // Request compressed copy to be sent to server + } + // Save DrawCmd for next frame delta compression + else { + pPendingDraw->mCompressed = false; + client.mpCmdDrawLast = pPendingDraw; + } + } + client.mServerCompressionSkip = false; + + //--------------------------------------------------------------------- + // Ready to send command to server + pPendingDraw->ToOffsets(); + client.mPendingSend.pCommand = pPendingDraw; + client.mPendingSend.bAutoFree = client.mpCmdDrawLast != pPendingDraw; + } +} + +//================================================================================================= +// OUTCOM: Clipboard +// Send client 'Copy' clipboard content to Server +//================================================================================================= +void Communications_Outgoing_Clipboard(ClientInfo& client) +{ + CmdClipboard* pPendingClipboard = client.mPendingClipboardOut.Release(); + if( pPendingClipboard ){ + pPendingClipboard->ToOffsets(); + client.mPendingSend.pCommand = pPendingClipboard; + client.mPendingSend.bAutoFree = true; + } +} + +//================================================================================================= +// INCOMING COMMUNICATIONS +//================================================================================================= +void Communications_Incoming(ClientInfo& client) +{ + if( Network::DataReceivePending(client.mpSocketComs) ) + { + //----------------------------------------------------------------------------------------- + // 1. Ready to receive new command, starts the process by reading Header + //----------------------------------------------------------------------------------------- + if( client.mPendingRcv.IsReady() ) + { + client.mCmdPendingRead = CmdPendingRead(); + client.mPendingRcv.pCommand = &client.mCmdPendingRead; + client.mPendingRcv.bAutoFree= false; + } + + //----------------------------------------------------------------------------------------- + // 2. Read incoming command from server + //----------------------------------------------------------------------------------------- + if( client.mPendingRcv.IsPending() ) + { + Network::DataReceive(client.mpSocketComs, client.mPendingRcv); + + // Detected a new command bigger than header, allocate memory for it + if( client.mPendingRcv.pCommand->mSize > sizeof(CmdPendingRead) && + client.mPendingRcv.pCommand == &client.mCmdPendingRead ) + { + CmdPendingRead* pCmdHeader = reinterpret_cast(netImguiSizedNew(client.mPendingRcv.pCommand->mSize)); + *pCmdHeader = client.mCmdPendingRead; + client.mPendingRcv.pCommand = pCmdHeader; + client.mPendingRcv.bAutoFree= true; + } + } + + //----------------------------------------------------------------------------------------- + // 3. Command fully received from Server, process it + //----------------------------------------------------------------------------------------- + if( client.mPendingRcv.IsDone() ) + { + if( !client.mPendingRcv.IsError() ) + { + switch( client.mPendingRcv.pCommand->mType ) + { + case CmdHeader::eCommands::Input: Communications_Incoming_Input(client); break; + case CmdHeader::eCommands::Clipboard: Communications_Incoming_Clipboard(client); break; + // Commands not received in main loop, by Client + case CmdHeader::eCommands::Version: + case CmdHeader::eCommands::Texture: + case CmdHeader::eCommands::DrawFrame: + case CmdHeader::eCommands::Background: + case CmdHeader::eCommands::Count: break; + } + } + + // Cleanup after read completion + if( client.mPendingRcv.IsError() ){ + client.mbDisconnectPending = true; + } + if( client.mPendingRcv.bAutoFree ){ + netImguiDeleteSafe(client.mPendingRcv.pCommand); + } + client.mPendingRcv = PendingCom(); + } + } + // Prevent high CPU usage when waiting for new data + else + { + //std::this_thread::yield(); + std::this_thread::sleep_for(std::chrono::microseconds(250)); + } +} + +//================================================================================================= +// OUTGOING COMMUNICATIONS +//================================================================================================= +void Communications_Outgoing(ClientInfo& client) +{ + //--------------------------------------------------------------------------------------------- + // Try finishing sending a pending command to Server + //--------------------------------------------------------------------------------------------- + if( client.mPendingSend.IsPending() ) + { + Network::DataSend(client.mpSocketComs, client.mPendingSend); + + // Free allocated memory for command + if( client.mPendingSend.IsDone() ) + { + if( client.mPendingSend.IsError() ){ + client.mbDisconnectPending = true; + } + if( client.mPendingSend.bAutoFree ){ + netImguiDeleteSafe(client.mPendingSend.pCommand); + } + client.mPendingSend = PendingCom(); + } + } + //--------------------------------------------------------------------------------------------- + // Initiate sending next command to Server, when none are in flight + // Keep track of what command was last send to prevent 1 type to monopolize coms + //--------------------------------------------------------------------------------------------- + constexpr CmdHeader::eCommands kCommandsOrder[] = { + CmdHeader::eCommands::Texture, CmdHeader::eCommands::Background, + CmdHeader::eCommands::Clipboard, CmdHeader::eCommands::DrawFrame}; + constexpr uint32_t kCommandCounts = static_cast(sizeof(kCommandsOrder)/sizeof(CmdHeader::eCommands)); + + uint32_t Index(client.mPendingSendNext); + while( client.mPendingSend.IsReady() && (Index-client.mPendingSendNext)(&cmdVersionRcv); + while( !PendingRcv.IsDone() && cmdVersionRcv.mType == CmdHeader::eCommands::Version ) + { + while( !client.mbDisconnectPending && !Network::DataReceivePending(client.mpSocketPending) ){ + std::this_thread::yield(); // Idle until we receive the remote data + } + Network::DataReceive(client.mpSocketPending, PendingRcv); + } + + bool bForceConnect = client.mServerForceConnectEnabled && (cmdVersionRcv.mFlags & static_cast(CmdVersion::eFlags::ConnectForce)) != 0; + bool bCanConnect = !PendingRcv.IsError() && + cmdVersionRcv.mType == cmdVersionSend.mType && + cmdVersionRcv.mVersion == cmdVersionSend.mVersion && + cmdVersionRcv.mWCharSize == cmdVersionSend.mWCharSize && + (!client.IsConnected() || bForceConnect); + + StringCopy(cmdVersionSend.mClientName, client.mName); + cmdVersionSend.mFlags = client.IsConnected() && !bCanConnect ? static_cast(CmdVersion::eFlags::IsConnected): 0; + cmdVersionSend.mFlags |= client.IsConnected() && !client.mServerForceConnectEnabled ? static_cast(CmdVersion::eFlags::IsUnavailable) : 0; + + PendingSend.pCommand = reinterpret_cast(&cmdVersionSend); + while( !PendingSend.IsDone() ){ + Network::DataSend(client.mpSocketPending, PendingSend); + } + + //--------------------------------------------------------------------- + // Connection established, init client + //--------------------------------------------------------------------- + if( bCanConnect && !PendingSend.IsError() && (!client.IsConnected() || bForceConnect) ) + { + Network::SocketInfo* pNewComSocket = client.mpSocketPending.exchange(nullptr); + + // If we detect an active connection with Server and 'ForceConnect was requested, close it first + if( client.IsConnected() ) + { + client.mbDisconnectPending = true; + while( client.IsConnected() ); + } + + for(auto& texture : client.mTextures) + { + texture.mbSent = false; + } + + client.mpSocketComs = pNewComSocket; // Take ownerhip of socket + client.mbHasTextureUpdate = true; // Force sending the client textures + client.mBGSettingSent.mTextureId = client.mBGSetting.mTextureId-1u; // Force sending the Background settings (by making different than current settings) + client.mFrameIndex = 0; + client.mPendingSendNext = 0; + client.mServerForceConnectEnabled = (cmdVersionRcv.mFlags & static_cast(CmdVersion::eFlags::ConnectExclusive)) == 0; + client.mPendingRcv = PendingCom(); + client.mPendingSend = PendingCom(); + } + + // Disconnect pending socket if init failed + Network::SocketInfo* SocketPending = client.mpSocketPending.exchange(nullptr); + bool bValidConnection = SocketPending == nullptr; + if( SocketPending ){ + NetImgui::Internal::Network::Disconnect(SocketPending); + } + + client.mbComInitActive = false; + return bValidConnection; +} + +//================================================================================================= +// COMMUNICATIONS MAIN LOOP +//================================================================================================= +void Communications_Loop(void* pClientVoid) +{ + IM_ASSERT(pClientVoid != nullptr); + ClientInfo* pClient = reinterpret_cast(pClientVoid); + pClient->mbDisconnectPending = false; + pClient->mbClientThreadActive = true; + + while( !pClient->mbDisconnectPending ) + { + Communications_Outgoing(*pClient); + Communications_Incoming(*pClient); + } + + Network::SocketInfo* pSocket = pClient->mpSocketComs.exchange(nullptr); + if (pSocket){ + NetImgui::Internal::Network::Disconnect(pSocket); + } + pClient->mbClientThreadActive = false; +} + +//================================================================================================= +// COMMUNICATIONS CONNECT THREAD : Reach out and connect to a NetImGuiServer +//================================================================================================= +void CommunicationsConnect(void* pClientVoid) +{ + IM_ASSERT(pClientVoid != nullptr); + ClientInfo* pClient = reinterpret_cast(pClientVoid); + if( Communications_Initialize(*pClient) ) + { + Communications_Loop(pClientVoid); + } +} + +//================================================================================================= +// COMMUNICATIONS HOST THREAD : Waiting NetImGuiServer reaching out to us. +// Launch a new com loop when connection is established +//================================================================================================= +void CommunicationsHost(void* pClientVoid) +{ + ClientInfo* pClient = reinterpret_cast(pClientVoid); + pClient->mbListenThreadActive = true; + pClient->mbDisconnectListen = false; + pClient->mpSocketListen = pClient->mpSocketPending.exchange(nullptr); + + while( pClient->mpSocketListen.load() != nullptr && !pClient->mbDisconnectListen ) + { + pClient->mpSocketPending = Network::ListenConnect(pClient->mpSocketListen); + if( pClient->mpSocketPending.load() != nullptr && Communications_Initialize(*pClient) ) + { + pClient->mThreadFunction(Client::Communications_Loop, pClient); + } + std::this_thread::sleep_for(std::chrono::milliseconds(16)); // Prevents this thread from taking entire core, waiting on server connection requests + } + + Network::SocketInfo* pSocket = pClient->mpSocketListen.exchange(nullptr); + NetImgui::Internal::Network::Disconnect(pSocket); + pClient->mbListenThreadActive = false; +} + +//================================================================================================= +// Support of the Dear ImGui hooks +// (automatic call to NetImgui::BeginFrame()/EndFrame() on ImGui::BeginFrame()/Imgui::Render() +//================================================================================================= +#if NETIMGUI_IMGUI_CALLBACK_ENABLED +void HookBeginFrame(ImGuiContext*, ImGuiContextHook* hook) +{ + Client::ClientInfo& client = *reinterpret_cast(hook->UserData); + if (!client.mbInsideNewEnd) + { + ScopedBool scopedInside(client.mbInsideHook, true); + NetImgui::NewFrame(false); + } +} + +void HookEndFrame(ImGuiContext*, ImGuiContextHook* hook) +{ + Client::ClientInfo& client = *reinterpret_cast(hook->UserData); + if (!client.mbInsideNewEnd) + { + ScopedBool scopedInside(client.mbInsideHook, true); + NetImgui::EndFrame(); + } +} + +#endif // NETIMGUI_IMGUI_CALLBACK_ENABLED + +//================================================================================================= +// CLIENT INFO Constructor +//================================================================================================= +ClientInfo::ClientInfo() +: mpSocketPending(nullptr) +, mpSocketComs(nullptr) +, mpSocketListen(nullptr) +, mFontTextureID(TextureCastFromUInt(uint64_t(0u))) +, mTexturesPendingSent(0) +, mTexturesPendingCreated(0) +, mbClientThreadActive(false) +, mbListenThreadActive(false) +, mbComInitActive(false) +{ + memset(mTexturesPending, 0, sizeof(mTexturesPending)); +} + +//================================================================================================= +// CLIENT INFO Constructor +//================================================================================================= +ClientInfo::~ClientInfo() +{ + ContextRemoveHooks(); + + for( auto& texture : mTextures ){ + texture.Set(nullptr); + } + + for(size_t i(0); iFonts.size() > 0) + { + float noScaleSize = ImGui::GetIO().Fonts->Fonts[0]->FontSize / mFontCreationScaling; + float originalScale = mSavedContextValues.mFontGeneratedSize / noScaleSize; + mFontCreationFunction(mFontCreationScaling, originalScale); + } + mSavedContextValues.Restore(mpContext); + } +} + +//================================================================================================= +// Remove callback hooks, once we detect a disconnection +//================================================================================================= +void ClientInfo::ContextRemoveHooks() +{ +#if NETIMGUI_IMGUI_CALLBACK_ENABLED + if (mpContext && mhImguiHookNewframe != 0) + { + ImGui::RemoveContextHook(mpContext, mhImguiHookNewframe); + ImGui::RemoveContextHook(mpContext, mhImguiHookEndframe); + mhImguiHookNewframe = mhImguiHookNewframe = 0; + } +#endif +} + +//================================================================================================= +// Process textures waiting to be sent to server +// 1. New textures are added tp pending queue (Main Thread) +// 2. Pending textures are sent to Server and added to our active texture list (Com Thread) +//================================================================================================= +void ClientInfo::ProcessTexturePending() +{ + while( mTexturesPendingCreated != mTexturesPendingSent ) + { + mbHasTextureUpdate |= true; + uint32_t idx = mTexturesPendingSent.fetch_add(1) % static_cast(ArrayCount(mTexturesPending)); + CmdTexture* pCmdTexture = mTexturesPending[idx]; + mTexturesPending[idx] = nullptr; + if( pCmdTexture ) + { + // Find the TextureId from our list (or free slot) + int texIdx = 0; + int texFreeSlot = static_cast(mTextures.size()); + while( texIdx < mTextures.size() && ( !mTextures[texIdx].IsValid() || mTextures[texIdx].mpCmdTexture->mTextureId != pCmdTexture->mTextureId) ) + { + texFreeSlot = !mTextures[texIdx].IsValid() ? texIdx : texFreeSlot; + ++texIdx; + } + + if( texIdx == mTextures.size() ) + texIdx = texFreeSlot; + if( texIdx == mTextures.size() ) + mTextures.push_back(ClientTexture()); + + mTextures[texIdx].Set( pCmdTexture ); + mTextures[texIdx].mbSent = false; + } + } +} + +//================================================================================================= +// Create a new Draw Command from Dear Imgui draw data. +// 1. New ImGui frame has been completed, create a new draw command from draw data (Main Thread) +// 2. We see a pending Draw Command, take ownership of it and send it to Server (Com thread) +//================================================================================================= +void ClientInfo::ProcessDrawData(const ImDrawData* pDearImguiData, ImGuiMouseCursor mouseCursor) +{ + if( !mbValidDrawFrame ) + return; + + CmdDrawFrame* pDrawFrameNew = ConvertToCmdDrawFrame(pDearImguiData, mouseCursor); + pDrawFrameNew->mCompressed = mClientCompressionMode == eCompressionMode::kForceEnable || (mClientCompressionMode == eCompressionMode::kUseServerSetting && mServerCompressionEnabled); + mPendingFrameOut.Assign(pDrawFrameNew); +} + +}}} // namespace NetImgui::Internal::Client + +#include "NetImgui_WarningReenable.h" +#endif //#if NETIMGUI_ENABLED diff --git a/Plugins/Cog/Source/ThirdParty/NetImgui/Private/NetImgui_Client.h b/Plugins/Cog/Source/ThirdParty/NetImgui/Private/NetImgui_Client.h new file mode 100644 index 0000000..a5414e7 --- /dev/null +++ b/Plugins/Cog/Source/ThirdParty/NetImgui/Private/NetImgui_Client.h @@ -0,0 +1,161 @@ +#pragma once + +#include "NetImgui_Shared.h" +#include "NetImgui_CmdPackets.h" + +//============================================================================= +// Forward Declares +//============================================================================= +namespace NetImgui { namespace Internal { namespace Network { struct SocketInfo; } } } + +namespace NetImgui { namespace Internal { namespace Client +{ + +//============================================================================= +// Keep a list of textures used by Imgui, needed by server +//============================================================================= +struct ClientTexture +{ + inline void Set( CmdTexture* pCmdTexture ); + inline bool IsValid()const; + CmdTexture* mpCmdTexture= nullptr; + bool mbSent = false; + uint8_t mPadding[7] = {}; +}; + +//============================================================================= +// Keeps a list of ImGui context values NetImgui overrides (to restore) +//============================================================================= +struct SavedImguiContext +{ + void Save(ImGuiContext* copyFrom); + void Restore(ImGuiContext* copyTo); + const char* mBackendPlatformName = nullptr; + const char* mBackendRendererName = nullptr; + void* mImeWindowHandle = nullptr; + float mFontGlobalScale = 1.f; + float mFontGeneratedSize = 0.f; + ImGuiBackendFlags mBackendFlags = 0; + ImGuiConfigFlags mConfigFlags = 0; + bool mDrawMouse = false; + bool mSavedContext = false; + char mPadding1[2] = {}; + void* mClipboardUserData = nullptr; +#if IMGUI_VERSION_NUM < 19110 + const char* (*mGetClipboardTextFn)(void*) = nullptr; + void (*mSetClipboardTextFn)(void*, const char*) = nullptr; +#else + const char* (*mGetClipboardTextFn)(ImGuiContext*) = nullptr; + void (*mSetClipboardTextFn)(ImGuiContext*, const char*) = nullptr; +#endif +#if IMGUI_VERSION_NUM < 18700 + int mKeyMap[ImGuiKey_COUNT] = {}; + char mPadding2[8 - (sizeof(mKeyMap) % 8)] = {}; +#endif +}; + +//============================================================================= +// Keep all Client infos needed for communication with server +//============================================================================= +struct ClientInfo +{ + using VecTexture = ImVector; + using BufferKeys = Ringbuffer; + using TimePoint = std::chrono::time_point; + + struct InputState + { + uint64_t mInputDownMask[(CmdInput::ImGuiKey_COUNT+63)/64] = {}; + float mInputAnalog[CmdInput::kAnalog_Count] = {}; + uint64_t mMouseDownMask = 0; + float mMouseWheelVertPrev = 0.f; + float mMouseWheelHorizPrev = 0.f; + }; + ClientInfo(); + ~ClientInfo(); + void ContextInitialize(); + void ContextOverride(); + void ContextRestore(); + void ContextRemoveHooks(); + inline bool IsContextOverriden()const; + + std::atomic mpSocketPending; // Hold socket info until communication is established + std::atomic mpSocketComs; // Socket used for communications with server + std::atomic mpSocketListen; // Socket used to wait for communication request from server + std::atomic_bool mbDisconnectPending; // Terminate Client/Server coms + std::atomic_bool mbDisconnectListen; // Terminate waiting connection from Server + uint32_t mSocketListenPort = 0; // Socket Port number used to wait for communication request from server + VecTexture mTextures; // List if textures created by this client (used un main thread) + char mName[64] = {}; + uint64_t mFrameIndex = 0; // Incremented everytime we send a DrawFrame Command + CmdTexture* mTexturesPending[16] = {}; + ExchangePtr mPendingFrameOut; + ExchangePtr mPendingBackgroundOut; + ExchangePtr mPendingInputIn; + ExchangePtr mPendingClipboardIn; // Clipboard content received from Server and waiting to be taken by client + ExchangePtr mPendingClipboardOut; // Clipboard content copied on Client and waiting to be sent to Server + ImGuiContext* mpContext = nullptr; // Context that the remote drawing should use (either the one active when connection request happened, or a clone) + PendingCom mPendingRcv; // Data being currently received from Server + PendingCom mPendingSend; // Data being currently sent to Server + uint32_t mPendingSendNext = 0; // Type of Cmd to next attempt sending, when channel is available + CmdPendingRead mCmdPendingRead; // Used to get info on the next incoming command from Server + CmdInput* mpCmdInputPending = nullptr; // Last Input Command from server, waiting to be processed by client + CmdClipboard* mpCmdClipboard = nullptr; // Last received clipboad command + CmdDrawFrame* mpCmdDrawLast = nullptr; // Last sent Draw Command. Used by data compression, to generate delta between previous and current frame + CmdBackground mBGSetting; // Current value assigned to background appearance by user + CmdBackground mBGSettingSent; // Last sent value to remote server + BufferKeys mPendingKeyIn; // Keys pressed received. Results of 2 CmdInputs are concatenated if received before being processed + TimePoint mLastOutgoingDrawCheckTime; // When we last checked if we have a pending draw command to send + TimePoint mLastOutgoingDrawTime; // When we last sent an updated draw command to the server + ImVec2 mSavedDisplaySize = {0, 0}; // Save original display size on 'NewFrame' and restore it on 'EndFrame' (making sure size is still valid after a disconnect) + const void* mpFontTextureData = nullptr; // Last font texture data send to server (used to detect if font was changed) + ImTextureID mFontTextureID; + SavedImguiContext mSavedContextValues; + std::atomic_uint32_t mTexturesPendingSent; + std::atomic_uint32_t mTexturesPendingCreated; + + std::atomic_bool mbClientThreadActive; // True when connected and communicating with Server + std::atomic_bool mbListenThreadActive; // True when listening from connection request from Server + std::atomic_bool mbComInitActive; // True when attempting to initialize a new connection + bool mbHasTextureUpdate = false; + bool mbIsDrawing = false; // We are inside a 'NetImgui::NewFrame' / 'NetImgui::EndFrame' (even if not for a remote draw) + bool mbIsRemoteDrawing = false; // True if the rendering it meant for the remote netImgui server + bool mbRestorePending = false; // Original context has had some settings overridden, original values stored in mRestoreXXX + bool mbFontUploaded = false; // Auto detect if font was sent to server + bool mbInsideHook = false; // Currently inside ImGui hook callback + bool mbInsideNewEnd = false; // Currently inside NetImgui::NewFrame() or NetImgui::EndFrame() (prevents recusrive hook call) + bool mbValidDrawFrame = false; // If we should forward the drawdata to the server at the end of ImGui::Render() + uint8_t mClientCompressionMode = eCompressionMode::kUseServerSetting; + bool mServerCompressionEnabled = false; // If Server would like compression to be enabled (mClientCompressionMode value can override this value) + bool mServerCompressionSkip = false; // Force ignore compression setting for 1 frame + bool mServerForceConnectEnabled = true; // If another NetImguiServer can take connection away from the one currently active + ThreadFunctPtr mThreadFunction = nullptr; // Function to use when laucnhing new threads + FontCreateFuncPtr mFontCreationFunction = nullptr; // Method to call to generate the remote ImGui font. By default, re-use the local font, but this doesn't handle native DPI scaling on remote server + float mFontCreationScaling = 1.f; // Last font scaling used when generating the NetImgui font + float mDesiredFps = 30.f; // How often we should update the remote drawing. Received from server + InputState mPreviousInputState; // Keeping track of last keyboard/mouse state + ImGuiID mhImguiHookNewframe = 0; + ImGuiID mhImguiHookEndframe = 0; + + void ProcessDrawData(const ImDrawData* pDearImguiData, ImGuiMouseCursor mouseCursor); + void ProcessTexturePending(); + inline bool IsConnected()const; + inline bool IsConnectPending()const; + inline bool IsActive()const; + +// Prevent warnings about implicitly created copy +protected: + ClientInfo(const ClientInfo&)=delete; + ClientInfo(const ClientInfo&&)=delete; + void operator=(const ClientInfo&)=delete; +}; + +//============================================================================= +// Main communication loop threads that are run in separate threads +//============================================================================= +void CommunicationsConnect(void* pClientVoid); +void CommunicationsHost(void* pClientVoid); + +}}} //namespace NetImgui::Internal::Client + +#include "NetImgui_Client.inl" diff --git a/Plugins/Cog/Source/ThirdParty/NetImgui/Private/NetImgui_Client.inl b/Plugins/Cog/Source/ThirdParty/NetImgui/Private/NetImgui_Client.inl new file mode 100644 index 0000000..c8daecb --- /dev/null +++ b/Plugins/Cog/Source/ThirdParty/NetImgui/Private/NetImgui_Client.inl @@ -0,0 +1,38 @@ + +#include "NetImgui_Network.h" + +namespace NetImgui { namespace Internal { namespace Client { + +void ClientTexture::Set( CmdTexture* pCmdTexture ) +{ + netImguiDeleteSafe(mpCmdTexture); + mpCmdTexture = pCmdTexture; + mbSent = pCmdTexture == nullptr; +} + +bool ClientTexture::IsValid()const +{ + return mpCmdTexture != nullptr; +} + +bool ClientInfo::IsConnected()const +{ + return mpSocketComs.load() != nullptr; +} + +bool ClientInfo::IsConnectPending()const +{ + return mbComInitActive || mpSocketPending.load() != nullptr || mpSocketListen.load() != nullptr; +} + +bool ClientInfo::IsActive()const +{ + return mbClientThreadActive || mbListenThreadActive; +} + +bool ClientInfo::IsContextOverriden()const +{ + return mSavedContextValues.mSavedContext; +} + +}}} // namespace NetImgui::Internal::Client diff --git a/Plugins/Cog/Source/ThirdParty/NetImgui/Private/NetImgui_CmdPackets.h b/Plugins/Cog/Source/ThirdParty/NetImgui/Private/NetImgui_CmdPackets.h new file mode 100644 index 0000000..1c8d5c1 --- /dev/null +++ b/Plugins/Cog/Source/ThirdParty/NetImgui/Private/NetImgui_CmdPackets.h @@ -0,0 +1,276 @@ +#pragma once + +#include "NetImgui_Shared.h" +#include "NetImgui_CmdPackets_DrawFrame.h" + +namespace NetImgui { namespace Internal +{ + +//Note: If updating any of these commands data structure, increase 'CmdVersion::eVersion' +struct alignas(8) CmdHeader +{ + enum class eCommands : uint8_t { Version, Texture, Input, DrawFrame, Background, Clipboard, Count }; + CmdHeader(eCommands CmdType, uint16_t Size) : mSize(Size), mType(CmdType){} + uint32_t mSize = 0; + eCommands mType = eCommands::Count; + uint8_t mPadding[3] = {}; +}; + +// Used as step 1 of 2 of reading incoming transmission between Client/Server, to get header whose size we know +struct alignas(8) CmdPendingRead : public CmdHeader +{ + CmdPendingRead() : CmdHeader(eCommands::Count, sizeof(CmdPendingRead) ){} +}; + +struct alignas(8) CmdVersion : public CmdHeader +{ + enum class eVersion : uint32_t + { + Initial = 1, + NewTextureFormat = 2, + ImguiVersionInfo = 3, // Added Dear Imgui/ NetImgui version info to 'CmdVersion' + ServerRefactor = 4, // Change to 'CmdInput' and 'CmdVersion' store size of 'ImWchar' to make sure they are compatible + BackgroundCmd = 5, // Added new command to control background appearance + ClientName = 6, // Increase maximum allowed client name that a program can set + DataCompression = 7, // Adding support for data compression between client/server. Simple low cost delta compressor (only send difference from previous frame) + DataCompression2 = 8, // Improvement to data compression (save corner position and use SoA for vertices data) + VertexUVRange = 9, // Changed vertices UV value range to [0,1] for increased precision on large font texture + Imgui_1_87 = 10, // Added Dear ImGui Input refactor + OffetPointer = 11, // Updated the handling of OffsetPoint. Moved flag bit from last bit to first bit. Addresses and data are always at least 4 bytes aligned, so should never conflict with potential address space + CustomTexture = 12, // Added a 'custom' texture format to let user potentially handle their how format + DPIScale = 13, // Server now handle monitor DPI + Clipboard = 14, // Added clipboard support between server/client + ForceReconnect = 15, // Server can now take over the connection from another server + UpdatedComs = 16, // Faster protocol by removing blocking coms + RemDisconnect = 17, // Removed Disconnect command + // Insert new version here + + //-------------------------------- + _count, + _current = _count -1 + }; + enum class eFlags : uint8_t + { + IsUnavailable = 0x01, // Client telling Server it cannot be used + IsConnected = 0x02, // Client telling Server there's already a valid connection (can potentially be taken over if !IsUnavailable) + ConnectForce = 0x04, // Server telling Client it want to take over connection if there's already one + ConnectExclusive = 0x08, // Server telling Client that once connected, others servers should be denied access + }; + CmdVersion() : CmdHeader(CmdHeader::eCommands::Version, sizeof(CmdVersion)){} + char mClientName[64] = {}; + char mImguiVerName[16] = {IMGUI_VERSION}; + char mNetImguiVerName[16] = {NETIMGUI_VERSION}; + eVersion mVersion = eVersion::_current; + uint32_t mImguiVerID = IMGUI_VERSION_NUM; + uint32_t mNetImguiVerID = NETIMGUI_VERSION_NUM; + uint8_t mWCharSize = static_cast(sizeof(ImWchar)); + uint8_t mFlags = 0; + char PADDING[2]; +}; + +struct alignas(8) CmdInput : public CmdHeader +{ + // Identify a mouse button. + // Those values are guaranteed to be stable and we frequently use 0/1 directly. Named enums provided for convenience. + enum NetImguiMouseButton + { + ImGuiMouseButton_Left = 0, + ImGuiMouseButton_Right = 1, + ImGuiMouseButton_Middle = 2, + ImGuiMouseButton_Extra1 = 3, // Additional entry + ImGuiMouseButton_Extra2 = 4, // Additional entry + ImGuiMouseButton_COUNT = 5 + }; + + // Copy of Dear ImGui key enum + // We keep our own internal version, to make sure Client key is the same as Server Key (since they can have different Imgui version) + enum NetImguiKeys + { + // Keyboard + ImGuiKey_Tab, + ImGuiKey_LeftArrow, + ImGuiKey_RightArrow, + ImGuiKey_UpArrow, + ImGuiKey_DownArrow, + ImGuiKey_PageUp, + ImGuiKey_PageDown, + ImGuiKey_Home, + ImGuiKey_End, + ImGuiKey_Insert, + ImGuiKey_Delete, + ImGuiKey_Backspace, + ImGuiKey_Space, + ImGuiKey_Enter, + ImGuiKey_Escape, + ImGuiKey_LeftCtrl, ImGuiKey_LeftShift, ImGuiKey_LeftAlt, ImGuiKey_LeftSuper, + ImGuiKey_RightCtrl, ImGuiKey_RightShift, ImGuiKey_RightAlt, ImGuiKey_RightSuper, + ImGuiKey_Menu, + ImGuiKey_0, ImGuiKey_1, ImGuiKey_2, ImGuiKey_3, ImGuiKey_4, ImGuiKey_5, ImGuiKey_6, ImGuiKey_7, ImGuiKey_8, ImGuiKey_9, + ImGuiKey_A, ImGuiKey_B, ImGuiKey_C, ImGuiKey_D, ImGuiKey_E, ImGuiKey_F, ImGuiKey_G, ImGuiKey_H, ImGuiKey_I, ImGuiKey_J, + ImGuiKey_K, ImGuiKey_L, ImGuiKey_M, ImGuiKey_N, ImGuiKey_O, ImGuiKey_P, ImGuiKey_Q, ImGuiKey_R, ImGuiKey_S, ImGuiKey_T, + ImGuiKey_U, ImGuiKey_V, ImGuiKey_W, ImGuiKey_X, ImGuiKey_Y, ImGuiKey_Z, + ImGuiKey_F1, ImGuiKey_F2, ImGuiKey_F3, ImGuiKey_F4, ImGuiKey_F5, ImGuiKey_F6, + ImGuiKey_F7, ImGuiKey_F8, ImGuiKey_F9, ImGuiKey_F10, ImGuiKey_F11, ImGuiKey_F12, + ImGuiKey_F13, ImGuiKey_F14, ImGuiKey_F15, ImGuiKey_F16, ImGuiKey_F17, ImGuiKey_F18, + ImGuiKey_F19, ImGuiKey_F20, ImGuiKey_F21, ImGuiKey_F22, ImGuiKey_F23, ImGuiKey_F24, + ImGuiKey_Apostrophe, // ' + ImGuiKey_Comma, // , + ImGuiKey_Minus, // - + ImGuiKey_Period, // . + ImGuiKey_Slash, // / + ImGuiKey_Semicolon, // ; + ImGuiKey_Equal, // = + ImGuiKey_LeftBracket, // [ + ImGuiKey_Backslash, // \ (this text inhibit multiline comment caused by backslash) + ImGuiKey_RightBracket, // ] + ImGuiKey_GraveAccent, // ` + ImGuiKey_CapsLock, + ImGuiKey_ScrollLock, + ImGuiKey_NumLock, + ImGuiKey_PrintScreen, + ImGuiKey_Pause, + ImGuiKey_Keypad0, ImGuiKey_Keypad1, ImGuiKey_Keypad2, ImGuiKey_Keypad3, ImGuiKey_Keypad4, + ImGuiKey_Keypad5, ImGuiKey_Keypad6, ImGuiKey_Keypad7, ImGuiKey_Keypad8, ImGuiKey_Keypad9, + ImGuiKey_KeypadDecimal, + ImGuiKey_KeypadDivide, ImGuiKey_KeypadMultiply, ImGuiKey_KeypadSubtract, + ImGuiKey_KeypadAdd, ImGuiKey_KeypadEnter, ImGuiKey_KeypadEqual, + ImGuiKey_AppBack, // Available on some keyboard/mouses. Often referred as "Browser Back" + ImGuiKey_AppForward, + + // Gamepad (some of those are analog values, 0.0f to 1.0f) // GAME NAVIGATION ACTION + // (download controller mapping PNG/PSD at http://dearimgui.org/controls_sheets) + ImGuiKey_GamepadStart, // Menu (Xbox) + (Switch) Start/Options (PS) + ImGuiKey_GamepadBack, // View (Xbox) - (Switch) Share (PS) + ImGuiKey_GamepadFaceLeft, // X (Xbox) Y (Switch) Square (PS) // Tap: Toggle Menu. Hold: Windowing mode (Focus/Move/Resize windows) + ImGuiKey_GamepadFaceRight, // B (Xbox) A (Switch) Circle (PS) // Cancel / Close / Exit + ImGuiKey_GamepadFaceUp, // Y (Xbox) X (Switch) Triangle (PS) // Text Input / On-screen Keyboard + ImGuiKey_GamepadFaceDown, // A (Xbox) B (Switch) Cross (PS) // Activate / Open / Toggle / Tweak + ImGuiKey_GamepadDpadLeft, // D-pad Left // Move / Tweak / Resize Window (in Windowing mode) + ImGuiKey_GamepadDpadRight, // D-pad Right // Move / Tweak / Resize Window (in Windowing mode) + ImGuiKey_GamepadDpadUp, // D-pad Up // Move / Tweak / Resize Window (in Windowing mode) + ImGuiKey_GamepadDpadDown, // D-pad Down // Move / Tweak / Resize Window (in Windowing mode) + ImGuiKey_GamepadL1, // L Bumper (Xbox) L (Switch) L1 (PS) // Tweak Slower / Focus Previous (in Windowing mode) + ImGuiKey_GamepadR1, // R Bumper (Xbox) R (Switch) R1 (PS) // Tweak Faster / Focus Next (in Windowing mode) + ImGuiKey_GamepadL2, // L Trig. (Xbox) ZL (Switch) L2 (PS) [Analog] + ImGuiKey_GamepadR2, // R Trig. (Xbox) ZR (Switch) R2 (PS) [Analog] + ImGuiKey_GamepadL3, // L Stick (Xbox) L3 (Switch) L3 (PS) + ImGuiKey_GamepadR3, // R Stick (Xbox) R3 (Switch) R3 (PS) + + ImGuiKey_GamepadLStickLeft, // [Analog] // Move Window (in Windowing mode) + ImGuiKey_GamepadLStickRight, // [Analog] // Move Window (in Windowing mode) + ImGuiKey_GamepadLStickUp, // [Analog] // Move Window (in Windowing mode) + ImGuiKey_GamepadLStickDown, // [Analog] // Move Window (in Windowing mode) + ImGuiKey_GamepadRStickLeft, // [Analog] + ImGuiKey_GamepadRStickRight, // [Analog] + ImGuiKey_GamepadRStickUp, // [Analog] + ImGuiKey_GamepadRStickDown, // [Analog] + + // Mouse Buttons (auto-submitted from AddMouseButtonEvent() calls) + // - This is mirroring the data also written to io.MouseDown[], io.MouseWheel, in a format allowing them to be accessed via standard key API. + ImGuiKey_MouseLeft, ImGuiKey_MouseRight, ImGuiKey_MouseMiddle, ImGuiKey_MouseX1, ImGuiKey_MouseX2, ImGuiKey_MouseWheelX, ImGuiKey_MouseWheelY, + + // Keyboard Modifiers (explicitly submitted by backend via AddKeyEvent() calls) + // - This is mirroring the data also written to io.KeyCtrl, io.KeyShift, io.KeyAlt, io.KeySuper, in a format allowing + // them to be accessed via standard key API, allowing calls such as IsKeyPressed(), IsKeyReleased(), querying duration etc. + // - Code polling every keys (e.g. an interface to detect a key press for input mapping) might want to ignore those + // and prefer using the real keys (e.g. ImGuiKey_LeftCtrl, ImGuiKey_RightCtrl instead of ImGuiKey_ModCtrl). + // - In theory the value of keyboard modifiers should be roughly equivalent to a logical or of the equivalent left/right keys. + // In practice: it's complicated; mods are often provided from different sources. Keyboard layout, IME, sticky keys and + // backends tend to interfere and break that equivalence. The safer decision is to relay that ambiguity down to the end-user... + ImGuiKey_ReservedForModCtrl, ImGuiKey_ReservedForModShift, ImGuiKey_ReservedForModAlt, ImGuiKey_ReservedForModSuper, + + // End of list + ImGuiKey_COUNT, // No valid ImGuiKey is ever greater than this value + }; + + + static constexpr uint32_t kAnalog_First = ImGuiKey_GamepadLStickLeft; + static constexpr uint32_t kAnalog_Last = ImGuiKey_GamepadRStickDown; + static constexpr uint32_t kAnalog_Count = kAnalog_Last - kAnalog_First + 1; + + CmdInput() : CmdHeader(CmdHeader::eCommands::Input, sizeof(CmdInput)){} + uint16_t mScreenSize[2] = {}; + int16_t mMousePos[2] = {}; + float mMouseWheelVert = 0.f; + float mMouseWheelHoriz = 0.f; + uint16_t mKeyChars[256] = {}; // Input characters + uint16_t mKeyCharCount = 0; // Number of valid input characters + bool mCompressionUse = false; // Server would like client to compress the communication data + bool mCompressionSkip = false; // Server forcing next client's frame data to be uncompressed + float mFontDPIScaling = 1.f; // Font scaling request by Server accounting for monitor DPI + float mDesiredFps = 30.f; // Requested redraw speed + uint64_t mMouseDownMask = 0; + uint64_t mInputDownMask[(ImGuiKey_COUNT+63)/64]={}; + float mInputAnalog[kAnalog_Count] = {}; + inline bool IsKeyDown(NetImguiKeys netimguiKey) const; +}; + +struct alignas(8) CmdTexture : public CmdHeader +{ + CmdTexture() : CmdHeader(CmdHeader::eCommands::Texture, sizeof(CmdTexture)){} + OffsetPointer mpTextureData; + uint64_t mTextureId = 0; + uint16_t mWidth = 0; + uint16_t mHeight = 0; + uint8_t mFormat = eTexFormat::kTexFmt_Invalid; // eTexFormat + uint8_t PADDING[3] = {}; +}; + +struct alignas(8) CmdDrawFrame : public CmdHeader +{ + CmdDrawFrame() : CmdHeader(CmdHeader::eCommands::DrawFrame, sizeof(CmdDrawFrame)){} + uint64_t mFrameIndex = 0; + uint32_t mMouseCursor = 0; // ImGuiMouseCursor value + float mDisplayArea[4] = {}; + uint32_t mIndiceByteSize = 0; + uint32_t mDrawGroupCount = 0; + uint32_t mTotalVerticeCount = 0; + uint32_t mTotalIndiceCount = 0; + uint32_t mTotalDrawCount = 0; + uint32_t mUncompressedSize = 0; + uint8_t mCompressed = false; + uint8_t PADDING[3] = {}; + OffsetPointer mpDrawGroups; + inline void ToPointers(); + inline void ToOffsets(); +}; + +struct alignas(8) CmdBackground : public CmdHeader +{ + CmdBackground() : CmdHeader(CmdHeader::eCommands::Background, sizeof(CmdBackground)){} + static constexpr uint64_t kDefaultTexture = ~0u; + float mClearColor[4] = {0.2f, 0.2f, 0.2f, 1.f}; // Background color + float mTextureTint[4] = {1.f, 1.f, 1.f, 0.5f}; // Tint/alpha applied to texture + uint64_t mTextureId = kDefaultTexture; // Texture rendered in background, use server texture by default + inline bool operator==(const CmdBackground& cmp)const; + inline bool operator!=(const CmdBackground& cmp)const; +}; + +struct alignas(8) CmdClipboard : public CmdHeader +{ + CmdClipboard() : CmdHeader(CmdHeader::eCommands::Clipboard, sizeof(CmdClipboard)){} + size_t mByteSize = 0; + OffsetPointer mContentUTF8; + inline void ToPointers(); + inline void ToOffsets(); + inline static CmdClipboard* Create(const char* clipboard); +}; + +//============================================================================= +// Keeping track of partial incoming/outgoing transmissions +//============================================================================= +struct PendingCom +{ + size_t SizeCurrent = 0; // Amount of data sent or received so far + bool bAutoFree = false; // Need to free data buffer at the end of processing + bool bError = false; // If an error occurs during coms + CmdHeader* pCommand = nullptr; // Where to store incoming data or read to send data + inline bool IsError()const{ return bError; } + inline bool IsDone()const { return IsError() || (pCommand && pCommand->mSize == SizeCurrent); } + inline bool IsReady()const{ return !IsError() && pCommand == nullptr; } + inline bool IsPending()const{ return !IsError() && !IsDone() && !IsReady(); } +}; + +}} // namespace NetImgui::Internal + +#include "NetImgui_CmdPackets.inl" diff --git a/Plugins/Cog/Source/ThirdParty/NetImgui/Private/NetImgui_CmdPackets.inl b/Plugins/Cog/Source/ThirdParty/NetImgui/Private/NetImgui_CmdPackets.inl new file mode 100644 index 0000000..e03b622 --- /dev/null +++ b/Plugins/Cog/Source/ThirdParty/NetImgui/Private/NetImgui_CmdPackets.inl @@ -0,0 +1,101 @@ +#include "NetImgui_CmdPackets.h" + +namespace NetImgui { namespace Internal +{ + +void CmdDrawFrame::ToPointers() +{ + if( !mpDrawGroups.IsPointer() ) + { + mpDrawGroups.ToPointer(); + for (uint32_t i(0); i < mDrawGroupCount; ++i) { + mpDrawGroups[i].ToPointers(); + } + } +} + +void CmdDrawFrame::ToOffsets() +{ + if( !mpDrawGroups.IsOffset() ) + { + for (uint32_t i(0); i < mDrawGroupCount; ++i) { + mpDrawGroups[i].ToOffsets(); + } + mpDrawGroups.ToOffset(); + } +} + +void ImguiDrawGroup::ToPointers() +{ + if( !mpIndices.IsPointer() ) //Safer to test the first element after CmdHeader + { + mpIndices.ToPointer(); + mpVertices.ToPointer(); + mpDraws.ToPointer(); + } +} + +void ImguiDrawGroup::ToOffsets() +{ + if( !mpIndices.IsOffset() ) //Safer to test the first element after CmdHeader + { + mpIndices.ToOffset(); + mpVertices.ToOffset(); + mpDraws.ToOffset(); + } +} + +bool CmdInput::IsKeyDown( CmdInput::NetImguiKeys netimguiKey) const +{ + uint32_t valIndex = netimguiKey/64; + uint64_t valMask = 0x0000000000000001ull << (netimguiKey%64); + return mInputDownMask[valIndex] & valMask; +} + +bool CmdBackground::operator==(const CmdBackground& cmp)const +{ + bool sameValue(true); + for(size_t i(0); i(this)[i] == reinterpret_cast(&cmp)[i]; + } + return sameValue; +} + +bool CmdBackground::operator!=(const CmdBackground& cmp)const +{ + return (*this == cmp) == false; +} + + +void CmdClipboard::ToPointers() +{ + if( !mContentUTF8.IsPointer() ){ + mContentUTF8.ToPointer(); + } +} + +void CmdClipboard::ToOffsets() +{ + if( !mContentUTF8.IsOffset() ){ + mContentUTF8.ToOffset(); + } +} + +CmdClipboard* CmdClipboard::Create(const char* clipboard) +{ + if( clipboard ) + { + size_t clipboardByteSize(0); + while(clipboard[clipboardByteSize++] != 0); + size_t totalDataCount = sizeof(CmdClipboard) + DivUp(clipboardByteSize, ComDataSize); + auto pNewClipboard = NetImgui::Internal::netImguiSizedNew(totalDataCount*ComDataSize); + pNewClipboard->mSize = static_cast(totalDataCount*ComDataSize); + pNewClipboard->mByteSize = clipboardByteSize; + pNewClipboard->mContentUTF8.SetPtr(reinterpret_cast(&pNewClipboard[1])); + memcpy(pNewClipboard->mContentUTF8.Get(), clipboard, clipboardByteSize); + return pNewClipboard; + } + return nullptr; +} + +}} // namespace NetImgui::Internal diff --git a/Plugins/Cog/Source/ThirdParty/NetImgui/Private/NetImgui_CmdPackets_DrawFrame.cpp b/Plugins/Cog/Source/ThirdParty/NetImgui/Private/NetImgui_CmdPackets_DrawFrame.cpp new file mode 100644 index 0000000..e0f1173 --- /dev/null +++ b/Plugins/Cog/Source/ThirdParty/NetImgui/Private/NetImgui_CmdPackets_DrawFrame.cpp @@ -0,0 +1,381 @@ +#include "NetImgui_Shared.h" + +#if NETIMGUI_ENABLED +#include "NetImgui_WarningDisable.h" +#include "NetImgui_CmdPackets.h" + +namespace NetImgui { namespace Internal +{ + +template +inline void SetAndIncreaseDataPointer(OffsetPointer& dataPointer, uint32_t dataSize, ComDataType*& pDataOutput) +{ + dataPointer.SetComDataPtr(pDataOutput); + const size_t dataCount = DivUp(dataSize, ComDataSize); + pDataOutput[dataCount-1] = 0; + pDataOutput += dataCount; +} + +//============================================================================= +// Safely convert a pointer to a int value, even if int storage size > pointer +//============================================================================= +template +TInt PointerCast(TPointer* pointer) +{ + union CastHelperUnion + { + TInt ValueInt; + TPointer* ValuePointer; + }; + CastHelperUnion helperObject = {}; + helperObject.ValuePointer = pointer; + return helperObject.ValueInt; +} + +//================================================================================================= +// +//================================================================================================= +inline void ImGui_ExtractIndices(const ImDrawList& cmdList, ImguiDrawGroup& drawGroupOut, ComDataType*& pDataOutput) +{ + bool is16Bit = sizeof(ImDrawIdx) == 2 || cmdList.VtxBuffer.size() <= 0xFFFF; // When Dear Imgui is compiled with ImDrawIdx = uint16, we know for certain that there won't be any drawcall with index > 65k, even if Vertex buffer is bigger than 65k. + drawGroupOut.mBytePerIndex = is16Bit ? 2 : 4; + drawGroupOut.mIndiceCount = static_cast(cmdList.IdxBuffer.size()); + uint32_t sizeNeeded = drawGroupOut.mIndiceCount*drawGroupOut.mBytePerIndex; + SetAndIncreaseDataPointer(drawGroupOut.mpIndices, sizeNeeded, pDataOutput); + + // No conversion needed, straight copy + if( drawGroupOut.mBytePerIndex == sizeof(ImDrawIdx) ) + { + memcpy(drawGroupOut.mpIndices.Get(), &cmdList.IdxBuffer.front(), sizeNeeded); + } + // From 32bits to 16bits + else if(is16Bit) + { + for(int i(0); i < static_cast(drawGroupOut.mIndiceCount); ++i) + reinterpret_cast(drawGroupOut.mpIndices.Get())[i] = static_cast(cmdList.IdxBuffer[i]); + } + // From 16bits to 32bits + else + { + for(int i(0); i < static_cast(drawGroupOut.mIndiceCount); ++i) + reinterpret_cast(drawGroupOut.mpIndices.Get())[i] = static_cast(cmdList.IdxBuffer[i]); + } +} + +//================================================================================================= +// +//================================================================================================= +inline void ImGui_ExtractVertices(const ImDrawList& cmdList, ImguiDrawGroup& drawGroupOut, ComDataType*& pDataOutput) +{ + drawGroupOut.mVerticeCount = static_cast(cmdList.VtxBuffer.size()); + drawGroupOut.mReferenceCoord[0] = drawGroupOut.mVerticeCount > 0 ? cmdList.VtxBuffer[0].pos.x : 0.f; + drawGroupOut.mReferenceCoord[1] = drawGroupOut.mVerticeCount > 0 ? cmdList.VtxBuffer[0].pos.y : 0.f; + SetAndIncreaseDataPointer(drawGroupOut.mpVertices, drawGroupOut.mVerticeCount*sizeof(ImguiVert), pDataOutput); + ImguiVert* pVertices = drawGroupOut.mpVertices.Get(); + for(int i(0); i(drawGroupOut.mVerticeCount); ++i) + { + const auto& Vtx = cmdList.VtxBuffer[i]; + pVertices[i].mColor = Vtx.col; + pVertices[i].mUV[0] = static_cast((Vtx.uv.x - static_cast(ImguiVert::kUvRange_Min) + 0.5f/65535.f) * 0xFFFF / (ImguiVert::kUvRange_Max - ImguiVert::kUvRange_Min)); + pVertices[i].mUV[1] = static_cast((Vtx.uv.y - static_cast(ImguiVert::kUvRange_Min) + 0.5f/65535.f) * 0xFFFF / (ImguiVert::kUvRange_Max - ImguiVert::kUvRange_Min)); + pVertices[i].mPos[0] = static_cast((Vtx.pos.x - drawGroupOut.mReferenceCoord[0] - static_cast(ImguiVert::kPosRange_Min)) * 0xFFFF / (ImguiVert::kPosRange_Max - ImguiVert::kPosRange_Min)); + pVertices[i].mPos[1] = static_cast((Vtx.pos.y - drawGroupOut.mReferenceCoord[1] - static_cast(ImguiVert::kPosRange_Min)) * 0xFFFF / (ImguiVert::kPosRange_Max - ImguiVert::kPosRange_Min)); + } +} + +//================================================================================================= +// +//================================================================================================= +inline void ImGui_ExtractDraws(const ImDrawList& cmdList, ImguiDrawGroup& drawGroupOut, ComDataType*& pDataOutput) +{ + int maxDrawCount = static_cast(cmdList.CmdBuffer.size()); + uint32_t drawCount = 0; + ImguiDraw* pOutDraws = reinterpret_cast(pDataOutput); + for(int cmd_i = 0; cmd_i < maxDrawCount; ++cmd_i) + { + const ImDrawCmd* pCmd = &cmdList.CmdBuffer[cmd_i]; + if( pCmd->UserCallback == nullptr ) + { + #if IMGUI_VERSION_NUM >= 17100 + pOutDraws[drawCount].mVtxOffset = pCmd->VtxOffset; + pOutDraws[drawCount].mIdxOffset = pCmd->IdxOffset; + #else + pOutDraws[drawCount].mVtxOffset = 0; + pOutDraws[drawCount].mIdxOffset = 0; + #endif + + pOutDraws[drawCount].mTextureId = TextureCastFromID(pCmd->TextureId); + pOutDraws[drawCount].mIdxCount = pCmd->ElemCount; + pOutDraws[drawCount].mClipRect[0] = pCmd->ClipRect.x; + pOutDraws[drawCount].mClipRect[1] = pCmd->ClipRect.y; + pOutDraws[drawCount].mClipRect[2] = pCmd->ClipRect.z; + pOutDraws[drawCount].mClipRect[3] = pCmd->ClipRect.w; + ++drawCount; + } + } + drawGroupOut.mDrawCount = drawCount; + static_assert(sizeof(ImguiDraw) % ComDataSize == 0, "Need to support zero-ing the pending bytes, when not a size multiple of DataComType"); + drawGroupOut.mpDraws.SetComDataPtr(pDataOutput); + pDataOutput += drawGroupOut.mDrawCount * sizeof(ImguiDraw) / ComDataSize; +} + +//================================================================================================= +// Delta comress data. +// Take a data stream and output a version with only the difference from other stream is written +//================================================================================================= +void CompressData(const ComDataType* pDataPrev, size_t dataSizePrev, const ComDataType* pDataNew, size_t dataSizeNew, ComDataType*& pCommandMemoryInOut) +{ + static_assert(sizeof(uint32_t)*2 <= ComDataSize, "Need to adjust compression algorithm pointer calculation"); + const size_t elemCountPrev = static_cast(DivUp(dataSizePrev, sizeof(uint64_t))); + const size_t elemCountNew = static_cast(DivUp(dataSizeNew, sizeof(uint64_t))); + const size_t elemCount = elemCountPrev < elemCountNew ? elemCountPrev : elemCountNew; + size_t n = 0; + + if( pDataPrev ) + { + while(n < elemCount) + { + uint32_t* pBlockInfo = reinterpret_cast(pCommandMemoryInOut++); // Add a new block info to output + + // Find number of elements with same value as last frame + size_t startN = n; + while( n < elemCount && pDataPrev[n] == pDataNew[n] ) + ++n; + pBlockInfo[0] = static_cast(n - startN); + + // Find number of elements with different value as last frame, and save new value + while (n < elemCount && pDataPrev[n] != pDataNew[n]) { + *pCommandMemoryInOut = pDataNew[n++]; + ++pCommandMemoryInOut; + } + pBlockInfo[1] = static_cast(pCommandMemoryInOut - reinterpret_cast(pBlockInfo)) - 1; + } + } + + // New frame has more element than previous frame, add the remaining entries + if(elemCount < elemCountNew) + { + uint32_t* pBlockInfo = reinterpret_cast(pCommandMemoryInOut++); // Add a new block info to output + while (n < elemCountNew) { + *pCommandMemoryInOut = pDataNew[n++]; + ++pCommandMemoryInOut; + } + pBlockInfo[0] = 0; + pBlockInfo[1] = static_cast(pCommandMemoryInOut - reinterpret_cast(pBlockInfo)) - 1; + } +} + +//================================================================================================= +// Unpack a delta data compressed stream +//================================================================================================= +void DecompressData(const ComDataType* pDataPrev, size_t dataSizePrev, const ComDataType* pDataPack, size_t dataUnpackSize, ComDataType*& pCommandMemoryInOut) +{ + const size_t elemCountPrev = DivUp(dataSizePrev, ComDataSize); + const size_t elemCountUnpack = DivUp(dataUnpackSize, ComDataSize); + const size_t elemCountCopy = elemCountPrev < elemCountUnpack ? elemCountPrev : elemCountUnpack; + uint64_t* pCommandMemoryEnd = &pCommandMemoryInOut[elemCountUnpack]; + if( pDataPrev ){ + memcpy(pCommandMemoryInOut, pDataPrev, elemCountCopy * ComDataSize); + } + while(pCommandMemoryInOut < pCommandMemoryEnd) + { + const uint32_t* pBlockInfo = reinterpret_cast(pDataPack++); // Add a new block info to output + pCommandMemoryInOut += pBlockInfo[0]; + memcpy(pCommandMemoryInOut, pDataPack, pBlockInfo[1] * sizeof(uint64_t)); + pCommandMemoryInOut += pBlockInfo[1]; + pDataPack += pBlockInfo[1]; + } +} + +//================================================================================================= +// Take a regular NetImgui DrawFrame command and create a new compressed command +// It uses a basic delta compression method that works really well with Imgui data +// - Most of the drawing data do not change between 2 frames +// - Even if 1 window content changes, the others windows probably won't be changing at all +// - This means that for each window, we can only send the data that changed +// - This requires little cpu usage and generate good results +// - In 'SampleBasic' with 3 windows open (Main Window, ImGui Demo, ImGui Metric) at 30fps +// - Compression Off: 1650KB/sec of transfert +// - Compression On : 12KB/sec of transfert (130x less data) +//================================================================================================= +CmdDrawFrame* CompressCmdDrawFrame(const CmdDrawFrame* pDrawFramePrev, const CmdDrawFrame* pDrawFrameNew) +{ + //----------------------------------------------------------------------------------------- + // Allocate memory for the new compressed command + //----------------------------------------------------------------------------------------- + // Allocate memory for worst case scenario (no compression possible) + // New DrawFrame size + 2 'compression block info' per data stream + size_t neededDataCount = DivUp(pDrawFrameNew->mSize, ComDataSize) + 6*static_cast(pDrawFrameNew->mDrawGroupCount); + CmdDrawFrame* pDrawFramePacked = netImguiSizedNew(neededDataCount*ComDataSize); + *pDrawFramePacked = *pDrawFrameNew; + pDrawFramePacked->mCompressed = true; + + ComDataType* pDataOutput = reinterpret_cast(&pDrawFramePacked[1]); + SetAndIncreaseDataPointer(pDrawFramePacked->mpDrawGroups, pDrawFramePacked->mDrawGroupCount * sizeof(ImguiDrawGroup), pDataOutput); + + //----------------------------------------------------------------------------------------- + // Copy draw data (vertices, indices, drawcall info, ...) + //----------------------------------------------------------------------------------------- + const uint32_t groupCountPrev = pDrawFramePrev->mDrawGroupCount; + for(uint32_t n = 0; n < pDrawFramePacked->mDrawGroupCount; n++) + { + // Look for the same drawgroup in previous frame + // Can usually avoid a search by checking same index in previous frame (drawgroup ordering shouldn't change often) + const ImguiDrawGroup& drawGroupNew = pDrawFrameNew->mpDrawGroups[n]; + ImguiDrawGroup& drawGroup = pDrawFramePacked->mpDrawGroups[n]; + drawGroup = drawGroupNew; + drawGroup.mDrawGroupIdxPrev = (n < groupCountPrev && drawGroup.mGroupID == pDrawFramePrev->mpDrawGroups[n].mGroupID) ? n : ImguiDrawGroup::kInvalidDrawGroup; + for(uint32_t j(0); jmpDrawGroups[j].mGroupID) ? j : ImguiDrawGroup::kInvalidDrawGroup; + } + + // Delta compress the 3 data streams + const uint64_t *pVerticePrev(nullptr), *pIndicePrev(nullptr), *pDrawsPrev(nullptr); + size_t verticeSizePrev(0), indiceSizePrev(0), drawSizePrev(0); + if (drawGroup.mDrawGroupIdxPrev < pDrawFramePrev->mDrawGroupCount) { + const ImguiDrawGroup& drawGroupPrev = pDrawFramePrev->mpDrawGroups[drawGroup.mDrawGroupIdxPrev]; + pVerticePrev = reinterpret_cast(drawGroupPrev.mpVertices.Get()); + pIndicePrev = reinterpret_cast(drawGroupPrev.mpIndices.Get()); + pDrawsPrev = reinterpret_cast(drawGroupPrev.mpDraws.Get()); + verticeSizePrev = drawGroupPrev.mVerticeCount * sizeof(ImguiVert); + indiceSizePrev = drawGroupPrev.mIndiceCount*static_cast(drawGroupPrev.mBytePerIndex); + drawSizePrev = drawGroupPrev.mDrawCount*sizeof(ImguiDraw); + } + + drawGroup.mpIndices.SetComDataPtr(pDataOutput); + CompressData( pIndicePrev, indiceSizePrev, + drawGroupNew.mpIndices.GetComData(), drawGroupNew.mIndiceCount*static_cast(drawGroupNew.mBytePerIndex), + pDataOutput); + + drawGroup.mpVertices.SetComDataPtr(pDataOutput); + CompressData( pVerticePrev, verticeSizePrev, + drawGroupNew.mpVertices.GetComData(), drawGroupNew.mVerticeCount * sizeof(ImguiVert), + pDataOutput); + + drawGroup.mpDraws.SetComDataPtr(pDataOutput); + CompressData( pDrawsPrev, drawSizePrev, + drawGroupNew.mpDraws.GetComData(), drawGroupNew.mDrawCount*sizeof(ImguiDraw), + pDataOutput); + } + + // Adjust data transfert amount to memory that has been actually needed + pDrawFramePacked->mSize = static_cast((pDataOutput - reinterpret_cast(pDrawFramePacked)))*static_cast(sizeof(uint64_t)); + return pDrawFramePacked; +} + +//================================================================================================= +// +//================================================================================================= +CmdDrawFrame* DecompressCmdDrawFrame(const CmdDrawFrame* pDrawFramePrev, const CmdDrawFrame* pDrawFramePacked) +{ + //----------------------------------------------------------------------------------------- + // Allocate memory for the new uncompressed compressed command + //----------------------------------------------------------------------------------------- + CmdDrawFrame* pDrawFrameNew = netImguiSizedNew(pDrawFramePacked->mUncompressedSize); + *pDrawFrameNew = *pDrawFramePacked; + pDrawFrameNew->mCompressed = false; + ComDataType* pDataOutput = reinterpret_cast(&pDrawFrameNew[1]); + SetAndIncreaseDataPointer(pDrawFrameNew->mpDrawGroups, pDrawFrameNew->mDrawGroupCount * sizeof(ImguiDrawGroup), pDataOutput); + + for(uint32_t n = 0; n < pDrawFrameNew->mDrawGroupCount; n++) + { + const ImguiDrawGroup& drawGroupPack = pDrawFramePacked->mpDrawGroups[n]; + ImguiDrawGroup& drawGroup = pDrawFrameNew->mpDrawGroups[n]; + drawGroup = drawGroupPack; + + // Uncompress the 3 data streams + const ComDataType* pVerticePrev = nullptr; + const ComDataType* pIndicePrev = nullptr; + const ComDataType* pDrawsPrev = nullptr; + size_t verticeSizePrev(0), indiceSizePrev(0), drawSizePrev(0); + if (drawGroup.mDrawGroupIdxPrev < pDrawFramePrev->mDrawGroupCount) { + const ImguiDrawGroup& drawGroupPrev = pDrawFramePrev->mpDrawGroups[drawGroup.mDrawGroupIdxPrev]; + pVerticePrev = reinterpret_cast(drawGroupPrev.mpVertices.Get()); + pIndicePrev = reinterpret_cast(drawGroupPrev.mpIndices.Get()); + pDrawsPrev = reinterpret_cast(drawGroupPrev.mpDraws.Get()); + verticeSizePrev = drawGroupPrev.mVerticeCount * sizeof(ImguiVert); + indiceSizePrev = drawGroupPrev.mIndiceCount*static_cast(drawGroupPrev.mBytePerIndex); + drawSizePrev = drawGroupPrev.mDrawCount*sizeof(ImguiDraw); + } + + drawGroup.mpIndices.SetComDataPtr(pDataOutput); + DecompressData( pIndicePrev, indiceSizePrev, + drawGroupPack.mpIndices.GetComData(), drawGroupPack.mIndiceCount*static_cast(drawGroupPack.mBytePerIndex), + pDataOutput); + + drawGroup.mpVertices.SetComDataPtr(pDataOutput); + DecompressData( pVerticePrev, verticeSizePrev, + drawGroupPack.mpVertices.GetComData(), drawGroupPack.mVerticeCount*sizeof(ImguiVert), + pDataOutput); + + drawGroup.mpDraws.SetComDataPtr(pDataOutput); + DecompressData( pDrawsPrev, drawSizePrev, + drawGroupPack.mpDraws.GetComData(), drawGroupPack.mDrawCount*sizeof(ImguiDraw), + pDataOutput); + } + return pDrawFrameNew; +} + +//================================================================================================= +// Take a regular Dear Imgui Draw Data, and convert it to a NetImgui DrawFrame Command +// It involves saving each window draw group vertex/indices/draw buffers +// and packing their data a little bit, to reduce the bandwidth usage +//================================================================================================= +CmdDrawFrame* ConvertToCmdDrawFrame(const ImDrawData* pDearImguiData, ImGuiMouseCursor mouseCursor) +{ + //----------------------------------------------------------------------------------------- + // Find memory needed for entire DrawFrame Command + //----------------------------------------------------------------------------------------- + static_assert(sizeof(CmdDrawFrame) % ComDataSize == 0, "Make sure Command Data is aligned to com data type size"); + size_t neededDataCount = DivUp(sizeof(CmdDrawFrame), ComDataSize); + neededDataCount += DivUp(static_cast(pDearImguiData->CmdListsCount) * sizeof(ImguiDrawGroup), ComDataSize); + for(int n = 0; n < pDearImguiData->CmdListsCount; n++) + { + const ImDrawList* pCmdList = pDearImguiData->CmdLists[n]; + bool is16Bit = pCmdList->VtxBuffer.size() <= 0xFFFF; + neededDataCount += DivUp(static_cast(pCmdList->VtxBuffer.size()) * sizeof(ImguiVert), ComDataSize); + neededDataCount += DivUp(static_cast(pCmdList->IdxBuffer.size()) * (is16Bit ? 2 : 4), ComDataSize); + neededDataCount += DivUp(static_cast(pCmdList->CmdBuffer.size()) * sizeof(ImguiDraw), ComDataSize); + } + + //----------------------------------------------------------------------------------------- + // Allocate Data and initialize general frame information + //----------------------------------------------------------------------------------------- + CmdDrawFrame* pDrawFrame = netImguiSizedNew(neededDataCount*ComDataSize); + ComDataType* pDataOutput = reinterpret_cast(&pDrawFrame[1]); + pDrawFrame->mMouseCursor = static_cast(mouseCursor); + pDrawFrame->mDisplayArea[0] = pDearImguiData->DisplayPos.x; + pDrawFrame->mDisplayArea[1] = pDearImguiData->DisplayPos.y; + pDrawFrame->mDisplayArea[2] = pDearImguiData->DisplayPos.x + pDearImguiData->DisplaySize.x; + pDrawFrame->mDisplayArea[3] = pDearImguiData->DisplayPos.y + pDearImguiData->DisplaySize.y; + pDrawFrame->mDrawGroupCount = static_cast(pDearImguiData->CmdListsCount); + SetAndIncreaseDataPointer(pDrawFrame->mpDrawGroups, static_cast(pDrawFrame->mDrawGroupCount * sizeof(ImguiDrawGroup)), pDataOutput); + + //----------------------------------------------------------------------------------------- + // Copy draw data (vertices, indices, drawcall info, ...) + //----------------------------------------------------------------------------------------- + + + for(size_t n = 0; n < pDrawFrame->mDrawGroupCount; n++) + { + ImguiDrawGroup& drawGroup = pDrawFrame->mpDrawGroups[n]; + const ImDrawList* pCmdList = pDearImguiData->CmdLists[static_cast(n)]; + drawGroup = ImguiDrawGroup(); + drawGroup.mGroupID = PointerCast(pCmdList->_OwnerName); // Use the name string pointer as a unique ID (seems to remain the same between frame) + ImGui_ExtractIndices(*pCmdList, drawGroup, pDataOutput); + ImGui_ExtractVertices(*pCmdList,drawGroup, pDataOutput); + ImGui_ExtractDraws(*pCmdList, drawGroup, pDataOutput); + pDrawFrame->mTotalVerticeCount += drawGroup.mVerticeCount; + pDrawFrame->mTotalIndiceCount += drawGroup.mIndiceCount; + pDrawFrame->mTotalDrawCount += drawGroup.mDrawCount; + } + + pDrawFrame->mSize = static_cast(pDataOutput - reinterpret_cast(pDrawFrame)) * ComDataSize; + pDrawFrame->mUncompressedSize = pDrawFrame->mSize; // No compression with this item, so same value + return pDrawFrame; +} + +}} // namespace NetImgui::Internal + +#include "NetImgui_WarningReenable.h" +#endif //#if NETIMGUI_ENABLED diff --git a/Plugins/Cog/Source/ThirdParty/NetImgui/Private/NetImgui_CmdPackets_DrawFrame.h b/Plugins/Cog/Source/ThirdParty/NetImgui/Private/NetImgui_CmdPackets_DrawFrame.h new file mode 100644 index 0000000..16d1ef8 --- /dev/null +++ b/Plugins/Cog/Source/ThirdParty/NetImgui/Private/NetImgui_CmdPackets_DrawFrame.h @@ -0,0 +1,50 @@ +#pragma once + +#include "NetImgui_Shared.h" + +namespace NetImgui { namespace Internal +{ + +struct ImguiVert +{ + //Note: If updating this, increase 'CmdVersion::eVersion' + enum Constants{ kUvRange_Min=0, kUvRange_Max=1, kPosRange_Min=-8192, kPosRange_Max=8192}; + uint16_t mPos[2]; + uint16_t mUV[2]; + uint32_t mColor; +}; + +struct ImguiDraw +{ + uint64_t mTextureId; + uint32_t mIdxCount; // Drawcall number of indices (3 indices per triangles) + uint32_t mVtxOffset; // Drawcall start position in vertices buffer (considered index 0) + uint32_t mIdxOffset; // Drawcall start position in indices buffer + float mClipRect[4]; + uint8_t PADDING[4]={}; +}; + +// Each DearImgui window has its own vertex/index buffers with multiple drawcalls +struct alignas(8) ImguiDrawGroup +{ + static constexpr uint32_t kInvalidDrawGroup = 0xFFFFFFFF; + uint64_t mGroupID = 0; // Unique ID to recognize DrawGroup between 2 frames + uint32_t mVerticeCount = 0; + uint32_t mIndiceCount = 0; + uint32_t mDrawCount = 0; + uint32_t mDrawGroupIdxPrev = kInvalidDrawGroup;// Group index in previous DrawFrame (kInvalidDrawGroup when not using delta compression) + uint8_t mBytePerIndex = 2; // 2, 4 bytes + uint8_t PADDING[7] = {}; + float mReferenceCoord[2] = {}; // Reference position for the encoded vertices offsets (1st vertice top/left position) + OffsetPointer mpIndices; + OffsetPointer mpVertices; + OffsetPointer mpDraws; + inline void ToPointers(); + inline void ToOffsets(); +}; + +struct CmdDrawFrame* ConvertToCmdDrawFrame(const ImDrawData* pDearImguiData, ImGuiMouseCursor cursor); +struct CmdDrawFrame* CompressCmdDrawFrame(const CmdDrawFrame* pDrawFramePrev, const CmdDrawFrame* pDrawFrameNew); +struct CmdDrawFrame* DecompressCmdDrawFrame(const CmdDrawFrame* pDrawFramePrev, const CmdDrawFrame* pDrawFramePacked); + +}} // namespace NetImgui::Internal diff --git a/Plugins/Cog/Source/ThirdParty/NetImgui/Private/NetImgui_Network.h b/Plugins/Cog/Source/ThirdParty/NetImgui/Private/NetImgui_Network.h new file mode 100644 index 0000000..6aa3fb4 --- /dev/null +++ b/Plugins/Cog/Source/ThirdParty/NetImgui/Private/NetImgui_Network.h @@ -0,0 +1,22 @@ +#pragma once + +namespace NetImgui { namespace Internal { struct PendingCom; }} + +namespace NetImgui { namespace Internal { namespace Network +{ + +struct SocketInfo; + +bool Startup (void); +void Shutdown (void); + +SocketInfo* Connect (const char* ServerHost, uint32_t ServerPort); // Communication Socket expected to be blocking +SocketInfo* ListenConnect (SocketInfo* ListenSocket); // Communication Socket expected to be blocking +SocketInfo* ListenStart (uint32_t ListenPort); // Listening Socket expected to be non blocking +void Disconnect (SocketInfo* pClientSocket); + +bool DataReceivePending (SocketInfo* pClientSocket); // True if some new data if waiting to be processed from remote connection +void DataReceive (SocketInfo* pClientSocket, PendingCom& PendingComRcv); // Try reading X amount of bytes from remote connection, but can fall short. +void DataSend (SocketInfo* pClientSocket, PendingCom& PendingComSend); // Try sending X amount of bytes to remote connection, but can fall short. + +}}} //namespace NetImgui::Internal::Network diff --git a/Plugins/Cog/Source/ThirdParty/NetImgui/Private/NetImgui_NetworkPosix.cpp b/Plugins/Cog/Source/ThirdParty/NetImgui/Private/NetImgui_NetworkPosix.cpp new file mode 100644 index 0000000..da51bdf --- /dev/null +++ b/Plugins/Cog/Source/ThirdParty/NetImgui/Private/NetImgui_NetworkPosix.cpp @@ -0,0 +1,154 @@ +#include "NetImgui_Shared.h" + +#if defined(_MSC_VER) +#pragma warning (disable: 4221) +#endif + +#if NETIMGUI_ENABLED && NETIMGUI_POSIX_SOCKETS_ENABLED +#include +#include +#include +#include +#include + +//NOTE: The socket handling has been modified to improve speed, but the Posix version +// has not been updated. Please review the changes made to 'NetImgui_NetworkWin32.cpp' +// between version 1.11 and 1.12 and bring them over to this file. In particular : +// -Sockets set to non blocking and immediate sending +// -Added 'DataReceivePending' function +// -Reworked 'DataReceive' and 'DataSend' to be non blocking socket operation +static_assert(0) + +namespace NetImgui { namespace Internal { namespace Network +{ + +struct SocketInfo +{ + SocketInfo(int socket) : mSocket(socket){} + int mSocket; +}; + +bool Startup() +{ + return true; +} + +void Shutdown() +{ +} + +inline void SetNonBlocking(int Socket, bool bIsNonBlocking) +{ + int Flags = fcntl(Socket, F_GETFL, 0); + Flags = bIsNonBlocking ? Flags | O_NONBLOCK : Flags ^ (Flags & O_NONBLOCK); + fcntl(Socket, F_SETFL, Flags); +} + +SocketInfo* Connect(const char* ServerHost, uint32_t ServerPort) +{ + int ConnectSocket = socket(AF_INET , SOCK_STREAM , 0 ); + if(ConnectSocket == -1) + return nullptr; + + char zPortName[32]; + addrinfo* pResults = nullptr; + SocketInfo* pSocketInfo = nullptr; + sprintf(zPortName, "%i", ServerPort); + getaddrinfo(ServerHost, zPortName, nullptr, &pResults); + addrinfo* pResultCur = pResults; + while( pResultCur && !pSocketInfo) + { + if( connect(ConnectSocket, pResultCur->ai_addr, static_cast(pResultCur->ai_addrlen)) == 0 ) + { + SetNonBlocking(ConnectSocket, false); + pSocketInfo = netImguiNew(ConnectSocket); + } + pResultCur = pResultCur->ai_next; + } + + freeaddrinfo(pResults); + if( !pSocketInfo ) + { + close(ConnectSocket); + } + return pSocketInfo; +} + +SocketInfo* ListenStart(uint32_t ListenPort) +{ + addrinfo hints; + + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE; + + addrinfo* addrInfo; + getaddrinfo(nullptr, std::to_string(ListenPort).c_str(), &hints, &addrInfo); + + int ListenSocket = socket(addrInfo->ai_family, addrInfo->ai_socktype, addrInfo->ai_protocol); + if( ListenSocket != -1 ) + { + #if NETIMGUI_FORCE_TCP_LISTEN_BINDING + int flag = 1; + setsockopt(ListenSocket, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag)); + setsockopt(ListenSocket, SOL_SOCKET, SO_REUSEPORT, &flag, sizeof(flag)); + #endif + if( bind(ListenSocket, addrInfo->ai_addr, addrInfo->ai_addrlen) != -1 && + listen(ListenSocket, 0) != -1) + { + SetNonBlocking(ListenSocket, false); + return netImguiNew(ListenSocket); + } + close(ListenSocket); + } + return nullptr; +} + +SocketInfo* ListenConnect(SocketInfo* ListenSocket) +{ + if( ListenSocket ) + { + sockaddr_storage ClientAddress; + socklen_t Size(sizeof(ClientAddress)); + int ServerSocket = accept(ListenSocket->mSocket, (sockaddr*)&ClientAddress, &Size) ; + if (ServerSocket != -1) + { + SetNonBlocking(ServerSocket, false); + return netImguiNew(ServerSocket); + } + } + return nullptr; +} + +void Disconnect(SocketInfo* pClientSocket) +{ + if( pClientSocket ) + { + shutdown(pClientSocket->mSocket, SHUT_RDWR); + close(pClientSocket->mSocket); + netImguiDelete(pClientSocket); + } +} + +bool DataReceive(SocketInfo* pClientSocket, void* pDataIn, size_t Size) +{ + int resultRcv = recv(pClientSocket->mSocket, static_cast(pDataIn), static_cast(Size), MSG_WAITALL); + return static_cast(Size) == resultRcv; +} + +bool DataSend(SocketInfo* pClientSocket, void* pDataOut, size_t Size) +{ + int resultSend = send(pClientSocket->mSocket, static_cast(pDataOut), static_cast(Size), 0); + return static_cast(Size) == resultSend; +} + +}}} // namespace NetImgui::Internal::Network +#else + +// Prevents Linker warning LNK4221 in Visual Studio (This object file does not define any previously undefined public symbols, so it will not be used by any link operation that consumes this library) +extern int sSuppresstLNK4221_NetImgui_NetworkPosix; +int sSuppresstLNK4221_NetImgui_NetworkPosix(0); + +#endif // #if NETIMGUI_ENABLED && NETIMGUI_POSIX_SOCKETS_ENABLED + diff --git a/Plugins/Cog/Source/ThirdParty/NetImgui/Private/NetImgui_NetworkUE4.cpp b/Plugins/Cog/Source/ThirdParty/NetImgui/Private/NetImgui_NetworkUE4.cpp new file mode 100644 index 0000000..941776e --- /dev/null +++ b/Plugins/Cog/Source/ThirdParty/NetImgui/Private/NetImgui_NetworkUE4.cpp @@ -0,0 +1,233 @@ +#include "NetImgui_Shared.h" + +// Tested with Unreal Engine 4.27, 5.3, 5.4, 5.5 + +#if NETIMGUI_ENABLED && defined(__UNREAL__) + +#include "CoreMinimal.h" +#include "Runtime/Launch/Resources/Version.h" +#include "Misc/OutputDeviceRedirector.h" +#include "SocketSubsystem.h" +#include "Sockets.h" +#include "HAL/PlatformProcess.h" +#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 2 +#include "IPAddressAsyncResolve.h" +#endif + +namespace NetImgui { namespace Internal { namespace Network +{ + +//================================================================================================= +// Wrapper around native socket object and init some socket options +//================================================================================================= +struct SocketInfo +{ + SocketInfo(FSocket* pSocket) + : mpSocket(pSocket) + { + if( mpSocket ) + { + mpSocket->SetNonBlocking(true); + mpSocket->SetNoDelay(true); + + int32 NewSize(0); + while( !mpSocket->SetSendBufferSize(2*mSendSize, NewSize) ){ + mSendSize /= 2; + } + mSendSize = NewSize/2; + } + } + + ~SocketInfo() + { + Close(); + } + + void Close() + { + if(mpSocket ) + { + mpSocket->Close(); + ISocketSubsystem::Get()->DestroySocket(mpSocket); + mpSocket = nullptr; + } + } + FSocket* mpSocket = nullptr; + int32 mSendSize = 1024*1024; // Limit tx data to avoid socket error on large amount (texture) +}; + +bool Startup() +{ + return true; +} + +void Shutdown() +{ +} + +//================================================================================================= +// Try establishing a connection to a remote client at given address +//================================================================================================= +SocketInfo* Connect(const char* ServerHost, uint32_t ServerPort) +{ + SocketInfo* pSocketInfo = nullptr; + ISocketSubsystem* SocketSubSystem = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM); + TSharedPtr IpAddressFind = SocketSubSystem->GetAddressFromString((TCHAR*)StringCast(static_cast(ServerHost)).Get()); + if(IpAddressFind) + { + TSharedRef IpAddress = IpAddressFind->Clone(); + IpAddress->SetPort(ServerPort); + if (IpAddress->IsValid()) + { + FSocket* pNewSocket = SocketSubSystem->CreateSocket(NAME_Stream, "NetImgui", IpAddress->GetProtocolType()); + if (pNewSocket) + { + pNewSocket->SetNonBlocking(true); + if (pNewSocket->Connect(*IpAddress)) + { + bool bConnectionReady = false; + pNewSocket->WaitForPendingConnection(bConnectionReady, FTimespan::FromSeconds(1.0f)); + if( bConnectionReady ) + { + pSocketInfo = netImguiNew(pNewSocket); + return pSocketInfo; + } + } + } + } + } + netImguiDelete(pSocketInfo); + return nullptr; +} + +//================================================================================================= +// Start waiting for connection request on this socket +//================================================================================================= +SocketInfo* ListenStart(uint32_t ListenPort) +{ + ISocketSubsystem* PlatformSocketSub = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM); + TSharedPtr IpAddress = PlatformSocketSub->GetLocalBindAddr(*GLog); + IpAddress->SetPort(ListenPort); + + FSocket* pNewListenSocket = PlatformSocketSub->CreateSocket(NAME_Stream, "NetImguiListen", IpAddress->GetProtocolType()); + if( pNewListenSocket ) + { + SocketInfo* pListenSocketInfo = netImguiNew(pNewListenSocket); + #if NETIMGUI_FORCE_TCP_LISTEN_BINDING + pNewListenSocket->SetReuseAddr(); + #endif + pNewListenSocket->SetNonBlocking(false); + pNewListenSocket->SetRecvErr(); + if (pNewListenSocket->Bind(*IpAddress)) + { + if (pNewListenSocket->Listen(1)) + { + return pListenSocketInfo; + } + } + netImguiDelete(pListenSocketInfo); + } + return nullptr; +} + +//================================================================================================= +// Establish a new connection to a remote request +//================================================================================================= +SocketInfo* ListenConnect(SocketInfo* pListenSocket) +{ + if (pListenSocket) + { + FSocket* pNewSocket = pListenSocket->mpSocket->Accept(FString("NetImgui")); + if( pNewSocket ) + { + SocketInfo* pSocketInfo = netImguiNew(pNewSocket); + return pSocketInfo; + } + } + return nullptr; +} + +//================================================================================================= +// Close a connection and free allocated object +//================================================================================================= +void Disconnect(SocketInfo* pClientSocket) +{ + netImguiDelete(pClientSocket); +} + +//================================================================================================= +// Return true if data has been received, or there's a connection error +//================================================================================================= +bool DataReceivePending(SocketInfo* pClientSocket) +{ + // Note: return true on a connection error, to exit code looping on the data wait. Will handle error after DataReceive() + uint32 PendingDataSize; + return !pClientSocket || pClientSocket->mpSocket->HasPendingData(PendingDataSize) || (pClientSocket->mpSocket->GetConnectionState() != ESocketConnectionState::SCS_Connected); +} + +//================================================================================================= +// Receive as much as possible a command and keep track of transfer status +//================================================================================================= +void DataReceive(SocketInfo* pClientSocket, NetImgui::Internal::PendingCom& PendingComRcv) +{ + // Invalid command + if( !pClientSocket || !PendingComRcv.pCommand || !pClientSocket->mpSocket || (pClientSocket->mpSocket->GetConnectionState() != ESocketConnectionState::SCS_Connected)){ + PendingComRcv.bError = true; + return; + } + + int32 sizeRcv(0); + if( pClientSocket->mpSocket->Recv( &reinterpret_cast(PendingComRcv.pCommand)[PendingComRcv.SizeCurrent], + static_cast(PendingComRcv.pCommand->mSize-PendingComRcv.SizeCurrent), + sizeRcv, + ESocketReceiveFlags::None) ) + { + PendingComRcv.SizeCurrent += static_cast(sizeRcv); + PendingComRcv.bError |= sizeRcv <= 0; // Error if no data read since DataReceivePending() said there was some available + } + else + { + // Connection error, abort transmission + const ESocketErrors SocketError = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->GetLastErrorCode(); + PendingComRcv.bError = SocketError != SE_NO_ERROR && SocketError != ESocketErrors::SE_EWOULDBLOCK; + } +} + +//================================================================================================= +// Receive as much as possible a command and keep track of transfer status +//================================================================================================= +void DataSend(SocketInfo* pClientSocket, NetImgui::Internal::PendingCom& PendingComSend) +{ + // Invalid command + if( !pClientSocket || !PendingComSend.pCommand || !pClientSocket->mpSocket || (pClientSocket->mpSocket->GetConnectionState() != ESocketConnectionState::SCS_Connected) ){ + PendingComSend.bError = true; + return; + } + + int32 sizeSent = 0; + int32 sizeToSend = PendingComSend.pCommand->mSize-PendingComSend.SizeCurrent; + sizeToSend = sizeToSend > pClientSocket->mSendSize ? pClientSocket->mSendSize : sizeToSend; + + if( pClientSocket->mpSocket->Send( &reinterpret_cast(PendingComSend.pCommand)[PendingComSend.SizeCurrent], + static_cast(sizeToSend), + sizeSent) ) + { + PendingComSend.SizeCurrent += static_cast(sizeSent); + } + else + { + // Connection error, abort transmission + const ESocketErrors SocketError = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->GetLastErrorCode(); + PendingComSend.bError = SocketError != SE_NO_ERROR && SocketError != ESocketErrors::SE_EWOULDBLOCK; + } +} + +}}} // namespace NetImgui::Internal::Network + +#else + +// Prevents Linker warning LNK4221 in Visual Studio (This object file does not define any previously undefined public symbols, so it will not be used by any link operation that consumes this library) +extern int sSuppresstLNK4221_NetImgui_NetworkUE4; +int sSuppresstLNK4221_NetImgui_NetworkUE4(0); + +#endif // #if NETIMGUI_ENABLED && defined(__UNREAL__) diff --git a/Plugins/Cog/Source/ThirdParty/NetImgui/Private/NetImgui_NetworkWin32.cpp b/Plugins/Cog/Source/ThirdParty/NetImgui/Private/NetImgui_NetworkWin32.cpp new file mode 100644 index 0000000..6cf4e91 --- /dev/null +++ b/Plugins/Cog/Source/ThirdParty/NetImgui/Private/NetImgui_NetworkWin32.cpp @@ -0,0 +1,253 @@ +#include "NetImgui_Shared.h" + +#if NETIMGUI_ENABLED && NETIMGUI_WINSOCKET_ENABLED +#include "NetImgui_WarningDisableStd.h" +#include +#include + +#if defined(_MSC_VER) +#pragma comment(lib, "ws2_32") +#endif + +#include "NetImgui_CmdPackets.h" + +namespace NetImgui { namespace Internal { namespace Network +{ +//================================================================================================= +// Wrapper around native socket object and init some socket options +//================================================================================================= +struct SocketInfo +{ + SocketInfo(SOCKET socket) + : mSocket(socket) + { + u_long kNonBlocking = true; + ioctlsocket(mSocket, static_cast(FIONBIO), &kNonBlocking); + + constexpr DWORD kComsNoDelay = 1; + setsockopt(mSocket, SOL_SOCKET, TCP_NODELAY, reinterpret_cast(&kComsNoDelay), sizeof(kComsNoDelay)); + + const int kComsSendBuffer = 2*mSendSizeMax; + setsockopt(mSocket, SOL_SOCKET, SO_SNDBUF, reinterpret_cast(&kComsSendBuffer), sizeof(kComsSendBuffer)); + + //constexpr int kComsRcvBuffer = 1014*1024; + //setsockopt(mSocket, SOL_SOCKET, SO_RCVBUF, reinterpret_cast(&kComsRcvBuffer), sizeof(kComsRcvBuffer)); + } + + SOCKET mSocket; + int mSendSizeMax = 1024*1024; // Limit tx data to avoid socket error on large amount (texture) +}; + +bool Startup() +{ + WSADATA wsa; + if (WSAStartup(MAKEWORD(2,2),&wsa) != 0) + return false; + + return true; +} + +void Shutdown() +{ + WSACleanup(); +} + +//================================================================================================= +// Try establishing a connection to a remote client at given address +//================================================================================================= +SocketInfo* Connect(const char* ServerHost, uint32_t ServerPort) +{ + const timeval kConnectTimeout = {1, 0}; // Waiting 1 seconds before failing connection attempt + u_long kNonBlocking = true; + + SOCKET ClientSocket = socket(AF_INET , SOCK_STREAM , 0); + if(ClientSocket == INVALID_SOCKET) + return nullptr; + + char zPortName[32] = {}; + addrinfo* pResults = nullptr; + SocketInfo* pSocketInfo = nullptr; + NetImgui::Internal::StringFormat(zPortName, "%i", ServerPort); + getaddrinfo(ServerHost, zPortName, nullptr, &pResults); + addrinfo* pResultCur = pResults; + fd_set SocketSet; + + ioctlsocket(ClientSocket, static_cast(FIONBIO), &kNonBlocking); + while( pResultCur && !pSocketInfo ) + { + int Result = connect(ClientSocket, pResultCur->ai_addr, static_cast(pResultCur->ai_addrlen)); + bool Connected = Result != SOCKET_ERROR; + + // Not connected yet, wait some time before bailing out + if( Result == SOCKET_ERROR && WSAGetLastError() == WSAEWOULDBLOCK ) + { + FD_ZERO(&SocketSet); + FD_SET(ClientSocket, &SocketSet); + Result = select(0, nullptr, &SocketSet, nullptr, &kConnectTimeout); + Connected = Result == 1; // when 1 socket ready for write, otherwise it's -1 or 0 + } + + if( Connected ) + { + pSocketInfo = netImguiNew(ClientSocket); + } + + pResultCur = pResultCur->ai_next; + } + freeaddrinfo(pResults); + if( !pSocketInfo ) + { + closesocket(ClientSocket); + } + return pSocketInfo; +} + +//================================================================================================= +// Start waiting for connection request on this socket +//================================================================================================= +SocketInfo* ListenStart(uint32_t ListenPort) +{ + SOCKET ListenSocket = INVALID_SOCKET; + if( (ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != INVALID_SOCKET ) + { + sockaddr_in server; + server.sin_family = AF_INET; + server.sin_addr.s_addr = INADDR_ANY; + server.sin_port = htons(static_cast(ListenPort)); + + #if NETIMGUI_FORCE_TCP_LISTEN_BINDING + constexpr BOOL ReUseAdrValue(true); + setsockopt(ListenSocket, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast(&ReUseAdrValue), sizeof(ReUseAdrValue)); + #endif + if( bind(ListenSocket, reinterpret_cast(&server), sizeof(server)) != SOCKET_ERROR && + listen(ListenSocket, 0) != SOCKET_ERROR ) + { + u_long kIsNonBlocking = false; + ioctlsocket(ListenSocket, static_cast(FIONBIO), &kIsNonBlocking); + return netImguiNew(ListenSocket); + } + closesocket(ListenSocket); + } + return nullptr; +} + +//================================================================================================= +// Establish a new connection to a remote request +//================================================================================================= +SocketInfo* ListenConnect(SocketInfo* ListenSocket) +{ + if( ListenSocket ) + { + sockaddr ClientAddress; + int Size(sizeof(ClientAddress)); + SOCKET ClientSocket = accept(ListenSocket->mSocket, &ClientAddress, &Size) ; + if (ClientSocket != INVALID_SOCKET) + { + return netImguiNew(ClientSocket); + } + } + return nullptr; +} + +//================================================================================================= +// Close a connection and free allocated object +//================================================================================================= +void Disconnect(SocketInfo* pClientSocket) +{ + if( pClientSocket ) + { + shutdown(pClientSocket->mSocket, SD_BOTH); + closesocket(pClientSocket->mSocket); + netImguiDelete(pClientSocket); + } +} + +//================================================================================================= +// Return true if data has been received, or there's a connection error +//================================================================================================= +bool DataReceivePending(SocketInfo* pClientSocket) +{ + const timeval kConnectTimeout = {0, 0}; // No wait time + if( pClientSocket ) + { + fd_set fdSetRead; + fd_set fdSetErr; + FD_ZERO(&fdSetRead); + FD_ZERO(&fdSetErr); + FD_SET(pClientSocket->mSocket, &fdSetRead); + FD_SET(pClientSocket->mSocket, &fdSetErr); + + // Note: return true if data ready or connection error (to exit parent loop waiting on data) + int result = select(0, &fdSetRead, nullptr, &fdSetErr, &kConnectTimeout); + return result != 0; + } + return true; +} + +//================================================================================================= +// Receive as much as possible a command and keep track of transfer status +//================================================================================================= +void DataReceive(SocketInfo* pClientSocket, NetImgui::Internal::PendingCom& PendingComRcv) +{ + // Invalid command + if( !pClientSocket || !PendingComRcv.pCommand || !pClientSocket->mSocket ){ + PendingComRcv.bError = true; + return; + } + + // Receive data from remote connection + int resultRcv = recv( pClientSocket->mSocket, + &reinterpret_cast(PendingComRcv.pCommand)[PendingComRcv.SizeCurrent], + static_cast(PendingComRcv.pCommand->mSize-PendingComRcv.SizeCurrent), + 0); + + // Note: 'DataReceive' is called after pending data has been confirm. + // 0 received data means connection lost + if( resultRcv != SOCKET_ERROR ){ + PendingComRcv.SizeCurrent += static_cast(resultRcv); + PendingComRcv.bError |= resultRcv <= 0; // Error if no data read since DataReceivePending() said there was some available + } + // Connection error, abort transmission + else if( WSAGetLastError() != WSAEWOULDBLOCK ){ + PendingComRcv.bError = true; + } +} + +//================================================================================================= +// Receive as much as possible a command and keep track of transfer status +//================================================================================================= +void DataSend(SocketInfo* pClientSocket, NetImgui::Internal::PendingCom& PendingComSend) +{ + // Invalid command + if( !pClientSocket || !PendingComSend.pCommand || !pClientSocket->mSocket ){ + PendingComSend.bError = true; + return; + } + + // Send data to remote connection + int sizeToSend = static_cast(PendingComSend.pCommand->mSize-PendingComSend.SizeCurrent); + sizeToSend = sizeToSend > pClientSocket->mSendSizeMax ? pClientSocket->mSendSizeMax : sizeToSend; + int resultSent = send( pClientSocket->mSocket, + &reinterpret_cast(PendingComSend.pCommand)[PendingComSend.SizeCurrent], + sizeToSend, + 0); + + if( resultSent != SOCKET_ERROR ){ + PendingComSend.SizeCurrent += static_cast(resultSent); + } + // Connection error, abort transmission + else if( WSAGetLastError() != WSAEWOULDBLOCK ){ + PendingComSend.bError = true; + } +} + +}}} // namespace NetImgui::Internal::Network + +#include "NetImgui_WarningReenable.h" +#else + +// Prevents Linker warning LNK4221 in Visual Studio (This object file does not define any previously undefined public symbols, so it will not be used by any link operation that consumes this library) +extern int sSuppresstLNK4221_NetImgui_NetworkWin23; +int sSuppresstLNK4221_NetImgui_NetworkWin23(0); + +#endif // #if NETIMGUI_ENABLED && NETIMGUI_WINSOCKET_ENABLED diff --git a/Plugins/Cog/Source/ThirdParty/NetImgui/Private/NetImgui_Shared.h b/Plugins/Cog/Source/ThirdParty/NetImgui/Private/NetImgui_Shared.h new file mode 100644 index 0000000..f970e0e --- /dev/null +++ b/Plugins/Cog/Source/ThirdParty/NetImgui/Private/NetImgui_Shared.h @@ -0,0 +1,200 @@ +#pragma once + +//================================================================================================= +// Include NetImgui_Api.h with almost no warning suppression. +// this is to make sure library user does not need to suppress any +#if defined(_MSC_VER) +#pragma warning (disable: 4464) // warning C4464: relative include path contains '..' +#endif + +#ifndef NETIMGUI_INTERNAL_INCLUDE + #define NETIMGUI_INTERNAL_INCLUDE 1 + #include "NetImgui_Api.h" + #undef NETIMGUI_INTERNAL_INCLUDE +#else + #include "NetImgui_Api.h" +#endif + +#if NETIMGUI_ENABLED + +//================================================================================================= +// Include a few standard c++ header, with additional warning suppression +#include "NetImgui_WarningDisableStd.h" +#include +#include +#include +#include +#include "NetImgui_WarningReenable.h" +//================================================================================================= + + +//================================================================================================= +#include "NetImgui_WarningDisable.h" +namespace NetImgui { namespace Internal +{ + +using ComDataType = uint64_t; +constexpr size_t ComDataSize = sizeof(ComDataType); + +//============================================================================= +// All allocations made by netImgui goes through here. +// Relies in ImGui allocator +//============================================================================= +template TType* netImguiNew(Args... args); +template TType* netImguiSizedNew(size_t placementSize); +template void netImguiDelete(TType* pData); +template void netImguiDeleteSafe(TType*& pData); + +class ScopedImguiContext +{ +public: + ScopedImguiContext(ImGuiContext* pNewContext) : mpSavedContext(ImGui::GetCurrentContext()){ ImGui::SetCurrentContext(pNewContext); } + ~ScopedImguiContext() { ImGui::SetCurrentContext(mpSavedContext); } + +protected: + ImGuiContext* mpSavedContext; +}; + +template +class ScopedValue +{ +public: + ScopedValue(TType& ValueRef, TType Value) + : mValueRef(ValueRef) + , mValueRestore(ValueRef) + { + mValueRef = Value; + } + ~ScopedValue() + { + mValueRef = mValueRestore; + } +protected: + TType& mValueRef; + TType mValueRestore; + uint8_t mPadding[sizeof(void*)-(sizeof(TType)%8)]={}; + + // Prevents warning about implicitly delete functions + ScopedValue(const ScopedValue&) = delete; + ScopedValue(const ScopedValue&&) = delete; + void operator=(const ScopedValue&) = delete; +}; + +using ScopedBool = ScopedValue; + +//============================================================================= +// Class to safely exchange a pointer between two threads +//============================================================================= +template +class ExchangePtr +{ +public: + ExchangePtr():mpData(nullptr){} + ~ExchangePtr(); + inline TType* Release(); + inline void Assign(TType*& pNewData); + inline void Free(); + inline bool IsNull()const { return mpData.load() == nullptr; } +private: + std::atomic mpData; + +// Prevents warning about implicitly delete functions +private: + ExchangePtr(const ExchangePtr&) = delete; + ExchangePtr(const ExchangePtr&&) = delete; + void operator=(const ExchangePtr&) = delete; +}; + +//============================================================================= +// Make data serialization easier +//============================================================================= +template +struct OffsetPointer +{ + inline OffsetPointer(); + inline explicit OffsetPointer(TType* pPointer); + inline explicit OffsetPointer(uint64_t offset); + + inline bool IsPointer()const; + inline bool IsOffset()const; + + inline TType* ToPointer(); + inline uint64_t ToOffset(); + inline TType* operator->(); + inline const TType* operator->()const; + inline TType& operator[](size_t index); + inline const TType& operator[](size_t index)const; + + inline TType* Get(); + inline const TType* Get()const; + inline const ComDataType* GetComData()const; + inline uint64_t GetOff()const; + inline void SetPtr(TType* pPointer); + inline void SetComDataPtr(ComDataType* pPointer); + inline void SetOff(uint64_t offset); + +private: + union + { + uint64_t mOffset; + TType* mPointer; + }; +}; + +//============================================================================= +//============================================================================= +template +class Ringbuffer +{ +public: + Ringbuffer():mPosCur(0),mPosLast(0){} + void AddData(const TType* pData, size_t& count); + bool ReadData(TType* pData); +private: + TType mBuffer[TCount] = {0}; + std::atomic_uint64_t mPosCur; + std::atomic_uint64_t mPosLast; + +// Prevents warning about implicitly delete functions +private: + Ringbuffer(const Ringbuffer&) = delete; + Ringbuffer(const Ringbuffer&&) = delete; + void operator=(const Ringbuffer&) = delete; +}; + +template +constexpr std::size_t ArrayCount(T const (&)[N]) noexcept +{ + return N; +} + +//============================================================================= +//============================================================================= +template +inline void StringCopy(char (&output)[charCount], const char* pSrc, size_t srcCharCount=0xFFFFFFFE); + +template +int StringFormat(char(&output)[charCount], char const* const format, ...); + +//============================================================================= +// Get the (value / Denominator) rounded up to the next int value big enough +//============================================================================= +template +IntType DivUp(IntType Value, IntType Denominator); + +//============================================================================= +// Get the rounded up value +//============================================================================= +template +IntType RoundUp(IntType Value, IntType Round); + +inline uint64_t TextureCastFromID(ImTextureID textureID); +inline ImTextureID TextureCastFromPtr(void* pTexture); +inline ImTextureID TextureCastFromUInt(uint64_t textureID); + +}} //namespace NetImgui::Internal + +#include "NetImgui_Shared.inl" +#include "NetImgui_WarningReenable.h" + +#endif //NETIMGUI_ENABLED diff --git a/Plugins/Cog/Source/ThirdParty/NetImgui/Private/NetImgui_Shared.inl b/Plugins/Cog/Source/ThirdParty/NetImgui/Private/NetImgui_Shared.inl new file mode 100644 index 0000000..6907203 --- /dev/null +++ b/Plugins/Cog/Source/ThirdParty/NetImgui/Private/NetImgui_Shared.inl @@ -0,0 +1,319 @@ +#pragma once + +#include +#include + +namespace NetImgui { namespace Internal +{ + +template +TType* netImguiNew(Args... args) +{ + return new( ImGui::MemAlloc(sizeof(TType)) ) TType(args...); +} + +template +TType* netImguiSizedNew(size_t placementSize) +{ + return new( ImGui::MemAlloc(placementSize > sizeof(TType) ? placementSize : sizeof(TType)) ) TType(); +} + +template +void netImguiDelete(TType* pData) +{ + if( pData ) + { + pData->~TType(); + ImGui::MemFree(pData); + } +} + +template +void netImguiDeleteSafe(TType*& pData) +{ + netImguiDelete(pData); + pData = nullptr; +} + +//============================================================================= +// Acquire ownership of the resource +//============================================================================= +template +TType* ExchangePtr::Release() +{ + return mpData.exchange(nullptr); +} + +//----------------------------------------------------------------------------- +// Take ownership of the provided data. +// If there's a previous unclaimed pointer to some data, release it +//----------------------------------------------------------------------------- +template +void ExchangePtr::Assign(TType*& pNewData) +{ + netImguiDelete( mpData.exchange(pNewData) ); + pNewData = nullptr; +} + +template +void ExchangePtr::Free() +{ + TType* pNull(nullptr); + Assign(pNull); +} + +template +ExchangePtr::~ExchangePtr() +{ + Free(); +} + +//============================================================================= +// +//============================================================================= +template +OffsetPointer::OffsetPointer() +: mOffset(0) +{ + SetOff(0); +} + +template +OffsetPointer::OffsetPointer(TType* pPointer) +{ + SetPtr(pPointer); +} + +template +OffsetPointer::OffsetPointer(uint64_t offset) +{ + SetOff(offset); +} + +template +void OffsetPointer::SetPtr(TType* pPointer) +{ + mOffset = 0; // Remove 'offset flag' that can be left active on non 64bits pointer + mPointer = pPointer; +} + +template +void OffsetPointer::SetComDataPtr(ComDataType* pPointer) +{ + SetPtr(reinterpret_cast(pPointer)); +} + +template +void OffsetPointer::SetOff(uint64_t offset) +{ + mOffset = offset | 0x0000000000000001u; +} + +template +uint64_t OffsetPointer::GetOff()const +{ + return mOffset & ~0x0000000000000001u; +} + +template +bool OffsetPointer::IsOffset()const +{ + return (mOffset & 0x0000000000000001u) != 0; +} + +template +bool OffsetPointer::IsPointer()const +{ + return !IsOffset(); +} + +template +TType* OffsetPointer::ToPointer() +{ + assert(IsOffset()); + SetPtr( reinterpret_cast( reinterpret_cast(&mPointer) + GetOff() ) ); + return mPointer; +} + +template +uint64_t OffsetPointer::ToOffset() +{ + assert(IsPointer()); + SetOff( reinterpret_cast(mPointer) - reinterpret_cast(&mPointer) ); + return mOffset; +} + +template +TType* OffsetPointer::operator->() +{ + assert(IsPointer()); + return mPointer; +} + +template +const TType* OffsetPointer::operator->()const +{ + assert(IsPointer()); + return mPointer; +} + +template +TType* OffsetPointer::Get() +{ + assert(IsPointer()); + return mPointer; +} + +template +const TType* OffsetPointer::Get()const +{ + assert(IsPointer()); + return mPointer; +} + +template +const ComDataType* OffsetPointer::GetComData()const +{ + return reinterpret_cast(Get()); +} + +template +TType& OffsetPointer::operator[](size_t index) +{ + assert(IsPointer()); + return mPointer[index]; +} + +template +const TType& OffsetPointer::operator[](size_t index)const +{ + assert(IsPointer()); + return mPointer[index]; +} + +//============================================================================= +template +void Ringbuffer::AddData(const TType* pData, size_t& count) +//============================================================================= +{ + size_t i(0); + while (i < count && (mPosLast - mPosCur < TCount)) { + mBuffer[mPosLast % TCount] = pData[i]; + mPosLast++; + i++; + } + count = i; +} + +//============================================================================= +template +bool Ringbuffer::ReadData(TType* pData) +//============================================================================= +{ + if (mPosCur < mPosLast) + { + *pData = mBuffer[mPosCur % TCount]; + mPosCur++; + return true; + } + return false; +} + + +//============================================================================= +// The _s string functions are a mess. There's really no way to do this right +// in a cross-platform way. Best solution I've found is to set just use +// strncpy, infer the buffer length, and null terminate. Still need to suppress +// the warning on Windows. +// See https://randomascii.wordpress.com/2013/04/03/stop-using-strncpy-already/ +// and many other discussions online on the topic. +//============================================================================= +template +void StringCopy(char (&output)[charCount], const char* pSrc, size_t srcCharCount) +{ +#if defined(__clang__) + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wdeprecated-declarations" +#elif defined(_MSC_VER) + #pragma warning (push) + #pragma warning (disable: 4996) // warning C4996: 'strncpy': This function or variable may be unsafe. +#endif + + size_t charToCopyCount = charCount < srcCharCount + 1 ? charCount : srcCharCount + 1; + strncpy(output, pSrc, charToCopyCount - 1); + output[charCount - 1] = 0; + +#if defined(_MSC_VER) && defined(__clang__) + #pragma clang diagnostic pop +#elif defined(_MSC_VER) + #pragma warning (pop) +#endif +} + +template +int StringFormat(char(&output)[charCount], char const* const format, ...) +{ +#if defined(__clang__) + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wformat-nonliteral" +#endif + + va_list args; + va_start(args, format); + int w = vsnprintf(output, charCount, format, args); + va_end(args); + output[charCount - 1] = 0; + return w; + +#if defined(__clang__) + #pragma clang diagnostic pop +#endif +} + +//============================================================================= +//============================================================================= +template +IntType DivUp(IntType Value, IntType Denominator) +{ + return (Value + Denominator - 1) / Denominator; +} + +template +IntType RoundUp(IntType Value, IntType Round) +{ + return DivUp(Value, Round) * Round; +} + +union TextureCastHelperUnion +{ + ImTextureID TextureID; + uint64_t TextureUint; + const void* TexturePtr; +}; + +uint64_t TextureCastFromID(ImTextureID textureID) +{ + TextureCastHelperUnion textureUnion; + textureUnion.TextureUint = 0; + textureUnion.TextureID = textureID; + return textureUnion.TextureUint; +} + +ImTextureID TextureCastFromPtr(void* pTexture) +{ + TextureCastHelperUnion textureUnion; + textureUnion.TextureUint = 0; + textureUnion.TexturePtr = pTexture; + return textureUnion.TextureID; +} + +#ifndef IS_NETIMGUISERVER +ImTextureID TextureCastFromUInt(uint64_t textureID) +{ + TextureCastHelperUnion textureUnion; + textureUnion.TextureUint = textureID; + return textureUnion.TextureID; +} +#endif + +}} //namespace NetImgui::Internal diff --git a/Plugins/Cog/Source/ThirdParty/NetImgui/Private/NetImgui_WarningDisable.h b/Plugins/Cog/Source/ThirdParty/NetImgui/Private/NetImgui_WarningDisable.h new file mode 100644 index 0000000..125f391 --- /dev/null +++ b/Plugins/Cog/Source/ThirdParty/NetImgui/Private/NetImgui_WarningDisable.h @@ -0,0 +1,33 @@ +#pragma once +// +// Deactivate a few warnings to allow internal netImgui code to compile +// with 'Warning as error' and '-Wall' compile actions enabled +// + +//================================================================================================= +// Clang +//================================================================================================= +#if defined (__clang__) + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wc++98-compat-pedantic" + #pragma clang diagnostic ignored "-Wmissing-prototypes" + +//================================================================================================= +// Visual Studio warnings +//================================================================================================= +#elif defined(_MSC_VER) + #pragma warning (disable: 5032) // detected #pragma warning(push) with no corresponding #pragma warning(pop) + + #pragma warning (push) + #pragma warning (disable: 4365) // conversion from 'long' to 'unsigned int', signed/unsigned mismatch for + #pragma warning (disable: 4464) // relative include path contains '..' + #pragma warning (disable: 4514) // unreferenced inline function has been removed + #pragma warning (disable: 4577) // 'noexcept' used with no exception handling mode specified; termination on exception is not guaranteed. Specify + #pragma warning (disable: 4710) // 'xxx': function not inlined + #pragma warning (disable: 4711) // function 'xxx' selected for automatic inline expansion + #pragma warning (disable: 4826) // Conversion from 'TType *' to 'uint64_t' is sign-extended. This may cause unexpected runtime behavior. + #pragma warning (disable: 5031) // #pragma warning(pop): likely mismatch, popping warning state pushed in different file + #pragma warning (disable: 5045) // Compiler will insert Spectre mitigation for memory load if / Qspectre switch specified + #pragma warning (disable: 5264) // 'xxx': 'const' variable is not used + +#endif diff --git a/Plugins/Cog/Source/ThirdParty/NetImgui/Private/NetImgui_WarningDisableImgui.h b/Plugins/Cog/Source/ThirdParty/NetImgui/Private/NetImgui_WarningDisableImgui.h new file mode 100644 index 0000000..ec16f63 --- /dev/null +++ b/Plugins/Cog/Source/ThirdParty/NetImgui/Private/NetImgui_WarningDisableImgui.h @@ -0,0 +1,33 @@ +#pragma once +// +// Deactivate a few warnings to allow Imgui header includes, +// without generating warnings in '-Wall' compile actions enabled +// + +//================================================================================================= +// Clang +//================================================================================================= +#if defined (__clang__) + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wunknown-warning-option" + #pragma clang diagnostic ignored "-Wc++98-compat-pedantic" + #pragma clang diagnostic ignored "-Wnonportable-include-path" // Sharpmake convert include path to lowercase, avoid warning + #pragma clang diagnostic ignored "-Wreserved-identifier" // Enuma values using '__' or member starting with '_' in imgui.h + +//================================================================================================= +// Visual Studio warnings +//================================================================================================= +#elif defined(_MSC_VER) + #pragma warning (push) + #pragma warning (disable: 4514) // 'xxx': unreferenced inline function has been removed + #pragma warning (disable: 4365) // '=': conversion from 'ImGuiTabItemFlags' to 'ImGuiID', signed/unsigned mismatch + #pragma warning (disable: 4710) // 'xxx': function not inlined + #pragma warning (disable: 4820) // 'xxx': 'yyy' bytes padding added after data member 'zzz' + #pragma warning (disable: 5031) // #pragma warning(pop): likely mismatch, popping warning state pushed in different file + #pragma warning (disable: 5045) // Compiler will insert Spectre mitigation for memory load if /Qspectre switch specified +#if _MSC_VER >= 1920 + #pragma warning (disable: 5219) // implicit conversion from 'int' to 'float', possible loss of data +#endif + #pragma warning (disable: 26495) // Code Analysis warning : Variable 'ImGuiStorage::ImGuiStoragePair::::val_p' is uninitialized. Always initialize a member variable (type.6). +#endif + diff --git a/Plugins/Cog/Source/ThirdParty/NetImgui/Private/NetImgui_WarningDisableStd.h b/Plugins/Cog/Source/ThirdParty/NetImgui/Private/NetImgui_WarningDisableStd.h new file mode 100644 index 0000000..b3ded98 --- /dev/null +++ b/Plugins/Cog/Source/ThirdParty/NetImgui/Private/NetImgui_WarningDisableStd.h @@ -0,0 +1,25 @@ +#pragma once +// +// Deactivate a few more warnings to allow standard header includes, +// without generating warnings in '-Wall' compile actions enabled +// + +#include "NetImgui_WarningDisable.h" + +//================================================================================================= +// Clang +//================================================================================================= +#if defined (__clang__) + + +//================================================================================================= +// Visual Studio warnings +//================================================================================================= +#elif defined(_MSC_VER) + #pragma warning (disable: 4061) // enumerator xxx in switch of enum yyy is not explicitly handled by a case label (d3d11.h) + #pragma warning (disable: 4548) // expression before comma has no effect; expected expression with side - effect (malloc.h VS2017) + #pragma warning (disable: 4668) // xxx is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' (winsock2.h) + #pragma warning (disable: 4574) // xxx is defined to be '0': did you mean to use yyy (winsock2.h VS2017) + #pragma warning (disable: 4820) // xxx : yyy bytes padding added after data member zzz + +#endif diff --git a/Plugins/Cog/Source/ThirdParty/NetImgui/Private/NetImgui_WarningReenable.h b/Plugins/Cog/Source/ThirdParty/NetImgui/Private/NetImgui_WarningReenable.h new file mode 100644 index 0000000..232ebc7 --- /dev/null +++ b/Plugins/Cog/Source/ThirdParty/NetImgui/Private/NetImgui_WarningReenable.h @@ -0,0 +1,18 @@ + +#pragma once + +//================================================================================================= +// Clang +//================================================================================================= +#if defined(__clang__) + #pragma clang diagnostic pop + + +//================================================================================================= +// Visual Studio warnings +//================================================================================================= +#elif defined(_MSC_VER) + #pragma warning(pop) +#endif + + diff --git a/Plugins/CogAI/Source/CogAI/Private/CogAIWindow_BehaviorTree.cpp b/Plugins/CogAI/Source/CogAI/Private/CogAIWindow_BehaviorTree.cpp index 4afbe36..278cdab 100644 --- a/Plugins/CogAI/Source/CogAI/Private/CogAIWindow_BehaviorTree.cpp +++ b/Plugins/CogAI/Source/CogAI/Private/CogAIWindow_BehaviorTree.cpp @@ -269,68 +269,66 @@ void FCogAIWindow_BehaviorTree::RenderNode(UBehaviorTreeComponent& BehaviorTreeC //------------------------ // Tooltip //------------------------ - if (ImGui::IsItemHovered()) + if (FCogWindowWidgets::BeginItemTableTooltip()) { - FCogWindowWidgets::BeginTableTooltip(); + if (ImGui::BeginTable("Effect", 2, ImGuiTableFlags_Borders)) + { + ImGui::TableSetupColumn("Property"); + ImGui::TableSetupColumn("Value", ImGuiTableColumnFlags_WidthStretch); - if (ImGui::BeginTable("Effect", 2, ImGuiTableFlags_Borders)) - { - ImGui::TableSetupColumn("Property"); - ImGui::TableSetupColumn("Value", ImGuiTableColumnFlags_WidthStretch); + const ImVec4 TextColor(1.0f, 1.0f, 1.0f, 0.5f); - const ImVec4 TextColor(1.0f, 1.0f, 1.0f, 0.5f); + //------------------------ + // Name + //------------------------ + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TextColored(TextColor, "Name"); + ImGui::TableNextColumn(); + ImGui::Text("%s", NodeName.Get()); - //------------------------ - // Name - //------------------------ - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::TextColored(TextColor, "Name"); - ImGui::TableNextColumn(); - ImGui::Text("%s", NodeName.Get()); + //------------------------ + // Static Description + //------------------------ + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TextColored(TextColor, "Description"); + ImGui::TableNextColumn(); + ImGui::Text("%s", TCHAR_TO_ANSI(*Node->GetStaticDescription())); - //------------------------ - // Static Description - //------------------------ - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::TextColored(TextColor, "Description"); - ImGui::TableNextColumn(); - ImGui::Text("%s", TCHAR_TO_ANSI(*Node->GetStaticDescription())); + //------------------------ + // Runtime Values + //------------------------ + TArray RunTimeValues; + uint8* NodeMemory = BehaviorTreeComponent.GetNodeMemory(Node, BehaviorTreeComponent.GetActiveInstanceIdx()); + Node->DescribeRuntimeValues(BehaviorTreeComponent, NodeMemory, EBTDescriptionVerbosity::Detailed, RunTimeValues); - //------------------------ - // Runtime Values - //------------------------ - TArray RunTimeValues; - uint8* NodeMemory = BehaviorTreeComponent.GetNodeMemory(Node, BehaviorTreeComponent.GetActiveInstanceIdx()); - Node->DescribeRuntimeValues(BehaviorTreeComponent, NodeMemory, EBTDescriptionVerbosity::Detailed, RunTimeValues); + for (const FString& RuntimeValue : RunTimeValues) + { + ImGui::TableNextRow(); - for (const FString& RuntimeValue : RunTimeValues) - { - ImGui::TableNextRow(); + FString Left, Right; + if (RuntimeValue.Split(TEXT(": "), &Left, &Right)) + { + ImGui::TableNextColumn(); + ImGui::TextColored(TextColor, "%s", TCHAR_TO_ANSI(*Left)); - FString Left, Right; - if (RuntimeValue.Split(TEXT(": "), &Left, &Right)) - { - ImGui::TableNextColumn(); - ImGui::TextColored(TextColor, "%s", TCHAR_TO_ANSI(*Left)); + ImGui::TableNextColumn(); + ImGui::Text("%s", TCHAR_TO_ANSI(*Right)); + } + else + { + ImGui::TableNextColumn(); + ImGui::TextColored(TextColor, "Value"); + ImGui::TableNextColumn(); + ImGui::Text("%s", TCHAR_TO_ANSI(*RuntimeValue)); + } + } - ImGui::TableNextColumn(); - ImGui::Text("%s", TCHAR_TO_ANSI(*Right)); - } - else - { - ImGui::TableNextColumn(); - ImGui::TextColored(TextColor, "Value"); - ImGui::TableNextColumn(); - ImGui::Text("%s", TCHAR_TO_ANSI(*RuntimeValue)); - } - } + ImGui::EndTable(); + } - ImGui::EndTable(); - } - - FCogWindowWidgets::EndTableTooltip(); + FCogWindowWidgets::EndItemTableTooltip(); } //------------------------ diff --git a/Plugins/CogAbility/Source/CogAbility/CogAbility.Build.cs b/Plugins/CogAbility/Source/CogAbility/CogAbility.Build.cs index 16e7478..b81d069 100644 --- a/Plugins/CogAbility/Source/CogAbility/CogAbility.Build.cs +++ b/Plugins/CogAbility/Source/CogAbility/CogAbility.Build.cs @@ -1,5 +1,4 @@ using UnrealBuildTool; -using UnrealBuildTool.Rules; public class CogAbility : ModuleRules { @@ -26,10 +25,11 @@ public class CogAbility : ModuleRules "CogImgui", "CogCommon", "CogDebug", + "CogEngine", "CogWindow", "GameplayAbilities", "GameplayTags", - "NetCore", + "NetCore", } ); diff --git a/Plugins/CogAbility/Source/CogAbility/Private/CogAbilityCheat_Execution_ApplyEffect.cpp b/Plugins/CogAbility/Source/CogAbility/Private/CogAbilityCheat_Execution_ApplyEffect.cpp new file mode 100644 index 0000000..1636fee --- /dev/null +++ b/Plugins/CogAbility/Source/CogAbility/Private/CogAbilityCheat_Execution_ApplyEffect.cpp @@ -0,0 +1,111 @@ +#include "CogAbilityCheat_Execution_ApplyEffect.h" + +#include "CogAbilityDataAsset.h" + +#include "AbilitySystemComponent.h" +#include "AbilitySystemGlobals.h" +#include "CogAbilityConfig_Alignment.h" +#include "CogImguiHelper.h" +#include "CogWindow.h" + +//-------------------------------------------------------------------------------------------------------------------------- +void UCogAbilityCheat_Execution_ApplyEffect::Execute_Implementation(const AActor* Instigator, const TArray& Targets) const +{ + UAbilitySystemComponent* DefaultInstigatorAbilitySystem = UAbilitySystemGlobals::GetAbilitySystemComponentFromActor(Instigator, true); + + for (AActor* Target : Targets) + { + UAbilitySystemComponent* TargetAbilitySystem = UAbilitySystemGlobals::GetAbilitySystemComponentFromActor(Target, true); + if (TargetAbilitySystem == nullptr) + { + UE_LOG(LogCogImGui, Warning, TEXT("ACogAbilityReplicator::Server_ApplyCheat_Implementation | Target:%s | Invalid Target AbilitySystem"), *GetNameSafe(Target)); + continue; + } + + if (TargetAbilitySystem->GetGameplayEffectCount(Effect, nullptr) > 0) + { + TargetAbilitySystem->RemoveActiveGameplayEffectBySourceEffect(Effect, nullptr); + } + else + { + //----------------------------------------------------------------------------------- + // When executing a cheat directly on the game server, there is not an obvious + // local player to use as the instigator. Instead, we use the target ability system. + //----------------------------------------------------------------------------------- + UAbilitySystemComponent* InstigatorAbilitySystem = (DefaultInstigatorAbilitySystem != nullptr) ? DefaultInstigatorAbilitySystem : TargetAbilitySystem; + + FGameplayEffectContextHandle ContextHandle = InstigatorAbilitySystem->MakeEffectContext(); + ContextHandle.AddSourceObject(InstigatorAbilitySystem); + FGameplayEffectSpecHandle SpecHandle = InstigatorAbilitySystem->MakeOutgoingSpec(Effect, 1, ContextHandle); + + if (const FGameplayEffectSpec* EffectSpec = SpecHandle.Data.Get()) + { + FHitResult HitResult; + HitResult.HitObjectHandle = FActorInstanceHandle(Target); + HitResult.Normal = FVector::ForwardVector; + HitResult.ImpactNormal = FVector::ForwardVector; + HitResult.Location = Target->GetActorLocation(); + HitResult.ImpactPoint = Target->GetActorLocation(); + HitResult.PhysMaterial = nullptr; + ContextHandle.AddHitResult(HitResult, true); + + InstigatorAbilitySystem->ApplyGameplayEffectSpecToTarget(*EffectSpec, TargetAbilitySystem); + } + } + } +} + +//-------------------------------------------------------------------------------------------------------------------------- +ECogEngineCheat_ActiveState UCogAbilityCheat_Execution_ApplyEffect::IsActiveOnTargets_Implementation(const TArray& Targets) const +{ + if (Effect == nullptr) + { + return ECogEngineCheat_ActiveState::Inactive; + } + + int32 NumWithEffect = 0; + for (const AActor* Target : Targets) + { + const UAbilitySystemComponent* AbilitySystem = UAbilitySystemGlobals::GetAbilitySystemComponentFromActor(Target, true); + if (AbilitySystem == nullptr) + { + continue; + } + + const int32 Count = AbilitySystem->GetGameplayEffectCount(Effect, nullptr); + if (Count > 0) + { + NumWithEffect++; + } + } + + if (NumWithEffect == 0) + { + return ECogEngineCheat_ActiveState::Inactive; + } + + if (NumWithEffect == Targets.Num()) + { + return ECogEngineCheat_ActiveState::Active; + } + + return ECogEngineCheat_ActiveState::Partial; +} + + +//-------------------------------------------------------------------------------------------------------------------------- +bool UCogAbilityCheat_Execution_ApplyEffect::GetColor(const FCogWindow& InCallingWindow, FLinearColor& OutColor) const +{ + if (Effect == nullptr) + { return false; } + + const UGameplayEffect* GameplayEffect = Effect->GetDefaultObject(); + if (GameplayEffect == nullptr) + { return false; } + + const UCogAbilityConfig_Alignment* Config = InCallingWindow.GetConfig(); + const UCogAbilityDataAsset* Asset = InCallingWindow.GetAsset(); + + OutColor = Config->GetEffectColor(Asset, *GameplayEffect); + return true; +} diff --git a/Plugins/CogAbility/Source/CogAbility/Private/CogAbilityReplicator.cpp b/Plugins/CogAbility/Source/CogAbility/Private/CogAbilityReplicator.cpp index a84d8f7..213f803 100644 --- a/Plugins/CogAbility/Source/CogAbility/Private/CogAbilityReplicator.cpp +++ b/Plugins/CogAbility/Source/CogAbility/Private/CogAbilityReplicator.cpp @@ -3,6 +3,7 @@ #include "AbilitySystemComponent.h" #include "AbilitySystemGlobals.h" #include "CogAbilityDataAsset.h" +#include "CogImguiHelper.h" #include "CogWindowHelper.h" #include "Components/SceneComponent.h" #include "Engine/World.h" @@ -30,8 +31,10 @@ ACogAbilityReplicator* ACogAbilityReplicator::GetFirstReplicator(const UWorld& W { for (TActorIterator It(&World, StaticClass()); It; ++It) { - ACogAbilityReplicator* Replicator = *It; - return Replicator; + if (ACogAbilityReplicator* Replicator = *It) + { + return Replicator; + } } return nullptr; @@ -95,17 +98,14 @@ void ACogAbilityReplicator::EndPlay(const EEndPlayReason::Type EndPlayReason) //-------------------------------------------------------------------------------------------------------------------------- void ACogAbilityReplicator::Server_ApplyCheat_Implementation(const AActor* CheatInstigator, const TArray& Targets, const FCogAbilityCheat& Cheat) const { - UAbilitySystemComponent* InstigatorAbilitySystem = UAbilitySystemGlobals::GetAbilitySystemComponentFromActor(CheatInstigator, true); - if (InstigatorAbilitySystem == nullptr) - { - return; - } + UAbilitySystemComponent* DefaultInstigatorAbilitySystem = UAbilitySystemGlobals::GetAbilitySystemComponentFromActor(CheatInstigator, true); for (AActor* Target : Targets) { UAbilitySystemComponent* TargetAbilitySystem = UAbilitySystemGlobals::GetAbilitySystemComponentFromActor(Target, true); if (TargetAbilitySystem == nullptr) { + UE_LOG(LogCogImGui, Warning, TEXT("ACogAbilityReplicator::Server_ApplyCheat_Implementation | Target:%s | Invalid Target AbilitySystem"), *GetNameSafe(Target)); continue; } @@ -115,6 +115,12 @@ void ACogAbilityReplicator::Server_ApplyCheat_Implementation(const AActor* Cheat } else { + //----------------------------------------------------------------------------------- + // When executing a cheat directly on the game server, there is not an obvious + // local player to use as the instigator. Instead, we use the target ability system. + //----------------------------------------------------------------------------------- + UAbilitySystemComponent* InstigatorAbilitySystem = (DefaultInstigatorAbilitySystem != nullptr) ? DefaultInstigatorAbilitySystem : TargetAbilitySystem; + FGameplayEffectContextHandle ContextHandle = InstigatorAbilitySystem->MakeEffectContext(); ContextHandle.AddSourceObject(InstigatorAbilitySystem); FGameplayEffectSpecHandle SpecHandle = InstigatorAbilitySystem->MakeOutgoingSpec(Cheat.Effect, 1, ContextHandle); diff --git a/Plugins/CogAbility/Source/CogAbility/Private/CogAbilityWindow_Abilities.cpp b/Plugins/CogAbility/Source/CogAbility/Private/CogAbilityWindow_Abilities.cpp index 60c5b91..2788e86 100644 --- a/Plugins/CogAbility/Source/CogAbility/Private/CogAbilityWindow_Abilities.cpp +++ b/Plugins/CogAbility/Source/CogAbility/Private/CogAbilityWindow_Abilities.cpp @@ -155,15 +155,13 @@ void FCogAbilityWindow_Abilities::RenderAbilitiesMenu(AActor* Selection) ImGui::Separator(); - RenderAbilitiesMenuFilters(); - - ImGui::Separator(); + ImGui::Checkbox("Sort by Name", &Config->SortByName); RenderAbilitiesMenuColorSettings(); ImGui::Separator(); - if (ImGui::MenuItem("Reset")) + if (ImGui::MenuItem("Reset Settings")) { ResetConfig(); } @@ -171,6 +169,12 @@ void FCogAbilityWindow_Abilities::RenderAbilitiesMenu(AActor* Selection) ImGui::EndMenu(); } + if (ImGui::BeginMenu("Filters")) + { + RenderAbilitiesMenuFilters(); + ImGui::EndMenu(); + } + FCogWindowWidgets::SearchBar(Filter); ImGui::EndMenuBar(); @@ -180,11 +184,10 @@ void FCogAbilityWindow_Abilities::RenderAbilitiesMenu(AActor* Selection) //-------------------------------------------------------------------------------------------------------------------------- void FCogAbilityWindow_Abilities::RenderAbilitiesMenuFilters() { - ImGui::Checkbox("Sort by Name", &Config->SortByName); - ImGui::Checkbox("Show Active", &Config->ShowActive); - ImGui::Checkbox("Show Inactive", &Config->ShowInactive); - ImGui::Checkbox("Show Pressed", &Config->ShowPressed); - ImGui::Checkbox("Show Blocked", &Config->ShowBlocked); + ImGui::Checkbox("Active", &Config->ShowActive); + ImGui::Checkbox("Inactive", &Config->ShowInactive); + ImGui::Checkbox("Pressed", &Config->ShowPressed); + ImGui::Checkbox("Blocked", &Config->ShowBlocked); } //-------------------------------------------------------------------------------------------------------------------------- @@ -201,13 +204,13 @@ void FCogAbilityWindow_Abilities::RenderAbilitiesMenuColorSettings() //-------------------------------------------------------------------------------------------------------------------------- void FCogAbilityWindow_Abilities::RenderAbilityActivation(FGameplayAbilitySpec& Spec) { - FCogWindowWidgets::PushStyleCompact(); - bool IsActive = Spec.IsActive(); - if (ImGui::Checkbox("##Activation", &IsActive)) - { - AbilityHandleToActivate = Spec.Handle; - } - FCogWindowWidgets::PopStyleCompact(); + FCogWindowWidgets::PushStyleCompact(); + bool IsActive = Spec.IsActive(); + if (ImGui::Checkbox("##Activation", &IsActive)) + { + AbilityHandleToActivate = Spec.Handle; + } + FCogWindowWidgets::PopStyleCompact(); } //-------------------------------------------------------------------------------------------------------------------------- @@ -216,15 +219,15 @@ void FCogAbilityWindow_Abilities::RenderAbilitiesTableAbilityName(UAbilitySystem const ImVec4 Color = GetAbilityColor(AbilitySystemComponent, Spec); ImGui::PushStyleColor(ImGuiCol_Text, Color); - if (ImGui::Selectable(TCHAR_TO_ANSI(*GetAbilityName(Ability)), SelectedIndex == Index, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowOverlap | ImGuiSelectableFlags_AllowDoubleClick)) - { - SelectedIndex = Index; + if (ImGui::Selectable(TCHAR_TO_ANSI(*GetAbilityName(Ability)), SelectedIndex == Index, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowOverlap | ImGuiSelectableFlags_AllowDoubleClick)) + { + SelectedIndex = Index; - if (ImGui::IsMouseDoubleClicked(0)) - { - OpenAbility(Spec.Handle); - } - } + if (ImGui::IsMouseDoubleClicked(0)) + { + OpenAbilityDetails(Spec.Handle); + } + } ImGui::PopStyleColor(1); } @@ -232,26 +235,26 @@ void FCogAbilityWindow_Abilities::RenderAbilitiesTableAbilityName(UAbilitySystem //-------------------------------------------------------------------------------------------------------------------------- void FCogAbilityWindow_Abilities::RenderAbilitiesTableAbilityBlocking(UAbilitySystemComponent& AbilitySystemComponent, UGameplayAbility* Ability) { - if (Ability->DoesAbilitySatisfyTagRequirements(AbilitySystemComponent) == false) - { - FGameplayTagContainer OwnedGameplayTags; - AbilitySystemComponent.GetOwnedGameplayTags(OwnedGameplayTags); + if (Ability->DoesAbilitySatisfyTagRequirements(AbilitySystemComponent) == false) + { + FGameplayTagContainer OwnedGameplayTags; + AbilitySystemComponent.GetOwnedGameplayTags(OwnedGameplayTags); - if (const FGameplayTagContainer* ActivationBlockedTags = &PRIVATE_ACCESS_PTR(Ability, GameplayAbility_ActivationBlockedTags)) - { - FGameplayTagContainer AllBlockingTags; - AbilitySystemComponent.GetBlockedAbilityTags(AllBlockingTags); - AllBlockingTags.AppendTags(OwnedGameplayTags); + if (const FGameplayTagContainer* ActivationBlockedTags = &PRIVATE_ACCESS_PTR(Ability, GameplayAbility_ActivationBlockedTags)) + { + FGameplayTagContainer AllBlockingTags; + AbilitySystemComponent.GetBlockedAbilityTags(AllBlockingTags); + AllBlockingTags.AppendTags(OwnedGameplayTags); - FCogAbilityHelper::RenderTagContainer(*ActivationBlockedTags, AllBlockingTags, false, true, true, ImVec4(0, 0, 0, 0), FCogImguiHelper::ToImVec4(Config->BlockedTagsColor)); - } + FCogAbilityHelper::RenderTagContainer(*ActivationBlockedTags, AllBlockingTags, false, true, true, ImVec4(0, 0, 0, 0), FCogImguiHelper::ToImVec4(Config->BlockedTagsColor)); + } - ImGui::SameLine(); - if (const FGameplayTagContainer* ActivationRequiredTags = &PRIVATE_ACCESS_PTR(Ability, GameplayAbility_ActivationRequiredTags)) - { - FCogAbilityHelper::RenderTagContainer(*ActivationRequiredTags, OwnedGameplayTags, true, true, true, ImVec4(0, 0, 0, 0), FCogImguiHelper::ToImVec4(Config->BlockedTagsColor)); - } - } + ImGui::SameLine(); + if (const FGameplayTagContainer* ActivationRequiredTags = &PRIVATE_ACCESS_PTR(Ability, GameplayAbility_ActivationRequiredTags)) + { + FCogAbilityHelper::RenderTagContainer(*ActivationRequiredTags, OwnedGameplayTags, true, true, true, ImVec4(0, 0, 0, 0), FCogImguiHelper::ToImVec4(Config->BlockedTagsColor)); + } + } } //-------------------------------------------------------------------------------------------------------------------------- @@ -259,7 +262,7 @@ void FCogAbilityWindow_Abilities::RenderAbilitiesTable(UAbilitySystemComponent& { TArray& Abilities = AbilitySystemComponent.GetActivatableAbilities(); - TArray FitleredAbilities; + TArray FilteredAbilities; for (FGameplayAbilitySpec& Spec : Abilities) { @@ -271,8 +274,8 @@ void FCogAbilityWindow_Abilities::RenderAbilitiesTable(UAbilitySystemComponent& if (ShouldShowAbility(AbilitySystemComponent, Spec, Ability) == false) { - continue; - } + continue; + } const auto AbilityName = StringCast(*GetAbilityName(Ability)); if (Filter.PassFilter(AbilityName.Get()) == false) @@ -280,12 +283,12 @@ void FCogAbilityWindow_Abilities::RenderAbilitiesTable(UAbilitySystemComponent& continue; } - FitleredAbilities.Add(Spec); + FilteredAbilities.Add(Spec); } if (Config->SortByName) { - FitleredAbilities.Sort([](const FGameplayAbilitySpec& Lhs, const FGameplayAbilitySpec& Rhs) + FilteredAbilities.Sort([](const FGameplayAbilitySpec& Lhs, const FGameplayAbilitySpec& Rhs) { return Lhs.Ability.GetName().Compare(Rhs.Ability.GetName()) < 0; }); @@ -296,7 +299,7 @@ void FCogAbilityWindow_Abilities::RenderAbilitiesTable(UAbilitySystemComponent& static int SelectedIndex = -1; int Index = 0; - for (FGameplayAbilitySpec& Spec : FitleredAbilities) + for (FGameplayAbilitySpec& Spec : FilteredAbilities) { UGameplayAbility* Ability = Spec.GetPrimaryInstance(); if (Ability == nullptr) @@ -357,7 +360,7 @@ bool FCogAbilityWindow_Abilities::RenderAbilitiesTableHeader(UAbilitySystemCompo | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable)) { - ImGui::TableSetupColumn("##Activation", ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("##ActivationCol", ImGuiTableColumnFlags_WidthFixed); ImGui::TableSetupScrollFreeze(0, 1); ImGui::TableSetupColumn("Ability"); ImGui::TableSetupColumn("Level"); @@ -390,11 +393,10 @@ void FCogAbilityWindow_Abilities::RenderAbilitiesTableRow(UAbilitySystemComponen //------------------------ // Popup //------------------------ - if (ImGui::IsItemHovered()) + if (FCogWindowWidgets::BeginItemTableTooltip()) { - FCogWindowWidgets::BeginTableTooltip(); RenderAbilityInfo(AbilitySystemComponent, Spec); - FCogWindowWidgets::EndTableTooltip(); + FCogWindowWidgets::EndItemTableTooltip(); } //------------------------ @@ -475,36 +477,45 @@ void FCogAbilityWindow_Abilities::RenderAbilityContextMenu(UAbilitySystemCompone if (ImGui::BeginPopupContextItem()) { bool bOpen = OpenedAbilities.Contains(Spec.Handle); - if (ImGui::Checkbox("Open", &bOpen)) + if (ImGui::Checkbox("Open Details", &bOpen)) { if (bOpen) { - OpenAbility(Spec.Handle); + OpenAbilityDetails(Spec.Handle); } else { - CloseAbility(Spec.Handle); + CloseAbilityDetails(Spec.Handle); } ImGui::CloseCurrentPopup(); } - if (ImGui::Button("Remove")) + const ImVec2 ButtonsSize = ImVec2(ImGui::GetFontSize() * 10, 0); + + if (ImGui::Button("Cancel", ButtonsSize)) + { + AbilitySystemComponent.CancelAbilityHandle(Spec.Handle); + } + + if (ImGui::Button("Remove", ButtonsSize)) { AbilityHandleToRemove = Spec.Handle; } + FCogWindowWidgets::OpenObjectAssetButton(Spec.Ability, ButtonsSize); + ImGui::EndPopup(); } } //-------------------------------------------------------------------------------------------------------------------------- -void FCogAbilityWindow_Abilities::OpenAbility(const FGameplayAbilitySpecHandle& Handle) +void FCogAbilityWindow_Abilities::OpenAbilityDetails(const FGameplayAbilitySpecHandle& Handle) { OpenedAbilities.AddUnique(Handle); } //-------------------------------------------------------------------------------------------------------------------------- -void FCogAbilityWindow_Abilities::CloseAbility(const FGameplayAbilitySpecHandle& Handle) +void FCogAbilityWindow_Abilities::CloseAbilityDetails(const FGameplayAbilitySpecHandle& Handle) { OpenedAbilities.Remove(Handle); } @@ -535,9 +546,9 @@ void FCogAbilityWindow_Abilities::RenderAbilityInfo(const UAbilitySystemComponen return; } - if (ImGui::BeginTable("Ability", 2, ImGuiTableFlags_Borders)) + if (ImGui::BeginTable("Ability", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable)) { - constexpr ImVec4 TextColor(1.0f, 1.0f, 1.0f, 0.5f); + constexpr ImVec4 TextColor(1.0f, 1.0f, 1.0f, 0.5f); ImGui::TableSetupColumn("Property"); ImGui::TableSetupColumn("Value"); @@ -631,7 +642,7 @@ void FCogAbilityWindow_Abilities::RenderAbilityInfo(const UAbilitySystemComponen ImGui::TableNextColumn(); ImGui::TextColored(TextColor, "Ability Tags"); ImGui::TableNextColumn(); - FCogAbilityHelper::RenderTagContainer(Ability->AbilityTags); + FCogAbilityHelper::RenderTagContainer(Ability->GetAssetTags()); //------------------------ // RequiredTags @@ -665,8 +676,8 @@ void FCogAbilityWindow_Abilities::RenderAbilityInfo(const UAbilitySystemComponen } //------------------------ - // Additional info - //------------------------ + // Additional info + //------------------------ RenderAbilityAdditionalInfo(AbilitySystemComponent, Spec, *Ability, TextColor); ImGui::EndTable(); diff --git a/Plugins/CogAbility/Source/CogAbility/Private/CogAbilityWindow_Attributes.cpp b/Plugins/CogAbility/Source/CogAbility/Private/CogAbilityWindow_Attributes.cpp index 7f7c6d7..69c00f7 100644 --- a/Plugins/CogAbility/Source/CogAbility/Private/CogAbilityWindow_Attributes.cpp +++ b/Plugins/CogAbility/Source/CogAbility/Private/CogAbilityWindow_Attributes.cpp @@ -8,6 +8,8 @@ #include "CogImguiHelper.h" #include "CogWindowWidgets.h" #include "AttributeSet.h" +#include "CogAbilityWindow_Abilities.h" +#include "imgui_internal.h" //-------------------------------------------------------------------------------------------------------------------------- void FCogAbilityWindow_Attributes::Initialize() @@ -41,6 +43,32 @@ void FCogAbilityWindow_Attributes::ResetConfig() Config->Reset(); } +//-------------------------------------------------------------------------------------------------------------------------- +void FCogAbilityWindow_Attributes::RenderTick(float DeltaTime) +{ + Super::RenderTick(DeltaTime); + + RenderOpenAttributes(); +} + +//-------------------------------------------------------------------------------------------------------------------------- +void FCogAbilityWindow_Attributes::FormatAttributeSetName(FString& AttributeSetName) +{ + if (Config->AttributeSetPrefixes.IsEmpty() == false) + { + TArray Prefixes; + Config->AttributeSetPrefixes.ParseIntoArray(Prefixes, TEXT(";")); + + for (const FString& Prefix : Prefixes) + { + if (AttributeSetName.RemoveFromStart(Prefix, ESearchCase::IgnoreCase)) + { + break; + } + } + } +} + //-------------------------------------------------------------------------------------------------------------------------- void FCogAbilityWindow_Attributes::RenderContent() { @@ -61,10 +89,17 @@ void FCogAbilityWindow_Attributes::RenderContent() ImGui::Checkbox("Group by Attribute Set", &Config->GroupByAttributeSet); ImGui::Checkbox("Group by Category", &Config->GroupByCategory); ImGui::Checkbox("Show Only Modified", &Config->ShowOnlyModified); + + FCogWindowWidgets::SetNextItemToShortWidth(); + FCogWindowWidgets::InputText("Attribute Set Prefixes", Config->AttributeSetPrefixes); + ImGui::SetItemTooltip("Prefixes to remove from the attribute set name. Separate multiple prefixes with the semicolon character ';'"); + ImGui::Separator(); ImGui::ColorEdit4("Positive Color", (float*)&AlignmentConfig->PositiveColor, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_AlphaPreviewHalf); ImGui::ColorEdit4("Negative Color", (float*)&AlignmentConfig->NegativeColor, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_AlphaPreviewHalf); ImGui::ColorEdit4("Neutral Color", (float*)&AlignmentConfig->NeutralColor, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_AlphaPreviewHalf); + ImGui::ColorEdit4("AttributeSet Color", (float*)&Config->AttributeSetColor, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_AlphaPreviewHalf); + ImGui::ColorEdit4("Category Color", (float*)&Config->CategoryColor, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_AlphaPreviewHalf); ImGui::Separator(); if (ImGui::MenuItem("Reset")) { @@ -78,10 +113,12 @@ void FCogAbilityWindow_Attributes::RenderContent() ImGui::EndMenuBar(); } - bool bGroupByAttributeSetValue = Filter.IsActive() == false && Config->ShowOnlyModified == false && Config->GroupByAttributeSet; - bool bGroupByCategoryValue = Filter.IsActive() == false && Config->ShowOnlyModified == false && Config->GroupByCategory; + const bool bGroupByAttributeSetValue = Filter.IsActive() == false && Config->ShowOnlyModified == false && Config->GroupByAttributeSet; + const bool bGroupByCategoryValue = Filter.IsActive() == false && Config->ShowOnlyModified == false && Config->GroupByCategory; + const float bShowGroup = bGroupByAttributeSetValue | bGroupByCategoryValue; + const float FirstColWidth = ((int32)bGroupByAttributeSetValue + (int32)bGroupByCategoryValue) * ImGui::GetFontSize() * 2; - if (ImGui::BeginTable("Attributes", 3, ImGuiTableFlags_SizingFixedFit + if (ImGui::BeginTable("Attributes", 5, ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Resizable | ImGuiTableFlags_NoBordersInBodyUntilResize | ImGuiTableFlags_ScrollY @@ -91,6 +128,8 @@ void FCogAbilityWindow_Attributes::RenderContent() | ImGuiTableFlags_Hideable)) { ImGui::TableSetupScrollFreeze(0, 1); + ImGui::TableSetupColumn("-", ImGuiTableColumnFlags_NoHide | ImGuiTableColumnFlags_NoHeaderLabel | ImGuiTableColumnFlags_NoResize | ImGuiTableColumnFlags_WidthFixed, FirstColWidth); + ImGui::TableSetupColumn("Set", bShowGroup ? ImGuiTableColumnFlags_DefaultHide : ImGuiTableColumnFlags_None); ImGui::TableSetupColumn("Attribute"); ImGui::TableSetupColumn("Base"); ImGui::TableSetupColumn("Current"); @@ -102,23 +141,36 @@ void FCogAbilityWindow_Attributes::RenderContent() //------------------------------------------------------------------------------------------ // Draw all the attribute sets //------------------------------------------------------------------------------------------ - for (const UAttributeSet* Set : AbilitySystemComponent->GetSpawnedAttributes()) + for (const UAttributeSet* AttributeSet : AbilitySystemComponent->GetSpawnedAttributes()) { + if (AttributeSet == nullptr) + { continue; } + + ImGui::PushID(TCHAR_TO_ANSI(*AttributeSet->GetName())); + + FString AttributeSetName = AttributeSet->GetName(); + FormatAttributeSetName(AttributeSetName); + const auto AttributeSetNameStr = StringCast(*AttributeSetName); + //------------------------------------------------------------------------------------------ - // Add an tree node categories are shown + // Add a tree node with the name of the attribute set if grouping by attribute set //------------------------------------------------------------------------------------------ bool bOpenAttributeSet = true; if (bGroupByAttributeSetValue) { ImGui::TableNextRow(); ImGui::TableNextColumn(); - bOpenAttributeSet = ImGui::TreeNodeEx(TCHAR_TO_ANSI(*Set->GetName()), ImGuiTreeNodeFlags_SpanFullWidth); + + ImGui::PushStyleColor(ImGuiCol_Text, FCogImguiHelper::ToImVec4(Config->AttributeSetColor)); + bOpenAttributeSet = ImGui::TreeNodeEx(AttributeSetNameStr.Get(), ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_SpanAllColumns | ImGuiTreeNodeFlags_LabelSpanAllColumns); + ImGui::PopStyleColor(); + } if (bOpenAttributeSet) { TArray AllAttributes; - for (TFieldIterator It(Set->GetClass()); It; ++It) + for (TFieldIterator It(AttributeSet->GetClass()); It; ++It) { FGameplayAttribute Attribute = *It; if (Attribute.IsValid()) @@ -176,7 +228,9 @@ void FCogAbilityWindow_Attributes::RenderContent() { ImGui::TableNextRow(); ImGui::TableNextColumn(); - bOpenCategory = ImGui::TreeNodeEx(TCHAR_TO_ANSI(*It.Key), ImGuiTreeNodeFlags_SpanFullWidth); + ImGui::PushStyleColor(ImGuiCol_Text, FCogImguiHelper::ToImVec4(Config->CategoryColor)); + bOpenCategory = ImGui::TreeNodeEx(TCHAR_TO_ANSI(*It.Key), ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_SpanAllColumns | ImGuiTreeNodeFlags_LabelSpanAllColumns); + ImGui::PopStyleColor(); } if (bOpenCategory) @@ -201,51 +255,66 @@ void FCogAbilityWindow_Attributes::RenderContent() for (const FGameplayAttribute& Attribute : AttributesInCategory) { if (!Attribute.IsValid()) - { - continue; - } + { continue; } - const auto AttributeName = StringCast(*Attribute.GetName()); + const auto AttributeNameStr = StringCast(*Attribute.GetName()); - if (Filter.PassFilter(AttributeName.Get()) == false) - { - continue; - } + if (Filter.PassFilter(AttributeNameStr.Get()) == false) + { continue; } const float BaseValue = AbilitySystemComponent->GetNumericAttributeBase(Attribute); const float CurrentValue = AbilitySystemComponent->GetNumericAttribute(Attribute); if (Config->ShowOnlyModified && FMath::IsNearlyEqual(CurrentValue, BaseValue)) - { - continue; - } + { continue; } + + ImGui::PushID(AttributeNameStr.Get()); ImGui::TableNextRow(); + //------------------------ + // Selectable + //------------------------ + ImGui::TableNextColumn(); + if (ImGui::Selectable("", Selected == Index, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowDoubleClick)) + { + Selected = Index; + + if (ImGui::IsMouseDoubleClicked(0)) + { + OpenAttributeDetails(Attribute); + } + } + + //------------------------ + // Popup + //------------------------ + if (FCogWindowWidgets::BeginItemTableTooltip()) + { + RenderAttributeDetails(*AbilitySystemComponent, AttributeSetNameStr.Get(), Attribute, true); + FCogWindowWidgets::EndItemTableTooltip(); + } + + //------------------------ + // ContextMenu + //------------------------ + RenderAttributeContextMenu(*AbilitySystemComponent, Attribute, Index); + const ImVec4 Color = FCogImguiHelper::ToImVec4(AlignmentConfig->GetAttributeColor(*AbilitySystemComponent, Attribute)); ImGui::PushStyleColor(ImGuiCol_Text, Color); //------------------------ - // Name + // Attribute Set //------------------------ ImGui::TableNextColumn(); - ImGui::Text(""); - ImGui::SameLine(); - if (ImGui::Selectable(AttributeName.Get(), Selected == Index, ImGuiSelectableFlags_SpanAllColumns)) - { - Selected = Index; - } - ImGui::PopStyleColor(1); + ImGui::Text("%s", AttributeSetNameStr.Get()); //------------------------ - // Popup + // Attribute Name //------------------------ - if (ImGui::IsItemHovered()) - { - FCogWindowWidgets::BeginTableTooltip(); - DrawAttributeInfo(*AbilitySystemComponent, Attribute); - FCogWindowWidgets::EndTableTooltip(); - } + ImGui::TableNextColumn(); + ImGui::Text("%s", AttributeNameStr.Get()); + ImGui::PopStyleColor(1); ImGui::PushStyleColor(ImGuiCol_Text, Color); @@ -263,6 +332,8 @@ void FCogAbilityWindow_Attributes::RenderContent() ImGui::PopStyleColor(1); + ImGui::PopID(); + Index++; } } @@ -274,10 +345,15 @@ void FCogAbilityWindow_Attributes::RenderContent() } } - if (bOpenAttributeSet && bGroupByAttributeSetValue) + if (bGroupByAttributeSetValue) { - ImGui::TreePop(); + if (bOpenAttributeSet) + { + ImGui::TreePop(); + } } + + ImGui::PopID(); } ImGui::EndTable(); @@ -285,17 +361,34 @@ void FCogAbilityWindow_Attributes::RenderContent() } //-------------------------------------------------------------------------------------------------------------------------- -void FCogAbilityWindow_Attributes::DrawAttributeInfo(const UAbilitySystemComponent& AbilitySystemComponent, const FGameplayAttribute& Attribute) +void FCogAbilityWindow_Attributes::RenderAttributeDetails(const UAbilitySystemComponent& AbilitySystemComponent, const char* AttributeSetName, const FGameplayAttribute& Attribute, bool IsForTooltip) { - if (ImGui::BeginTable("Attribute", 2, ImGuiTableFlags_Borders)) + ImGuiTableFlags TableFlags = IsForTooltip ? ImGuiTableFlags_Borders + : ImGuiTableFlags_Borders | ImGuiTableFlags_NoBordersInBodyUntilResize | ImGuiTableFlags_Resizable; + + const float BaseValue = AbilitySystemComponent.GetNumericAttributeBase(Attribute); + const float CurrentValue = AbilitySystemComponent.GetNumericAttribute(Attribute); + + if (ImGui::BeginTable("Details", 2, TableFlags)) { - const ImVec4 TextColor(1.0f, 1.0f, 1.0f, 0.5f); + constexpr ImVec4 TextColor(1.0f, 1.0f, 1.0f, 0.5f); ImGui::TableSetupColumn("Property"); ImGui::TableSetupColumn("Value", ImGuiTableColumnFlags_WidthStretch); - const float BaseValue = AbilitySystemComponent.GetNumericAttributeBase(Attribute); - const float CurrentValue = AbilitySystemComponent.GetNumericAttribute(Attribute); + if (IsForTooltip == false) + { + ImGui::TableHeadersRow(); + } + + //------------------------ + // Attribute Set + //------------------------ + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TextColored(TextColor, "Attribute Set"); + ImGui::TableNextColumn(); + ImGui::Text("%s", AttributeSetName); //------------------------ // Name @@ -326,38 +419,197 @@ void FCogAbilityWindow_Attributes::DrawAttributeInfo(const UAbilitySystemCompone ImGui::Text("%0.2f", CurrentValue); ImGui::PopStyleColor(1); - //------------------------ - // Modifiers - //------------------------ - FGameplayEffectQuery Query; - for (const FActiveGameplayEffectHandle& ActiveHandle : AbilitySystemComponent.GetActiveEffects(Query)) - { - const FActiveGameplayEffect* ActiveEffect = AbilitySystemComponent.GetActiveGameplayEffect(ActiveHandle); - if (ActiveEffect == nullptr) - { - continue; - } - - for (int32 i = 0; i < ActiveEffect->Spec.Modifiers.Num(); ++i) - { - const FModifierSpec& ModSpec = ActiveEffect->Spec.Modifiers[i]; - const FGameplayModifierInfo& ModInfo = ActiveEffect->Spec.Def->Modifiers[i]; - - if (ModInfo.Attribute == Attribute) - { - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::TextColored(TextColor, "Effect"); - ImGui::TextColored(TextColor, "Operation"); - ImGui::TextColored(TextColor, "Magnitude"); - ImGui::TableNextColumn(); - ImGui::Text("%s", TCHAR_TO_ANSI(*FCogAbilityHelper::CleanupName(GetNameSafe(ActiveEffect->Spec.Def)))); - ImGui::Text("%s", TCHAR_TO_ANSI(*EGameplayModOpToString(ModInfo.ModifierOp))); - ImGui::TextColored(FCogImguiHelper::ToImVec4(AlignmentConfig->GetEffectModifierColor(ModSpec, ModInfo, BaseValue)), "%0.2f", ModSpec.GetEvaluatedMagnitude()); - } - } - } - ImGui::EndTable(); } + + //------------------------ + // Modifiers + //------------------------ + int32 ModifierIndex = 1; + + const FGameplayEffectQuery Query; + for (const FActiveGameplayEffectHandle& ActiveHandle : AbilitySystemComponent.GetActiveEffects(Query)) + { + const FActiveGameplayEffect* ActiveEffect = AbilitySystemComponent.GetActiveGameplayEffect(ActiveHandle); + if (ActiveEffect == nullptr) + { + continue; + } + + for (int32 i = 0; i < ActiveEffect->Spec.Modifiers.Num(); ++i) + { + const FModifierSpec& ModSpec = ActiveEffect->Spec.Modifiers[i]; + const FGameplayModifierInfo& ModInfo = ActiveEffect->Spec.Def->Modifiers[i]; + + if (ModInfo.Attribute == Attribute) + { + char Buffer[128]; + ImFormatString(Buffer, IM_ARRAYSIZE(Buffer), "Modifier %d", ModifierIndex); + + if (FCogWindowWidgets::DarkCollapsingHeader(Buffer, ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_DefaultOpen)) + { + if (ImGui::BeginTable("Details", 2, TableFlags)) + { + constexpr ImVec4 TextColor(1.0f, 1.0f, 1.0f, 0.5f); + + ImGui::TableSetupColumn("Property"); + ImGui::TableSetupColumn("Value", ImGuiTableColumnFlags_WidthStretch); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TextColored(TextColor, "Effect"); + ImGui::TableNextColumn(); + ImGui::Text("%s", TCHAR_TO_ANSI(*FCogAbilityHelper::CleanupName(GetNameSafe(ActiveEffect->Spec.Def)))); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TextColored(TextColor, "Operation"); + ImGui::TableNextColumn(); + ImGui::Text("%s", TCHAR_TO_ANSI(*EGameplayModOpToString(ModInfo.ModifierOp))); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TextColored(TextColor, "Magnitude"); + ImGui::TableNextColumn(); + ImGui::TextColored(FCogImguiHelper::ToImVec4(AlignmentConfig->GetEffectModifierColor(ModSpec, ModInfo, BaseValue)), "%0.2f", ModSpec.GetEvaluatedMagnitude()); + + if (ModInfo.SourceTags.RequireTags.IsEmpty() == false) + { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TextColored(TextColor, "SourceTags - Require"); + ImGui::TableNextColumn(); + FCogAbilityHelper::RenderTagContainer(ModInfo.SourceTags.RequireTags, false); + } + + if (ModInfo.SourceTags.IgnoreTags.IsEmpty() == false) + { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TextColored(TextColor, "SourceTags - Ignore"); + ImGui::TableNextColumn(); + FCogAbilityHelper::RenderTagContainer(ModInfo.SourceTags.IgnoreTags, false); + } + + if (ModInfo.SourceTags.TagQuery.IsEmpty() == false) + { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TextColored(TextColor, "SourceTags - Query"); + ImGui::TableNextColumn(); + const auto Str = StringCast(*ModInfo.SourceTags.TagQuery.GetDescription()); + ImGui::Text("%s", Str.Get()); + } + + if (ModInfo.TargetTags.RequireTags.IsEmpty() == false) + { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TextColored(TextColor, "TargetTags - Require"); + ImGui::TableNextColumn(); + FCogAbilityHelper::RenderTagContainer(ModInfo.TargetTags.RequireTags, false); + } + + if (ModInfo.TargetTags.IgnoreTags.IsEmpty() == false) + { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TextColored(TextColor, "TargetTags - Ignore"); + ImGui::TableNextColumn(); + FCogAbilityHelper::RenderTagContainer(ModInfo.TargetTags.IgnoreTags, false); + } + + if (ModInfo.TargetTags.TagQuery.IsEmpty() == false) + { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TextColored(TextColor, "TargetTags - Query"); + ImGui::TableNextColumn(); + const auto Str = StringCast(*ModInfo.TargetTags.TagQuery.GetDescription()); + ImGui::Text("%s", Str.Get()); + } + + ImGui::EndTable(); + } + } + + ModifierIndex++; + } + } + } } + +//-------------------------------------------------------------------------------------------------------------------------- +void FCogAbilityWindow_Attributes::RenderOpenAttributes() +{ + const AActor* Selection = GetSelection(); + if (Selection == nullptr) + { + return; + } + + const UAbilitySystemComponent* AbilitySystemComponent = UAbilitySystemGlobals::GetAbilitySystemComponentFromActor(Selection, true); + if (AbilitySystemComponent == nullptr) + { + return; + } + + for (int i = OpenedAttributes.Num() - 1; i >= 0; --i) + { + const FGameplayAttribute& Attribute = OpenedAttributes[i]; + + FString AttributeSetName = Attribute.GetAttributeSetClass()->GetFName().ToString(); + FormatAttributeSetName(AttributeSetName); + + const FString WindowName = AttributeSetName + FString(" - ") + Attribute.GetName(); + const auto WindowNameStr = StringCast(*WindowName); + + bool Open = true; + if (ImGui::Begin(WindowNameStr.Get(), &Open)) + { + const auto AttributeSetNameStr = StringCast(*AttributeSetName); + RenderAttributeDetails(*AbilitySystemComponent, AttributeSetNameStr.Get(), Attribute, false); + ImGui::End(); + } + + if (Open == false) + { + OpenedAttributes.RemoveAt(i); + } + } +} + +//-------------------------------------------------------------------------------------------------------------------------- +void FCogAbilityWindow_Attributes::RenderAttributeContextMenu(UAbilitySystemComponent& AbilitySystemComponent, const FGameplayAttribute& InAttribute, int Index) +{ + if (ImGui::BeginPopupContextItem()) + { + bool bOpen = OpenedAttributes.Contains(InAttribute); + if (ImGui::Checkbox("Open Details", &bOpen)) + { + if (bOpen) + { + OpenAttributeDetails(InAttribute); + } + else + { + CloseAttributeDetails(InAttribute); + } + ImGui::CloseCurrentPopup(); + } + + ImGui::EndPopup(); + } +} + +//-------------------------------------------------------------------------------------------------------------------------- +void FCogAbilityWindow_Attributes::OpenAttributeDetails(const FGameplayAttribute& InAttribute) +{ + OpenedAttributes.AddUnique(InAttribute); +} + +//-------------------------------------------------------------------------------------------------------------------------- +void FCogAbilityWindow_Attributes::CloseAttributeDetails(const FGameplayAttribute& InAttribute) +{ + OpenedAttributes.Remove(InAttribute); +} \ No newline at end of file diff --git a/Plugins/CogAbility/Source/CogAbility/Private/CogAbilityWindow_Cheats.cpp b/Plugins/CogAbility/Source/CogAbility/Private/CogAbilityWindow_Cheats.cpp index 644f0af..fed189a 100644 --- a/Plugins/CogAbility/Source/CogAbility/Private/CogAbilityWindow_Cheats.cpp +++ b/Plugins/CogAbility/Source/CogAbility/Private/CogAbilityWindow_Cheats.cpp @@ -5,6 +5,7 @@ #include "CogAbilityReplicator.h" #include "CogCommonAllegianceActorInterface.h" #include "CogImguiHelper.h" +#include "CogWindowConsoleCommandManager.h" #include "CogWindowWidgets.h" #include "EngineUtils.h" #include "GameFramework/Character.h" @@ -21,6 +22,29 @@ void FCogAbilityWindow_Cheats::Initialize() Asset = GetAsset(); Config = GetConfig(); AlignmentConfig = GetConfig(); + + FCogWindowConsoleCommandManager::RegisterWorldConsoleCommand( + TEXT("Cog.Cheat"), + TEXT("Apply a cheat to the selection. Cog.Cheat -Allies -Enemies -Controlled"), + GetWorld(), + FCogWindowConsoleCommandDelegate::CreateLambda([this](const TArray& InArgs, UWorld* InWorld) + { + if (InArgs.Num() > 0) + { + if (const FCogAbilityCheat* cheat = FindCheatByName(InArgs[0])) + { + const bool ApplyToEnemies = InArgs.Contains("-Enemies"); + const bool ApplyToAllies = InArgs.Contains("-Allies"); + const bool ApplyToControlled = InArgs.Contains("-Controlled"); + + RequestCheat(GetLocalPlayerPawn(), GetSelection(), *cheat, ApplyToEnemies, ApplyToAllies, ApplyToControlled); + } + else + { + UE_LOG(LogCogImGui, Warning, TEXT("Cog.Cheat %s | Cheat not found"), *InArgs[0]); + } + } + })); } //-------------------------------------------------------------------------------------------------------------------------- @@ -84,8 +108,8 @@ void FCogAbilityWindow_Cheats::TryReapplyCheats() return; } - APawn* LocalPawn = GetLocalPlayerPawn(); - if (LocalPawn == nullptr) + APawn* ControlledActor = GetLocalPlayerPawn(); + if (ControlledActor == nullptr) { return; } @@ -96,7 +120,7 @@ void FCogAbilityWindow_Cheats::TryReapplyCheats() return; } - TArray Targets { LocalPawn }; + TArray Targets { ControlledActor }; for (int32 i = Config->AppliedCheats.Num() - 1; i >= 0; i--) { @@ -105,7 +129,7 @@ void FCogAbilityWindow_Cheats::TryReapplyCheats() if (const FCogAbilityCheat* Cheat = Asset->PersistentEffects.FindByPredicate( [AppliedCheatName](const FCogAbilityCheat& Cheat) { return Cheat.Name == AppliedCheatName; })) { - Replicator->Server_ApplyCheat(LocalPawn, Targets, *Cheat); + Replicator->Server_ApplyCheat(ControlledActor, Targets, *Cheat); } else { @@ -247,13 +271,17 @@ bool FCogAbilityWindow_Cheats::AddCheat(AActor* ControlledActor, AActor* Selecte FCogWindowWidgets::PushBackColor(FCogImguiHelper::ToImVec4(AlignmentConfig->GetEffectColor(Asset, *EffectCDO))); } + const bool IsShiftDown = (ImGui::GetCurrentContext()->IO.KeyMods & ImGuiMod_Shift) != 0; + const bool IsAltDown = (ImGui::GetCurrentContext()->IO.KeyMods & ImGuiMod_Alt) != 0; + const bool IsControlDown = (ImGui::GetCurrentContext()->IO.KeyMods & ImGuiMod_Ctrl) != 0; + bool bIsPressed = false; if (IsPersistent) { bool isEnabled = ACogAbilityReplicator::IsCheatActive(SelectedActor, Cheat); if (ImGui::Checkbox(TCHAR_TO_ANSI(*Cheat.Name), &isEnabled)) { - RequestCheat(ControlledActor, SelectedActor, Cheat); + RequestCheat(ControlledActor, SelectedActor, Cheat, IsShiftDown, IsAltDown, IsControlDown); bIsPressed = true; } } @@ -261,22 +289,18 @@ bool FCogAbilityWindow_Cheats::AddCheat(AActor* ControlledActor, AActor* Selecte { if (ImGui::Button(TCHAR_TO_ANSI(*Cheat.Name), ImVec2(-1, 0))) { - RequestCheat(ControlledActor, SelectedActor, Cheat); + RequestCheat(ControlledActor, SelectedActor, Cheat, IsShiftDown, IsAltDown, IsControlDown); bIsPressed = true; } } if (ImGui::IsItemHovered()) { - const bool IsShiftDown = (ImGui::GetCurrentContext()->IO.KeyMods & ImGuiMod_Shift) != 0; - const bool IsAltDown = (ImGui::GetCurrentContext()->IO.KeyMods & ImGuiMod_Alt) != 0; - const bool IsControlDown = (ImGui::GetCurrentContext()->IO.KeyMods & ImGuiMod_Ctrl) != 0; - ImGui::BeginTooltip(); - ImGui::TextColored(ImVec4(1.0f, 1.0f, 1.0f, IsShiftDown || IsAltDown || IsControlDown ? 0.5f : 1.0f), "On Selection"); - ImGui::TextColored(ImVec4(1.0f, 1.0f, 1.0f, IsShiftDown ? 1.0f : 0.5f), "On Enemies [SHIFT]"); - ImGui::TextColored(ImVec4(1.0f, 1.0f, 1.0f, IsAltDown ? 1.0f : 0.5f), "On Allies [ALT]"); - ImGui::TextColored(ImVec4(1.0f, 1.0f, 1.0f, IsControlDown ? 1.0f : 0.5f), "On Controlled [CTRL]"); + ImGui::TextColored(ImVec4(1.0f, 1.0f, 1.0f, IsShiftDown || IsAltDown || IsControlDown ? 0.5f : 1.0f), "On Selection"); + ImGui::TextColored(ImVec4(1.0f, 1.0f, 1.0f, IsShiftDown ? 1.0f : 0.5f), "On Enemies [SHIFT]"); + ImGui::TextColored(ImVec4(1.0f, 1.0f, 1.0f, IsAltDown ? 1.0f : 0.5f), "On Allies [ALT]"); + ImGui::TextColored(ImVec4(1.0f, 1.0f, 1.0f, IsControlDown ? 1.0f : 0.5f), "On Controlled [CTRL]"); ImGui::EndTooltip(); } @@ -289,20 +313,16 @@ bool FCogAbilityWindow_Cheats::AddCheat(AActor* ControlledActor, AActor* Selecte } //-------------------------------------------------------------------------------------------------------------------------- -void FCogAbilityWindow_Cheats::RequestCheat(AActor* ControlledActor, AActor* SelectedActor, const FCogAbilityCheat& Cheat) +void FCogAbilityWindow_Cheats::RequestCheat(AActor* ControlledActor, AActor* SelectedActor, const FCogAbilityCheat& Cheat, bool ApplyToEnemies, bool ApplyToAllies, bool ApplyToControlled) { - const bool IsShiftDown = (ImGui::GetCurrentContext()->IO.KeyMods & ImGuiMod_Shift) != 0; - const bool IsAltDown = (ImGui::GetCurrentContext()->IO.KeyMods & ImGuiMod_Alt) != 0; - const bool IsControlDown = (ImGui::GetCurrentContext()->IO.KeyMods & ImGuiMod_Ctrl) != 0; - TArray Actors; - if (IsControlDown) + if (ApplyToControlled) { Actors.Add(ControlledActor); } - if (IsShiftDown || IsAltDown) + if (ApplyToEnemies || ApplyToAllies) { for (TActorIterator It(GetWorld(), ACharacter::StaticClass()); It; ++It) { @@ -315,8 +335,8 @@ void FCogAbilityWindow_Cheats::RequestCheat(AActor* ControlledActor, AActor* Sel Allegiance = AllegianceInterface->GetAllegianceWithOtherActor(ControlledActor); } - if ((IsShiftDown && (Allegiance == ECogCommonAllegiance::Enemy)) - || (IsAltDown && (Allegiance == ECogCommonAllegiance::Friendly))) + if ((ApplyToEnemies && (Allegiance == ECogCommonAllegiance::Enemy)) + || (ApplyToAllies && (Allegiance == ECogCommonAllegiance::Friendly))) { Actors.Add(OtherActor); } @@ -324,7 +344,7 @@ void FCogAbilityWindow_Cheats::RequestCheat(AActor* ControlledActor, AActor* Sel } } - if ((IsControlDown || IsShiftDown || IsAltDown) == false) + if ((ApplyToControlled || ApplyToEnemies || ApplyToAllies) == false) { Actors.Add(SelectedActor); } @@ -333,4 +353,30 @@ void FCogAbilityWindow_Cheats::RequestCheat(AActor* ControlledActor, AActor* Sel { Replicator->Server_ApplyCheat(ControlledActor, Actors, Cheat); } + else + { + UE_LOG(LogCogImGui, Warning, TEXT("FCogAbilityWindow_Cheats::RequestCheat | Replicator not found")); + } +} + +//-------------------------------------------------------------------------------------------------------------------------- +const FCogAbilityCheat* FCogAbilityWindow_Cheats::FindCheatByName(const FString& CheatName) +{ + for (const FCogAbilityCheat& cheat : Asset->PersistentEffects) + { + if (cheat.Name == CheatName) + { + return &cheat; + } + } + + for (const FCogAbilityCheat& cheat : Asset->InstantEffects) + { + if (cheat.Name == CheatName) + { + return &cheat; + } + } + + return nullptr; } diff --git a/Plugins/CogAbility/Source/CogAbility/Private/CogAbilityWindow_Effects.cpp b/Plugins/CogAbility/Source/CogAbility/Private/CogAbilityWindow_Effects.cpp index 38c657d..2df399e 100644 --- a/Plugins/CogAbility/Source/CogAbility/Private/CogAbilityWindow_Effects.cpp +++ b/Plugins/CogAbility/Source/CogAbility/Private/CogAbilityWindow_Effects.cpp @@ -42,9 +42,9 @@ void FCogAbilityWindow_Effects::ResetConfig() } //-------------------------------------------------------------------------------------------------------------------------- -void FCogAbilityWindow_Effects::RenderTick(float DetlaTime) +void FCogAbilityWindow_Effects::RenderTick(float DeltaTime) { - Super::RenderTick(DetlaTime); + Super::RenderTick(DeltaTime); RenderOpenEffects(); } @@ -85,7 +85,7 @@ void FCogAbilityWindow_Effects::RenderContent() //-------------------------------------------------------------------------------------------------------------------------- void FCogAbilityWindow_Effects::RenderEffectsTable() { - const UAbilitySystemComponent* AbilitySystemComponent = UAbilitySystemGlobals::GetAbilitySystemComponentFromActor(GetSelection(), true); + UAbilitySystemComponent* AbilitySystemComponent = UAbilitySystemGlobals::GetAbilitySystemComponentFromActor(GetSelection(), true); if (AbilitySystemComponent == nullptr) { ImGui::TextDisabled("Selection has no ability system component"); @@ -170,7 +170,7 @@ void FCogAbilityWindow_Effects::RenderEffectsTable() } //-------------------------------------------------------------------------------------------------------------------------- -void FCogAbilityWindow_Effects::RenderEffectRow(const UAbilitySystemComponent& AbilitySystemComponent, const FActiveGameplayEffectHandle& ActiveHandle, int32 Index, int32& Selected) +void FCogAbilityWindow_Effects::RenderEffectRow(UAbilitySystemComponent& AbilitySystemComponent, const FActiveGameplayEffectHandle& ActiveHandle, int32 Index, int32& Selected) { const FActiveGameplayEffect* ActiveEffectPtr = AbilitySystemComponent.GetActiveGameplayEffect(ActiveHandle); if (ActiveEffectPtr == nullptr) @@ -213,11 +213,10 @@ void FCogAbilityWindow_Effects::RenderEffectRow(const UAbilitySystemComponent& A //------------------------ // Popup //------------------------ - if (ImGui::IsItemHovered()) + if (FCogWindowWidgets::BeginItemTableTooltip()) { - FCogWindowWidgets::BeginTableTooltip(); RenderEffectInfo(AbilitySystemComponent, ActiveEffect, Effect); - FCogWindowWidgets::EndTableTooltip(); + FCogWindowWidgets::EndItemTableTooltip(); } //------------------------ @@ -225,8 +224,10 @@ void FCogAbilityWindow_Effects::RenderEffectRow(const UAbilitySystemComponent& A //------------------------ if (ImGui::BeginPopupContextItem()) { + const ImVec2 ButtonsSize = ImVec2(ImGui::GetFontSize() * 10, 0); + bool bOpen = OpenedEffects.Contains(ActiveHandle); - if (ImGui::Checkbox("Open", &bOpen)) + if (ImGui::Checkbox("Open Details", &bOpen)) { if (bOpen) { @@ -238,6 +239,15 @@ void FCogAbilityWindow_Effects::RenderEffectRow(const UAbilitySystemComponent& A } ImGui::CloseCurrentPopup(); } + + if (ImGui::Button("Remove", ButtonsSize)) + { + AbilitySystemComponent.RemoveActiveGameplayEffect(ActiveHandle); + ImGui::CloseCurrentPopup(); + } + + FCogWindowWidgets::OpenObjectAssetButton(EffectPtr, ButtonsSize); + ImGui::EndPopup(); } @@ -270,7 +280,7 @@ void FCogAbilityWindow_Effects::RenderEffectRow(const UAbilitySystemComponent& A //-------------------------------------------------------------------------------------------------------------------------- void FCogAbilityWindow_Effects::RenderEffectInfo(const UAbilitySystemComponent& AbilitySystemComponent, const FActiveGameplayEffect& ActiveEffect, const UGameplayEffect& Effect) { - if (ImGui::BeginTable("Effect", 2, ImGuiTableFlags_Borders)) + if (ImGui::BeginTable("Effect", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable)) { constexpr ImVec4 TextColor(1.0f, 1.0f, 1.0f, 0.5f); diff --git a/Plugins/CogAbility/Source/CogAbility/Private/CogAbilityWindow_Tags.cpp b/Plugins/CogAbility/Source/CogAbility/Private/CogAbilityWindow_Tags.cpp index 5f41f7a..6cf697f 100644 --- a/Plugins/CogAbility/Source/CogAbility/Private/CogAbilityWindow_Tags.cpp +++ b/Plugins/CogAbility/Source/CogAbility/Private/CogAbilityWindow_Tags.cpp @@ -134,11 +134,10 @@ void FCogAbilityWindow_Tags::RenderTagContainer(const UAbilitySystemComponent& A //------------------------ // Tooltip //------------------------ - if (ImGui::IsItemHovered()) + if (FCogWindowWidgets::BeginItemTableTooltip()) { - FCogWindowWidgets::BeginTableTooltip(); RenderTag(AbilitySystemComponent, Tag); - FCogWindowWidgets::EndTableTooltip(); + FCogWindowWidgets::EndItemTableTooltip(); } ImGui::PopID(); diff --git a/Plugins/CogAbility/Source/CogAbility/Private/CogAbilityWindow_Tasks.cpp b/Plugins/CogAbility/Source/CogAbility/Private/CogAbilityWindow_Tasks.cpp index e971eb3..bea5113 100644 --- a/Plugins/CogAbility/Source/CogAbility/Private/CogAbilityWindow_Tasks.cpp +++ b/Plugins/CogAbility/Source/CogAbility/Private/CogAbilityWindow_Tasks.cpp @@ -2,11 +2,8 @@ #include "AbilitySystemGlobals.h" #include "AbilitySystemComponent.h" -#include "CogAbilityDataAsset.h" #include "CogAbilityHelper.h" -#include "CogAbilityReplicator.h" #include "CogImguiHelper.h" -#include "CogWindowHelper.h" #include "CogWindowWidgets.h" #include "imgui.h" @@ -160,15 +157,15 @@ void FCogAbilityWindow_Tasks::RenderTasksTable(UAbilitySystemComponent& AbilityS continue; } - const char* TaskName = StringCast(*Task->GetName()).Get(); - bool PassFilter = Filter.PassFilter(TaskName); + const auto& TaskName = StringCast(*Task->GetName()); + bool PassFilter = Filter.PassFilter(TaskName.Get()); if (PassFilter == false) { if (const UGameplayAbility* Ability = Cast(Task->GetTaskOwner())) { - const char* AbilityName = StringCast(*FCogAbilityHelper::CleanupName(Ability->GetName())).Get(); - PassFilter = Filter.PassFilter(AbilityName); + const auto& AbilityName = StringCast(*FCogAbilityHelper::CleanupName(Ability->GetName())); + PassFilter = Filter.PassFilter(AbilityName.Get()); } } @@ -177,7 +174,7 @@ void FCogAbilityWindow_Tasks::RenderTasksTable(UAbilitySystemComponent& AbilityS continue; } - FilteredTasks.Add(Task); + FilteredTasks.Add(Task); } if (Config->SortByName) @@ -228,8 +225,8 @@ void FCogAbilityWindow_Tasks::RenderTasksTable(UAbilitySystemComponent& AbilityS //------------------------ ImGui::TableNextColumn(); - const char* TaskName = StringCast(*Task->GetName()).Get(); - if (ImGui::Selectable(TaskName, SelectedIndex == LineIndex, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowOverlap | ImGuiSelectableFlags_AllowDoubleClick)) + const auto& TaskName = StringCast(*Task->GetName()); + if (ImGui::Selectable(TaskName.Get(), SelectedIndex == LineIndex, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowOverlap | ImGuiSelectableFlags_AllowDoubleClick)) { SelectedIndex = LineIndex; } @@ -237,11 +234,10 @@ void FCogAbilityWindow_Tasks::RenderTasksTable(UAbilitySystemComponent& AbilityS //------------------------ // Popup //------------------------ - if (ImGui::IsItemHovered()) + if (FCogWindowWidgets::BeginItemTableTooltip()) { - FCogWindowWidgets::BeginTableTooltip(); RenderTaskInfo(Task); - FCogWindowWidgets::EndTableTooltip(); + FCogWindowWidgets::EndItemTableTooltip(); } //------------------------ @@ -254,7 +250,7 @@ void FCogAbilityWindow_Tasks::RenderTasksTable(UAbilitySystemComponent& AbilityS // IsTicking //------------------------ ImGui::TableNextColumn(); - ImGui::Text(Task->IsTickingTask() ? "Yes" : "No"); + ImGui::Text(Task->IsTickingTask() ? "Yes" : "No"); ImGui::PopID(); } @@ -275,7 +271,7 @@ void FCogAbilityWindow_Tasks::RenderTaskInfo(const UGameplayTask* Task) if (ImGui::BeginTable("Task", 2, ImGuiTableFlags_Borders)) { - constexpr ImVec4 TextColor(1.0f, 1.0f, 1.0f, 0.5f); + constexpr ImVec4 TextColor(1.0f, 1.0f, 1.0f, 0.5f); ImGui::TableSetupColumn("Property"); ImGui::TableSetupColumn("Value"); @@ -287,20 +283,20 @@ void FCogAbilityWindow_Tasks::RenderTaskInfo(const UGameplayTask* Task) ImGui::TableNextColumn(); ImGui::TextColored(TextColor, "Name"); ImGui::TableNextColumn(); - ImGui::Text(StringCast(*Task->GetName()).Get()); + ImGui::Text("%s", StringCast(*Task->GetName()).Get()); //------------------------ - // Instance Name - //------------------------ + // Instance Name + //------------------------ ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::TextColored(TextColor, "Instance Name"); ImGui::TableNextColumn(); - ImGui::Text(StringCast(*Task->GetInstanceName().ToString()).Get()); + ImGui::Text("%s", StringCast(*Task->GetInstanceName().ToString()).Get()); //------------------------ - // Owner - //------------------------ + // Owner + //------------------------ ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::TextColored(TextColor, "Ability"); @@ -316,9 +312,9 @@ void FCogAbilityWindow_Tasks::RenderTaskInfo(const UGameplayTask* Task) ImGui::TableNextColumn(); RenderTaskState(Task); - //------------------------ - // Priority - //------------------------ + //------------------------ + // Priority + //------------------------ ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::TextColored(TextColor, "Priority"); @@ -326,17 +322,17 @@ void FCogAbilityWindow_Tasks::RenderTaskInfo(const UGameplayTask* Task) ImGui::Text("%d", (int32)Task->GetPriority()); //------------------------ - // IsTicking - //------------------------ + // IsTicking + //------------------------ ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::TextColored(TextColor, "Is Ticking"); ImGui::TableNextColumn(); ImGui::Text(Task->IsTickingTask() ? "Yes" : "No"); - //------------------------ - // IsSimulated - //------------------------ + //------------------------ + // IsSimulated + //------------------------ ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::TextColored(TextColor, "Is Simulated"); @@ -344,8 +340,8 @@ void FCogAbilityWindow_Tasks::RenderTaskInfo(const UGameplayTask* Task) ImGui::Text(Task->IsSimulatedTask() ? "Yes" : "No"); //------------------------ - // IsSimulating - //------------------------ + // IsSimulating + //------------------------ ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::TextColored(TextColor, "Is Simulating"); @@ -353,15 +349,15 @@ void FCogAbilityWindow_Tasks::RenderTaskInfo(const UGameplayTask* Task) ImGui::Text(Task->IsSimulating() ? "Yes" : "No"); //------------------------ - // Debug - //------------------------ + // Debug + //------------------------ ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::TextColored(TextColor, "Debug"); ImGui::TableNextColumn(); ImGui::PushTextWrapPos(FCogWindowWidgets::GetFontWidth() * 80); - ImGui::Text(StringCast(*Task->GetDebugString()).Get()); - ImGui::PopTextWrapPos(); + ImGui::Text("%s", StringCast(*Task->GetDebugString()).Get()); + ImGui::PopTextWrapPos(); ImGui::EndTable(); } @@ -383,7 +379,7 @@ void FCogAbilityWindow_Tasks::RenderTaskOwner(const UGameplayTask* Task) OwnerName = GetNameSafe(Object); } - ImGui::Text(StringCast(*OwnerName).Get()); + ImGui::Text("%s", StringCast(*OwnerName).Get()); } //-------------------------------------------------------------------------------------------------------------------------- diff --git a/Plugins/CogAbility/Source/CogAbility/Public/CogAbilityCheat_Execution_ApplyEffect.h b/Plugins/CogAbility/Source/CogAbility/Public/CogAbilityCheat_Execution_ApplyEffect.h new file mode 100644 index 0000000..fd388e9 --- /dev/null +++ b/Plugins/CogAbility/Source/CogAbility/Public/CogAbilityCheat_Execution_ApplyEffect.h @@ -0,0 +1,24 @@ +#pragma once + +#include "CoreMinimal.h" +#include "CogEngineDataAsset.h" +#include "GameplayEffect.h" +#include "CogAbilityCheat_Execution_ApplyEffect.generated.h" + +//-------------------------------------------------------------------------------------------------------------------------- +UCLASS(DisplayName = "Apply Effect") +class COGABILITY_API UCogAbilityCheat_Execution_ApplyEffect + : public UCogEngineCheat_Execution +{ + GENERATED_BODY() + +public: + void Execute_Implementation(const AActor* Instigator, const TArray& Targets) const override; + + ECogEngineCheat_ActiveState IsActiveOnTargets_Implementation(const TArray& Targets) const override; + + virtual bool GetColor(const FCogWindow& InCallingWindow, FLinearColor& OutColor) const override; + + UPROPERTY(EditAnywhere) + TSubclassOf Effect; +}; diff --git a/Plugins/CogAbility/Source/CogAbility/Public/CogAbilityWindow_Abilities.h b/Plugins/CogAbility/Source/CogAbility/Public/CogAbilityWindow_Abilities.h index 99806f3..868a820 100644 --- a/Plugins/CogAbility/Source/CogAbility/Public/CogAbilityWindow_Abilities.h +++ b/Plugins/CogAbility/Source/CogAbility/Public/CogAbilityWindow_Abilities.h @@ -73,9 +73,9 @@ protected: virtual void DeactivateAbility(UAbilitySystemComponent& AbilitySystemComponent, FGameplayAbilitySpec& Spec); - virtual void OpenAbility(const FGameplayAbilitySpecHandle& Handle); + virtual void OpenAbilityDetails(const FGameplayAbilitySpecHandle& Handle); - virtual void CloseAbility(const FGameplayAbilitySpecHandle& Handle); + virtual void CloseAbilityDetails(const FGameplayAbilitySpecHandle& Handle); virtual ImVec4 GetAbilityColor(const UAbilitySystemComponent& AbilitySystemComponent, FGameplayAbilitySpec& Spec); diff --git a/Plugins/CogAbility/Source/CogAbility/Public/CogAbilityWindow_Attributes.h b/Plugins/CogAbility/Source/CogAbility/Public/CogAbilityWindow_Attributes.h index 19fa71c..0b7980e 100644 --- a/Plugins/CogAbility/Source/CogAbility/Public/CogAbilityWindow_Attributes.h +++ b/Plugins/CogAbility/Source/CogAbility/Public/CogAbilityWindow_Attributes.h @@ -2,13 +2,14 @@ #include "CoreMinimal.h" #include "CogCommonConfig.h" +#include "AttributeSet.h" #include "CogWindow.h" #include "CogAbilityWindow_Attributes.generated.h" +class UAttributeSet; class UAbilitySystemComponent; class UCogAbilityConfig_Attributes; class UCogAbilityConfig_Alignment; -struct FGameplayAttribute; struct FModifierSpec; struct FGameplayModifierInfo; @@ -27,9 +28,21 @@ protected: virtual void RenderHelp() override; + virtual void RenderTick(float DeltaTime); + virtual void RenderContent() override; - virtual void DrawAttributeInfo(const UAbilitySystemComponent& AbilitySystemComponent, const FGameplayAttribute& Attribute); + virtual void RenderAttributeDetails(const UAbilitySystemComponent& AbilitySystemComponent, const char* AttributeSetName, const FGameplayAttribute& Attribute, bool IsForTooltip); + + virtual void RenderOpenAttributes(); + + virtual void FormatAttributeSetName(FString& AttributeSetName); + + virtual void OpenAttributeDetails(const FGameplayAttribute& InAttribute); + + virtual void CloseAttributeDetails(const FGameplayAttribute& InAttribute); + + virtual void RenderAttributeContextMenu(UAbilitySystemComponent& AbilitySystemComponent, const FGameplayAttribute& InAttribute, int Index); private: @@ -38,6 +51,8 @@ private: TObjectPtr Config = nullptr; TObjectPtr AlignmentConfig = nullptr; + + TArray OpenedAttributes; }; //-------------------------------------------------------------------------------------------------------------------------- @@ -60,6 +75,15 @@ public: UPROPERTY(Config) bool ShowOnlyModified = false; + UPROPERTY(Config) + FString AttributeSetPrefixes; + + UPROPERTY(Config) + FVector4f CategoryColor = FVector4f(1.0f, 1.0f, 1.0f, 0.5f); + + UPROPERTY(Config) + FVector4f AttributeSetColor = FVector4f(1.0f, 1.0f, 1.0f, 0.5f); + virtual void Reset() override { Super::Reset(); @@ -68,5 +92,8 @@ public: GroupByAttributeSet = false; GroupByCategory = false; ShowOnlyModified = false; + AttributeSetPrefixes = FString(); + CategoryColor = FVector4f(1.0f, 1.0f, 1.0f, 0.5f); + AttributeSetColor = FVector4f(1.0f, 1.0f, 1.0f, 0.5f); } }; \ No newline at end of file diff --git a/Plugins/CogAbility/Source/CogAbility/Public/CogAbilityWindow_Cheats.h b/Plugins/CogAbility/Source/CogAbility/Public/CogAbilityWindow_Cheats.h index 478ea92..dafa15b 100644 --- a/Plugins/CogAbility/Source/CogAbility/Public/CogAbilityWindow_Cheats.h +++ b/Plugins/CogAbility/Source/CogAbility/Public/CogAbilityWindow_Cheats.h @@ -31,10 +31,13 @@ protected: virtual void RenderContent() override; virtual void TryReapplyCheats(); + APawn* GetCheatInstigator(); virtual bool AddCheat(AActor* ControlledActor, AActor* TargetActor, const FCogAbilityCheat& CheatEffect, bool IsPersistent); - virtual void RequestCheat(AActor* ControlledActor, AActor* TargetActor, const FCogAbilityCheat& CheatEffect); + virtual void RequestCheat(AActor* ControlledActor, AActor* SelectedActor, const FCogAbilityCheat& Cheat, bool ApplyToEnemies, bool ApplyToAllies, bool ApplyToControlled); + + virtual const FCogAbilityCheat* FindCheatByName(const FString& CheatName); TObjectPtr Asset = nullptr; diff --git a/Plugins/CogAbility/Source/CogAbility/Public/CogAbilityWindow_Effects.h b/Plugins/CogAbility/Source/CogAbility/Public/CogAbilityWindow_Effects.h index 36237dd..afcd673 100644 --- a/Plugins/CogAbility/Source/CogAbility/Public/CogAbilityWindow_Effects.h +++ b/Plugins/CogAbility/Source/CogAbility/Public/CogAbilityWindow_Effects.h @@ -32,13 +32,13 @@ protected: virtual void RenderContent() override; - virtual void RenderTick(float DetlaTime) override; + virtual void RenderTick(float DeltaTime) override; virtual void ResetConfig() override; virtual void RenderEffectsTable(); - virtual void RenderEffectRow(const UAbilitySystemComponent& AbilitySystemComponent, const FActiveGameplayEffectHandle& ActiveHandle, int32 Index, int32& Selected); + virtual void RenderEffectRow(UAbilitySystemComponent& AbilitySystemComponent, const FActiveGameplayEffectHandle& ActiveHandle, int32 Index, int32& Selected); virtual void RenderEffectInfo(const UAbilitySystemComponent& AbilitySystemComponent, const FActiveGameplayEffect& ActiveEffect, const UGameplayEffect& Effect); diff --git a/Plugins/CogAll/Source/CogAll/Private/CogAll.cpp b/Plugins/CogAll/Source/CogAll/Private/CogAll.cpp index b44f392..ad4b176 100644 --- a/Plugins/CogAll/Source/CogAll/Private/CogAll.cpp +++ b/Plugins/CogAll/Source/CogAll/Private/CogAll.cpp @@ -2,7 +2,6 @@ #include "CogAbilityWindow_Abilities.h" #include "CogAbilityWindow_Attributes.h" -#include "CogAbilityWindow_Cheats.h" #include "CogAbilityWindow_Effects.h" #include "CogAbilityWindow_Pools.h" #include "CogAbilityWindow_Tags.h" @@ -10,6 +9,7 @@ #include "CogAbilityWindow_Tweaks.h" #include "CogAIWindow_BehaviorTree.h" #include "CogAIWindow_Blackboard.h" +#include "CogEngineWindow_Cheats.h" #include "CogEngineWindow_CollisionTester.h" #include "CogEngineWindow_CollisionViewer.h" #include "CogEngineWindow_CommandBindings.h" @@ -18,6 +18,7 @@ #include "CogEngineWindow_Inspector.h" #include "CogEngineWindow_LogCategories.h" #include "CogEngineWindow_Metrics.h" +#include "CogEngineWindow_NetImgui.h" #include "CogEngineWindow_NetEmulation.h" #include "CogEngineWindow_OutputLog.h" #include "CogEngineWindow_Plots.h" @@ -65,11 +66,13 @@ void Cog::AddAllWindows(UCogWindowManager& CogWindowManager) CogWindowManager.AddWindow("Engine.Log Categories"); + CogWindowManager.AddWindow("Engine.Metrics"); + CogWindowManager.AddWindow("Engine.Net Emulation"); - CogWindowManager.AddWindow("Engine.Output Log"); + CogWindowManager.AddWindow("Engine.Net ImGui"); - CogWindowManager.AddWindow("Engine.Metrics"); + CogWindowManager.AddWindow("Engine.Output Log"); CogWindowManager.AddWindow("Engine.Plots"); @@ -100,7 +103,9 @@ void Cog::AddAllWindows(UCogWindowManager& CogWindowManager) CogWindowManager.AddWindow("Gameplay.Blocking Tags"); - CogWindowManager.AddWindow("Gameplay.Cheats"); + //CogWindowManager.AddWindow("Gameplay.Cheats"); + + CogWindowManager.AddWindow("Gameplay.Cheats"); CogWindowManager.AddWindow("Gameplay.Effects"); diff --git a/Plugins/CogInput/Source/CogInput/Private/CogInjectActionInfo.cpp b/Plugins/CogInput/Source/CogInput/Private/CogInputActionInfo.cpp similarity index 89% rename from Plugins/CogInput/Source/CogInput/Private/CogInjectActionInfo.cpp rename to Plugins/CogInput/Source/CogInput/Private/CogInputActionInfo.cpp index c831a17..7dc1e0b 100644 --- a/Plugins/CogInput/Source/CogInput/Private/CogInjectActionInfo.cpp +++ b/Plugins/CogInput/Source/CogInput/Private/CogInputActionInfo.cpp @@ -1,9 +1,9 @@ -#include "CogInjectActionInfo.h" +#include "CogInputActionInfo.h" #include "EnhancedInputSubsystems.h" //-------------------------------------------------------------------------------------------------------------------------- -void FCogInjectActionInfo::Inject(UEnhancedInputLocalPlayerSubsystem& EnhancedInput, bool IsTimeToRepeat) +void FCogInputActionInfo::Inject(UEnhancedInputLocalPlayerSubsystem& EnhancedInput, bool IsTimeToRepeat) { if (Action == nullptr) { diff --git a/Plugins/CogInput/Source/CogInput/Private/CogInputWindow_Actions.cpp b/Plugins/CogInput/Source/CogInput/Private/CogInputWindow_Actions.cpp index ee8cf2d..747643f 100644 --- a/Plugins/CogInput/Source/CogInput/Private/CogInputWindow_Actions.cpp +++ b/Plugins/CogInput/Source/CogInput/Private/CogInputWindow_Actions.cpp @@ -1,12 +1,11 @@ #include "CogInputWindow_Actions.h" -#include "CogInputDataAsset.h" -#include "CogWindowHelper.h" #include "CogWindowWidgets.h" #include "Engine/LocalPlayer.h" #include "Engine/World.h" #include "EnhancedInputSubsystems.h" #include "GameFramework/Pawn.h" +#include "imgui_internal.h" #include "InputAction.h" #include "InputMappingContext.h" @@ -17,7 +16,6 @@ void FCogInputWindow_Actions::Initialize() bHasMenu = true; - Asset = GetAsset(); Config = GetConfig(); } @@ -26,10 +24,7 @@ void FCogInputWindow_Actions::RenderHelp() { ImGui::Text( "This window displays the current state of each Input Action. " - "It can also be used to inject inputs to help debugging. " - "The input action are read from a Input Mapping Context defined in '%s' data asset. " - , TCHAR_TO_ANSI(*GetNameSafe(Asset.Get())) - ); + "It can also be used to inject inputs to help debugging."); } //-------------------------------------------------------------------------------------------------------------------------- @@ -45,12 +40,6 @@ void FCogInputWindow_Actions::RenderContent() { Super::RenderContent(); - if (Asset == nullptr) - { - ImGui::TextDisabled("Invalid Asset"); - return; - } - ULocalPlayer* LocalPlayer = GetWorld()->GetFirstLocalPlayerFromController(); if (LocalPlayer == nullptr) { @@ -65,122 +54,226 @@ void FCogInputWindow_Actions::RenderContent() return; } - if(EnhancedInputSubsystem->GetPlayerInput() == nullptr) + UEnhancedPlayerInput* PlayerInput = EnhancedInputSubsystem->GetPlayerInput(); + if(PlayerInput == nullptr) { ImGui::TextDisabled("No Player Input"); return; } - + + const bool IsControlDown = (ImGui::GetCurrentContext()->IO.KeyMods & ImGuiMod_Ctrl) != 0; + if (ImGui::BeginMenuBar()) { if (ImGui::BeginMenu("Options")) { + ImGui::Checkbox("Show Header", &Config->ShowHeader); ImGui::SliderFloat("##Repeat", &Config->RepeatPeriod, 0.1f, 10.0f, "Repeat: %0.1fs"); ImGui::EndMenu(); } if (ImGui::MenuItem("Reset")) { - for (FCogInjectActionInfo& ActionInfo : Actions) + for (FCogInputMappingContextInfo Mapping : Mappings) { - ActionInfo.Reset(); + for (FCogInputActionInfo& Action : Mapping.Actions) + { + Action.Reset(); + } } } ImGui::EndMenuBar(); } - if (Actions.Num() == 0) + //-------------------------------------------------------------------------- + // Get all the existing mapping. This is not publicly exposed so we rob it. + //-------------------------------------------------------------------------- + TArray> AllAppliedMappings; + if (const CogInputMappingContextMap* AppliedMappingContexts = &PRIVATE_ACCESS_PTR(PlayerInput, UEnhancedPlayerInput_AppliedInputContexts)) { - for (TObjectPtr MappingContext : Asset->MappingContexts) + for (auto& kv : *AppliedMappingContexts) { - for (const FEnhancedActionKeyMapping& Mapping : MappingContext->GetMappings()) - { - if (Mapping.Action != nullptr && Actions.ContainsByPredicate([&Mapping](const FCogInjectActionInfo& ActionInfo) { return Mapping.Action == ActionInfo.Action; }) == false) - { - FCogInjectActionInfo& ActionInfo = Actions.AddDefaulted_GetRef(); - ActionInfo.Action = Mapping.Action; - } - } + FCogInputMappingContextInfo& MappingInfo = AllAppliedMappings.AddDefaulted_GetRef(); + MappingInfo.MappingContext = kv.Key; + MappingInfo.Priority = kv.Value; } - - Actions.Sort([](const FCogInjectActionInfo& Lhs, const FCogInjectActionInfo& Rhs) - { - return GetNameSafe(Lhs.Action).Compare(GetNameSafe(Rhs.Action)) < 0; - }); } - if (ImGui::BeginTable("Actions", 3, ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Resizable | ImGuiTableFlags_NoBordersInBodyUntilResize)) + //-------------------------------------------------------------------------- + // Remove mappings that are not present anymore. + //-------------------------------------------------------------------------- + for (int32 i = Mappings.Num() - 1; i >= 0; i--) { - ImGui::TableSetupColumn("Action", ImGuiTableColumnFlags_WidthFixed); - ImGui::TableSetupColumn("Value", ImGuiTableColumnFlags_WidthStretch); - ImGui::TableSetupColumn("Inject", ImGuiTableColumnFlags_WidthStretch); - ImGui::TableHeadersRow(); - - int Index = 0; - - for (FCogInjectActionInfo& ActionInfo : Actions) - { - ImGui::PushID(Index); - - const auto ActionName = StringCast(*ActionInfo.Action->GetName()); - - FInputActionValue ActionValue = EnhancedInputSubsystem->GetPlayerInput()->GetActionValue(ActionInfo.Action); - - switch (ActionInfo.Action->ValueType) + const FCogInputMappingContextInfo& MappingInfo = Mappings[i]; + if (AllAppliedMappings.ContainsByPredicate([&MappingInfo](const FCogInputMappingContextInfo& m) { - case EInputActionValueType::Boolean: - { - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::Text("%s", ActionName.Get()); + return m.MappingContext == MappingInfo.MappingContext; + })) + { + continue; + } - const ImVec4 ActiveColor(1, 0.8f, 0, 1); - const ImVec4 InnactiveColor(0.3f, 0.3f, 0.3f, 1); - const ImVec2 ButtonSize(FCogWindowWidgets::GetFontWidth() * 10, 0); + Mappings.RemoveAt(i); + } - ImGui::TableNextColumn(); - ImGui::BeginDisabled(); - bool Value = ActionValue.Get(); - FCogWindowWidgets::ToggleButton(&Value, "Pressed##Value", "Released##Value", ActiveColor, InnactiveColor, ButtonSize); - ImGui::EndDisabled(); + //-------------------------------------------------------------------------- + // Add mappings that were not yet added. + //-------------------------------------------------------------------------- + for (FCogInputMappingContextInfo& MappingInfo : AllAppliedMappings) + { + //---------------------------------------------------- + // The mapping was already added + //---------------------------------------------------- + if (Mappings.ContainsByPredicate([&MappingInfo](const FCogInputMappingContextInfo& m) { return m.MappingContext == MappingInfo.MappingContext; })) + { + continue; + } - ImGui::TableNextColumn(); - FCogWindowWidgets::ToggleButton(&ActionInfo.bPressed, "Pressed##Inject", "Released##Inject", ActiveColor, InnactiveColor, ButtonSize); - ImGui::SameLine(); - FCogWindowWidgets::ToggleButton(&ActionInfo.bRepeat, "Repeat", "Repeat", ActiveColor, InnactiveColor, ButtonSize); - break; - } + //---------------------------------------------------- + // Add the mapping + //---------------------------------------------------- + FCogInputMappingContextInfo& NewMappingInfo = Mappings.AddDefaulted_GetRef(); + NewMappingInfo.MappingContext = MappingInfo.MappingContext; + NewMappingInfo.Priority = MappingInfo.Priority; - case EInputActionValueType::Axis1D: - { - const float Value = ActionValue.Get(); - DrawAxis("%s", ActionName.Get(), Value, &ActionInfo.X); - break; - } - - case EInputActionValueType::Axis2D: - { - const FVector2D Value = ActionValue.Get(); - DrawAxis("%s X", ActionName.Get(), Value.X, &ActionInfo.X); - DrawAxis("%s Y", ActionName.Get(), Value.Y, &ActionInfo.Y); - break; - } - - case EInputActionValueType::Axis3D: - { - const FVector Value = ActionValue.Get(); - DrawAxis("%s X", ActionName.Get(), Value.X, &ActionInfo.X); - DrawAxis("%s Y", ActionName.Get(), Value.Y, &ActionInfo.Y); - DrawAxis("%s Z", ActionName.Get(), Value.Z, &ActionInfo.Z); - break; - } + //---------------------------------------------------- + // Add all the mapping actions + //---------------------------------------------------- + for (const FEnhancedActionKeyMapping& Mapping : NewMappingInfo.MappingContext->GetMappings()) + { + TObjectPtr Action = Mapping.Action; + if (Action == nullptr) + { + continue; } - ImGui::PopID(); - Index++; + //---------------------------------------------------- + // Actions are present multiple time, as many times + // as they are mapped to key. We only want to display + // the same action once per mapping + //---------------------------------------------------- + if (NewMappingInfo.Actions.ContainsByPredicate([&Action](const FCogInputActionInfo& m){ return m.Action == Action; })) + { + continue; + } + + FCogInputActionInfo& ActionInfo = NewMappingInfo.Actions.AddDefaulted_GetRef(); + ActionInfo.Action = Mapping.Action; + } + + Mappings.Sort([](const FCogInputMappingContextInfo& Lhs, const FCogInputMappingContextInfo& Rhs) + { + return Lhs.Priority < Rhs.Priority; + }); + } + + int Index = 0; + + for (FCogInputMappingContextInfo& Mapping : Mappings) + { + const auto MappingName = StringCast(*Mapping.MappingContext.GetName()); + const bool Open = ImGui::CollapsingHeader(MappingName.Get(), ImGuiTreeNodeFlags_DefaultOpen); + if (Open && ImGui::BeginTable("Actions", 3, ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Resizable | ImGuiTableFlags_NoBordersInBodyUntilResize)) + { + ImGui::TableSetupColumn("Action", ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("Current", ImGuiTableColumnFlags_WidthStretch); + ImGui::TableSetupColumn("Inject", ImGuiTableColumnFlags_WidthStretch); + + if (Config->ShowHeader) + { + ImGui::TableHeadersRow(); + } + + for (FCogInputActionInfo& ActionInfo : Mapping.Actions) + { + ImGui::PushID(Index); + + const auto ActionName = StringCast(*ActionInfo.Action->GetName()); + + FInputActionValue ActionValue = PlayerInput->GetActionValue(ActionInfo.Action); + + switch (ActionInfo.Action->ValueType) + { + case EInputActionValueType::Boolean: + { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("%s", ActionName.Get()); + + ImGui::TableNextColumn(); + ImGui::BeginDisabled(); + bool Value = ActionValue.Get(); + FCogWindowWidgets::PushBackColor(ImVec4(0.8f, 0.8f, 0.8f, 1)); + ImGui::Checkbox("##Current", &Value); + FCogWindowWidgets::PopBackColor(); + ImGui::EndDisabled(); + + ImGui::TableNextColumn(); + + ECheckBoxState State = ActionInfo.bRepeat ? ECheckBoxState::Undetermined : ActionInfo.bPressed ? ECheckBoxState::Checked : ECheckBoxState::Unchecked; + + if (FCogWindowWidgets::CheckBoxState("##Inject", State, false)) + { + if (IsControlDown) + { + ActionInfo.bRepeat = !ActionInfo.bRepeat; + ActionInfo.bPressed = false; + } + else + { + ActionInfo.bPressed = !ActionInfo.bPressed; + ActionInfo.bRepeat = false; + } + } + + if (ImGui::BeginPopupContextItem()) + { + ImGui::Checkbox("Repeat", &ActionInfo.bRepeat); + ImGui::EndPopup(); + } + + if (ImGui::IsItemHovered(ImGuiHoveredFlags_Stationary | ImGuiHoveredFlags_DelayShort)) + { + ImGui::BeginTooltip(); + ImGui::TextColored(ImVec4(1.0f, 1.0f, 1.0f, IsControlDown ? 1.0f : 0.5f), "Repeat [CTRL]"); + ImGui::EndTooltip(); + } + + break; + } + + case EInputActionValueType::Axis1D: + { + const float Value = ActionValue.Get(); + DrawAxis("%s", ActionName.Get(), Value, &ActionInfo.X); + break; + } + + case EInputActionValueType::Axis2D: + { + const FVector2D Value = ActionValue.Get(); + DrawAxis("%s X", ActionName.Get(), Value.X, &ActionInfo.X); + DrawAxis("%s Y", ActionName.Get(), Value.Y, &ActionInfo.Y); + break; + } + + case EInputActionValueType::Axis3D: + { + const FVector Value = ActionValue.Get(); + DrawAxis("%s X", ActionName.Get(), Value.X, &ActionInfo.X); + DrawAxis("%s Y", ActionName.Get(), Value.Y, &ActionInfo.Y); + DrawAxis("%s Z", ActionName.Get(), Value.Z, &ActionInfo.Z); + break; + } + } + + ImGui::PopID(); + Index++; + } + + ImGui::EndTable(); } - ImGui::EndTable(); } } @@ -214,9 +307,12 @@ void FCogInputWindow_Actions::RenderTick(float DeltaSeconds) IsTimeToRepeat = true; } - for (FCogInjectActionInfo& ActionInfo : Actions) + for (FCogInputMappingContextInfo Mapping : Mappings) { - ActionInfo.Inject(*EnhancedInput, IsTimeToRepeat); + for (FCogInputActionInfo& ActionInfo : Mapping.Actions) + { + ActionInfo.Inject(*EnhancedInput, IsTimeToRepeat); + } } } @@ -232,7 +328,9 @@ void FCogInputWindow_Actions::DrawAxis(const char* Format, const char* ActionNam ImGui::TableNextColumn(); ImGui::SetNextItemWidth(-1); ImGui::BeginDisabled(); + FCogWindowWidgets::PushBackColor(ImVec4(0.8f, 0.8f, 0.8f, 1)); ImGui::SliderFloat("##Value", &CurrentValue, -1.0f, 1.0f, "%0.2f"); + FCogWindowWidgets::PopBackColor(); ImGui::EndDisabled(); ImGui::TableNextColumn(); diff --git a/Plugins/CogInput/Source/CogInput/Private/CogInputWindow_Gamepad.cpp b/Plugins/CogInput/Source/CogInput/Private/CogInputWindow_Gamepad.cpp index 3182f98..d8f81a8 100644 --- a/Plugins/CogInput/Source/CogInput/Private/CogInputWindow_Gamepad.cpp +++ b/Plugins/CogInput/Source/CogInput/Private/CogInputWindow_Gamepad.cpp @@ -1,7 +1,6 @@ #include "CogInputWindow_Gamepad.h" #include "CogImguiHelper.h" -#include "CogInputDataAsset.h" #include "CogWindowWidgets.h" #include "Engine/LocalPlayer.h" #include "Engine/World.h" @@ -14,7 +13,6 @@ void FCogInputWindow_Gamepad::Initialize() { Super::Initialize(); - Asset = GetAsset(); Config = GetConfig(); } @@ -43,7 +41,7 @@ void FCogInputWindow_Gamepad::ResetConfig() } //-------------------------------------------------------------------------------------------------------------------------- -void FCogInputWindow_Gamepad::RenderButtonContextMenu(const FKey& Key, FCogInjectActionInfo* ActionInfoButton) +void FCogInputWindow_Gamepad::RenderButtonContextMenu(const FKey& Key, FCogInputActionInfo* ActionInfoButton) { if (ActionInfoButton != nullptr) { @@ -66,7 +64,7 @@ void FCogInputWindow_Gamepad::RenderButtonContextMenu(const FKey& Key, FCogInjec } //-------------------------------------------------------------------------------------------------------------------------- -void FCogInputWindow_Gamepad::RenderStickContextMenu(const FKey& Key, FCogInjectActionInfo* ActionInfo2D, bool& InvertY, float& Sensitivity) +void FCogInputWindow_Gamepad::RenderStickContextMenu(const FKey& Key, FCogInputActionInfo* ActionInfo2D, bool& InvertY, float& Sensitivity) { if (ActionInfo2D != nullptr) { @@ -83,7 +81,7 @@ void FCogInputWindow_Gamepad::RenderStickContextMenu(const FKey& Key, FCogInject } //-------------------------------------------------------------------------------------------------------------------------- -void FCogInputWindow_Gamepad::OnButtonClicked(FCogInjectActionInfo* ActionInfo) +void FCogInputWindow_Gamepad::OnButtonClicked(FCogInputActionInfo* ActionInfo) { if (ActionInfo == nullptr) { @@ -116,7 +114,7 @@ void FCogInputWindow_Gamepad::RenderButton(const FKey& Key, const ImVec2& Relati const ImVec2 Position = (CanvasMin + CanvasSize * RelativePosition) - Alignment * Size; bool IsPressed = false; - FCogInjectActionInfo* ActionInfo = Actions.Find(Key); + FCogInputActionInfo* ActionInfo = Actions.Find(Key); if (ActionInfo != nullptr) { if (ActionInfo->Action != nullptr) @@ -169,8 +167,8 @@ void FCogInputWindow_Gamepad::RenderStick(const FKey& Key2D, const FKey& KeyBool { ImGui::PushID((void*)(&Key2D)); - FCogInjectActionInfo* ActionInfoBool = Actions.Find(KeyBool); - FCogInjectActionInfo* ActionInfo2D = Actions.Find(Key2D); + FCogInputActionInfo* ActionInfoBool = Actions.Find(KeyBool); + FCogInputActionInfo* ActionInfo2D = Actions.Find(Key2D); FVector Value = Input->GetRawVectorKeyValue(Key2D); if (ActionInfo2D != nullptr && ActionInfo2D->Action != nullptr) @@ -288,48 +286,44 @@ void FCogInputWindow_Gamepad::RenderContent() return; } - if (Asset == nullptr) + if (Actions.Num() == 0) { - ImGui::TextDisabled("Invalid Asset"); - } - else - { - if (Actions.Num() == 0) - { - Actions.FindOrAdd(EKeys:: Gamepad_Left2D); - Actions.FindOrAdd(EKeys:: Gamepad_LeftX); - Actions.FindOrAdd(EKeys:: Gamepad_LeftY); - Actions.FindOrAdd(EKeys:: Gamepad_Right2D); - Actions.FindOrAdd(EKeys:: Gamepad_RightX); - Actions.FindOrAdd(EKeys:: Gamepad_RightY); - Actions.FindOrAdd(EKeys:: Gamepad_LeftTriggerAxis); - Actions.FindOrAdd(EKeys:: Gamepad_RightTriggerAxis); - Actions.FindOrAdd(EKeys:: Gamepad_LeftThumbstick); - Actions.FindOrAdd(EKeys:: Gamepad_RightThumbstick); - Actions.FindOrAdd(EKeys:: Gamepad_Special_Left); - Actions.FindOrAdd(EKeys:: Gamepad_Special_Left_X); - Actions.FindOrAdd(EKeys:: Gamepad_Special_Left_Y); - Actions.FindOrAdd(EKeys:: Gamepad_Special_Right); - Actions.FindOrAdd(EKeys:: Gamepad_FaceButton_Bottom); - Actions.FindOrAdd(EKeys:: Gamepad_FaceButton_Right); - Actions.FindOrAdd(EKeys:: Gamepad_FaceButton_Left); - Actions.FindOrAdd(EKeys:: Gamepad_FaceButton_Top); - Actions.FindOrAdd(EKeys:: Gamepad_LeftShoulder); - Actions.FindOrAdd(EKeys:: Gamepad_RightShoulder); - Actions.FindOrAdd(EKeys:: Gamepad_LeftTrigger); - Actions.FindOrAdd(EKeys:: Gamepad_RightTrigger); - Actions.FindOrAdd(EKeys:: Gamepad_DPad_Up); - Actions.FindOrAdd(EKeys:: Gamepad_DPad_Down); - Actions.FindOrAdd(EKeys:: Gamepad_DPad_Right); - Actions.FindOrAdd(EKeys:: Gamepad_DPad_Left); + Actions.FindOrAdd(EKeys:: Gamepad_Left2D); + Actions.FindOrAdd(EKeys:: Gamepad_LeftX); + Actions.FindOrAdd(EKeys:: Gamepad_LeftY); + Actions.FindOrAdd(EKeys:: Gamepad_Right2D); + Actions.FindOrAdd(EKeys:: Gamepad_RightX); + Actions.FindOrAdd(EKeys:: Gamepad_RightY); + Actions.FindOrAdd(EKeys:: Gamepad_LeftTriggerAxis); + Actions.FindOrAdd(EKeys:: Gamepad_RightTriggerAxis); + Actions.FindOrAdd(EKeys:: Gamepad_LeftThumbstick); + Actions.FindOrAdd(EKeys:: Gamepad_RightThumbstick); + Actions.FindOrAdd(EKeys:: Gamepad_Special_Left); + Actions.FindOrAdd(EKeys:: Gamepad_Special_Left_X); + Actions.FindOrAdd(EKeys:: Gamepad_Special_Left_Y); + Actions.FindOrAdd(EKeys:: Gamepad_Special_Right); + Actions.FindOrAdd(EKeys:: Gamepad_FaceButton_Bottom); + Actions.FindOrAdd(EKeys:: Gamepad_FaceButton_Right); + Actions.FindOrAdd(EKeys:: Gamepad_FaceButton_Left); + Actions.FindOrAdd(EKeys:: Gamepad_FaceButton_Top); + Actions.FindOrAdd(EKeys:: Gamepad_LeftShoulder); + Actions.FindOrAdd(EKeys:: Gamepad_RightShoulder); + Actions.FindOrAdd(EKeys:: Gamepad_LeftTrigger); + Actions.FindOrAdd(EKeys:: Gamepad_RightTrigger); + Actions.FindOrAdd(EKeys:: Gamepad_DPad_Up); + Actions.FindOrAdd(EKeys:: Gamepad_DPad_Down); + Actions.FindOrAdd(EKeys:: Gamepad_DPad_Right); + Actions.FindOrAdd(EKeys:: Gamepad_DPad_Left); - for (TObjectPtr MappingContext : Asset->MappingContexts) + if (const CogInputMappingContextMap* AppliedMappingContexts = &PRIVATE_ACCESS_PTR(Input, UEnhancedPlayerInput_AppliedInputContexts)) + { + for (auto& kv : *AppliedMappingContexts) { - for (const FEnhancedActionKeyMapping& Mapping : MappingContext->GetMappings()) + for (const FEnhancedActionKeyMapping& Mapping : kv.Key->GetMappings()) { if (Mapping.Action != nullptr) { - FCogInjectActionInfo& ActionInfo = Actions.FindOrAdd(Mapping.Key); + FCogInputActionInfo& ActionInfo = Actions.FindOrAdd(Mapping.Key); ActionInfo.Action = Mapping.Action; } } @@ -337,7 +331,6 @@ void FCogInputWindow_Gamepad::RenderContent() } } - constexpr float AspectRatio = 0.55f; constexpr float StickAmplitude = 0.04f; constexpr float StickRadius = 0.08f; @@ -345,8 +338,8 @@ void FCogInputWindow_Gamepad::RenderContent() constexpr float GamepadRound = 0.15f; constexpr float HandleWidth = 0.26f; constexpr ImVec2 DPadButtonSize(0.08f, 0.08f); - constexpr float DpadButtonDistance = 0.075f; - constexpr float DpadButtonRounding = 0.1f; + constexpr float DPadButtonDistance = 0.075f; + constexpr float DPadButtonRounding = 0.1f; constexpr ImVec2 SpecialButtonSize(0.08f, 0.04f); constexpr float SpecialButtonRound = 0.05f; constexpr float SpecialButtonDistance = 0.15f; @@ -420,19 +413,19 @@ void FCogInputWindow_Gamepad::RenderContent() // DPad Buttons //------------------------------ constexpr ImVec2 DPad_Pos(0.15f, 0.44f); - RenderButton(EKeys::Gamepad_DPad_Up, DPad_Pos + ImVec2(0.0f, -DpadButtonDistance / AspectRatio), DPadButtonSize, ImVec2(0.5f, 0.5f), DpadButtonRounding); - RenderButton(EKeys::Gamepad_DPad_Down, DPad_Pos + ImVec2(0.0f, DpadButtonDistance / AspectRatio), DPadButtonSize, ImVec2(0.5f, 0.5f), DpadButtonRounding); - RenderButton(EKeys::Gamepad_DPad_Left, DPad_Pos + ImVec2(-DpadButtonDistance, 0.0f), DPadButtonSize, ImVec2(0.5f, 0.5f), DpadButtonRounding); - RenderButton(EKeys::Gamepad_DPad_Right, DPad_Pos + ImVec2(DpadButtonDistance, 0.0f), DPadButtonSize, ImVec2(0.5f, 0.5f), DpadButtonRounding); + RenderButton(EKeys::Gamepad_DPad_Up, DPad_Pos + ImVec2(0.0f, -DPadButtonDistance / AspectRatio), DPadButtonSize, ImVec2(0.5f, 0.5f), DPadButtonRounding); + RenderButton(EKeys::Gamepad_DPad_Down, DPad_Pos + ImVec2(0.0f, DPadButtonDistance / AspectRatio), DPadButtonSize, ImVec2(0.5f, 0.5f), DPadButtonRounding); + RenderButton(EKeys::Gamepad_DPad_Left, DPad_Pos + ImVec2(-DPadButtonDistance, 0.0f), DPadButtonSize, ImVec2(0.5f, 0.5f), DPadButtonRounding); + RenderButton(EKeys::Gamepad_DPad_Right, DPad_Pos + ImVec2(DPadButtonDistance, 0.0f), DPadButtonSize, ImVec2(0.5f, 0.5f), DPadButtonRounding); //------------------------------ // Face Buttons //------------------------------ constexpr ImVec2 Face_Pos(1.0f - 0.15f, 0.44f); - RenderButton(EKeys::Gamepad_FaceButton_Top, Face_Pos + ImVec2(0.0f, -DpadButtonDistance / AspectRatio), DPadButtonSize, ImVec2(0.5f, 0.5f), DpadButtonRounding); - RenderButton(EKeys::Gamepad_FaceButton_Bottom, Face_Pos + ImVec2(0.0f, DpadButtonDistance / AspectRatio), DPadButtonSize, ImVec2(0.5f, 0.5f), DpadButtonRounding); - RenderButton(EKeys::Gamepad_FaceButton_Left, Face_Pos + ImVec2(-DpadButtonDistance, 0.0f), DPadButtonSize, ImVec2(0.5f, 0.5f), DpadButtonRounding); - RenderButton(EKeys::Gamepad_FaceButton_Right, Face_Pos + ImVec2(DpadButtonDistance, 0.0f), DPadButtonSize, ImVec2(0.5f, 0.5f), DpadButtonRounding); + RenderButton(EKeys::Gamepad_FaceButton_Top, Face_Pos + ImVec2(0.0f, -DPadButtonDistance / AspectRatio), DPadButtonSize, ImVec2(0.5f, 0.5f), DPadButtonRounding); + RenderButton(EKeys::Gamepad_FaceButton_Bottom, Face_Pos + ImVec2(0.0f, DPadButtonDistance / AspectRatio), DPadButtonSize, ImVec2(0.5f, 0.5f), DPadButtonRounding); + RenderButton(EKeys::Gamepad_FaceButton_Left, Face_Pos + ImVec2(-DPadButtonDistance, 0.0f), DPadButtonSize, ImVec2(0.5f, 0.5f), DPadButtonRounding); + RenderButton(EKeys::Gamepad_FaceButton_Right, Face_Pos + ImVec2(DPadButtonDistance, 0.0f), DPadButtonSize, ImVec2(0.5f, 0.5f), DPadButtonRounding); //------------------------------ // Special Buttons @@ -475,7 +468,7 @@ void FCogInputWindow_Gamepad::RenderTick(float DeltaSeconds) for (auto& Entry : Actions) { - FCogInjectActionInfo& ActionInfo = Entry.Value; + FCogInputActionInfo& ActionInfo = Entry.Value; ActionInfo.Inject(*EnhancedInput, IsTimeToRepeat); } } diff --git a/Plugins/CogInput/Source/CogInput/Public/CogInjectActionInfo.h b/Plugins/CogInput/Source/CogInput/Public/CogInputActionInfo.h similarity index 52% rename from Plugins/CogInput/Source/CogInput/Public/CogInjectActionInfo.h rename to Plugins/CogInput/Source/CogInput/Public/CogInputActionInfo.h index da58749..a645d83 100644 --- a/Plugins/CogInput/Source/CogInput/Public/CogInjectActionInfo.h +++ b/Plugins/CogInput/Source/CogInput/Public/CogInputActionInfo.h @@ -1,13 +1,19 @@ #pragma once #include "CoreMinimal.h" +#include "CogDebugRob.h" +#include "EnhancedPlayerInput.h" class UInputAction; +class UInputMappingContext; class UEnhancedInputLocalPlayerSubsystem; -struct FCogInjectActionInfo +typedef TMap, int32> CogInputMappingContextMap; +DEFINE_PRIVATE_ACCESSOR_VARIABLE(UEnhancedPlayerInput_AppliedInputContexts, UEnhancedPlayerInput, CogInputMappingContextMap, AppliedInputContexts); + +struct FCogInputActionInfo { - const UInputAction* Action = nullptr; + TObjectPtr Action; bool bPressed = false; @@ -36,3 +42,12 @@ struct FCogInjectActionInfo void Inject(UEnhancedInputLocalPlayerSubsystem& EnhancedInput, bool IsTimeToRepeat); }; + +struct FCogInputMappingContextInfo +{ + TObjectPtr MappingContext; + + int32 Priority = 0; + + TArray Actions; +}; \ No newline at end of file diff --git a/Plugins/CogInput/Source/CogInput/Public/CogInputDataAsset.h b/Plugins/CogInput/Source/CogInput/Public/CogInputDataAsset.h deleted file mode 100644 index bceb2a4..0000000 --- a/Plugins/CogInput/Source/CogInput/Public/CogInputDataAsset.h +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -#include "CoreMinimal.h" -#include "Engine/DataAsset.h" -#include "CogInputDataAsset.generated.h" - -class UInputAction; -class UInputMappingContext; - -UCLASS(Blueprintable) -class COGINPUT_API UCogInputDataAsset : public UPrimaryDataAsset -{ - GENERATED_BODY() - -public: - UCogInputDataAsset() {} - - UPROPERTY(EditAnywhere, Category="Cog") - TArray> MappingContexts; -}; diff --git a/Plugins/CogInput/Source/CogInput/Public/CogInputWindow_Actions.h b/Plugins/CogInput/Source/CogInput/Public/CogInputWindow_Actions.h index b85ddbd..a13835e 100644 --- a/Plugins/CogInput/Source/CogInput/Public/CogInputWindow_Actions.h +++ b/Plugins/CogInput/Source/CogInput/Public/CogInputWindow_Actions.h @@ -2,13 +2,12 @@ #include "CoreMinimal.h" #include "CogCommonConfig.h" -#include "CogInjectActionInfo.h" +#include "CogInputActionInfo.h" #include "CogWindow.h" #include "CogInputWindow_Actions.generated.h" class UInputAction; class UCogInputConfig_Actions; -class UCogInputDataAsset; //-------------------------------------------------------------------------------------------------------------------------- class COGINPUT_API FCogInputWindow_Actions : public FCogWindow @@ -35,11 +34,9 @@ private: float RepeatTime = 0.0f; - TObjectPtr Asset = nullptr; - TObjectPtr Config = nullptr; - TArray Actions; + TArray Mappings; }; //-------------------------------------------------------------------------------------------------------------------------- @@ -53,10 +50,14 @@ public: UPROPERTY(Config) float RepeatPeriod = 0.5f; + UPROPERTY(Config) + bool ShowHeader = true; + virtual void Reset() override { Super::Reset(); RepeatPeriod = 0.5f; + ShowHeader = true; } }; \ No newline at end of file diff --git a/Plugins/CogInput/Source/CogInput/Public/CogInputWindow_Gamepad.h b/Plugins/CogInput/Source/CogInput/Public/CogInputWindow_Gamepad.h index 05913d6..cbab139 100644 --- a/Plugins/CogInput/Source/CogInput/Public/CogInputWindow_Gamepad.h +++ b/Plugins/CogInput/Source/CogInput/Public/CogInputWindow_Gamepad.h @@ -2,7 +2,7 @@ #include "CoreMinimal.h" #include "CogCommonConfig.h" -#include "CogInjectActionInfo.h" +#include "CogInputActionInfo.h" #include "CogWindow.h" #include "imgui.h" #include "InputCoreTypes.h" @@ -37,19 +37,17 @@ protected: virtual void RenderStick(const FKey& Key2D, const FKey& KeyBool, bool& InvertY, float& Sensitivity, float Amplitude, const ImVec2& Position, float Radius); - virtual void OnButtonClicked(FCogInjectActionInfo* ActionInfo); + virtual void OnButtonClicked(FCogInputActionInfo* ActionInfo); virtual void RenderMainContextMenu(); - virtual void RenderButtonContextMenu(const FKey& Key, FCogInjectActionInfo* ActionInfoButton); + virtual void RenderButtonContextMenu(const FKey& Key, FCogInputActionInfo* ActionInfoButton); - virtual void RenderStickContextMenu(const FKey& Key, FCogInjectActionInfo* ActionInfo2D, bool& InvertY, float& Sensitivity); - - TObjectPtr Asset; + virtual void RenderStickContextMenu(const FKey& Key, FCogInputActionInfo* ActionInfo2D, bool& InvertY, float& Sensitivity); TObjectPtr Config; - TMap Actions; + TMap Actions; UEnhancedPlayerInput* Input = nullptr; diff --git a/README.md b/README.md index 6181a17..565a64c 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ Cog provides: - Window mangement with persistent configuration and layouts. - C++ and Blueprint functions to log and debug draw within Log Categories. - Control over the server regarding debug draw, logging, spawning, cheats. +- NetImgui support to ease the debugging of game server. General Info: - Cog can be used both in editor and package builds. It is disabled by default on shipping builds. @@ -149,6 +150,15 @@ Used to configure the network emulation ![Net Emulation](https://github.com/arnaud-jamin/Cog/assets/13844285/97103f15-fae8-4fe9-8189-8fdbcab5cb20) +### NetImgui +Handle connections to a [NetImgui](https://github.com/sammyfreg/netImgui) server. + +![NetImgui](https://github.com/user-attachments/assets/ea1d4a28-4c2f-460c-ac7d-5f6ef8e6e6dd) + +The following image shows the editor running along a dedicated server. The NetImgui server displays the dedicated server imgui windows. +This can be used to debug the state of the game server. For example the behavior trees are only available on the game server. +![image](https://github.com/user-attachments/assets/3cd788c9-9884-4c1c-8333-7a311bdcd20a) + ### Output Log Display the output log based on each log categories verbosity. @@ -258,7 +268,7 @@ Log and debug draw functions can be filtered by the selected actor. ### Testing the sample -You must have Unreal 5.1 or greater and Visual Studio to launch the sample +You must have Unreal 5.5 or greater and Visual Studio to launch the sample 1. Download the code 2. Right Click `Cog.uproject` and click `Generate Visual Studio project files` @@ -272,7 +282,7 @@ You must have Unreal 5.1 or greater and Visual Studio to launch the sample ### Integrating Cog in your project The Cog repository has the following structure: -- `CogSample` - A Sample that demonstrate various Cog functionalities. The project was saved in Unreal 5.1 +- `CogSample` - A Sample that demonstrate various Cog functionalities. The project was saved in Unreal 5.5 - `Plugins/CogAbility` - ImGui windows for the Gameplay Ability System (Abilities, Effects, Tags, ...) - `Plugins/CogAI` - ImGui windows for AI (Behavior Tree, Blackboard) - `Plugins/CogInput` - ImGui windows for the Enhanced Input library (Input action, Gamepad) @@ -456,8 +466,3 @@ class ACogSamplePlayerController ![Data Assets](https://github.com/arnaud-jamin/Cog/assets/13844285/1f4f3255-4104-4dfc-ab9e-fd34335c0289) -Currently, Cog does not properly work when running under a single process in multiplayer mode. You might want to disable the setting `Editor Preferences - Run Under One Process`: - -![image](https://github.com/arnaud-jamin/Cog/assets/13844285/6079b71c-bd41-4193-b3c6-aa76a70984e5) - - diff --git a/Source/CogSample.Target.cs b/Source/CogSample.Target.cs index c8d8b72..32b4e38 100644 --- a/Source/CogSample.Target.cs +++ b/Source/CogSample.Target.cs @@ -5,11 +5,9 @@ public class CogSampleTarget : TargetRules { public CogSampleTarget(TargetInfo Target) : base(Target) { - Type = TargetType.Game; - DefaultBuildSettings = BuildSettingsVersion.V2; - //IncludeOrderVersion = EngineIncludeOrderVersion.Unreal5_2; - ExtraModuleNames.Add("CogSample"); - //bUseUnityBuild = false; - //bUsePCHFiles = false; + Type = TargetType.Game; + DefaultBuildSettings = BuildSettingsVersion.V2; + DefaultBuildSettings = BuildSettingsVersion.Latest; + IncludeOrderVersion = EngineIncludeOrderVersion.Latest; } } diff --git a/Source/CogSample/CogSampleAnimNotify.cpp b/Source/CogSample/CogSampleAnimNotify.cpp new file mode 100644 index 0000000..0f9580c --- /dev/null +++ b/Source/CogSample/CogSampleAnimNotify.cpp @@ -0,0 +1,52 @@ +#include "CogSampleAnimNotify.h" + +#include "CogCommon.h" + +#include "Animation/AnimSequenceBase.h" +#include "Components/SkeletalMeshComponent.h" + +#if ENABLE_COG +#include "CogDebugPlot.h" +#endif + +//-------------------------------------------------------------------------------------------------------------------------- +UCogSampleAnimNotify::UCogSampleAnimNotify(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ + bIsNativeBranchingPoint = true; +} + +//-------------------------------------------------------------------------------------------------------------------------- +void UCogSampleAnimNotify::Notify(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation, const FAnimNotifyEventReference& EventReference) +{ + Super::Notify(MeshComp, Animation, EventReference); + +#if ENABLE_COG + FCogDebugPlot::PlotEventInstant(MeshComp->GetOwner(), "Anim Notify", GetFName()) + .AddParam("Name", GetNameSafe(this)) + .AddParam("Animation", GetNameSafe(Animation)) + .AddParam("Debug Info", GetDebugInfo()); +#endif +} + +//-------------------------------------------------------------------------------------------------------------------------- +void UCogSampleAnimNotify::BranchingPointNotify(FBranchingPointNotifyPayload& BranchingPointPayload) +{ + //-------------------------------------------------------------------------------------------------------- + // Replace UAnimNotify::BranchingPointNotify to fill the EventReference with the NotifyEvent for + // UGPCoreAnimMotifyFunctionLibrary::AnimNotifyEventReferenceGetMontage to work properly + //-------------------------------------------------------------------------------------------------------- + // Super::BranchingPointNotify(BranchingPointPayload); + const FAnimNotifyEventReference EventReference(BranchingPointPayload.NotifyEvent, + BranchingPointPayload.SequenceAsset); + + Notify(BranchingPointPayload.SkelMeshComponent, BranchingPointPayload.SequenceAsset, EventReference); +} + +//-------------------------------------------------------------------------------------------------------------------------- +FString UCogSampleAnimNotify::GetDebugInfo_Implementation() const +{ + FString DebugInfo; + return DebugInfo; +} + \ No newline at end of file diff --git a/Source/CogSample/CogSampleAnimNotify.h b/Source/CogSample/CogSampleAnimNotify.h new file mode 100644 index 0000000..1578581 --- /dev/null +++ b/Source/CogSample/CogSampleAnimNotify.h @@ -0,0 +1,23 @@ +#pragma once + +#include "CoreMinimal.h" + +#include "Animation/AnimNotifies/AnimNotify.h" + +#include "CogSampleAnimNotify.generated.h" + +UCLASS() +class UCogSampleAnimNotify : public UAnimNotify +{ + GENERATED_BODY() + +public: + UCogSampleAnimNotify(const FObjectInitializer& ObjectInitializer); + + UFUNCTION(BlueprintNativeEvent) + FString GetDebugInfo() const; + + void Notify(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation, const FAnimNotifyEventReference& EventReference) override; + + void BranchingPointNotify(FBranchingPointNotifyPayload& BranchingPointPayload) override; +}; diff --git a/Source/CogSample/CogSampleAnimNotifyState.cpp b/Source/CogSample/CogSampleAnimNotifyState.cpp new file mode 100644 index 0000000..1469fd1 --- /dev/null +++ b/Source/CogSample/CogSampleAnimNotifyState.cpp @@ -0,0 +1,86 @@ +#include "CogSampleAnimNotifyState.h" + +#include "CogCommon.h" + +#include "Animation/AnimNotifies/AnimNotify.h" +#include "Animation/AnimNotifyEndDataContext.h" +#include "Animation/AnimSequenceBase.h" +#include "Components/SkeletalMeshComponent.h" + +#if ENABLE_COG +#include "CogDebugPlot.h" +#endif + +//-------------------------------------------------------------------------------------------------------------------------- +UCogSampleAnimNotifyState::UCogSampleAnimNotifyState(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ + bIsNativeBranchingPoint = false; +} + +//-------------------------------------------------------------------------------------------------------------------------- +void UCogSampleAnimNotifyState::NotifyBegin(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation, float TotalDuration, const FAnimNotifyEventReference& EventReference) +{ +#if ENABLE_COG + FCogDebugPlot::PlotEventStart(MeshComp->GetOwner(), "Anim Notify", GetFName()) + .AddParam("Name", GetNameSafe(this)) + .AddParam("Animation", GetNameSafe(Animation)) + .AddParam("Debug Info", GetDebugInfo()); +#endif + + Super::NotifyBegin(MeshComp, Animation, TotalDuration, EventReference); +} + +//-------------------------------------------------------------------------------------------------------------------------- +void UCogSampleAnimNotifyState::NotifyEnd(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation, const FAnimNotifyEventReference& EventReference) +{ +#if ENABLE_COG + FCogDebugPlot::PlotEventStop(MeshComp->GetOwner(), "Anim Notify", GetFName()); +#endif + + Super::NotifyEnd(MeshComp, Animation, EventReference); +} + +//-------------------------------------------------------------------------------------------------------------------------- +void UCogSampleAnimNotifyState::BranchingPointNotifyBegin(FBranchingPointNotifyPayload& BranchingPointPayload) +{ + //-------------------------------------------------------------------------------------------------------- + // Replace UAnimNotifyState::BranchingPointNotifyBegin to fill the EventReference with the NotifyEvent for + // UGPCoreAnimMotifyFunctionLibrary::AnimNotifyEventReferenceGetMontage to work properly + //-------------------------------------------------------------------------------------------------------- + // Super::BranchingPointNotifyBegin(BranchingPointPayload); + + const FAnimNotifyEventReference EventReference(BranchingPointPayload.NotifyEvent, + BranchingPointPayload.SequenceAsset); + + NotifyBegin(BranchingPointPayload.SkelMeshComponent, + BranchingPointPayload.SequenceAsset, + BranchingPointPayload.NotifyEvent + ? BranchingPointPayload.NotifyEvent->GetDuration() + : 0.f, + EventReference); +} + +//-------------------------------------------------------------------------------------------------------------------------- +void UCogSampleAnimNotifyState::BranchingPointNotifyEnd(FBranchingPointNotifyPayload& BranchingPointPayload) +{ + //-------------------------------------------------------------------------------------------------------- + // Replace UAnimNotifyState::BranchingPointNotifyEnd to fill the EventReference with the NotifyEvent for + // UGPCoreAnimMotifyFunctionLibrary::AnimNotifyEventReferenceGetMontage to work properly + //-------------------------------------------------------------------------------------------------------- + // Super::BranchingPointNotifyEnd(BranchingPointPayload); + + FAnimNotifyEventReference EventReference(BranchingPointPayload.NotifyEvent, BranchingPointPayload.SequenceAsset); + if (BranchingPointPayload.bReachedEnd) + { + EventReference.AddContextData(true); + } + NotifyEnd(BranchingPointPayload.SkelMeshComponent, BranchingPointPayload.SequenceAsset, EventReference); +} + +//-------------------------------------------------------------------------------------------------------------------------- +FString UCogSampleAnimNotifyState::GetDebugInfo_Implementation() const +{ + FString DebugInfo; + return DebugInfo; +} diff --git a/Source/CogSample/CogSampleAnimNotifyState.h b/Source/CogSample/CogSampleAnimNotifyState.h new file mode 100644 index 0000000..9897118 --- /dev/null +++ b/Source/CogSample/CogSampleAnimNotifyState.h @@ -0,0 +1,27 @@ +#pragma once + +#include "CoreMinimal.h" + +#include "Animation/AnimNotifies/AnimNotifyState.h" + +#include "CogSampleAnimNotifyState.generated.h" + +UCLASS() +class UCogSampleAnimNotifyState : public UAnimNotifyState +{ + GENERATED_BODY() + +public: + UCogSampleAnimNotifyState(const FObjectInitializer& ObjectInitializer); + + UFUNCTION(BlueprintNativeEvent) + FString GetDebugInfo() const; + + void NotifyBegin(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation, float TotalDuration, const FAnimNotifyEventReference& EventReference) override; + + void NotifyEnd(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation, const FAnimNotifyEventReference& EventReference) override; + + void BranchingPointNotifyBegin(FBranchingPointNotifyPayload& BranchingPointPayload) override; + + void BranchingPointNotifyEnd(FBranchingPointNotifyPayload& BranchingPointPayload) override; +}; diff --git a/Source/CogSample/CogSampleAttributeSet_Ability_Blast.cpp b/Source/CogSample/CogSampleAttributeSet_Ability_Blast.cpp new file mode 100644 index 0000000..d76a28a --- /dev/null +++ b/Source/CogSample/CogSampleAttributeSet_Ability_Blast.cpp @@ -0,0 +1,22 @@ +#include "CogSampleAttributeSet_Ability_Blast.h" + +#include "Net/Core/PushModel/PushModel.h" +#include "Net/UnrealNetwork.h" + +//-------------------------------------------------------------------------------------------------------------------------- +UCogSampleAttributeSet_Ability_Blast::UCogSampleAttributeSet_Ability_Blast() +{ +} + +//-------------------------------------------------------------------------------------------------------------------------- +void UCogSampleAttributeSet_Ability_Blast::GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const +{ + Super::GetLifetimeReplicatedProps(OutLifetimeProps); + + FDoRepLifetimeParams Params; + Params.bIsPushBased = true; + Params.RepNotifyCondition = REPNOTIFY_Always; + + DOREPLIFETIME_WITH_PARAMS_FAST(UCogSampleAttributeSet_Ability_Blast, Cooldown, Params); + DOREPLIFETIME_WITH_PARAMS_FAST(UCogSampleAttributeSet_Ability_Blast, Cost, Params); +} diff --git a/Source/CogSample/CogSampleAttributeSet_Ability_Blast.h b/Source/CogSample/CogSampleAttributeSet_Ability_Blast.h new file mode 100644 index 0000000..9df7ef0 --- /dev/null +++ b/Source/CogSample/CogSampleAttributeSet_Ability_Blast.h @@ -0,0 +1,31 @@ +#pragma once + +#include "CoreMinimal.h" +#include "AttributeSet.h" +#include "AbilitySystemComponent.h" +#include "CogSampleFunctionLibrary_Gameplay.h" +#include "CogSampleAttributeSet_Ability_Blast.generated.h" + +UCLASS() +class UCogSampleAttributeSet_Ability_Blast : public UAttributeSet +{ + GENERATED_BODY() + +public: + + UCogSampleAttributeSet_Ability_Blast(); + +protected: + + UPROPERTY(BlueprintReadOnly, Replicated, Meta = (AllowPrivateAccess = true)) + FGameplayAttributeData Cooldown; + + UPROPERTY(BlueprintReadOnly, Replicated, Meta = (AllowPrivateAccess = true)) + FGameplayAttributeData Cost; + + +public: + ATTRIBUTE_ACCESSORS(UCogSampleAttributeSet_Ability_Blast, Cooldown); + ATTRIBUTE_ACCESSORS(UCogSampleAttributeSet_Ability_Blast, Cost); +}; + diff --git a/Source/CogSample/CogSampleAttributeSet_Ability_Shield.cpp b/Source/CogSample/CogSampleAttributeSet_Ability_Shield.cpp new file mode 100644 index 0000000..fe43433 --- /dev/null +++ b/Source/CogSample/CogSampleAttributeSet_Ability_Shield.cpp @@ -0,0 +1,22 @@ +#include "CogSampleAttributeSet_Ability_Shield.h" + +#include "Net/Core/PushModel/PushModel.h" +#include "Net/UnrealNetwork.h" + +//-------------------------------------------------------------------------------------------------------------------------- +UCogSampleAttributeSet_Ability_Shield::UCogSampleAttributeSet_Ability_Shield() +{ +} + +//-------------------------------------------------------------------------------------------------------------------------- +void UCogSampleAttributeSet_Ability_Shield::GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const +{ + Super::GetLifetimeReplicatedProps(OutLifetimeProps); + + FDoRepLifetimeParams Params; + Params.bIsPushBased = true; + Params.RepNotifyCondition = REPNOTIFY_Always; + + DOREPLIFETIME_WITH_PARAMS_FAST(UCogSampleAttributeSet_Ability_Shield, Cooldown, Params); + DOREPLIFETIME_WITH_PARAMS_FAST(UCogSampleAttributeSet_Ability_Shield, Cost, Params); +} diff --git a/Source/CogSample/CogSampleAttributeSet_Ability_Shield.h b/Source/CogSample/CogSampleAttributeSet_Ability_Shield.h new file mode 100644 index 0000000..f61b08c --- /dev/null +++ b/Source/CogSample/CogSampleAttributeSet_Ability_Shield.h @@ -0,0 +1,31 @@ +#pragma once + +#include "CoreMinimal.h" +#include "AttributeSet.h" +#include "AbilitySystemComponent.h" +#include "CogSampleFunctionLibrary_Gameplay.h" +#include "CogSampleAttributeSet_Ability_Shield.generated.h" + +UCLASS() +class UCogSampleAttributeSet_Ability_Shield : public UAttributeSet +{ + GENERATED_BODY() + +public: + + UCogSampleAttributeSet_Ability_Shield(); + +private: + + UPROPERTY(BlueprintReadOnly, Replicated, Meta = (AllowPrivateAccess = true)) + FGameplayAttributeData Cooldown; + + UPROPERTY(BlueprintReadOnly, Replicated, Meta = (AllowPrivateAccess = true)) + FGameplayAttributeData Cost; + + +public: + ATTRIBUTE_ACCESSORS(UCogSampleAttributeSet_Ability_Shield, Cooldown); + ATTRIBUTE_ACCESSORS(UCogSampleAttributeSet_Ability_Shield, Cost); +}; + diff --git a/Source/CogSample/CogSampleCharacter.cpp b/Source/CogSample/CogSampleCharacter.cpp index b72b622..a74b44c 100644 --- a/Source/CogSample/CogSampleCharacter.cpp +++ b/Source/CogSample/CogSampleCharacter.cpp @@ -370,8 +370,18 @@ void ACogSampleCharacter::SetupPlayerInputComponent(class UInputComponent* Playe int32 AbilityIndex = 0; for (const FActiveAbilityInfo& AbilityInfo : ActiveAbilities) { - EnhancedInputComponent->BindAction(AbilityInfo.InputAction, ETriggerEvent::Started, this, &ACogSampleCharacter::OnAbilityInputStarted, AbilityIndex); - EnhancedInputComponent->BindAction(AbilityInfo.InputAction, ETriggerEvent::Completed, this, &ACogSampleCharacter::OnAbilityInputCompleted, AbilityIndex); + EnhancedInputComponent->BindActionValueLambda(AbilityInfo.InputAction, ETriggerEvent::Started, + [this, &AbilityInfo, AbilityIndex](const FInputActionValue& InputActionValue) + { + OnAbilityInputStarted(AbilityInfo.InputAction, InputActionValue, AbilityIndex); + }); + + EnhancedInputComponent->BindActionValueLambda(AbilityInfo.InputAction, ETriggerEvent::Completed, + [this, &AbilityInfo, AbilityIndex](const FInputActionValue& InputActionValue) + { + OnAbilityInputCompleted(AbilityInfo.InputAction, InputActionValue, AbilityIndex); + }); + AbilityIndex++; } @@ -385,10 +395,14 @@ void ACogSampleCharacter::SetupPlayerInputComponent(class UInputComponent* Playe } //-------------------------------------------------------------------------------------------------------------------------- -void ACogSampleCharacter::OnAbilityInputStarted(const FInputActionValue& Value, int32 Index) +void ACogSampleCharacter::OnAbilityInputStarted(const UInputAction* InputAction, const FInputActionValue& Value, int32 Index) { COG_LOG_OBJECT(LogCogInput, ELogVerbosity::Verbose, this, TEXT("%d"), Index); +#if ENABLE_COG + FCogDebugPlot::PlotEventStart(this, "Input", InputAction->GetFName()); +#endif + if (ActiveAbilityHandles.IsValidIndex(Index) == false) { return; @@ -403,6 +417,12 @@ void ACogSampleCharacter::OnAbilityInputStarted(const FInputActionValue& Value, Spec->InputPressed = true; + UGameplayAbility* Ability = Spec->GetPrimaryInstance(); + if (Ability == nullptr) + { + return; + } + //----------------------------------------------------- // Replicate button press if ability is already active //----------------------------------------------------- @@ -414,7 +434,7 @@ void ACogSampleCharacter::OnAbilityInputStarted(const FInputActionValue& Value, AbilitySystem->ServerSetInputPressed(Spec->Handle); } AbilitySystem->AbilitySpecInputPressed(*Spec); - AbilitySystem->InvokeReplicatedEvent(EAbilityGenericReplicatedEvent::InputPressed, Spec->Handle, Spec->ActivationInfo.GetActivationPredictionKey()); + AbilitySystem->InvokeReplicatedEvent(EAbilityGenericReplicatedEvent::InputPressed, Spec->Handle, Ability->GetCurrentActivationInfo().GetActivationPredictionKey()); } else { @@ -423,10 +443,14 @@ void ACogSampleCharacter::OnAbilityInputStarted(const FInputActionValue& Value, } //-------------------------------------------------------------------------------------------------------------------------- -void ACogSampleCharacter::OnAbilityInputCompleted(const FInputActionValue& Value, int32 Index) +void ACogSampleCharacter::OnAbilityInputCompleted(const UInputAction* InputAction, const FInputActionValue& Value, int32 Index) { COG_LOG_OBJECT(LogCogInput, ELogVerbosity::Verbose, this, TEXT("%d"), Index); +#if ENABLE_COG + FCogDebugPlot::PlotEventStop(this, "Input", InputAction->GetFName()); +#endif + if (ActiveAbilityHandles.IsValidIndex(Index) == false) { return; @@ -441,7 +465,7 @@ void ACogSampleCharacter::OnAbilityInputCompleted(const FInputActionValue& Value Spec->InputPressed = false; - UGameplayAbility* Ability= Spec->GetPrimaryInstance(); + UGameplayAbility* Ability = Spec->GetPrimaryInstance(); if (Ability == nullptr) { return; @@ -458,7 +482,7 @@ void ACogSampleCharacter::OnAbilityInputCompleted(const FInputActionValue& Value } AbilitySystem->AbilitySpecInputReleased(*Spec); - AbilitySystem->InvokeReplicatedEvent(EAbilityGenericReplicatedEvent::InputReleased, Spec->Handle, Spec->ActivationInfo.GetActivationPredictionKey()); + AbilitySystem->InvokeReplicatedEvent(EAbilityGenericReplicatedEvent::InputReleased, Spec->Handle, Ability->GetCurrentActivationInfo().GetActivationPredictionKey()); } //-------------------------------------------------------------------------------------------------------------------------- diff --git a/Source/CogSample/CogSampleCharacter.h b/Source/CogSample/CogSampleCharacter.h index d40ed24..0d4d6ce 100644 --- a/Source/CogSample/CogSampleCharacter.h +++ b/Source/CogSample/CogSampleCharacter.h @@ -310,9 +310,9 @@ protected: void Look(const FInputActionValue& Value); - void OnAbilityInputStarted(const FInputActionValue& Value, int32 Index); + void OnAbilityInputStarted(const UInputAction* InputAction, const FInputActionValue& Value, int32 Index); - void OnAbilityInputCompleted(const FInputActionValue& Value, int32 Index); + void OnAbilityInputCompleted(const UInputAction* InputAction, const FInputActionValue& Value, int32 Index); void ActivateItem(const FInputActionValue& Value, int32 Index); diff --git a/Source/CogSample/CogSampleGameState.cpp b/Source/CogSample/CogSampleGameState.cpp index cdd0881..f4bc76e 100644 --- a/Source/CogSample/CogSampleGameState.cpp +++ b/Source/CogSample/CogSampleGameState.cpp @@ -2,7 +2,9 @@ #include "CogSampleAbilitySystemComponent.h" #include "GameFramework/GameState.h" +#include "GameFramework/PlayerState.h" #include "Modules/ModuleManager.h" +#include "Net/UnrealNetwork.h" #if ENABLE_COG #include "CogAll.h" @@ -25,6 +27,13 @@ ACogSampleGameState::ACogSampleGameState(const FObjectInitializer & ObjectInitia AbilitySystemComponent->SetReplicationMode(EGameplayEffectReplicationMode::Minimal); } +//-------------------------------------------------------------------------------------------------------------------------- +void ACogSampleGameState::GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const +{ + Super::GetLifetimeReplicatedProps(OutLifetimeProps); + DOREPLIFETIME(ThisClass, _ServerFramerateRaw); +} + //-------------------------------------------------------------------------------------------------------------------------- void ACogSampleGameState::BeginPlay() { @@ -66,9 +75,52 @@ void ACogSampleGameState::Tick(float DeltaSeconds) #if ENABLE_COG extern ENGINE_API float GAverageFPS; - extern ENGINE_API float GAverageMS; - FCogDebugPlot::PlotValue(this, "Frame Rate", GAverageFPS); - FCogDebugPlot::PlotValue(this, "Frame Time", GAverageMS); + + constexpr float smoothing = 10.0f; + + _ClientFramerateSmooth = _ClientFramerateSmooth >= 0.0f + ? FMath::FInterpTo(_ClientFramerateSmooth, GAverageFPS, DeltaSeconds, smoothing) + : GAverageFPS; + + _ServerFramerateSmooth = _ServerFramerateSmooth >= 0.0f + ? FMath::FInterpTo(_ServerFramerateSmooth, _ServerFramerateRaw, DeltaSeconds, smoothing) + : _ServerFramerateRaw; + + if (GetLocalRole() != ROLE_Authority) + { + FCogDebugPlot::PlotValue(this, "Frame Rate Client Raw", GAverageFPS); + FCogDebugPlot::PlotValue(this, "Frame Rate Client Smooth", _ClientFramerateSmooth); + FCogDebugPlot::PlotValue(this, "Frame Rate Server Raw", _ServerFramerateRaw); + FCogDebugPlot::PlotValue(this, "Frame Rate Server Smooth", _ServerFramerateSmooth); + + if (const ULocalPlayer* LocalPlayer = GetWorld()->GetFirstLocalPlayerFromController()) + { + if (const APlayerController* PlayerController = LocalPlayer->PlayerController) + { + if (const APlayerState* PlayerState = PlayerController->GetPlayerState()) + { + FCogDebugPlot::PlotValue(this, "Ping", PlayerState->GetPingInMilliseconds()); + } + + if (const UNetConnection* Connection = PlayerController->GetNetConnection()) + { + FCogDebugPlot::PlotValue(this, + "Packet Loss In", + Connection->GetInLossPercentage().GetAvgLossPercentage() * 100.0f); + + FCogDebugPlot::PlotValue(this, + "Packet Loss Out", + Connection->GetOutLossPercentage().GetAvgLossPercentage() * 100.0f); + } + } + } + } + else + { + FCogDebugPlot::PlotValue(this, "Frame Rate Raw", GAverageFPS); + FCogDebugPlot::PlotValue(this, "Frame Rate Smooth", _ClientFramerateSmooth); + } + if (CogWindowManager != nullptr) { diff --git a/Source/CogSample/CogSampleGameState.h b/Source/CogSample/CogSampleGameState.h index ba071e1..654b3f7 100644 --- a/Source/CogSample/CogSampleGameState.h +++ b/Source/CogSample/CogSampleGameState.h @@ -36,11 +36,19 @@ private: UPROPERTY() TObjectPtr CogWindowManagerRef = nullptr; +protected: + UPROPERTY(Replicated) + float _ServerFramerateRaw = 0.0f; + #if ENABLE_COG void InitializeCog(); TObjectPtr CogWindowManager = nullptr; + float _ClientFramerateSmooth = 0.0f; + + float _ServerFramerateSmooth = 0.0f; + #endif //ENABLE_COG }; diff --git a/Source/CogSample/CogSampleGameplayAbility.cpp b/Source/CogSample/CogSampleGameplayAbility.cpp index 958b245..df867b2 100644 --- a/Source/CogSample/CogSampleGameplayAbility.cpp +++ b/Source/CogSample/CogSampleGameplayAbility.cpp @@ -8,6 +8,10 @@ #include "CogSamplePlayerController.h" #include "CogSampleSpawnPredictionComponent.h" +#if ENABLE_COG +#include "CogDebugPlot.h" +#endif + //-------------------------------------------------------------------------------------------------------------------------- UCogSampleGameplayAbility::UCogSampleGameplayAbility() { @@ -18,14 +22,30 @@ UCogSampleGameplayAbility::UCogSampleGameplayAbility() //-------------------------------------------------------------------------------------------------------------------------- void UCogSampleGameplayAbility::PreActivate(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, FOnGameplayAbilityEnded::FDelegate* OnGameplayAbilityEndedDelegate, const FGameplayEventData* TriggerEventData) { - COG_LOG_ABILITY(ELogVerbosity::Verbose, this, TEXT("PreActivate")); +#if ENABLE_COG + + COG_LOG_ABILITY(ELogVerbosity::Verbose, this, TEXT("")); + + FCogDebugPlot::PlotEventStart(this, "Ability", GetFName()) + .AddParam("Name", GetNameSafe(this)) + .AddParam("Owner", GetNameSafe(ActorInfo->OwnerActor.Get())) + .AddParam("Avatar", GetNameSafe(ActorInfo->AvatarActor.Get())) + .AddParam("Player Controller", GetNameSafe(ActorInfo->PlayerController.Get())) + .AddParam("Prediction Key", ActivationInfo.GetActivationPredictionKey().ToString()) + .AddParam("Event Tag", TriggerEventData ? *TriggerEventData->EventTag.ToString() : FString("None")) + .AddParam("Event Magnitude", TriggerEventData ? TriggerEventData->EventMagnitude : 0.0f); + +#endif + Super::PreActivate(Handle, ActorInfo, ActivationInfo, OnGameplayAbilityEndedDelegate, TriggerEventData); + + } //-------------------------------------------------------------------------------------------------------------------------- void UCogSampleGameplayAbility::ActivateAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, const FGameplayEventData* TriggerEventData) { - COG_LOG_ABILITY(ELogVerbosity::Verbose, this, TEXT("PredictionKey:%s"), *GetAbilitySystemComponentFromActorInfo_Checked()->ScopedPredictionKey.ToString()); + COG_LOG_ABILITY(ELogVerbosity::Verbose, this, TEXT("")); Super::ActivateAbility(Handle, ActorInfo, ActivationInfo, TriggerEventData); } @@ -33,7 +53,14 @@ void UCogSampleGameplayAbility::ActivateAbility(const FGameplayAbilitySpecHandle void UCogSampleGameplayAbility::EndAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, bool bReplicateEndAbility, bool bWasCancelled) { Super::EndAbility(Handle, ActorInfo, ActivationInfo, bReplicateEndAbility, bWasCancelled); + +#if ENABLE_COG + COG_LOG_ABILITY(ELogVerbosity::Verbose, this, TEXT("")); + + FCogDebugPlot::PlotEventStop(this, "Ability", GetFName()); + +#endif } //-------------------------------------------------------------------------------------------------------------------------- diff --git a/Source/CogSample/CogSamplePlayerController.cpp b/Source/CogSample/CogSamplePlayerController.cpp index 6c4dccb..d297933 100644 --- a/Source/CogSample/CogSamplePlayerController.cpp +++ b/Source/CogSample/CogSamplePlayerController.cpp @@ -12,7 +12,6 @@ #if ENABLE_COG #include "CogAbilityReplicator.h" #include "CogDebugDraw.h" -#include "CogDebugPlot.h" #include "CogDebugReplicator.h" #include "CogEngineReplicator.h" #include "Framework/Application/NavigationConfig.h" diff --git a/Source/CogSample/CogSampleSpawnPredictionComponent.cpp b/Source/CogSample/CogSampleSpawnPredictionComponent.cpp index 63907e6..d251b0c 100644 --- a/Source/CogSample/CogSampleSpawnPredictionComponent.cpp +++ b/Source/CogSample/CogSampleSpawnPredictionComponent.cpp @@ -47,7 +47,7 @@ FCogSampleSpawnPredictionKey FCogSampleSpawnPredictionKey::MakeFromAbility(const FCogSampleSpawnPredictionKey Key; Key.Creator = InAbility.GetAvatarActorFromActorInfo() != nullptr ? InAbility.GetAvatarActorFromActorInfo()->GetFName() : FName(); Key.Ability = InAbility.GetFName(); - Key.PredictionKey = Spec->ActivationInfo.GetActivationPredictionKey(); + Key.PredictionKey = InAbility.GetCurrentActivationInfo().GetActivationPredictionKey(); Key.InstanceIndex = InInstanceIndex; Key.GameTime = InAbility.GetWorld()->GetTimeSeconds(); return Key; diff --git a/Source/CogSample/CogSampleTargetAcquisition.cpp b/Source/CogSample/CogSampleTargetAcquisition.cpp index 0b5dba7..58cae34 100644 --- a/Source/CogSample/CogSampleTargetAcquisition.cpp +++ b/Source/CogSample/CogSampleTargetAcquisition.cpp @@ -7,6 +7,7 @@ #include "CogSampleLogCategories.h" #include "CogSampleTargetableInterface.h" #include "Components/CapsuleComponent.h" +#include "Engine/OverlapResult.h" #include "GameFramework/PlayerController.h" #if ENABLE_COG diff --git a/Source/CogSampleEditor.Target.cs b/Source/CogSampleEditor.Target.cs index 20b78b3..67ddc82 100644 --- a/Source/CogSampleEditor.Target.cs +++ b/Source/CogSampleEditor.Target.cs @@ -5,9 +5,10 @@ public class CogSampleEditorTarget : TargetRules { public CogSampleEditorTarget(TargetInfo Target) : base(Target) { - Type = TargetType.Editor; - DefaultBuildSettings = BuildSettingsVersion.V2; - //IncludeOrderVersion = EngineIncludeOrderVersion.Unreal5_2; - ExtraModuleNames.Add("CogSample"); - } + Type = TargetType.Editor; + DefaultBuildSettings = BuildSettingsVersion.V2; + DefaultBuildSettings = BuildSettingsVersion.Latest; + IncludeOrderVersion = EngineIncludeOrderVersion.Latest; + ExtraModuleNames.Add("CogSample"); + } }