You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
Merge conflict. jason.bestimt, please merge this change by hand. More info at https://robomerge.epicgames.net#DEVVR -------------------------------------- Copying //UE4/Release-Staging-4.21 to //UE4/Dev-Main (Source: //UE4/Release-4.21 [at] 4447256) ============================ MAJOR FEATURES & CHANGES ============================ Change 4447256 by Joe.Graf Added a video settings field to the debug menu so you can see your choice #jira: UE-65026, UE-65017 Change 4446451 by Matt.Kuhlenschmidt Fix inline edit conditions not supporting undo PR #4854: UE-61432: Add FScopedTransaction to SetEditConditionState (Contributed by projectgheist) #jira UE-61432 Change 4446389 by Mieszko.Zielinski Fixed navmesh tiles AABB being calculated wrong for large agents #UE4 #jira UE-65038 Change 4446171 by Matt.Kuhlenschmidt Fix crash resetting cascade distributions to default #jira UE-64458 Change 4446143 by Uriel.Doyon Re-worked fix from CL 4442729 to handle !SUPPORTS_INDEPENDENT_SAMPLERS #jira UE-64695 Change 4446071 by Jeff.Fisher Duplicating for 4.21 Change: 4446057 UE-64942 Material Switching in MRMesh -Fixed run time material switching on MRMesh #jira UE-64942 Files: //UE4/Dev-VR/Engine/Source/Runtime/MRMesh/Private/MRMeshComponent.cpp#24 //UE4/Dev-VR/Engine/Source/Runtime/MRMesh/Public/MRMeshComponent.h#16 Change 4445939 by Joe.Conley #jira UE-54503 - Transparency for textures applied to the spectator screen for VR Added a flag bUseAlpha that is checked in FDefaultSpectatorScreenController::RenderSpectatorModeMirrorAndTexture(), if (SpectatorScreenModeTexturePlusEyeLayout_RenderThread.bDrawEyeFirst). It can be set with the SetSpectatorScreenModeTexturePlusEyeLayout Blueprint node. Change 4445917 by Matt.Kuhlenschmidt Guarad against crash when destroying asset view items #jira UE-61108 Change 4445911 by Matt.Kuhlenschmidt Guard against null objects in asset editors #jira UE-64499 Change 4445574 by Wyeth.Johnson Kill volume cleanup, helper function for cone, edge case on pendulum #jira none Change 4445472 by Matt.Collins UE-64680 The new depth bounds optimization in PostAO doesn't work with MSAA. The AO target and depth buffer are different sample counts. Forcing this feature off for now. In the future if we want to turn it back on we will either have to resolve the depth buffer or increase the AO target sample count. #jira UE-64680 Change 4444917 by Bogdan.Vasilache UE-63963 - Fix FSystemTextures.InitializeTextures initialization ordering #jira UE-63963 Change 4444779 by andrew.porter QAGane: Updating focus so we can select UMG test button in TM-PlaybackControls #jira UE-29618 Change 4444678 by Richard.Wallis Clone of Dev-Rendering CL 4444343: Fix for eyedropper in the Color Picker window not grabbing any color values on Mac. Bug also says Linux - unable to verify if its the same issue so kept change to Mac specific code. #jira UE-53789 Change 4444677 by Lauren.Ridge Context menu opening cancels a rename #jira UE-64525 Change 4444321 by Michael.Dupuis #jira none: uncomment the lazy obj ptr warning as the integration is completed Change 4444288 by Simon.Tourangeau BP_SunPosition now has a soft ref to BP_SkySphere to prevent cross level referencing #jira UE-64607 Change 4444287 by JeanMichel.Dignard Copied 4442004 Daniel.Coelho Fix for being unable to trigger on variants from UMG blueprints #jira UE-64948 Change 4444105 by Mitchell.Wilson Saving assets to resolve UMeshDescription warnings #jira UE-64022 Change 4444080 by Ben.Marsh Fix path to Win64 DLLs when building DDC on Linux. #jira Change 4444036 by Patrick.Boutot Fix crash when there are too many pending task in ImageWriteQueue. #jira UE-64991 Change 4443920 by Ben.Marsh Fix runtime dependencies not being enumerated for modules that aren't linked into a binary. #jira UE-65024 Change 4443889 by Ben.Marsh Copy Windows DDCUtils DLLs when building DDC for Linux on the Win64 host platform. #jira UE-64975 Change 4443882 by Ben.Marsh Fix CIS compile error in UE4Game HTML5. #jira Change4443531by Nick.Shin #jira UE-65015 HTML5: Project Crashes During Launching Engine due to "Texture format 'R8G8B8A8_UINT' not supported" this solution was based on: UE-48208 Change 4443358 by Joe.Graf Changed the world mapping state conversion in ARKit to return NotAvailable, Mapping, Mapped #jira: UE-65023 Change 4443217 by Dan.Oconnor Fixed crash after hitting stop when in-stack-debugging Clear GPlayInEditorID when stopping PIE at a blueprint exception/breakpoint #jira UE-64895, UE-65005, UE-65008 Change 4443200 by Max.Chen Sequencer: Now accouting for frame rate when copying key tangents when converting from matinee to level sequence. #jira UE-65020 Change 4443062 by Dan.Oconnor Fixed crash when undoing after deleting a function graph that has a math expression node #jira UE-62134 Change 4442903 by Lauren.Ridge Allowing material graph nodes to have duplicate names in all cases except creating a new parameter from a constant #jira UE-64421 Change 4442878 by Joe.Graf Disabled the clion ignore file generation on Windows since it isn't supported correctly there #jira: UE-64871 Change 4442840 by Max.Chen Control Rig: Fix crash tearing down sequencer object spawner #jira UE-65013 Change 4442810 by Ethan.Geller Fix build for SoundVisualizations plugin: add const qualifiers for WaveInfo. #jira none #rb none #fyi aaron.mcleran Change 4442769 by Brandon.Schaefer Linux: Use the size of our In Rect which is the size of our buffer rather then the size of the Texture which is not always the same size as the buffer #jira UE-64785 [at]Rolando.Caloca, [at]Arciel.Rekman Change 4442758 by Dan.Oconnor "Assign [Delegate Name]" blueprint context menu entries now properly create a custom event node again #jira UE-65000 Change 4442729 by Uriel.Doyon Changed GetForwardDynamicShadowFactors implementation to use Texture2DSampleLevel instead of Load. This is because we sometime bind the GWhiteDummy when the light attenuation buffer is not required, which is a 1x1 texture. #jira UE-64695 Change 4442724 by Max.Chen Sequencer: Added back in ScrubHandleUp/Down for the VisualLoggerTimeSliderController to fix missing brush warning #jira UE-64994 Change 4442519 by Marc.Audy Avoid broadcasting events that could result in invalidating the array we're iterating. #jira UE-64959 Change 4442460 by JeanMichel.Dignard Fixed crash with VRED importer - DataTable wasn't counting its changes properly resulting in a failed check. #jira UE-64982 Change 4442216 by Ethan.Geller Unshelved from pending changelist '4438353': Ensure const correctness in USoundWave cook processing. Change 4442191 by Mitchell.Wilson Updating min ios version to resolve warnings. #jira UE-64815 Change 4442124 by Arciel.Rekman Another fix for lock up on starting without audio devices (UE-64506). #jira UE-64506 Change 4442006 by Ben.Marsh Fix debug info being included for Lumin binaries on Mac. #jira UE-65002 Change 4441939 by Ben.Marsh Fix inability to package Mac targets from Windows. #jira UE-64148 Change 4441374 by tim.gautier QAGame: Resaved Niagara assets. Rebuilt lighting / resaved TM-ShaderModels #jira UE-29618 Change 4441369 by Rolando.Caloca UE4.21 - hlslcc - Fix UAV getting removed #jira Change 4441347 by Michael.Dupuis #jira UE-63631: LOD Distribution settings, must be > 1.01 as otherwise 1/1 will not give correct result. Change 4441132 by Dan.Oconnor Remove unused dtor #jira None Change 4441108 by Dan.Oconnor Fix leaking entries for PLACEHOLDER classes in the new ClassToPlaceholderMap #jira UE-64971 Change 4441096 by tim.gautier Adding the VRMode_Ball asset for VRMode testing. #jira UE-29618 Change 4441093 by Ryan.Gerleve Fix the writer's size issue in the auth handler when requesting resends. This fixes packet over/underflows. Also make it so that dropall drops all of auth's packets as well. #Jira UE-63796, UE-64156 #AUTOMERGE using branch //UE4/Dev-Networking_to_//UE4/Release-4.21 of change#4374419 by Jake.Leonard on 2018/09/18 15:41:48. Change 4441065 by Ryan.Gerleve Fix using SetIp(uint) on an IPv6 only platform so that both cases are handled properly. Should contain the same flow as the IPv6 framework. #Jira UE-64129 #AUTOMERGE using branch //UE4/Dev-Networking_to_//UE4/Release-4.21 of change#4374299 by Jake.Leonard on 2018/09/18 15:23:37. Change 4441052 by Ben.Zeigler #jira UE-64446 Fix crash on cooked devices when using GameplayCues but not explicitly setting a manager It is unsafe to reference dynamic objects from a CDO so spawn an instance of the default class Change 4441042 by Ryan.Gerleve Remove the bForceUDP from the new CreateSocket signature. This is an argument that came in from UE3 and is not supported. It should not continue to exist anymore. #Jira: UE-63879 #AUTOMERGE using branch //UE4/Dev-Networking_to_//UE4/Release-4.21 of change#4356623 by Jake.Leonard on 2018/09/10 20:35:09. Change 4441005 by Ben.Zeigler #jira UE-64446 Call InitGlobalData from ActionRPG sample and set up path for cue notifies. All projects using abilities should do this Change 4440944 by Ryan.Gerleve Because addrconfig is not supported on HTML5. This is not documented anywhere, so any query with the flag will just be removed from any queries. #Jira UE-63791 #AUTOMERGE using branch //UE4/Dev-Networking_to_//UE4/Release-4.21 of change#4356538 by Jake.Leonard on 2018/09/10 19:35:29. Change 4440912 by Ryan.Gerleve Skip lobbies we are already a part of when generating matchmaking results. This allows us to not try to fetch data on ourselves. #Jira UE-63543 #AUTOMERGE using branch //UE4/Dev-Networking_to_//UE4/Release-4.21 of change#4356532 by Jake.Leonard on 2018/09/10 19:34:39. Change 4440861 by Ben.Zeigler #jira UE-61890 Fix XGE shader compilation on newer incredibuilds by checking registry for path Change 4440850 by Michael.Dupuis #jira UE-62426: Reset InstanceCountToRender if the static mesh is valid or we have no instances Change 4440514 by Ben.Marsh Add additional info to comment around optimization being disabled due to codegen bug. #jira Change 4440501 by Ben.Zeigler #jira UE-64971 Fix resolving export tracker to clean itself up after resolving. This fixes the immediate crash, but there may be another way it can end up crashing so this needs further investigation as the structure is unsafe Change 4440479 by Rex.Hill Fix debug hud not rendering when swapping between PIE/SIE modes #jira UE-64704 Change 4440447 by Joe.Graf Rename/move AR samples #jira: UE-64944 Change 4440338 by Joe.Graf Cleaned up leftover files from the bad 4.20->Dev-VR merge #jira: UE-64957 Change 4440318 by Joe.Graf Fixed the bad asset merge that happened from 4.20 back to Dev-VR #jira: UE-64957 Change 4440237 by Ben.Zeigler #jira UE-64960 Disable validating data dialog when saving, and ony show if > 0.1 seconds Change 4440157 by Mieszko.Zielinski Fixed a bug in how UNavModifierComponent handles FKConvexElems #UE4 #jira UE-60987 Change 4440017 by Mitchell.Wilson Saving SunlightColorLUT in KiteDemo to resolve warnings. #jira UE-64744 Change 4439856 by Jurre.deBaare Crash when trying to "Update Mesh Section" on any procedural mesh just after "Clear Mesh Section" and "Create Mesh Section" for different vertices and triangles. #fix Ensure that we recreate the scene proxy whener a mesh section is updated with a larger amount of vertices than original, this will reinit the vertex buffers to the correct sizes #jira UE-60607 Change 4439831 by Ben.Marsh Fix ClangEditor CIS warning. Change MSVC_PRAGMA to not be defined when compiling using Clang on Windows. Also add a link to bad codegen report on Microsoft's developer forum for an instance of optimization being disabled. #jira Change 4439828 by mason.seay Added variable to blueprint #jira UE-29618 Change 4439763 by Jurre.deBaare #jira UE-62048 PR #4892: HLOD System: Fix crash when static mesh has no valid material (Contributed by user37337) #fix slightly modifier fix Change 4439731 by Joe.Graf Rename/move AR samples #jira: UE-64944 Change 4439715 by Cosmin.Sulea UE-64937 - IphonePackager cannot verify UDID on new devices (XS or newer) #jira UE-64937 Change 4439697 by Wyeth.Johnson Metadata errors and fixes #jira none Change 4439658 by Michael.Dupuis #jira UE-63831: Added some guard to prevent the crash Change 4439605 by Michael.Dupuis #jira UE-53944: Added some asserto help track what could be happening in this case Change 4439516 by Ben.Marsh UBT: Set the permissions on directories containing scripts to be executed as part of remote builds. #jira UE-64860 Change 4439395 by Michael.Dupuis #jira UE-63637: When doing migration from 4.18, if the data was in a BP, use a Reset instead of a Reserve, as otherwise we will end up with twice the amounf of instances. Change 4439197 by Michael.Dupuis #jira UE-63242 #jira UE-63123: Integrate from Dev-Editor branch Change 4439162 by Mieszko.Zielinski Made sure NavigationSystemConfig respects GEngine->NavigationSystemClassName #UE4 #jira UE-62991 Change 4439106 by Cosmin.Sulea UE-64603 - Android Devices do not show up in device list for Device Output Log #jira UE-64603 Change 4438283 by Ben.Zeigler #jira UE-63825 Integrate pull request: PR #5073: Implement LoadGameFromMemory function. (Contributed by KelbyG) Change 4438242 by Ben.Zeigler Test case for #jira UE-63705. To verify, open WeakReferencedPrimaryAsset and note that the UntrackedMeshPtr is set to AT_StaticMesh. Then, right click and show references, that mesh should NOT show up, as it is marked as Untracked via metadata Change 4438238 by Ben.Zeigler #jira UE-63843 Temporary fix for Visual Studio 2017 compile bug causing crashes in Audio Mixer code Change 4438237 by Ben.Zeigler #jira UE-64770 Fix bug where AssetManager could fail to call delegates in sync load mode Change 4438236 by Ben.Zeigler #jira UE-64466 Fix issues with debug builds with ENABLE_NAN_DIAGNOSTIC and TransformNonVectorized, it's not safe to use the FVector constructor as it will always ensure. Also unified checks with the vectorized version to be consistent Change 4438234 by Ben.Zeigler #jira UE-63705 Add full support for Untracked soft object references, enable by adding that tag to the metadata for a property or using FSoftObjectPathSerializationScope with NeverCollect If set the references will not be automatically cooked, reported to the asset registry, or cause warnings when deleting a referenced actor They are meant to be used for cases where they are just used as a lazy cache, such as things converted from FLazyObjectPtr The reference from Foliage to it's base actor is now an Untracked SoftObjectPtr instead of a LazyPtr Change 4437969 by Michael.Lentine Fix gpu skin cache with multiple cloth sections. #jira ue-62951 Change 4437907 by Joe.Graf Rename/move AR samples #jira: UE-64944 Change 4437901 by Mikey.Boyd Resaved QA-Promotion and TM-ShaderModels to clear up warnings for Linear Color Curves in UE-64949. #jira UE-29618 Change 4437877 by Dan.Oconnor Guard against double-queuing in Macro BP gather phase #jira None Change 4437615 by Sorin.Gradinaru UE-64624 App fails to open when packaged for Distribution - Android #jira UE-64624 #Android #4.21 As Chris.Babcock mentioned, this is caused by an app pause event triggered when the obb downloader starts and puts the activity in background. Adding a flag to ignore the first app pause in this situation. Change 4437541 by Andrew.Porter QAGame: Updating location of an animation so it can be visiblty in the sequence #jira UE-29618 Change 4437078 by Mitchell.Wilson Updating lerp tooltip based on updates by Sam Deiter. #jira UEDOC-8219 Change 4436943 by Bogdan.Vasilache UE-61698 - Android + Mouse: Hover events and Get Mouse Position on Viewport not working #jira UE-61698 Change 4436915 by Dan.Oconnor Remove debugging hook accidentally added in 4235135 #jira None Change 4436204 by Joe.Graf Switched the AREnvProbe sample to Metal 2.1 to fix the z-fighting that happens in 2.0 and below #jira: UE-64932 Change 4435856 by Arciel.Rekman Fix CIS (UE-64925). #jira UE-64925 Change 4435811 by Mark.Satterthwaite Sort out the way we report R11G11B10 support for Metal so that it should work correctly on iOS & tvOS. #jira UE-64905 Change 4435783 by Brandon.Schaefer libvpx: Rebuild on centos7 #jira UE-64887 Change4435710by Thomas.Sarkanen Fixed crash drag-dropping a variable onto a state machine #jira UE-64539 - [CrashReport] UE4Editor-CoreUObject.dylib!CastLogError() Change 4435694 by Andrew.Grant Removed some stale Orion tests #jira UE-64857 Change 4435662 by Ben.Marsh Rework the way that custom icons are used on Windows. * For code projects, the custom icon is embedded into the resource when compiled from UBT. This ensures the custom icon is set even before packaging, and removes the need for a deployment step. * For content projects, the custom icon is set after packaging using the previous method. #jira UE-64527 Change 4435599 by Michael.Lentine Avoid crash with null materials #jira ue-64819 Change 4435596 by Michael.Lentine Account for the case where skeletal mesh doesn't exsit in the component body setup. #jira ue-63104 Change 4435563 by Brandon.Schaefer SDL2: Fix pointer barriers on resize/move and multimonitor Part of this change is from PR 5041 (thanks yaakuro) #jira UE-60461, UE-63372 Change 4435557 by Michael.Lentine Allow for non uniform scaling in some of the capsule functions. #jira ue-59651 Change 4435518 by Mitchell.Wilson Saving two assets to resolve empty engine version warnings in RemoteSessionApp #jira UE-64747 Change 4435416 by Robert.Manuszewski Fixing a Cook On The Fly server crash when an asset that has been requested by the client is missing from the server #jira UE-64616 Change 4434780 by Uriel.Doyon Fixed Niagara proxy rendering in ES2 while the shaders are not available. #jira UE-64666 Change 4434758 by Joe.Graf Fixed the use of deprecated NSKeyedArchiver and NSKeyedUnarchiver methods #jira: UE-64913 Change 4434757 by Joe.Graf Removed invalid plugins that were specified for the AR samples #jira: UE-64914 Change 4434497 by Joe.Graf Fixed incomplete merge of ARSharedWorld sample #jira: UE-64673 Change 4434281 by Joe.Conley #jira UE-63793 - ARKit Crash with Session Type: Image Removing error logging since it's also getting logged higher up in the callstack. Change 4434250 by Joe.Conley #jira UE-63793 - ARKit Crash with Session Type: Image Instead of an assert (and thus crash) if Session Configuration is null (which happens if device/os doesn't support ARKit 2.0), just print out an error to the log and keep running. Change 4434173 by Aaron.McLeran Fix for audio device shutdown -- Actually, need to make sure the flush code doesn't execute on platforms without threads. This will still fail on HTML5 #jira UE-64619 Change 4434112 by Aaron.McLeran Bug fix pausability - Pausing sound while stopping can cause a crash when updating the sound #jira none Change 4433986 by Michael.Lentine Avoid dereferencing null. #jira ue-63593 Change 4433954 by Michael.Lentine Use correct enable flag. #jira ue-64801 Change 4433867 by Uriel.Doyon Fixed integration issue from Niagara with "Collision Query" module #jira UE-64906 Change 4433779 by Dan.Oconnor Mirror 4379405 from Dev-Framework Add flags to track bMarkedObjectsPendingKill and bCleanedUpWorld to ensure that sublevels are cleaned up properly #jira UE-64227 Change 4433771 by Dan.Oconnor Mirror 4365800 from Dev-Framework Avoid marking a blueprint as modified when the compiler renames a graph #jira UE-63942 Change 4433763 by Dan.Oconnor Mirror 4363197 from Dev-Framework Perform a placeholder resolve pass immediately after the CDO has been serialized #jira UE-62928 Change 4433716 by Chris.Bunner #author Bogdan.Vasilache Comitting shelf 4433043 for UE-64237. #jira UE-64237 Change 4433609 by Uriel.Doyon Fixed how UNiagaraDataInterfaceCurlNoise release its render resource by adding a release command in BeginDestroy. #jira UE-64898 Change 4433524 by zak.parrish Final functionality for AR SaveLoad now in place. Just needs cleanup/commenting and About screen #JIRA UE-64681 Change 4433512 by Christina.TempelaarL Mirror 4373989 from Dev-Editor. Cascade: Copy particle emitter properties when invoking Duplicate Emitter or Export Emitter in the Cascade editor. #jira UE-63856 Change 4433328 by Chris.Babcock Fix ConfigRules.jar parsing for Linux line endings #jira UE-64892 #ue4 #android Change 4433279 by Zachary.Wilson Switching DoF methods for PostProcess volumes in QA_PostProcessing and TM_Showflags_LightingFeatures. #jira UE-64659 Change 4433092 by Dan.Oconnor Fix missing include #jira None Change 4433046 by Michael.Lentine Renamed command to relfect actual behavior. #jira ue-55368 Change 4433024 by Ben.Marsh PR #5154: Prevent crunch_x64.exe from showing in Git commit changes (Contributed by projectgheist) #jira Change 4432990 by Wyeth.Johnson Fixing issues related to particle mass and gravity #jira none Change 4432979 by Uriel.Doyon Fixed DOF when enabling Pre-Exposure Added units to the intensity property of point, spot, rect, directional and sky lights. Refactored the VisualizeHDR so that it shows the HDR view is a PIP on top of the main render. Fixed PixelInspector results being affected by pre-exposure. Added a pre-exposure output value to the PixelInspector. Moved ExposureCompensation to the Exposure tab in post-process settings. Changed max slider intensity for directional light to be in 120 000 lux Changed max slider intensity for sky light to be in 50 000 cd/m2 Non bUseInverseSquaredFalloff point lights now have their units forced to ELightUnits::Unitless Moved light units to advanced display, now that the unit is embeded in the Intensity property Added Candela, Lux and CandelaPerMeterSquared units to the engine units Fixed meta data properties to support the "Units" keyword. #jira UE-64881 Change 4432953 by Chris.Gagnon CL 4356067 copied to Release-4.21 #jira UE-63861 Change 4432934 by Chris.Gagnon CL 4399650 copied to Release-4.21 #jira UE-64070 Change 4432913 by Dan.Oconnor Mirror 4363175 from Dev-Framework Reuse subobjects during archetype reinstancing path #jira UE-59135 Change 4432901 by Michael.Lentine Adding missing counter. #jira ue-59969 Change 4432895 by Dan.Oconnor Mirror 4344890 from Dev-Framework Make FObjectFinder visibile to reference collectors and properly replace subobjects on the CDO. This fixes instability after reloading the FirstPersonCharacter blueprint #jira UE-54419, UE-63061 Change 4432805 by Uriel.Doyon Fixed error when compiling some Niagara GPU particles #jira UE-64885 Change 4432789 by Michael.Lentine Fix comments. #jira 58064 Change 4432766 by Ben.Marsh Fix issues with mismatched solution/project configurations. * Every C++ project now has an "invalid" configuration. Trying to build any solution configuration which does not apply to the project will now build that, which prints an error rather than building a completely different configuration. * Available configurations are now parsed from C# files, so the "Release" configuration will now be used if "Development" is not available, and platforms are supported correctly. * Programs are now built in game and editor configurations. #jira UE-59288 Change 4432649 by Michael.Lentine Resize Temp instead of Out. #jira ue-62919 Change4432540by Chris.Bunner [Duplicating 4432262] - HLOD visibility state is now cleared when not in use. #jira UE-64432 Change 4431926 by Chad.Garyet Integrating changes from dev-build over to release-4.21 - Add win64 host support to DDC Group Linux - Change project params split to remove empty entries - Change BuildDerivedDataCache to skip building a feature pack if there are no project specific platforms for it out of the available targetplatforms #jira UE-62311 Change 4431602 by Simon.Therriault Merging MediaBundle fix #jira UE-64853 Change 4431481 by Brandon.Schaefer Linux: Break grabs and bring down pointer barreirs when we have crashed #jira UE-63981 [at]Arciel.Rekman Change 4431456 by Jules.Blok Merging CL 4428447 from Dev-VR - Update the WMR plugin for Dev-Rendering changes. #jira UE-64507 Change 4431310 by Robert.Manuszewski Fixed a crash when setting the initial size of the disregard for Garbage Collection pool to a value greater than 66560. #jira UE-64844 Change 4431307 by Sorin.Gradinaru UE-64749 App crashes on device when a Widget Blueprint in use contains a Web Browser widget #jira UE-64749 #Android #iOS #4.21 Moving SharedThis(this) out of the WB Window's constructor Change 4431161 by Robert.Manuszewski Fixing CIS #jira none Change 4431153 by Sorin.Gradinaru UE-63263 Startup movies are not playing on tvOS #jira UE-63263 #4.21 #tvOS Startup movies need AppleMoviePlayer.uplugin, which was never enabled for tvOS. Same behavior as an iPhone/iPad, slightly stuttering at first run, plays fine afterwards Change 4430958 by Matt.Collins Returns the default context from GetCurrentContext if none is set. Fixes crash in UE-64369. This is probably not 100% correct - we should fix all the cases where GetCurrentContext is called and a context is not set. #jira UE-64369 Change 4430862 by Matt.Collins Turning GPU Command Buffer timing back on. Enables correct profiling. #jira UE-64841 Change 4430813 by Marcin.Undak Linux: fixed editor launch with no audio device #jira UE-64506 Change 4430783 by Ben.Marsh Include Mac build files on Windows (eg. shell scripts, mono) to support remote compilation. #jira UE-64684 Change 4430761 by Ben.Marsh Fix issues with running DsymExporter remotely from a PC, and reorder engine filters to reduce the amount of junk which has to be re-transferred every time. #jira UE-63883 Change 4430445 by Chris.Gagnon Copy of CL 4416373 Extend GCompilingBlueprint lifetime to include BroadcastBlueprintReinstanced when compiling synchronously #jira None Change 4430103 by Ben.Marsh Make sure Newtonsoft is included in the installed engine build. (Also ignore *.build.cs that aren't enumerated from the targets we build; they won't be usable) #jira UE-64777 Change 4430050 by Ben.Marsh PR #5151: Fix BuildPlugin automation command to include Shaders folder (Contributed by pluranium) #jira UE-64781 Change 4430037 by Ben.Marsh UBT: Fix generating and checking for UHT manifest in the wrong location. If a target does not have a script plugin, the manifest should not be stored in the project binaries directory. #jira Change 4430035 by Alexis.Matte Port a fix from cl: 4366690 Fix the material ID when creating generating reduce LODs from a mesh where the materials was re-order to the FBX order. #jira UE-64028 Change 4429730 by Ryan.Vance #jira UEVR-1322 Instead of tearing down and spinning up the render thread / rhi thread pipeline on pause, simply disable and enable rendering. This leaves the rendering infrastructure intact, but with no work to do. Change 4429709 by Ryan.Vance #jira UE-64289 Distortion correct mesh generation needs to happen on the render thread. Change 4429690 by Ryan.Vance #jira UE-63538 From 4.20.3 hotfix: 4333358 Test render target texture size if available to ensure we don't do an extra upscale when not needed. The render target size is not updated when the backing render target texture is reallocated. Change 4429671 by Ryan.Vance #jira UE-63333 Lumin needs task threads to avoid saturating a single core. Reverting to previous task thread behavior for lumin. Change 4429489 by Mitchell.Wilson Saving curve assets to resolve warnings. #jira UE-64744 Change 4429160 by Wyeth.Johnson First pass at integrating mass as a first class citizen. This includes solver changes, a new gravity force, and updates to a number of other force modules and templates #jira none Change 4429064 by Mitchell.Wilson Updating default iOS version to 10 in samples and templates #jira UE-64815 Change 4428944 by Michael.Trepka Fixed issues with cursor locking on window activation on Mac #jira UE-13768 Change 4428879 by Ben.Marsh Fix error generating dsyms on Mac through the remote toolchain. #jira UE-63883 Change 4428729 by Ben.Marsh Fix warning about missing expat libs when generating projects from installed build on Mac. #jira UE-64740 Change 4428710 by Dan.Oconnor When recompiling a blueprint macro library we now do a full compile of all dependent blueprints #jira UE-63284 Change 4428331 by frankie.dipietro Update TM-FocusPriority to utilize a looping Music file #jira UE-29618 Change 4428295 by Rex.Hill Fixed debug hud not drawing during simulate in editor #jira UE-64704 Change 4428255 by Zachary.Wilson Removing Bokeh and Gaussian DoF tests that were displaying a warning #jira UE-64659 Change 4428236 by Andrew.Rodham Sequencer: Fixed edge case where equvalent range bounds were not considered equal #jira UE-64742 Change 4428210 by zak.parrish #JIRA UE-64681 Getting proper save reporting in place on AR Save Load Change 4428146 by Ben.Marsh Fix CIS error. #jira Change 4428046 by Chris.Babcock Fix bad merge #jira UE-64784 #ue4 #android Change 4427865 by Ben.Marsh Add missing include causing CIS error. #jira Change 4427846 by Ben.Marsh When we detect a hang and send an ensure crash report, include the callstack of the thread that hung. #jira UE-63982 Change 4427716 by Peter.Sauerbrei deprecate IOS 9 #jira UE-64018 Change 4427575 by Cody.Albert Fixed ShooterGame best score logic #jira UE-64514 Change 4427537 by Frank.Fella Niagara - Disable the houdini plugin in engine test since we're not actively testing it and it's causing lots of cooking problems. #jira UE-64736 Change 4427273 by Stefan.Boberg PR #5123: Small typo in Engine.h (Contributed by Vatyx) #jira UE-64496 Change 4427126 by Simon.Tovey Merging from Dev-Niagara 4427076 Fix for static analysis warnings. #jira UE-64717 Change 4427014 by Simon.Therriault Fix for MediaFrameworkUtilities plugin #jira UE-64774 Change 4426983 by Ben.Marsh Remove natvis file from UE4 project. #jira Change 4426920 by Sorin.Gradinaru Unshelved from pending changelist '4398174': UE-54804 Graphical stuttering for weapon model on Lenovo S939 in First Person Template Project #jira UE-54804 #Android #4.21 The bug was generated by CL3840215 - the fix for UE-53592: Assertion right after rendering scene on Lenovo S939. I've retested UE-53592 on my side and it's OK. Also, when building a sample (eg. First Person) on //Dev-Main, the game crashed at start with: D/UE4 (22619): Assertion failed: glProgramParameteri [File:C:/Work/UE4_Main/Engine/Source/Runtime/OpenGLDrv/Private\Android/AndroidOpenGL.h] [Line: 479] Change 4426571 by Ben.Marsh Fix UAT compile error. #jira Change 4426569 by Ben.Marsh UnrealVS: Fix single-file compile not working for foreign projects where the engine folder contains a space. #jira UE-64752 Change 4426529 by Ben.Marsh Various fixes/improvements to program plugins. * Runtime plugins are no longer loaded for every program (as was the case in 4.20) * If a module is whitelisted for a specific program, it will be enabled regardless of whether the Type is "Program" or not. * The bCanBeUsedWithUnrealHeaderTool flag in the plugin descriptor is now translated into support for the "UnrealHeaderTool" program on load. * Restored support for the RuntimeAndProgram module type. * Plugins are now enabled in UHT by passing the project on the command line, rather than passing explicit plugins to enable. #jira UE-64247, UE-64595 Change 4426481 by Jeff.Fisher UE-64597 //UE4/Release-4.21 - Build DDC Win64 - BP_DebugMenu has been saved with empty engine version -resaved #jira UE-64597 Change 4426400 by Ben.Marsh Fix extra blank line at the end of ManagedProcess output. #jira UE-64780 Change 4426398 by Arciel.Rekman Linux: fix ARM server build (UE-64775). #jira UE-64775 Change 4426126 by Dan.Oconnor Harden EdGraphPin serialization #jira UE-64500 Change 4426071 by Dan.Oconnor Added logging to Blueprint merge operation #jira UE-58891 Change 4426061 by Phillip.Kavan Fix for an EDL runtime assertion on load when constructing the CDO for a nativized Blueprint class that contains an instanced object reference of another nativized Blueprint class type that references an instance of a non-nativized Blueprint class as a nested, class-owned subobject. - Mirrored from //UE4/Dev-Framework (4413311). #jira UE-62514 Change 4426031 by Phillip.Kavan Fix potential data loss in inherited SCS component default value overrides at runtime in a cooked build for an instance of a non-nativized child Blueprint class that inherits from a nativized parent Blueprint class. - Mirrored from //UE4/Dev-Framework (4365827). #jira UE-63757 Change 4425975 by Phillip.Kavan Fix potential CDO validation failures at cook time during the C++ code generation pass when Blueprint nativization is enabled. - Mirrored from 4371073. #jira UE-63647 Change 4425952 by Chris.Babcock Add notification channel for Android 26 compatibility #jira UE-62741 #ue4 #android Change 4425916 by Dan.Oconnor Added logging to package reloading #jira UE-63834 Change 4425857 by Rolando.Caloca UE4.21 - FIx crash on html5 #jira UE-64690 Change 4425808 by Jeff.Fisher Merging using Dev-VR_to_Release-4.21 Change: 4425273 UEVR-1333 MRMesh normals problems -Normals should not be world scaled. #jira UEVR-1333 Files: //UE4/Dev-VR/Engine/Plugins/Lumin/MagicLeap/Source/MagicLeap/Private/MeshTrackerComponent.cpp#13 Change 4425722 by Rolando.Caloca UE4.21 - Android compile fix #jira Change 4425408 by Phillip.Kavan Fix UBT warnings when building/packaging with Blueprint nativization enabled. - Mirrored from //UE4/Dev-Framework (4352144). #jira UE-62946, UE-63311 Change 4425238 by frankie.dipietro Update TM-FocusPriority so that tests may utilize 8 audio channels #jira UE-29618 Change 4425232 by Jamie.Dale Fixed crash when re-pointing an object referenced in Python #jira UE-64363 Change 4425194 by Phillip.Kavan Support a proper fallback to construct any native 'noexport' struct-typed literal term in a nativized Blueprint class. - Mirrored from //UE4/Dev-Framework (4347635). #jira UE-63364 Change 4424786 by Brian.Zaugg Add support for new iOS UserNotifications framework, enabled if min iOS version is set >= 10. #jira UE-51041, UE-59178 Change4424584by Ben.Marsh Include the Visual Studio .natvis file as a solution item, to fix problems with VS2017 15.8.5 not finding it in a makefile project. #jira UE-64733 Change 4424410 by Max.Chen Sequencer: Fix deprecation #jira UE-48190 Change 4424364 by Frank.Fella Niagara - Fix static analysis for SItemSelector.h - Preflight passed. #jira UE-64719 Change 4424291 by Shaun.Kime Volume texture work should not be pulled over from Dev-Niagara yet #jira UE-64756 Change 4424021 by Jason.Bestimt Merging CL 4401151 from Dev-VR - Adding destructor to SoundPresets #JIRA:none Change 4423955 by Brandon.Schaefer Linux: Add a timer when we lose focus to check if we have lost application focus #jira UE-63931 Change 4422974 by Robert.Manuszewski Fixing CIS #jira UE-64741 Change 4422709 by Jason.Bestimt Merging CL# 4419752 from Dev-VR - Fixes to prevent audio from crashing on exit #JIRA: none Change 4422691 by Jamie.Dale Fixing localization warnings Added support for gathering from the newly added UI_COMMAND_EXT macro #jira Change 4422394 by Sorin.Gradinaru UE-64066 TM-Gameplay Load Game does not work on TVOS #jira UE-64066 TM-Gameplay Load Game does not work on TVOS #tvOS #4.21 Blocker: GRHIHDRDisplayOutputFormat must have a default value for tvOS (PF_B8G8R8A8, just like mac or ios for non-hdr). The issue appeared at CL4092793 [at] //UE4/Dev-Rendering, 5/24/2018 Change 4422285 by Jamie.Dale Fixing localization warnings #jira Change 4421911 by Chris.Babcock Fix issues with LLDB data formatters with 2 byte characters #jira UE-64737 #ue4 Change 4421833 by Wyeth.Johnson #jira 64735 Sample Skel Mesh refactor to fix it not initializing, still bugged for vertex colors Change 4421316 by Jamie.Dale Fixing localization warnings #jira Change 4421223 by Ben.Marsh Add an experimental setting to enable support for long paths in the content browser. #jira Change 4421197 by Jamie.Dale Fixing localization warnings #jira Change 4421191 by Jamie.Dale Fixing localization warnings #jira Change 4421179 by Rolando.Caloca UE4.21 - Vulkan - Add missing viewport resize function - Separate num buffers per usage #jira Change 4420955 by Michael.Trepka Ignore tooltips and cursor decorator windows when determining the window under cursor on Mac #jira UE-64645 Change 4420323 by Robert.Manuszewski Reimplementing CL #4402016 from Dev-Core: Fixed cooked materials not working in the editor #jira UE-64389 Change 4420227 by Rex.Hill Fix USD Linux compiler warning #jira UE-63658 Change 4420198 by Ben.Marsh UBT: Detect changes to source directories and invalidate the makefile if they are newer. Forces the makefile to be rebuilt when files are added or removed. #jira UE-42601 Change 4420194 by Mitchell.Wilson Saving color curve assets to resolve warnings. #jira UE-64724 Change 4419740 by Jamie.Dale Don't force LocRes files to always use Unicode strings The automatic Unicode detection works just fine for them, and changing this can produce considerably smaller (up-to 50% smaller!) LocRes files #jira Change 4419728 by Mikey.Boyd Updating TM-MaterialAttributes map and MaterialAttributes_Widget for cleaner testing of UEQATC-3497. Set the level to the default GameMode, updated the level blueprint, and disabled interaction with the widget bp. #jira UE-29618 Change 4419646 by Ben.Marsh UBT: Determine the correct user directory when remote compiling on Mac, rather than inferring it from the user name. The user name can be changed after an account is created. #jira UE-64071 Change 4419529 by Jules.Blok Merging CL 4323685 from Dev-VR - Fix GLES occlusion queries when HDR is disabled. Add occlusion query support for Multi-View. Add ShowFlag to visualize occlusion query bounding meshes. #jira UE-62347 Change 4419528 by Jules.Blok Merging CL 4323400 from Dev-VR - Remove StereoPair in favor of visibility map merging introduced in CL 4036044 #jira UE-62738 Change 4419525 by Stefan.Boberg Reduce CPU usage for Cook-on-the-fly server by not busy-waiting for assets to cook. Added an event which is signaled when a network request has been received. The main COTF loop blocks on this event when the cook request queue is empty. This reduces CPU usage while keeping the request latency low. #jira UE-51348 graeme.thornton, martin.ridgers Change 4419034 by Ben.Marsh Allow plugins specified on the command line to override engine plugins. #jira UE-64685 Change 4419015 by Frank.Fella Niagara - Fix linux compile error from CL 4418815. #jira UE-63379 Change 4418931 by Frank.Fella Niagara - Fix Win32 compile issue caused by cl 4418639 #jira UE-61823 Change 4418887 by Frank.Fella Merging from Dev-Niagara all plugin content updates. #jira UE-64711 Change 4418883 by Uriel.Doyon Fixed GPU emitters not being ticked correctly on the renderthread. #jira UE-64710 Change 4418817 by Chris.Babcock Fix for x86 and x86_64 Android architectures with NDK14b #jira UE-64708 #ue4 #android Change 4418815 by Frank.Fella Merging from Dev-Niagara 4399353 for nicholas.goldstein Improve discoverability of and navigability to parent Emitters in Systems #jira UE-63379 Change 4418709 by Frank.Fella Merging from Dev-Niagara 4397394 for nicholas.goldstein Add missing entries and param creation subcategory to Set Variables module. #jira UE-63373 Change 4418639 by Frank.Fella Merging from Dev-Niagara 4360525, 4360676, 4364096 for Simon.Tovey Some compile time optimizations - Moved large map of hlsl keyword replacements from C++ to ini file to improve compile times. - Now not using templates to handle input parameters to data interface. Now taking a bit from the bytecode offset to denote constant vs register. - As well as improving compile times, this also makes DIs far easier to write and maintain so I've rolled out to all DIs. Has no affect on perf. - Moved some things into the VectorVM namesspace. #jira UE-61823 Change 4418333 by Mark.Satterthwaite Fix incorrect usage of a CFDictionary passed into IOServiceGetMatchingServices which releases it for us. #rb none #jira UE-62569 Change 4418323 by zak.parrish Checking in files for SaveLoad - almost done. Need to update save status and do the helpAbout screen #JIRA UE-64681 Change 4418307 by Frank.Fella Merging from Dev-Niagara 4357655 for nicholas.goldstein Fix various capitalization inconsistencies in niagara stack menus #jira UE-63371 #jira UE-63446 Change 4418242 by Frank.Fella Merging from Dev-Niagara 4356331 for nicholas.goldstein Add Spacer between Event Handler header row and added Event Handler properties #jira UE-63390 Change 4418222 by Dan.Oconnor Close blueprint editor when replacing a blueprint, avoiding crash when using the merge tool to reload a blueprint #jira UE-64435 Change 4418217 by Frank.Fella Merging from Dev-Niagara 4356318 for nicholas.goldstein Adjust DisplayName generation of linked inputs in Niagara Stack input options to show the entire namespace and to not pass through FName::NameToDisplayString #jira UE-63387 #jira UE-60349 Change 4418163 by Frank.Fella Merging from Dev-Niagara 4346597, 4346602, 4346709, 4353333, 4353344, 4353346, 4353355, 4355466, 4355948, 4356192 Niagara - New emitter and new system dialogs #jira UE-63765 Change 4418114 by Mark.Satterthwaite Assert that Metal heaps and sub-allocated buffers are actually created properly to catch OoM errors. #rb none #jira UE-62235 Change 4417947 by Ben.Marsh Compile DebugGame version of the launch module for installed builds. #jira UE-64604 Change 4417554 by Joe.Conley Merging using Dev-VR_to_Release-4.21 #jira UE-63210 - "Stereo layers persist in HMD after VR Preview" #jira UE-54565 - "Packaged game/Editor with Stereo Layers crashes when exiting game through steam VR overlay" Remove check(VROverlay) in FSteamVRHMD::GetStereoLayers() and just return nullptr if it is null. Revert previous fix for UE-54565 that caused UE-63210 Change 4417553 by Joe.Conley Merging using Dev-VR_to_Release-4.21 #jira UE-64054 MRC - Mixed Reality Calibration app does not let users toggle between attachment devices. Enumerate Motion Sources was getting called before the Motion Controller modular features were being added. Added a delay before calling Enumerate Motion Sources. Change 4417552 by Joe.Conley Merging to Release-4.21 (//UE4/Release-4.21) #jira UE-63579 Assert when having too many VR devices Increase max controllers to support more. Change 4417533 by Ben.Marsh Fix IPhonePackager not being included in installed builds created on a Mac. #jira UE-58493 Change 4417495 by Joe.Conley Back out changelist 4417484 Integrate automatically submitted this before I could convert it to an edit, back out. #jira UE-63579 Assert when having too many VR devices Change 4417484 by Joe.Conley Merging using Dev-VR_to_Release-4.21 #jira UE-63579 Assert when having too many VR devices Increase max controllers to support more. Change 4417438 by Ben.Marsh Prevent unzipped frameworks from being removed every time a remote IOS compile is started, preventing iterative builds. #jira Change 4417422 by Ben.Marsh PR #4937: UE-62508: Add option to project launcher to include prerequisites com. (Contributed by projectgheist) #jira UE-62508 Change 4417362 by Ben.Marsh Fix compile warning when converting a blueprint project to native. #jira UE-63802 Change 4417357 by Jerome.Delattre Copying from Dev-Enterprise CL 4364256 Fix typo in FGenericPlatformMemory::DumpStats to properly report the free virtual memory. #author Martin.Sevigny #jira Change 4417350 by Jerome.Delattre Copying from Dev-Enterprise CL 4364260 SceneCapture: Don't CaptureOnMovement if CaptureEveryFrame is enabled. This prevent the capture from happening twice in 1 frame. #author Martin.Sevigny #jira UE-64686 Change 4417333 by Uriel.Doyon Reduced the amount of interpolants in FVertexFactoryInterpolantsVSToPS by the Niagara when using DynamicParameters. Now only the param required are used where as before the count was defined by the max index. #jira UE-63712 Change 4417318 by Dan.Oconnor Improve error messaging when a class creates its CDO while the class layout is being created #jira UE-64534 Change 4417276 by Frank.Fella Merging 4340773 from Dev-Niagara for nicholas.goldstein Add UProperty Specifiers to PropertyMetaData to fix displayed name and tooltip #jira UE-63233 Change 4417226 by Frank.Fella Merging 4340719 from Dev-Niagara for nicholas.goldstein Disable Widget focus of expander arrows and pulldown arrows in Niagara Stack to prevent unexpected tab selection #jira UE-63380 Change 4417196 by Patrick.Boutot Create a 10bit media texture for CharBGR10A2 media format. #jira UE-64682 Change 4417193 by Patrick.Boutot Keep a reference to the current MediaProfile's proxy to prevent GC Move MediaProfileSettings to default config. #jira UE-64475 Change 4417192 by Patrick.Boutot Deprecate ABGR16 and Float RGB from EDefaultBackBufferPixelFormat. They are not supported by D3DX SwapChain. The jira has more info on which formats are supported. #jira UE-63090 Change 4416191 by zak.parrish Resaving Debug menu for TP_ARBP template #JIRA UE-64678 Change 4416030 by Marc.Audy Remove broken test (as best it can be told it could never have worked) #jira UE-64547 Change 4415784 by Marc.Audy PR #5133: UE-64479 Fix the icon display for the Timeline node replication status (Contributed by mamoniem) PR #5132: UE-64479: Replicated icon shows up for timelines in BP (Contributed by projectgheist) #jira UE-64479 #jira UE-64596 #jira UE-64606 Change 4415763 by Steve.Robb Fixes for improperly initialized USTRUCT() members. #jira UE-64551 #jira UE-64546 Change 4415723 by Rolando.Caloca UE4.21 - Remove Linux hack for Vulkan #jira Change 4415679 by Rolando.Caloca UE4.21 - Copy fix from 4415584 and 4401641 - Added support for -vulkanpresentmode=N where N is a VkPresentModeKHR - This prevents the CPU from getting more than one frame ahead of the GPU. In addition to making the Vulkan RHI more consistent with the DX RHIs and reducing game input latency, this also fixes the issue where memory for volatile uniform buffers could be overwritten by the CPU before the GPU was done with it. This could happen when running in immediate present mode with frame pacing and smoothing disabled, as the CPU could get several frames ahead of the GPU. #jira Change 4415654 by Jamie.Dale Fixed the editor failing to load the native game localization data during init #jira UE-64097 Change 4415635 by Jamie.Dale Fixed null pointer access in setting helpers #jira Change 4415630 by Jamie.Dale Ensure we GC at various points that could have left lingering references to items being content hot-reloaded #jira Change 4415624 by Jamie.Dale Ensure that the transient instance created by the material editor is marked pending-kill once the material editor is closed This fixes an issue where a lingering material editor instance would re-apply old material constant values after a content hot-reload, as the content hot-reload would call PostEditChange on the lingering instance. #jira Change 4415620 by Jamie.Dale Fixed type validation of objects within containers #jira UE-64151 Change 4415613 by Jamie.Dale Fixed crash when deleting a package without an SSC state #jira Change 4415592 by Marcin.Undak UAT: Aways create directory before saving encryption parameters #jira none Change 4415590 by Jamie.Dale Merging CL# 4357533, CL# 4366557 and CL# 4374101 #jira Change 4415577 by Marcin.Undak Linux: fixed WebM crash #jira UE-64157 Change 4415340 by frankie.dipietro Empty M_VolumeSampler for testing #jira UE-29618 Change 4415334 by frankie.dipietro Adjust M_VolumeSample test material to use Emissive #jira UE-29618 Change 4415085 by Ben.Marsh Restore const signature for FApplePlatformCrashContext::ReportCrash() for compatibility with callbacks. #jira Change 4415032 by Ben.Marsh Fix Mac compile error due to calling non-const function. #jira Change 4415005 by frankie.dipietro Add M_VolumeSample to QAGame to aid Volume Texture testing #jira UE-29618 Change 4414930 by Ben.Marsh Include portable callstacks in ensures. #jira UE-64574 Change 4414631 by Graeme.Thornton Fix for crash when running automation tests #jira UE-64652 Change 4414055 by Dan.Oconnor Remove use of FAssetData to avoid side effects that can result in CDO creation #jira UE-64534 Change 4413933 by Jeff.Fisher Merging using Dev-VR_to_Release-4.21 4374589 UE-57680 [CrashReport] UE4Editor_SteamVR!FSteamVRModel::GetRawMeshData() [steamvrassetmanager.cpp:307] -Added some more logging to try to figure out why this is crashing. Logs the resourceID of the steamVRMesh which might tell us if this is happening with some specific hardware. Also logs index and vertex counts and pointers to see if the data is somewhat malformed or just completely invalid.4380355UE-57680 [CrashReport] UE4Editor_SteamVR!FSteamVRModel::GetRawMeshData() [steamvrassetmanager.cpp:307] -Two more log lines for steamvr shutdown. Maybe we are trying to get the models after shutdown and get bad data? #jira UE-57680 Change 4413599 by Mitchell.Wilson Saving SunlightColorLUT to resolve warning. #jira UE-64648 Change 4413343 by Ben.Marsh Add Rsync filters to installed build on Windows. #jira UE-64623 Change 4413276 by Ben.Marsh Remove logic that prevents UHT compiling on Mac during a remote build. #jira UE-64493 Change 4413205 by Ben.Marsh Fix missing dependencies from installed build on Mac and Linux. #jira UE-64629 Change 4413154 by Jason.Bestimt Merging CL 4379292 from Dev-VR - Fixes for mobile static draw list using incorrect material render proxy #JIRA: UEVR-1321 Change 4413148 by Jason.Bestimt Merging CL 4373138 from Dev-VR - Fix for media texture crash on Lumin #JIRA: UEVR-1319 Change 4413142 by Jason.Bestimt Merging CL 4347297 from Dev-VR - Swapping double to single quote to fix Mac Editor packaging for Lumin #JIRA: UE-63556 Change 4412619 by Jason.Bestimt Merging CL 4331753 from Dev-VR - Allowing output log to capture warning and error verbosity from commandline output it receives (like launch on Lumin) #JIRA: UE-62981 Change 4412526 by Jason.Bestimt Merging CL 4311018 from Dev-VR - Preventing multiple lumin frame timing hints while the graphics context isn't valid #JIRA: UE-62031 Change 4412517 by Jason.Bestimt Merging CL 4304939 from Dev-VR - Commenting out Eye Tracker init log until the feature is complete. #JIRA: UE-61413 Change4412515by Jason.Bestimt Merging CL 4304711 from Dev-VR - Downgrading sandbox jail warning to log, as it is expected output #JIRA: UE-62992 Change 4412508 by Jason.Bestimt Merging CL 4303846 from Dev-VR - Fix for fully qualified name in header #JIRA: UE-62068 Change 4412496 by Jason.Bestimt Merging CL 4303647 from Dev-VR - Fixing synth style warnings in Lumin Sample #JIRA: UE-62068 Change 4412491 by Jason.Bestimt Integrating CL 4303618 from Dev-VR to remove Lumin Emulator plugins Change 4412425 by Mitchell.Wilson Updating GetLinearColor nodes in BP_Sky_Sphere to GetClampedLinearColor nodes. Saving curves due to the change to resolve warnings. #jira UE-64228 Change 4412349 by Lauren.Ridge Adding custom version to linear color curve assets #jira UE-64228 Change 4412302 by Ben.Marsh Include the full filename of the config file if we can't save a backup. Attempt to track down UE-64554. #jira UE-64554 Change 4412161 by frankie.dipietro Adding bUsedWithStaticLighting flag to M_Roughness_0 to fix RectLight test #jira UE-29618 Change 4411692 by tim.gautier Minor adjustment to M_Tree_FallTreeMerged_01 - added a StaticSwitchParam #jira UE-29618 Change 4411522 by Lauren.Ridge PostLoad check and additional GetClampedColorValue BP function for linear color curves #jira UE-64228 Change 4411494 by Francis.Hurteau Copied 4359025 Francis.Hurteau Test if have a valid continuation before running it when setting continuation on a ready future #jira UE-64567 Change 4411151 by Jeff.Fisher Merging using Dev-VR_to_Release-4.21 4345353 UE-62255 Google 6DOF Motion Controller Support -Added support for 6DOF controller tracking on daydream. -Project Settings->Android->Advanced APK Packaging->Configure GoogleVR to support specific hardware configurations-> Set to Daydream(6.6 DoF) to enable support for two 6dof controllers. A single 3dof controller is also supported by this configuration, as is a single 6dof controller. -Currently the 3dof controller is detected only by noticing that the positions returned for all controllers are exactly 0,0,0 per Google reccomendation. A future API should make it explicit when a controller is 3dof or 6dof. -Currently we arbitrarily make the controller at index 0 the right and the one at 1 the left. A future api should let us query for controller handedness. 4346387 Fixing build break in GoogleVRControllerFunctionLibrary.h 4349142 Fixing GoogleVRController build warning 4349742 Fixing AndroidRuntimeSettings build errors. 4350977 Fix for static analysis warning 4351170 Build fix for bad assert #jira UE-62255 Change 4410947 by Lina.Halper #DUPEMERGE Fixes many reference pose issues, where they want to add node, and how it updates, and how they could move - mainly execution can be disabled by button, and we will mark to compile when it needs recompile due to hierarchy change - added quick warning to log when hierarchy is missing - still lots of things need more iteration - fixed assets #jira: UE-63136 Change 4410550 by Lauren.Ridge Fix for ListView not propagating selection change events #jira UE-64118 Change 4410527 by Lauren.Ridge Adding condition to guard against crash when pasting comments #jira UE-63214 Change4410512by Marcin.Undak UAT: Create manifest directory, before writing to it #jira none Change 4410511 by Lauren.Ridge Fix for crash on spamming trigger presses in VR mode #jira UE-63608 Change 4410489 by Lauren.Ridge Fix for disappearing UI handle in VR mode #jira UE-63622 Change 4410364 by Ben.Marsh PR #5138: Fix bForceBuildShaderFormats not being read correctly in TargetRules (Contributed by rlabrecque) #jira UE-64611 Change 4410086 by Ben.Marsh UAT: Show timing/agent info in UAT the same way as in UBT, to make it easier to track down badly configured agents. (Originallly CL 4343393 in Dev-Build) #jira Change 4410018 by Lina.Halper #DUPE MERGe Merging using Dev-Anim<->Release4.21 fix motion blur issue on poseable mesh component #jira: UE-62296 Change 4409981 by Simon.Tourangeau SunPosition plugin #jira UE-64075 Change 4409913 by Michael.Kirzinger Fix FUniqueNetIdRepl serialization for out of engine OSSs. Use FNetBitReader/Writer in the serialization test so it properly tests network replication #jira UE-63326 [at]josh.markiewicz Change 4409838 by Simon.Tourangeau Integrate misc nDisplay fixes from Dev-Enterprise - nDisplayLauncher: Removed useless no-val command line arguments - Fixed Editor crash when translation direction is set in BP_DemoWand_Blueprint - Use quotation marks for paths - A lot of nDisplay warings "wand not found" - nDisplayLauncher passes custom arguments at beginning - Update blueprints (resubmit + comments) - Single view for monoscipic devices - Move swap eye attribute to [cluster_node] - Removed viewport flip feature - Disable input on slave nodes - Fix for GL3/4 monoscopic device. Missed changes for 'Viewport positioning fix'. - Removed custom swap_int - Fixed demo blueprints - Fixed crash in DC components when the DC is not initialized - Fixed visibility of some inherited members - Fixed Editor crash on second PIE session start - Fix for viewport positioning - BP API docs (comments) - Turn off some screen effects in the nDisplay template project #jira UE-64170 Change 4409812 by Simon.Tourangeau USD SDK updated to v18.09 Merged from Dev-Enterprise #author Rex.Hill #jira UE-64140 Change 4409754 by Graeme.Thornton Copy of CL 4385549 from Dev-Core Try and detect a serialize function inside arbitrary preprocessor blocks and throw an error Make a couple of other "can't have things inside preprocessor blocks" messages consistent with this one #jira none Change 4409671 by Jeff.Fisher Merging using Dev-VR_to_Release-4.21 4392743 UE-63646 MagicLeap 4.21 redirects need updating -Made redirectors more specific, found a way to do the updates without the MatchSubstring package update flag, to avoid a warning about how it is very slow. #jira UE-63647 Change 4409395 by Ben.Marsh Fix Python.build.cs adding locally generated *.pyc files as runtime dependencies. Since these files are not tracked as build products, they will not exist on other build machines, causing warnings when building DDC. #jira Change 4408881 by Max.Chen Sequencer: Added missing ini change for 4395032 #jira UE-64258 Change 4408670 by Max.Chen Sequencer: Step to next/prev key no longer uses ExclusiveEndFrame - 1. This fixes cases where you want to step to the last key of a section and add another animation clip that doesn't overlap. #jira none Change 4408662 by Max.Chen Sequencer: Removed derived blueprint type for level sequence director blueprints #jira UE-64258 Change 4408661 by Max.Chen Sequencer: When evaluating a range of a sequence, all overlapping segments of that range are now guaranteed to be up-to-date and compiled. This is a newer version of 4280319 which was backed out in4317353, with the TRange::Overlaps issues addressed. #jira UE-63336 #jira UE-62873 Change 4408660 by Max.Chen Sequencer: Fix crash when converting matinee assets to sequences due to changes in events. Event keys will now have blueprint event endpoints created in the level sequence blueprint when converting. #jira none Change 4408354 by Marc.Audy Fix additional cases where GetBlueprint could get called without a valid blueprint, thus checking #jira UE-62444 Change 4408286 by Joe.Conley #jira UE-64552 [CrashReport] UE4Editor_MagicLeap!UImageTrackerComponent::TickComponent() [imagetrackercomponent.cpp:391] MagicLeap ImageTrackerComponent: Adding check for PLATFORM_LUMIN to prevent PIE crash running code that was designed to only run on device. This had been fixed previously but somehow the fix got lost merging between streams. Change 4408252 by Brandon.Schaefer Doubles in the form of 1e+9999 can be larger then 30 chars, set aside more room #jira UE-64582 Change 4408076 by Mike.Erwin UAT: fix Iterative Deploy leaving behind old files on Android (copy 4369737 from Dev-Build) For iterative deploy on Android, files & directories not in staging will be zapped from the device. The following directories are spared, to maintain config & logs on device: Engine/Saved Engine/Config ProjectName/Saved ProjectName/Config Tested with Samsung Galaxy S6+ (Android 6.0) and Google Pixel 2 (Android 9.0) #android #jira UE-61686 Change 4408070 by Mike.Erwin UAT: iterative deploy no longer prevents cleaning of staging directory (copy 4369732 from Dev-Build) Partial fix for #jira UE-58838 UE-61686 UE-62879 Might need additional work to reduce file copies from Build to Stage. Change 4407741 by Ben.Marsh UBT: Avoid trying to figure out which mobile provision to use for a project when we already know the path to the provision we want. Also fix certificate not being updated if mobile provision changes. #jira Change 4407632 by Jamie.Dale Removed pyc files from Python SDK #jira UE-64531 Change 4407622 by Jamie.Dale Updated Python SDK copy script to exclude pyc files #jira UE-64531 Change 4407431 by Anousack.Kitisa Copied 4392037 Anousack.Kitisa Modified API for UV map generation. #jira UE-63814 Change 4407427 by Ben.Marsh Suppress warning for missing DebugNonUFS files when staging installed build. #jira UE-64579 Change 4407401 by Anousack.Kitisa Copied 4383601 Anousack.Kitisa [StaticMeshEditor]: * Fixed material assignment issue when re-importing Datasmith static mesh after deleting a section from the mesh. * Fixed material issue when deleting a section from a mesh and undoing and chaging material on the mesh. #jira UE-62480 Change 4407274 by Joe.Graf Over merge reverted #jira: fix Change 4407268 by Anousack.Kitisa Copied 4369800 Anousack.Kitisa Import/export FBX metadata on SkeletalMesh and Skeleton assets. #jira UEENT-1881 Change 4407220 by Joe.Graf Merging using Dev-VR_to_Release-4.21 - AR samples updated #jira: UE-64673 Change 4407213 by Rolando.Caloca UE4.21 - Copy 4403346 DR - Fix post opaque extension running before lights #jira Change 4407208 by Anousack.Kitisa Copied 4369604 JeanLuc.Corenthin - Fixed indexing issue with FOverlappingCorners object created using a FmeshDescription object: - Changed logic in building of FOverlappingCorners to be based on index of wedge, number of wedges equal 3 times the number of triangles like in FRawMesh, instead of index of vertex instances. - Updated BuildVertexBuffer to take this new logic in account. - Fixed crash in FMeshDescriptionOperations::CreateMikktTangents: - MikkTSpace sdk does not handle properly faces with 0 vertices which occur with mesh description with invalid polygons. #jira UE-62478, UE-63758 Change 4407188 by Joe.Graf Merging using Dev-VR_to_Release-4.21 - Fixed missing include when not using unity builds #jira: UE-64673 Change 4407179 by Joe.Graf Merging using Dev-VR_to_Release-4.21 - Added a way to see the ARKit CPU consumption across all of its threads #jira: UE-64673 Change 4407178 by Joe.Graf Merging using Dev-VR_to_Release-4.21 - Bug fix for landscape image detection being at the wrong distance #jira: UE-64673 Change 4407174 by Joe.Graf Merging using Dev-VR_to_Release-4.21 - Improved debug rendering of AR tracked images #jira: UE-64673 Change 4407165 by Joe.Graf Merging using Dev-VR_to_Release-4.21 - Added post edit change to force correct aspect ratios when editing physical size for detected images #jira: UE-64673 Change 4407162 by Joe.Graf Merging using Dev-VR_to_Release-4.21 - Reverted premature merge #jira: merge Change 4407156 by Joe.Graf Merging using Dev-VR_to_Release-4.21 #jira: merge Change 4407146 by Joe.Graf Merging using Dev-VR_to_Release-4.21 - Point cloud rendering additions #jira: UE-64673 Change 4407134 by Joe.Graf Merging using Dev-VR_to_Release-4.21 - Added some config properties to box component for debug rendering #jira: UE-64673 Change 4407128 by Joe.Graf Merging using Dev-VR_to_Release-4.21 - Added missing #ifdef #jira: UE-64673 Change 4407127 by Joe.Graf Merging using Dev-VR_to_Release-4.21 - AR point cloud debug rendering support added #jira: UE-64673 Change 4407119 by Joe.Graf Merging using Dev-VR_to_Release-4.21 - ARVideoSettings sample #jira: UE-64673 Change 4407113 by Joe.Graf Merging using Dev-VR_to_Release-4.21 - Added a device orientation query in addition to the event that is present #jira: UE-64673 Change 4407109 by Joe.Graf Merging using Dev-VR_to_Release-4.21 - Fixed a missing nullptr check that was causing AR apps to crash #jira: UE-64673 Change 4407105 by Joe.Graf Merging using Dev-VR_to_Release-4.21 - Added support for rotating an image while generating a jpeg for ARSharedWorld sample #jira: UE-64673 Change 4407101 by Joe.Graf Merging using Dev-VR_to_Release-4.21 - Added a set of properties to override thread priorities when using ARKit and UE4 is causing ARKit to starve #jira: UE-64673 Change 4407098 by Joe.Graf Merging using Dev-VR_to_Release-4.21 #jira: merge Change 4407093 by Francis.Hurteau Copied 4372687 Francis.Hurteau Fix potential assert when changing ProtocolVersion based on ping messages #jira UE-64035 Change 4407088 by Joe.Graf Merging using Dev-VR_to_Release-4.21 - Added scaling to jpeg creation for ARSharedWorld sample #jira: UE-64673 Change 4407082 by Joe.Graf Merging using Dev-VR_to_Release-4.21 - ARSharedWorld sample #jira: UE-64673 Change 4407078 by Joe.Graf Merging using Dev-VR_to_Release-4.21 - Fix for null session config being passed to AR system #jira: UE-64673 Change 4407074 by Joe.Graf Merging using Dev-VR_to_Release-4.21 - ARSharedWorld sample #jira: UE-64673 Change 4407064 by Joe.Graf Merging using Dev-VR_to_Release-4.21 - ARSharedWorld sample #jira: UE-64673 Change 4407061 by Joe.Graf Merging using Dev-VR_to_Release-4.21 - ARSharedWorld sample #jira: UE-64673 Change 4407052 by JeanLuc.Corenthin Copy CL #4392021 - Fixed crash when importing model thru VRED importer - Includes changes to StaticMeshBuilder.cpp made in CL #4369604 #jira UE-64152 Change 4407051 by Joe.Graf Merging using Dev-VR_to_Release-4.21 - ARSharedWorld sample #jira: UE-64673 Change 4407045 by Joe.Graf Merging using Dev-VR_to_Release-4.21 - Code suupport for streaming ar shared worlds #jira: UE-64673 Change 4407039 by Joe.Graf Merging using Dev-VR_to_Release-4.21 - ARSharedWorld sample #jira: UE-64673 Change 4407032 by Joe.Graf Merging using Dev-VR_to_Release-4.21 - Improved AR template #jira: UE-64673 Change 4407030 by Joe.Graf Merging using Dev-VR_to_Release-4.21 - Better BP exposure of GetMappingStatus for AR #jira: UE-64673 Change 4407017 by Joe.Graf Merging using Dev-VR_to_Release-4.21 - Better double free fix for ar env probes #jira: UE-64673 Change 4407012 by Joe.Graf Merging using Dev-VR_to_Release-4.21 - Double free fix for env probes #jira: UE-64673 Change 4407007 by Joe.Graf Merging using Dev-VR_to_Release-4.21 - AREnvProbe sample #jira: UE-64673 Change 4407006 by Joe.Graf Merging using Dev-VR_to_Release-4.21 - AREnvProbe sample #jira: UE-64673 Change 4407003 by Joe.Graf Merging using Dev-VR_to_Release-4.21 - AREnvProbe sample #jira: UE-64673 Change 4406999 by Joe.Graf Merging using Dev-VR_to_Release-4.21 - Render doc fix for non-editor builds #jira: merge Change 4406994 by Anousack.Kitisa Copied 4362955 JeanMichel.Dignard Static Mesh Library : SetLodFromStaticMesh - Assign materials to new LOD sections based on source mesh LOD. - Copy LOD build settings from source. #jira UE-63659, UE-64016 Change 4406992 by Joe.Graf Merging using Dev-VR_to_Release-4.21 - Fix for CLion IDE usage #jira: merge Change 4406987 by Joe.Graf Merging using Dev-VR_to_Release-4.21 - Fix for missing property decoration for video modes #jira: UE-64673 Change 4406944 by Max.Chen Sequencer: Stop all sounds on tear down #jira UE-63501 Change 4406942 by Mark.Satterthwaite Duplicate CL #4398322: Rebuild mtlpp using Xcode 10 so Metal 2.1 works on iOS. #jira N/A Change 4406880 by Anousack.Kitisa Copied 4356072 Anousack.Kitisa [StaticMeshEditor]: * Moved the UV channel removal functionality from the LOD details panel to the UV drop-down menu. #jira UEENT-1827 Change 4406826 by Francis.Hurteau Copied 4366928 Jeremie.Roy Fix crashes related to the UndoHistory. Add missing UndoBufferChangedDelegate broadcasts in EditorTransaction #jira UE-64096 Change 4406820 by Anousack.Kitisa Copied 4350474 Johan.Duparc Fix UEditorAssetLibrary::DoesAssetExist to handle sub object name #jira UE-62333 Change 4406783 by Anousack.Kitisa Copied 4348861 Anousack.Kitisa [StaticMeshEditor]: * Fixed vertices being merged even though they don't share mergeable attributes. #jira UE-62980 Change 4406752 by Anousack.Kitisa Copied 4348838 Anousack.Kitisa Fixed ConvertAnyPathToObjectPath returning wrong path for objects that are named differently than their package. #jira UE-62333 Change 4406721 by Brandon.Schaefer Linux: Set FORCE_ANSI_ALLOCATOR when using -EnableTSan to avoid multiple definitions #jira UE-62804 Change 4406461 by Francis.Hurteau Copied 4382276 Francis.Hurteau Fix syncing streaming level visibility state with undo/redo #jira UE-64315 Change 4406459 by Ben.Marsh Fix temporary files containing dependency lists being created in Engine directory. Move them under Engine/Intermediate instead. #jira Change 4406451 by Brandon.Schaefer Linux: Dont try to make current if our current window was the SplashScreen window we just destroyed #jira UE-64211 Change 4406440 by Chris.Babcock Remove AKEYCODE_BACK from valid gamepad keycodes to allow it when controllers are disabled #jira UE-64350 #ue4 #android Change 4406382 by Anousack.Kitisa Copied 4393087 Patrick.Boutot Add a shader source directory for the OpenCVLensDistortion plugin. #jira UE-64568 Change4406345by Joe.Graf Merge Xcode project generation fix to defaul to Legacy build mode using Dev-VR->Release-4.21 #jira: merge Change 4405792 by JeanMichel.Dignard Copied 4393315 JeanMichel.Dignard Better telemetry for plugin warden - Added more event attributes to track potential issues. #jira UE-64280 Change 4405776 by JeanMichel.Dignard Copied 4392578 JeanMichel.Dignard Fixed actors not saving properly on a reimport when moved to a sublevel. The issue is that they were being parented to actors from another level which isn't supported. Also, the scene component template should refer to the parent component through a TSoftObjectPtr in case it's in another package. #jira UE-62070 Change 4405738 by Mark.Satterthwaite Duplicate CL #4396224: Remove another broken bit of legacy Metal code. #jira UE-64128 Change 4405733 by Mark.Satterthwaite Duplicate CL #4399472: Handle all Metal formats in ShaderPlatformToPlatformName - I have not made this handle all formats or platforms so this function is *wrong* for a number of others and should *assert* on failure to identify a platform. This fixes incorrect shader compilation for Forward rendering on iOS. #jira UE-64355 Change 4405630 by JeanMichel.Dignard Copied 43737703 Johan.Duparc Prevent crash for old datasmith assets Clear transactional flag in user asset data that could cause a crash for Blueprint assets. #jira UE-63349 Change 4405481 by Sorin.Gradinaru UE-61699 Kindle Fire 5th Gen crashes rotating Remote Session #jira UE-61699 #Android #4.21 From //UE4/Dev-Mobile CL4360704 Disabling threaded rendering for Kindle Fire HD 7 5th gen in DefaultDeviceProfiles.ini Change 4405276 by Frankie.DiPietro Adding test content for Volume Textures, Iris Normals, and Subsurface Boundary Bleed Color coverage #jira UE-29618 Change 4405138 by JeanMichel.Dignard Copied 4350470 Johan.Duparc Fix crash on property edition for blueprint actors with templated asset user data #jira UE-63349 Change 4404967 by Mikey.Boyd Making content change to M_Translucent_PanNrm for UEQATC-244. Added a Texture Sample node to be used to test Platform Stats. #jira UE-29618 Change 4404909 by Robert.Manuszewski When enabling cooked assets in the editor, the engine will now use FArchiveAsync2 in the editor to be able to open them. (re-implemented CL #4400327 from Dev-Core) #jira UE-64389 Change 4404901 by Robert.Manuszewski Fixed a hang when entering PIE when Background Streaming is disabled #jira UE-63320 Change 4404816 by Ben.Marsh Fix "Non-void function should return a value" warning in CIS. #jira Change 4404621 by Stefan.Boberg Re-enabled LLM on Editor builds since the performance issue has been addressed #jira UE-60020 Change 4404491 by Max.Chen Sequencer: Use cached object bindings when drawing motion trails. FindObjectId can be slow because it clears the cached bindings. Added FindCachedObjectId which retrieves the binding without clearing the cache. #jira UE-63347 Change 4404490 by Max.Chen Sequencer: Fix key reduction not working on imported fbx channel. Implement channel Optimize() so that it follows the curve editor's SimplifySelection by evaluating whether a key is needed (rather than removing the key and checking whether the value has changed). The main fix is that the tangents need to be calculated as non-normalized (ie. with the DisplayRate) #jira UE-62353 Change 4404488 by Max.Chen Sequencer: Changed HandleSingleNode fallback check for collapsed parents. #jira UE-64394 Change 4404486 by Max.Chen Sequencer: Remove restriction on hidden mobility. It's too wide to restrict transform tracks. #jira UE-63415 Change 4404472 by Max.Chen Sequencer: Restore drawing paths for selected nodes and channels #jira UE-64204 Change 4404468 by Max.Chen Sequencer: Check for property type in evaluation. This fixes an issue where the property type is changed after the track has been created. #jira UE-64278 Change 4404439 by Keli.Hlodversson Merging critical SteamVR fixes from Dev-VR #jira UE-63198 #jira UE-64098 #jira UEVR-1250 Change 4403717 by Marc.Audy Inline templated version of GetGameInstance #jira UE-62591 Change 4403702 by Marc.Audy PR #4944: Added template cast versions of multiple methods. (Contributed by francoap) #jira UE-62591 Change 4403699 by Marc.Audy Make reregistering an object in the significance manager an ensure not a check #jira Change 4403697 by Marc.Audy PR #5074: Fixed minor bugs in GameUserSettings. (Contributed by phoenxin) #jira UE-63893 Change 4403695 by Marc.Audy Fix crash pasting timeline with external curve that has been force deleted #jira UE-64504 Change 4403693 by Marc.Audy PR #5077: Prevent TimelineComponent Update delegate from being executed 3 times when looping (Contributed by nedwardsnae) #jira UE-63927 Change 4403691 by Marc.Audy PR #5076: Correct icon when dragging an event dispatcher variable (Contributed by projectgheist) #jira UE-63895 Change 4403689 by Marc.Audy PR #5075: Mouse decorator when dragging a category from My Blueprint panel (Contributed by projectgheist) #jira UE-63894 Change 4403686 by Marc.Audy PR #5096: UE-64019: Use compare function for tooltip FText instead of != operator (Contributed by projectgheist) #jira UE-64109 #jira UE-64019 Change 4403662 by Marc.Audy Ensure that objects created via duplication in PIE are correctly constructed #jira UE-63505 Change 4403462 by tim.gautier Cleaned up M_Tree_FallTreeMerged_01, added comment blocks for UEQATC-212 #jira UE-29618 Change 4403308 by Michael.Trepka Update mouse position on NSDraggingUpdate event on Mac #jira UE-60800 Change 4403290 by Michael.Trepka Fixed issues with window position and size when toggling between fullscreen and windowed modes #jira UE-63212 Change 4403270 by Michael.Trepka Fixed a problem with mouse click/drag events being received by incorrect window/widget in certain conditions while dragging windows on Mac #jira UE-57506 Change 4403216 by Ben.Marsh Fix null reference exception when resolving paths. #jira Change 4403213 by Ben.Marsh Revert change to use FileReference for executable to use in the <Spawn> task, to ensure we can use programs in the PATH. #jira Change 4403209 by Ben.Marsh Prevent null dereference when tagging a set of files. #jira Change 4403200 by Ben.Marsh BuildGraph: Add support for automatic parsing of collection types in BuildGraph parameters. #jira Change 4403188 by Mikey.Boyd Adding content for Data Table test coverage. #jira UE-29618 Change 4403163 by Ben.Marsh Sanitize the contents of all the receipts in the installed engine build, to make sure they don't reference any files we don't distribute. #jira UE-56424 Change 4403151 by Ben.Marsh UBT: Don't assume that console encoding is UTF-8 when using ParallelExecutor. #jira UE-64248 Change 4403136 by Ben.Marsh Fix IWYU issues with SQLite support. #jira UE-64523 Change 4403116 by Ben.Marsh UBT: Fix project files being generated for VS2017 if the user only has AutoSDKs, and does not have the IDE installed. #jira UE-62726 Change 4403074 by Ben.Marsh UBT: Fix a couple of edge cases when parsing output from child processes. * If a single line was larger than 32kb, the process would be treated as having terminated. * If the last output line did not have a trailing newline, the line would be dropped. #jira UE-64234 Change 4403066 by Ben.Marsh Fix project browser reopening when creating a new project, if other command line arguments are present. Missing a space between the project file and previous argument list. #jira UE-63724 #lockdown Nick.Penwarden #rb none #ROBOMERGE-OWNER: jason.bestimt #ROBOMERGE-AUTHOR: ben.marsh #ROBOMERGE-SOURCE: CL 4447546 in //UE4/Main/... #ROBOMERGE-BOT: DEVVR (Main -> Dev-VR) [CL 4452228 by jason bestimt in Dev-VR branch]
4512 lines
137 KiB
C++
4512 lines
137 KiB
C++
// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "NavigationSystem.h"
|
|
#include "Misc/ScopeLock.h"
|
|
#include "Stats/StatsMisc.h"
|
|
#include "Modules/ModuleManager.h"
|
|
#include "AI/Navigation/NavAgentInterface.h"
|
|
#include "Engine/World.h"
|
|
#include "GameFramework/Controller.h"
|
|
#include "AI/Navigation/NavRelevantInterface.h"
|
|
#include "UObject/UObjectIterator.h"
|
|
#include "EngineUtils.h"
|
|
#include "Logging/MessageLog.h"
|
|
#include "NavAreas/NavArea.h"
|
|
#include "NavigationOctree.h"
|
|
#include "VisualLogger/VisualLogger.h"
|
|
#include "NavMesh/NavMeshBoundsVolume.h"
|
|
#include "NavigationInvokerComponent.h"
|
|
#include "AI/Navigation/NavigationDataChunk.h"
|
|
#include "Engine/Engine.h"
|
|
#include "UObject/Package.h"
|
|
#include "Components/PrimitiveComponent.h"
|
|
#include "UObject/UObjectThreadContext.h"
|
|
|
|
#if WITH_RECAST
|
|
#include "NavMesh/RecastNavMesh.h"
|
|
#include "NavMesh/RecastHelpers.h"
|
|
#include "NavMesh/RecastNavMeshGenerator.h"
|
|
#endif // WITH_RECAST
|
|
#if WITH_EDITOR
|
|
#include "EditorModeManager.h"
|
|
#include "EditorModes.h"
|
|
#include "Editor/GeometryMode/Public/GeometryEdMode.h"
|
|
#include "Editor/GeometryMode/Public/EditorGeometry.h"
|
|
#endif
|
|
|
|
#if WITH_HOT_RELOAD
|
|
#include "Misc/HotReloadInterface.h"
|
|
#endif
|
|
|
|
#include "NavAreas/NavArea_Null.h"
|
|
#include "NavAreas/NavArea_Obstacle.h"
|
|
#include "NavAreas/NavArea_Default.h"
|
|
#include "NavAreas/NavAreaMeta_SwitchByAgent.h"
|
|
#include "NavLinkCustomInterface.h"
|
|
#include "NavigationPath.h"
|
|
#include "AbstractNavData.h"
|
|
#include "CrowdManagerBase.h"
|
|
|
|
|
|
static const uint32 INITIAL_ASYNC_QUERIES_SIZE = 32;
|
|
static const uint32 REGISTRATION_QUEUE_SIZE = 16; // and we'll not reallocate
|
|
|
|
#define LOCTEXT_NAMESPACE "Navigation"
|
|
|
|
DEFINE_LOG_CATEGORY_STATIC(LogNavOctree, Warning, All);
|
|
|
|
DECLARE_CYCLE_STAT(TEXT("Rasterize triangles"), STAT_Navigation_RasterizeTriangles,STATGROUP_Navigation);
|
|
DECLARE_CYCLE_STAT(TEXT("Nav Tick: area register"), STAT_Navigation_TickNavAreaRegister, STATGROUP_Navigation);
|
|
DECLARE_CYCLE_STAT(TEXT("Nav Tick: mark dirty"), STAT_Navigation_TickMarkDirty, STATGROUP_Navigation);
|
|
DECLARE_CYCLE_STAT(TEXT("Nav Tick: async build"), STAT_Navigation_TickAsyncBuild, STATGROUP_Navigation);
|
|
DECLARE_CYCLE_STAT(TEXT("Nav Tick: async pathfinding"), STAT_Navigation_TickAsyncPathfinding, STATGROUP_Navigation);
|
|
DECLARE_CYCLE_STAT(TEXT("Debug NavOctree Time"), STAT_DebugNavOctree, STATGROUP_Navigation);
|
|
//----------------------------------------------------------------------//
|
|
// Stats
|
|
//----------------------------------------------------------------------//
|
|
|
|
DEFINE_STAT(STAT_Navigation_QueriesTimeSync);
|
|
DEFINE_STAT(STAT_Navigation_RequestingAsyncPathfinding);
|
|
DEFINE_STAT(STAT_Navigation_PathfindingSync);
|
|
DEFINE_STAT(STAT_Navigation_PathfindingAsync);
|
|
DEFINE_STAT(STAT_Navigation_AddGeneratedTiles);
|
|
DEFINE_STAT(STAT_Navigation_TileNavAreaSorting);
|
|
DEFINE_STAT(STAT_Navigation_TileGeometryExportToObjAsync);
|
|
DEFINE_STAT(STAT_Navigation_TileVoxelFilteringAsync);
|
|
DEFINE_STAT(STAT_Navigation_TileBuildAsync);
|
|
DEFINE_STAT(STAT_Navigation_TileBuildPreparationSync);
|
|
DEFINE_STAT(STAT_Navigation_BSPExportSync);
|
|
DEFINE_STAT(STAT_Navigation_GatheringNavigationModifiersSync);
|
|
DEFINE_STAT(STAT_Navigation_ActorsGeometryExportSync);
|
|
DEFINE_STAT(STAT_Navigation_ProcessingActorsForNavMeshBuilding);
|
|
DEFINE_STAT(STAT_Navigation_AdjustingNavLinks);
|
|
DEFINE_STAT(STAT_Navigation_AddingActorsToNavOctree);
|
|
DEFINE_STAT(STAT_Navigation_RecastTick);
|
|
DEFINE_STAT(STAT_Navigation_RecastPathfinding);
|
|
DEFINE_STAT(STAT_Navigation_RecastBuildCompressedLayers);
|
|
DEFINE_STAT(STAT_Navigation_RecastBuildNavigation);
|
|
DEFINE_STAT(STAT_Navigation_UpdateNavOctree);
|
|
DEFINE_STAT(STAT_Navigation_CollisionTreeMemory);
|
|
DEFINE_STAT(STAT_Navigation_NavDataMemory);
|
|
DEFINE_STAT(STAT_Navigation_TileCacheMemory);
|
|
DEFINE_STAT(STAT_Navigation_OutOfNodesPath);
|
|
DEFINE_STAT(STAT_Navigation_PartialPath);
|
|
DEFINE_STAT(STAT_Navigation_CumulativeBuildTime);
|
|
DEFINE_STAT(STAT_Navigation_BuildTime);
|
|
DEFINE_STAT(STAT_Navigation_OffsetFromCorners);
|
|
DEFINE_STAT(STAT_Navigation_PathVisibilityOptimisation);
|
|
DEFINE_STAT(STAT_Navigation_ObservedPathsCount);
|
|
DEFINE_STAT(STAT_Navigation_RecastMemory);
|
|
|
|
CSV_DEFINE_CATEGORY(NAV_SYSTEM, true);
|
|
|
|
//----------------------------------------------------------------------//
|
|
// consts
|
|
//----------------------------------------------------------------------//
|
|
namespace FNavigationSystem
|
|
{
|
|
FORCEINLINE bool IsValidExtent(const FVector& Extent)
|
|
{
|
|
return Extent != INVALID_NAVEXTENT;
|
|
}
|
|
|
|
FCustomLinkOwnerInfo::FCustomLinkOwnerInfo(INavLinkCustomInterface* Link)
|
|
{
|
|
LinkInterface = Link;
|
|
LinkOwner = Link->GetLinkOwner();
|
|
}
|
|
|
|
bool ShouldLoadNavigationOnClient(ANavigationData& NavData)
|
|
{
|
|
const UWorld* World = NavData.GetWorld();
|
|
|
|
if (World && World->GetNavigationSystem())
|
|
{
|
|
const UNavigationSystemV1* NavSys = Cast<UNavigationSystemV1>(World->GetNavigationSystem());
|
|
return NavSys && NavSys->ShouldLoadNavigationOnClient(&NavData);
|
|
}
|
|
else
|
|
{
|
|
const UNavigationSystemV1* NavSysCDO = (*GEngine->NavigationSystemClass != nullptr)
|
|
? (GEngine->NavigationSystemClass->GetDefaultObject<const UNavigationSystemV1>())
|
|
: (const UNavigationSystemV1*)nullptr;
|
|
return NavSysCDO && NavSysCDO->ShouldLoadNavigationOnClient(&NavData);
|
|
}
|
|
}
|
|
|
|
bool ShouldDiscardSubLevelNavData(ANavigationData& NavData)
|
|
{
|
|
const UWorld* World = NavData.GetWorld();
|
|
|
|
if (World && World->GetNavigationSystem())
|
|
{
|
|
const UNavigationSystemV1* NavSys = Cast<UNavigationSystemV1>(World->GetNavigationSystem());
|
|
if (NavSys)
|
|
{
|
|
return NavSys->ShouldDiscardSubLevelNavData(&NavData);
|
|
}
|
|
}
|
|
|
|
const UNavigationSystemV1* NavSysCDO = (*GEngine->NavigationSystemClass != nullptr)
|
|
? (GEngine->NavigationSystemClass->GetDefaultObject<const UNavigationSystemV1>())
|
|
: (const UNavigationSystemV1*)nullptr;
|
|
return NavSysCDO == nullptr || NavSysCDO->ShouldDiscardSubLevelNavData(&NavData);
|
|
}
|
|
|
|
void MakeAllComponentsNeverAffectNav(AActor& Actor)
|
|
{
|
|
const TSet<UActorComponent*> Components = Actor.GetComponents();
|
|
for (UActorComponent* ActorComp : Components)
|
|
{
|
|
ActorComp->SetCanEverAffectNavigation(false);
|
|
}
|
|
}
|
|
}
|
|
|
|
namespace NavigationDebugDrawing
|
|
{
|
|
const float PathLineThickness = 3.f;
|
|
const FVector PathOffset(0,0,15);
|
|
const FVector PathNodeBoxExtent(16.f);
|
|
}
|
|
|
|
//----------------------------------------------------------------------//
|
|
// FNavigationInvoker
|
|
//----------------------------------------------------------------------//
|
|
FNavigationInvoker::FNavigationInvoker()
|
|
: Actor(nullptr)
|
|
, GenerationRadius(0)
|
|
, RemovalRadius(0)
|
|
{
|
|
|
|
}
|
|
|
|
FNavigationInvoker::FNavigationInvoker(AActor& InActor, float InGenerationRadius, float InRemovalRadius)
|
|
: Actor(&InActor)
|
|
, GenerationRadius(InGenerationRadius)
|
|
, RemovalRadius(InRemovalRadius)
|
|
{
|
|
|
|
}
|
|
|
|
//----------------------------------------------------------------------//
|
|
// helpers
|
|
//----------------------------------------------------------------------//
|
|
namespace
|
|
{
|
|
#if ENABLE_VISUAL_LOG
|
|
void NavigationDataDump(const UObject* Object, const FName& CategoryName, const ELogVerbosity::Type Verbosity, const FBox& Box, const UWorld& World, FVisualLogEntry& CurrentEntry)
|
|
{
|
|
const ANavigationData* MainNavData = FNavigationSystem::GetCurrent<UNavigationSystemV1>(&World)->GetDefaultNavDataInstance();
|
|
const FNavDataGenerator* Generator = MainNavData ? MainNavData->GetGenerator() : nullptr;
|
|
if (Generator)
|
|
{
|
|
Generator->GrabDebugSnapshot(&CurrentEntry, FMath::IsNearlyZero(Box.GetVolume()) ? MainNavData->GetBounds().ExpandBy(FVector(20, 20, 20)) : Box, CategoryName, Verbosity);
|
|
}
|
|
}
|
|
#endif // ENABLE_VISUAL_LOG
|
|
}
|
|
//----------------------------------------------------------------------//
|
|
// UNavigationSystemV1
|
|
//----------------------------------------------------------------------//
|
|
bool UNavigationSystemV1::bNavigationAutoUpdateEnabled = true;
|
|
TMap<INavLinkCustomInterface*, FWeakObjectPtr> UNavigationSystemV1::PendingCustomLinkRegistration;
|
|
FCriticalSection UNavigationSystemV1::CustomLinkRegistrationSection;
|
|
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
|
|
FNavigationSystemExec UNavigationSystemV1::ExecHandler;
|
|
#endif // !UE_BUILD_SHIPPING
|
|
|
|
/** called after navigation influencing event takes place*/
|
|
UNavigationSystemV1::FOnNavigationDirty UNavigationSystemV1::NavigationDirtyEvent;
|
|
|
|
bool UNavigationSystemV1::bUpdateNavOctreeOnComponentChange = true;
|
|
bool UNavigationSystemV1::bStaticRuntimeNavigation = false;
|
|
bool UNavigationSystemV1::bIsPIEActive = false;
|
|
//----------------------------------------------------------------------//
|
|
// life cycle stuff
|
|
//----------------------------------------------------------------------//
|
|
|
|
UNavigationSystemV1::UNavigationSystemV1(const FObjectInitializer& ObjectInitializer)
|
|
: Super(ObjectInitializer)
|
|
, bTickWhilePaused(false)
|
|
, bWholeWorldNavigable(false)
|
|
, bSkipAgentHeightCheckWhenPickingNavData(false)
|
|
, DirtyAreasUpdateFreq(60)
|
|
, OperationMode(FNavigationSystemRunMode::InvalidMode)
|
|
, NavOctree(NULL)
|
|
, NavBuildingLockFlags(0)
|
|
, InitialNavBuildingLockFlags(0)
|
|
, bNavOctreeLock(false)
|
|
, bInitialSetupHasBeenPerformed(false)
|
|
, bInitialLevelsAdded(false)
|
|
, bWorldInitDone(false)
|
|
, CurrentlyDrawnNavDataIndex(0)
|
|
, DirtyAreasUpdateTime(0)
|
|
{
|
|
#if WITH_EDITOR
|
|
NavUpdateLockFlags = 0;
|
|
#endif
|
|
struct FDelegatesInitializer
|
|
{
|
|
FDelegatesInitializer()
|
|
{
|
|
UNavigationSystemBase::UpdateActorDataDelegate().BindStatic(&UNavigationSystemV1::UpdateActorInNavOctree);
|
|
UNavigationSystemBase::UpdateComponentDataDelegate().BindStatic(&UNavigationSystemV1::UpdateComponentInNavOctree);
|
|
UNavigationSystemBase::UpdateComponentDataAfterMoveDelegate().BindLambda([](USceneComponent& Comp) { UNavigationSystemV1::UpdateNavOctreeAfterMove(&Comp); });
|
|
UNavigationSystemBase::OnActorBoundsChangedDelegate().BindLambda([](AActor& Actor) { UNavigationSystemV1::UpdateNavOctreeBounds(&Actor); });
|
|
UNavigationSystemBase::OnPostEditActorMoveDelegate().BindLambda([](AActor& Actor) {
|
|
// update actor and all its components in navigation system after finishing move
|
|
// USceneComponent::UpdateNavigationData works only in game world
|
|
UNavigationSystemV1::UpdateNavOctreeBounds(&Actor);
|
|
|
|
TArray<AActor*> ParentedActors;
|
|
Actor.GetAttachedActors(ParentedActors);
|
|
for (int32 Idx = 0; Idx < ParentedActors.Num(); Idx++)
|
|
{
|
|
UNavigationSystemV1::UpdateNavOctreeBounds(ParentedActors[Idx]);
|
|
}
|
|
|
|
// not doing manual update of all attached actors since UpdateActorAndComponentsInNavOctree should take care of it
|
|
UNavigationSystemV1::UpdateActorAndComponentsInNavOctree(Actor);
|
|
});
|
|
UNavigationSystemBase::OnComponentTransformChangedDelegate().BindLambda([](USceneComponent& Comp) {
|
|
if (UNavigationSystemV1::ShouldUpdateNavOctreeOnComponentChange())
|
|
{
|
|
UWorld* World = Comp.GetWorld();
|
|
UNavigationSystemV1* NavSys = FNavigationSystem::GetCurrent<UNavigationSystemV1>(World);
|
|
if (NavSys != nullptr
|
|
&& (NavSys->ShouldAllowClientSideNavigation() || !World->IsNetMode(ENetMode::NM_Client)))
|
|
{
|
|
// use propagated component's transform update in editor OR server game with additional navsys check
|
|
UNavigationSystemV1::UpdateNavOctreeAfterMove(&Comp);
|
|
}
|
|
}
|
|
});
|
|
UNavigationSystemBase::OnActorRegisteredDelegate().BindLambda([](AActor& Actor) { UNavigationSystemV1::OnActorRegistered(&Actor); });
|
|
UNavigationSystemBase::OnActorUnregisteredDelegate().BindLambda([](AActor& Actor) { UNavigationSystemV1::OnActorUnregistered(&Actor); });
|
|
UNavigationSystemBase::OnComponentRegisteredDelegate().BindLambda([](UActorComponent& Comp) { UNavigationSystemV1::OnComponentRegistered(&Comp); });
|
|
UNavigationSystemBase::OnComponentUnregisteredDelegate().BindLambda([](UActorComponent& Comp) { UNavigationSystemV1::OnComponentUnregistered(&Comp); });
|
|
UNavigationSystemBase::RemoveActorDataDelegate().BindLambda([](AActor& Actor) { UNavigationSystemV1::ClearNavOctreeAll(&Actor); });
|
|
UNavigationSystemBase::HasComponentDataDelegate().BindLambda([](UActorComponent& Comp) {
|
|
UNavigationSystemV1* NavSys = FNavigationSystem::GetCurrent<UNavigationSystemV1>(Comp.GetWorld());
|
|
return (NavSys && (NavSys->GetObjectsNavOctreeId(Comp) || NavSys->HasPendingObjectNavOctreeId(&Comp)));
|
|
});
|
|
UNavigationSystemBase::GetDefaultSupportedAgentDelegate().BindStatic(&UNavigationSystemV1::GetDefaultSupportedAgent);
|
|
UNavigationSystemBase::UpdateActorAndComponentDataDelegate().BindStatic(&UNavigationSystemV1::UpdateActorAndComponentsInNavOctree);
|
|
UNavigationSystemBase::OnComponentBoundsChangedDelegate().BindLambda([](UActorComponent& Comp, const FBox& NewBounds, const FBox& DirtyArea) {
|
|
UNavigationSystemV1* NavSys = FNavigationSystem::GetCurrent<UNavigationSystemV1>(Comp.GetWorld());
|
|
if (NavSys)
|
|
{
|
|
NavSys->UpdateNavOctreeElementBounds(&Comp, NewBounds, DirtyArea);
|
|
}
|
|
});
|
|
//UNavigationSystemBase::GetNavDataForPropsDelegate();
|
|
UNavigationSystemBase::GetNavDataForActorDelegate().BindStatic(&UNavigationSystemV1::GetNavDataForActor);
|
|
|
|
#if WITH_RECAST
|
|
UNavigationSystemBase::GetDefaultNavDataClassDelegate().BindLambda([]() { return ARecastNavMesh::StaticClass(); });
|
|
#endif // WITH_RECAST
|
|
UNavigationSystemBase::VerifyNavigationRenderingComponentsDelegate().BindLambda([](UWorld& World, const bool bShow) {
|
|
UNavigationSystemV1* NavSys = FNavigationSystem::GetCurrent<UNavigationSystemV1>(&World);
|
|
if (NavSys)
|
|
{
|
|
NavSys->VerifyNavigationRenderingComponents(bShow);
|
|
}
|
|
});
|
|
UNavigationSystemBase::BuildDelegate().BindLambda([](UWorld& World) {
|
|
UNavigationSystemV1* NavSys = FNavigationSystem::GetCurrent<UNavigationSystemV1>(&World);
|
|
if (NavSys)
|
|
{
|
|
NavSys->Build();
|
|
}
|
|
});
|
|
#if WITH_EDITOR
|
|
UNavigationSystemBase::OnPIEStartDelegate().BindLambda([](UWorld& World) {
|
|
UNavigationSystemV1* NavSys = FNavigationSystem::GetCurrent<UNavigationSystemV1>(&World);
|
|
if (NavSys)
|
|
{
|
|
NavSys->OnPIEStart();
|
|
}
|
|
});
|
|
UNavigationSystemBase::OnPIEEndDelegate().BindLambda([](UWorld& World) {
|
|
UNavigationSystemV1* NavSys = FNavigationSystem::GetCurrent<UNavigationSystemV1>(&World);
|
|
if (NavSys)
|
|
{
|
|
NavSys->OnPIEEnd();
|
|
}
|
|
});
|
|
UNavigationSystemBase::UpdateLevelCollisionDelegate().BindLambda([](ULevel& Level) {
|
|
UNavigationSystemV1* NavSys = FNavigationSystem::GetCurrent<UNavigationSystemV1>(&Level);
|
|
if (NavSys)
|
|
{
|
|
NavSys->UpdateLevelCollision(&Level);
|
|
}
|
|
});
|
|
UNavigationSystemBase::SetNavigationAutoUpdateEnableDelegate().BindStatic(&UNavigationSystemV1::SetNavigationAutoUpdateEnabled);
|
|
/*.BindLambda([](const bool bNewEnable, UNavigationSystemBase* InNavigationSystem) {
|
|
|
|
})*/
|
|
UNavigationSystemBase::AddNavigationUpdateLockDelegate().BindLambda([](UWorld& World, uint8 Flags) {
|
|
UNavigationSystemV1* NavSys = FNavigationSystem::GetCurrent<UNavigationSystemV1>(&World);
|
|
if (NavSys)
|
|
{
|
|
NavSys->AddNavigationUpdateLock(Flags);
|
|
}
|
|
});
|
|
UNavigationSystemBase::RemoveNavigationUpdateLockDelegate().BindLambda([](UWorld& World, uint8 Flags) {
|
|
UNavigationSystemV1* NavSys = FNavigationSystem::GetCurrent<UNavigationSystemV1>(&World);
|
|
if (NavSys)
|
|
{
|
|
NavSys->RemoveNavigationUpdateLock(Flags);
|
|
}
|
|
});
|
|
#endif // WITH_EDITOR
|
|
|
|
#if ENABLE_VISUAL_LOG
|
|
FVisualLogger::NavigationDataDumpDelegate.AddStatic(&NavigationDataDump);
|
|
#endif // ENABLE_VISUAL_LOG
|
|
}
|
|
};
|
|
static FDelegatesInitializer DelegatesInitializer;
|
|
|
|
// @hack, trying to load AIModule's CrowdManager
|
|
UClass* Class = StaticLoadClass(UCrowdManagerBase::StaticClass(), nullptr, TEXT("/Script/AIModule.CrowdManager"));
|
|
CrowdManagerClass = Class ? Class : UCrowdManagerBase::StaticClass();
|
|
|
|
// active tiles
|
|
NextInvokersUpdateTime = 0.f;
|
|
ActiveTilesUpdateInterval = 1.f;
|
|
bGenerateNavigationOnlyAroundNavigationInvokers = false;
|
|
DataGatheringMode = ENavDataGatheringModeConfig::Instant;
|
|
bCanAccumulateDirtyAreas = true;
|
|
bShouldDiscardSubLevelNavData = true;
|
|
#if !UE_BUILD_SHIPPING
|
|
bDirtyAreasReportedWhileAccumulationLocked = false;
|
|
#endif // !UE_BUILD_SHIPPING
|
|
|
|
if (HasAnyFlags(RF_ClassDefaultObject) == false)
|
|
{
|
|
// reserve some arbitrary size
|
|
AsyncPathFindingQueries.Reserve( INITIAL_ASYNC_QUERIES_SIZE );
|
|
NavDataRegistrationQueue.Reserve( REGISTRATION_QUEUE_SIZE );
|
|
|
|
FWorldDelegates::LevelAddedToWorld.AddUObject(this, &UNavigationSystemV1::OnLevelAddedToWorld);
|
|
FWorldDelegates::LevelRemovedFromWorld.AddUObject(this, &UNavigationSystemV1::OnLevelRemovedFromWorld);
|
|
#if !UE_BUILD_SHIPPING
|
|
FCoreDelegates::OnGetOnScreenMessages.AddUObject(this, &UNavigationSystemV1::GetOnScreenMessages);
|
|
#endif // !UE_BUILD_SHIPPING
|
|
}
|
|
else if (GetClass() == UNavigationSystemV1::StaticClass())
|
|
{
|
|
SetDefaultWalkableArea(UNavArea_Default::StaticClass());
|
|
SetDefaultObstacleArea(UNavArea_Obstacle::StaticClass());
|
|
|
|
const FTransform RecastToUnrealTransfrom(Recast2UnrealMatrix());
|
|
SetCoordTransformFrom(ENavigationCoordSystem::Recast, RecastToUnrealTransfrom);
|
|
}
|
|
|
|
#if WITH_EDITOR
|
|
if (GIsEditor && HasAnyFlags(RF_ClassDefaultObject) == false)
|
|
{
|
|
FEditorDelegates::EditorModeEnter.AddUObject(this, &UNavigationSystemV1::OnEditorModeChanged, true);
|
|
FEditorDelegates::EditorModeExit.AddUObject(this, &UNavigationSystemV1::OnEditorModeChanged, false);
|
|
}
|
|
#endif // WITH_EDITOR
|
|
}
|
|
|
|
UNavigationSystemV1::~UNavigationSystemV1()
|
|
{
|
|
CleanUp(FNavigationSystem::ECleanupMode::CleanupUnsafe);
|
|
|
|
#if WITH_EDITOR
|
|
if (GIsEditor)
|
|
{
|
|
FEditorDelegates::EditorModeEnter.RemoveAll(this);
|
|
FEditorDelegates::EditorModeExit.RemoveAll(this);
|
|
}
|
|
#endif // WITH_EDITOR
|
|
|
|
#if !UE_BUILD_SHIPPING
|
|
FCoreDelegates::OnGetOnScreenMessages.RemoveAll(this);
|
|
#endif // !UE_BUILD_SHIPPING
|
|
}
|
|
|
|
void UNavigationSystemV1::ConfigureAsStatic()
|
|
{
|
|
bStaticRuntimeNavigation = true;
|
|
SetWantsComponentChangeNotifies(false);
|
|
}
|
|
|
|
void UNavigationSystemV1::SetUpdateNavOctreeOnComponentChange(bool bNewUpdateOnComponentChange)
|
|
{
|
|
bUpdateNavOctreeOnComponentChange = bNewUpdateOnComponentChange;
|
|
}
|
|
|
|
void UNavigationSystemV1::DoInitialSetup()
|
|
{
|
|
if (bInitialSetupHasBeenPerformed)
|
|
{
|
|
return;
|
|
}
|
|
|
|
UpdateAbstractNavData();
|
|
CreateCrowdManager();
|
|
|
|
bInitialSetupHasBeenPerformed = true;
|
|
}
|
|
|
|
void UNavigationSystemV1::UpdateAbstractNavData()
|
|
{
|
|
if (AbstractNavData != nullptr && !AbstractNavData->IsPendingKill())
|
|
{
|
|
return;
|
|
}
|
|
|
|
// spawn abstract nav data separately
|
|
// it's responsible for direct paths and shouldn't be picked for any agent type as default one
|
|
UWorld* NavWorld = GetWorld();
|
|
for (TActorIterator<AAbstractNavData> It(NavWorld); It; ++It)
|
|
{
|
|
AAbstractNavData* Nav = (*It);
|
|
if (Nav && !Nav->IsPendingKill())
|
|
{
|
|
AbstractNavData = Nav;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (AbstractNavData == NULL)
|
|
{
|
|
FNavDataConfig DummyConfig;
|
|
DummyConfig.NavigationDataClass = AAbstractNavData::StaticClass();
|
|
AbstractNavData = CreateNavigationDataInstance(DummyConfig);
|
|
if (AbstractNavData)
|
|
{
|
|
AbstractNavData->SetFlags(RF_Transient);
|
|
}
|
|
}
|
|
}
|
|
|
|
void UNavigationSystemV1::SetSupportedAgentsNavigationClass(int32 AgentIndex, TSubclassOf<ANavigationData> NavigationDataClass)
|
|
{
|
|
check(SupportedAgents.IsValidIndex(AgentIndex));
|
|
SupportedAgents[AgentIndex].NavigationDataClass = NavigationDataClass;
|
|
|
|
// keep preferred navigation data class in sync with actual class
|
|
// this will be passed to navigation data actor and will be required
|
|
// for comparisons done in DoesSupportAgent calls
|
|
//
|
|
// "Any" navigation data preference is valid only for instanced agents
|
|
SupportedAgents[AgentIndex].SetPreferredNavData(NavigationDataClass);
|
|
|
|
if (NavigationDataClass != nullptr)
|
|
{
|
|
SupportedAgents[AgentIndex].NavigationDataClassName = FSoftClassPath::GetOrCreateIDForClass(NavigationDataClass);
|
|
}
|
|
else
|
|
{
|
|
SupportedAgents[AgentIndex].NavigationDataClassName.Reset();
|
|
}
|
|
|
|
#if WITH_EDITOR
|
|
if (GIsEditor)
|
|
{
|
|
if (HasAnyFlags(RF_ClassDefaultObject) == false)
|
|
{
|
|
// set it at CDO to properly show up in project settings
|
|
// @hack the reason for doing it this way is that engine doesn't handle default TSubclassOf properties
|
|
// set to game-specific classes;
|
|
UNavigationSystemV1* NavigationSystemCDO = GetMutableDefault<UNavigationSystemV1>(GetClass());
|
|
NavigationSystemCDO->SetSupportedAgentsNavigationClass(AgentIndex, NavigationDataClass);
|
|
}
|
|
}
|
|
#endif // WITH_EDITOR
|
|
}
|
|
|
|
void UNavigationSystemV1::PostInitProperties()
|
|
{
|
|
Super::PostInitProperties();
|
|
|
|
if (HasAnyFlags(RF_ClassDefaultObject) == false)
|
|
{
|
|
// Populate our NavAreaClasses list with all known nav area classes.
|
|
// If more are loaded after this they will be registered as they come
|
|
TArray<UClass*> CurrentNavAreaClasses;
|
|
GetDerivedClasses(UNavArea::StaticClass(), CurrentNavAreaClasses);
|
|
for (UClass* NavAreaClass : CurrentNavAreaClasses)
|
|
{
|
|
RegisterNavAreaClass(NavAreaClass);
|
|
}
|
|
|
|
// make sure there's at least one supported navigation agent size
|
|
if (SupportedAgents.Num() == 0)
|
|
{
|
|
SupportedAgents.Add(FNavDataConfig(FNavigationSystem::FallbackAgentRadius, FNavigationSystem::FallbackAgentHeight));
|
|
}
|
|
else
|
|
{
|
|
for (int32 AgentIndex = 0; AgentIndex < SupportedAgents.Num(); ++AgentIndex)
|
|
{
|
|
FNavDataConfig& SupportedAgentConfig = SupportedAgents[AgentIndex];
|
|
// a piece of legacy maintanance
|
|
if (SupportedAgentConfig.NavigationDataClass != nullptr && SupportedAgentConfig.NavigationDataClassName.IsValid() == false)
|
|
{
|
|
// fill NavigationDataClassName
|
|
SupportedAgentConfig.NavigationDataClassName = FSoftClassPath(SupportedAgentConfig.NavigationDataClass);
|
|
}
|
|
else
|
|
{
|
|
TSubclassOf<ANavigationData> NavigationDataClass = SupportedAgentConfig.NavigationDataClassName.IsValid()
|
|
? LoadClass<ANavigationData>(NULL, *SupportedAgentConfig.NavigationDataClassName.ToString(), NULL, LOAD_None, NULL)
|
|
: nullptr;
|
|
|
|
SetSupportedAgentsNavigationClass(AgentIndex, NavigationDataClass);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (bInitialBuildingLocked)
|
|
{
|
|
InitialNavBuildingLockFlags |= ENavigationBuildLock::InitialLock;
|
|
}
|
|
|
|
uint8 UseLockFlags = InitialNavBuildingLockFlags;
|
|
|
|
AddNavigationBuildLock(UseLockFlags);
|
|
|
|
// register for any actor move change
|
|
#if WITH_EDITOR
|
|
if ( GIsEditor )
|
|
{
|
|
GEngine->OnActorMoved().AddUObject(this, &UNavigationSystemV1::OnActorMoved);
|
|
}
|
|
#endif
|
|
FCoreUObjectDelegates::PostLoadMapWithWorld.AddUObject(this, &UNavigationSystemV1::OnPostLoadMap);
|
|
UNavigationSystemV1::NavigationDirtyEvent.AddUObject(this, &UNavigationSystemV1::OnNavigationDirtied);
|
|
|
|
#if WITH_HOT_RELOAD
|
|
IHotReloadInterface& HotReloadSupport = FModuleManager::LoadModuleChecked<IHotReloadInterface>("HotReload");
|
|
HotReloadDelegateHandle = HotReloadSupport.OnHotReload().AddUObject(this, &UNavigationSystemV1::OnHotReload);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
bool UNavigationSystemV1::ConditionalPopulateNavOctree()
|
|
{
|
|
// Discard all navigation updates caused by octree construction
|
|
TGuardValue<TArray<FNavigationDirtyArea>> DirtyGuard(DirtyAreas, TArray<FNavigationDirtyArea>());
|
|
|
|
// We are going to fully re-populate NavOctree so all pending update request are outdated
|
|
PendingOctreeUpdates.Empty(32);
|
|
|
|
// Discard current octree
|
|
DestroyNavOctree();
|
|
|
|
// See if any of registered navigation data need navoctree
|
|
bSupportRebuilding = RequiresNavOctree();
|
|
|
|
if (bSupportRebuilding)
|
|
{
|
|
NavOctree = MakeShareable(new FNavigationOctree(FVector(0,0,0), 64000));
|
|
NavOctree->SetDataGatheringMode(DataGatheringMode);
|
|
|
|
const ERuntimeGenerationType RuntimeGenerationType = GetRuntimeGenerationType();
|
|
const bool bStoreNavGeometry = (RuntimeGenerationType == ERuntimeGenerationType::Dynamic);
|
|
NavOctree->SetNavigableGeometryStoringMode(bStoreNavGeometry ? FNavigationOctree::StoreNavGeometry : FNavigationOctree::SkipNavGeometry);
|
|
if (bStoreNavGeometry)
|
|
{
|
|
#if WITH_RECAST
|
|
NavOctree->ComponentExportDelegate = FNavigationOctree::FNavigableGeometryComponentExportDelegate::CreateStatic(&FRecastNavMeshGenerator::ExportComponentGeometry);
|
|
#endif // WITH_RECAST
|
|
}
|
|
|
|
if (!IsNavigationOctreeLocked())
|
|
{
|
|
UWorld* World = GetWorld();
|
|
check(World);
|
|
|
|
// now process all actors on all levels
|
|
for (int32 LevelIndex = 0; LevelIndex < World->GetNumLevels(); ++LevelIndex)
|
|
{
|
|
ULevel* Level = World->GetLevel(LevelIndex);
|
|
AddLevelCollisionToOctree(Level);
|
|
|
|
for (int32 ActorIndex = 0; ActorIndex < Level->Actors.Num(); ActorIndex++)
|
|
{
|
|
AActor* Actor = Level->Actors[ActorIndex];
|
|
|
|
const bool bLegalActor = Actor && !Actor->IsPendingKill();
|
|
if (bLegalActor)
|
|
{
|
|
UpdateActorAndComponentsInNavOctree(*Actor);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Add all found elements to octree, this will not add new dirty areas to navigation
|
|
if (PendingOctreeUpdates.Num())
|
|
{
|
|
for (TSet<FNavigationDirtyElement>::TIterator It(PendingOctreeUpdates); It; ++It)
|
|
{
|
|
AddElementToNavOctree(*It);
|
|
}
|
|
PendingOctreeUpdates.Empty(32);
|
|
}
|
|
|
|
return bSupportRebuilding;
|
|
}
|
|
|
|
#if WITH_EDITOR
|
|
void UNavigationSystemV1::PostEditChangeChainProperty(FPropertyChangedChainEvent& PropertyChangedEvent)
|
|
{
|
|
static const FName NAME_NavigationDataClass = GET_MEMBER_NAME_CHECKED(FNavDataConfig, NavigationDataClass);
|
|
static const FName NAME_SupportedAgents = GET_MEMBER_NAME_CHECKED(UNavigationSystemV1, SupportedAgents);
|
|
static const FName NAME_AllowClientSideNavigation = GET_MEMBER_NAME_CHECKED(UNavigationSystemV1, bAllowClientSideNavigation);
|
|
|
|
Super::PostEditChangeChainProperty(PropertyChangedEvent);
|
|
|
|
if (PropertyChangedEvent.Property)
|
|
{
|
|
FName PropName = PropertyChangedEvent.Property->GetFName();
|
|
if (PropName == NAME_NavigationDataClass)
|
|
{
|
|
int32 SupportedAgentIndex = PropertyChangedEvent.GetArrayIndex(NAME_SupportedAgents.ToString());
|
|
if (SupportedAgents.IsValidIndex(SupportedAgentIndex))
|
|
{
|
|
// reflect the change to SupportedAgent's
|
|
TSubclassOf<ANavigationData> NavClass = SupportedAgents[SupportedAgentIndex].NavigationDataClass.Get();
|
|
SetSupportedAgentsNavigationClass(SupportedAgentIndex, NavClass);
|
|
SaveConfig();
|
|
}
|
|
}
|
|
else if (PropName == NAME_AllowClientSideNavigation && HasAnyFlags(RF_ClassDefaultObject))
|
|
{
|
|
for (FObjectIterator It(UNavigationSystemModuleConfig::StaticClass()); It; ++It)
|
|
{
|
|
((UNavigationSystemModuleConfig*)*It)->UpdateWithNavSysCDO(*this);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void UNavigationSystemV1::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
|
|
{
|
|
static const FName NAME_EnableActiveTiles = GET_MEMBER_NAME_CHECKED(UNavigationSystemV1, bGenerateNavigationOnlyAroundNavigationInvokers);
|
|
|
|
Super::PostEditChangeProperty(PropertyChangedEvent);
|
|
|
|
if (PropertyChangedEvent.Property)
|
|
{
|
|
FName PropName = PropertyChangedEvent.Property->GetFName();
|
|
if (PropName == NAME_EnableActiveTiles)
|
|
{
|
|
if (NavOctree.IsValid())
|
|
{
|
|
NavOctree->SetDataGatheringMode(DataGatheringMode);
|
|
}
|
|
|
|
for (auto NavData : NavDataSet)
|
|
{
|
|
if (NavData)
|
|
{
|
|
NavData->RestrictBuildingToActiveTiles(bGenerateNavigationOnlyAroundNavigationInvokers);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif // WITH_EDITOR
|
|
|
|
void UNavigationSystemV1::OnInitializeActors()
|
|
{
|
|
|
|
}
|
|
|
|
void UNavigationSystemV1::OnWorldInitDone(FNavigationSystemRunMode Mode)
|
|
{
|
|
static const bool bSkipRebuildInEditor = true;
|
|
OperationMode = Mode;
|
|
DoInitialSetup();
|
|
|
|
UWorld* World = GetWorld();
|
|
|
|
if (IsThereAnywhereToBuildNavigation() == false
|
|
// Simulation mode is a special case - better not do it in this case
|
|
&& OperationMode != FNavigationSystemRunMode::SimulationMode)
|
|
{
|
|
// remove all navigation data instances
|
|
for (TActorIterator<ANavigationData> It(World); It; ++It)
|
|
{
|
|
ANavigationData* Nav = (*It);
|
|
if (Nav != NULL && Nav->IsPendingKill() == false && Nav != GetAbstractNavData())
|
|
{
|
|
UnregisterNavData(Nav);
|
|
Nav->CleanUpAndMarkPendingKill();
|
|
bNavDataRemovedDueToMissingNavBounds = true;
|
|
}
|
|
}
|
|
|
|
if (OperationMode == FNavigationSystemRunMode::EditorMode)
|
|
{
|
|
RemoveNavigationBuildLock(InitialNavBuildingLockFlags, bSkipRebuildInEditor);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Discard all bounds updates that was submitted during world initialization,
|
|
// to avoid navigation rebuild right after map is loaded
|
|
PendingNavBoundsUpdates.Empty();
|
|
|
|
// gather navigable bounds
|
|
GatherNavigationBounds();
|
|
|
|
// gather all navigation data instances and register all not-yet-registered
|
|
// (since it's quite possible navigation system was not ready by the time
|
|
// those instances were serialized-in or spawned)
|
|
RegisterNavigationDataInstances();
|
|
|
|
if (bAutoCreateNavigationData == true)
|
|
{
|
|
SpawnMissingNavigationData();
|
|
// in case anything spawned has registered
|
|
ProcessRegistrationCandidates();
|
|
}
|
|
else
|
|
{
|
|
const bool bIsBuildLocked = IsNavigationBuildingLocked();
|
|
if (GetDefaultNavDataInstance(FNavigationSystem::DontCreate) != NULL)
|
|
{
|
|
// trigger navmesh update
|
|
for (TActorIterator<ANavigationData> It(World); It; ++It)
|
|
{
|
|
ANavigationData* NavData = (*It);
|
|
if (NavData != NULL)
|
|
{
|
|
ERegistrationResult Result = RegisterNavData(NavData);
|
|
|
|
if (Result == RegistrationSuccessful)
|
|
{
|
|
if (!bIsBuildLocked && bNavigationAutoUpdateEnabled)
|
|
{
|
|
NavData->RebuildAll();
|
|
}
|
|
}
|
|
else if (Result != RegistrationFailed_DataPendingKill
|
|
&& Result != RegistrationFailed_AgentNotValid
|
|
)
|
|
{
|
|
NavData->CleanUpAndMarkPendingKill();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (OperationMode == FNavigationSystemRunMode::EditorMode)
|
|
{
|
|
// don't lock navigation building in editor
|
|
RemoveNavigationBuildLock(InitialNavBuildingLockFlags, bSkipRebuildInEditor);
|
|
}
|
|
|
|
// See if any of registered navigation data needs NavOctree
|
|
ConditionalPopulateNavOctree();
|
|
|
|
// All navigation actors are registered
|
|
// Add NavMesh parts from all sub-levels that were streamed in prior NavMesh registration
|
|
const auto& Levels = World->GetLevels();
|
|
for (ULevel* Level : Levels)
|
|
{
|
|
if (!Level->IsPersistentLevel() && Level->bIsVisible)
|
|
{
|
|
for (ANavigationData* NavData : NavDataSet)
|
|
{
|
|
if (NavData)
|
|
{
|
|
NavData->OnStreamingLevelAdded(Level, World);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Mode == FNavigationSystemRunMode::EditorMode)
|
|
{
|
|
#if WITH_EDITOR
|
|
// make sure this static get applied to this instance
|
|
bNavigationAutoUpdateEnabled = !bNavigationAutoUpdateEnabled;
|
|
SetNavigationAutoUpdateEnabled(!bNavigationAutoUpdateEnabled, this);
|
|
#endif
|
|
|
|
// update navigation invokers
|
|
if (bGenerateNavigationOnlyAroundNavigationInvokers)
|
|
{
|
|
for (TObjectIterator<UNavigationInvokerComponent> It; It; ++It)
|
|
{
|
|
if (World == It->GetWorld())
|
|
{
|
|
It->RegisterWithNavigationSystem(*this);
|
|
}
|
|
}
|
|
}
|
|
|
|
// update navdata after loading world
|
|
if (bNavigationAutoUpdateEnabled)
|
|
{
|
|
const bool bIsLoadTime = true;
|
|
RebuildAll(bIsLoadTime);
|
|
}
|
|
}
|
|
|
|
if (!bCanAccumulateDirtyAreas)
|
|
{
|
|
DirtyAreas.Empty();
|
|
}
|
|
|
|
bWorldInitDone = true;
|
|
OnNavigationInitDone.Broadcast();
|
|
}
|
|
|
|
void UNavigationSystemV1::RegisterNavigationDataInstances()
|
|
{
|
|
UWorld* World = GetWorld();
|
|
|
|
bool bProcessRegistration = false;
|
|
for (TActorIterator<ANavigationData> It(World); It; ++It)
|
|
{
|
|
ANavigationData* Nav = (*It);
|
|
if (Nav != NULL && Nav->IsPendingKill() == false && Nav->IsRegistered() == false)
|
|
{
|
|
RequestRegistration(Nav, false);
|
|
bProcessRegistration = true;
|
|
}
|
|
}
|
|
if (bProcessRegistration == true)
|
|
{
|
|
ProcessRegistrationCandidates();
|
|
}
|
|
}
|
|
|
|
void UNavigationSystemV1::CreateCrowdManager()
|
|
{
|
|
if (CrowdManagerClass)
|
|
{
|
|
SetCrowdManager(NewObject<UCrowdManagerBase>(this, CrowdManagerClass));
|
|
}
|
|
}
|
|
|
|
void UNavigationSystemV1::SetCrowdManager(UCrowdManagerBase* NewCrowdManager)
|
|
{
|
|
if (NewCrowdManager == CrowdManager.Get())
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (CrowdManager.IsValid())
|
|
{
|
|
CrowdManager->RemoveFromRoot();
|
|
}
|
|
CrowdManager = NewCrowdManager;
|
|
if (NewCrowdManager != NULL)
|
|
{
|
|
CrowdManager->AddToRoot();
|
|
}
|
|
}
|
|
|
|
void UNavigationSystemV1::Tick(float DeltaSeconds)
|
|
{
|
|
SET_DWORD_STAT(STAT_Navigation_ObservedPathsCount, 0);
|
|
|
|
UWorld* World = GetWorld();
|
|
|
|
if (World == nullptr
|
|
|| (bTickWhilePaused == false && World->IsPaused())
|
|
#if WITH_EDITOR
|
|
|| (bIsPIEActive && !World->IsGameWorld())
|
|
#endif // WITH_EDITOR
|
|
)
|
|
{
|
|
return;
|
|
}
|
|
|
|
const bool bIsGame = World->IsGameWorld();
|
|
|
|
if (PendingCustomLinkRegistration.Num())
|
|
{
|
|
ProcessCustomLinkPendingRegistration();
|
|
}
|
|
|
|
if (PendingNavBoundsUpdates.Num() > 0)
|
|
{
|
|
PerformNavigationBoundsUpdate(PendingNavBoundsUpdates);
|
|
PendingNavBoundsUpdates.Reset();
|
|
}
|
|
|
|
if (PendingOctreeUpdates.Num() > 0)
|
|
{
|
|
SCOPE_CYCLE_COUNTER(STAT_Navigation_AddingActorsToNavOctree);
|
|
|
|
SCOPE_CYCLE_COUNTER(STAT_Navigation_BuildTime)
|
|
STAT(double ThisTime = 0);
|
|
{
|
|
SCOPE_SECONDS_COUNTER(ThisTime);
|
|
for (TSet<FNavigationDirtyElement>::TIterator It(PendingOctreeUpdates); It; ++It)
|
|
{
|
|
AddElementToNavOctree(*It);
|
|
}
|
|
PendingOctreeUpdates.Empty(32);
|
|
}
|
|
INC_FLOAT_STAT_BY(STAT_Navigation_CumulativeBuildTime,(float)ThisTime*1000);
|
|
}
|
|
|
|
if (bGenerateNavigationOnlyAroundNavigationInvokers)
|
|
{
|
|
UpdateInvokers();
|
|
}
|
|
|
|
{
|
|
SCOPE_CYCLE_COUNTER(STAT_Navigation_TickMarkDirty);
|
|
|
|
DirtyAreasUpdateTime += DeltaSeconds;
|
|
const float DirtyAreasUpdateDeltaTime = 1.0f / DirtyAreasUpdateFreq;
|
|
const bool bCanRebuildNow = (DirtyAreasUpdateTime >= DirtyAreasUpdateDeltaTime) || !bIsGame;
|
|
const bool bIsLocked = IsNavigationBuildingLocked();
|
|
|
|
if (DirtyAreas.Num() > 0 && bCanRebuildNow && !bIsLocked)
|
|
{
|
|
for (int32 NavDataIndex = 0; NavDataIndex < NavDataSet.Num(); ++NavDataIndex)
|
|
{
|
|
ANavigationData* NavData = NavDataSet[NavDataIndex];
|
|
if (NavData)
|
|
{
|
|
NavData->RebuildDirtyAreas(DirtyAreas);
|
|
}
|
|
}
|
|
|
|
DirtyAreasUpdateTime = 0;
|
|
DirtyAreas.Reset();
|
|
}
|
|
}
|
|
|
|
// Tick navigation mesh async builders
|
|
if (!bAsyncBuildPaused)
|
|
{
|
|
SCOPE_CYCLE_COUNTER(STAT_Navigation_TickAsyncBuild);
|
|
CSV_SCOPED_TIMING_STAT(NAV_SYSTEM, Navigation_TickAsyncBuild);
|
|
|
|
for (ANavigationData* NavData : NavDataSet)
|
|
{
|
|
if (NavData)
|
|
{
|
|
NavData->TickAsyncBuild(DeltaSeconds);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (AsyncPathFindingQueries.Num() > 0)
|
|
{
|
|
SCOPE_CYCLE_COUNTER(STAT_Navigation_TickAsyncPathfinding);
|
|
TriggerAsyncQueries(AsyncPathFindingQueries);
|
|
AsyncPathFindingQueries.Reset();
|
|
}
|
|
|
|
if (CrowdManager.IsValid())
|
|
{
|
|
CrowdManager->Tick(DeltaSeconds);
|
|
}
|
|
}
|
|
|
|
void UNavigationSystemV1::AddReferencedObjects(UObject* InThis, FReferenceCollector& Collector)
|
|
{
|
|
UNavigationSystemV1* This = CastChecked<UNavigationSystemV1>(InThis);
|
|
UCrowdManagerBase* CrowdManager = This->GetCrowdManager();
|
|
Collector.AddReferencedObject(CrowdManager, InThis);
|
|
|
|
// don't reference NavAreaClasses in editor (unless PIE is active)
|
|
if (This->OperationMode != FNavigationSystemRunMode::EditorMode)
|
|
{
|
|
Collector.AddReferencedObjects(This->NavAreaClasses, InThis);
|
|
}
|
|
}
|
|
|
|
#if WITH_EDITOR
|
|
void UNavigationSystemV1::SetNavigationAutoUpdateEnabled(bool bNewEnable, UNavigationSystemBase* InNavigationSystemBase)
|
|
{
|
|
if (bNewEnable != bNavigationAutoUpdateEnabled)
|
|
{
|
|
bNavigationAutoUpdateEnabled = bNewEnable;
|
|
|
|
UNavigationSystemV1* NavSystem = Cast<UNavigationSystemV1>(InNavigationSystemBase);
|
|
if (NavSystem)
|
|
{
|
|
NavSystem->bCanAccumulateDirtyAreas = bNavigationAutoUpdateEnabled
|
|
|| (NavSystem->OperationMode != FNavigationSystemRunMode::EditorMode && NavSystem->OperationMode != FNavigationSystemRunMode::InvalidMode);
|
|
|
|
if (bNavigationAutoUpdateEnabled)
|
|
{
|
|
const bool bSkipRebuildsInEditor = false;
|
|
NavSystem->RemoveNavigationBuildLock(ENavigationBuildLock::NoUpdateInEditor, bSkipRebuildsInEditor);
|
|
}
|
|
else
|
|
{
|
|
#if !UE_BUILD_SHIPPING
|
|
NavSystem->bDirtyAreasReportedWhileAccumulationLocked = false;
|
|
#endif // !UE_BUILD_SHIPPING
|
|
NavSystem->AddNavigationBuildLock(ENavigationBuildLock::NoUpdateInEditor);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif // WITH_EDITOR
|
|
|
|
//----------------------------------------------------------------------//
|
|
// Public querying interface
|
|
//----------------------------------------------------------------------//
|
|
FPathFindingResult UNavigationSystemV1::FindPathSync(const FNavAgentProperties& AgentProperties, FPathFindingQuery Query, EPathFindingMode::Type Mode)
|
|
{
|
|
SCOPE_CYCLE_COUNTER(STAT_Navigation_PathfindingSync);
|
|
|
|
if (Query.NavData.IsValid() == false)
|
|
{
|
|
Query.NavData = GetNavDataForProps(AgentProperties);
|
|
}
|
|
|
|
FPathFindingResult Result(ENavigationQueryResult::Error);
|
|
if (Query.NavData.IsValid())
|
|
{
|
|
if (Mode == EPathFindingMode::Hierarchical)
|
|
{
|
|
Result = Query.NavData->FindHierarchicalPath(AgentProperties, Query);
|
|
}
|
|
else
|
|
{
|
|
Result = Query.NavData->FindPath(AgentProperties, Query);
|
|
}
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
FPathFindingResult UNavigationSystemV1::FindPathSync(FPathFindingQuery Query, EPathFindingMode::Type Mode)
|
|
{
|
|
SCOPE_CYCLE_COUNTER(STAT_Navigation_PathfindingSync);
|
|
|
|
if (Query.NavData.IsValid() == false)
|
|
{
|
|
Query.NavData = GetDefaultNavDataInstance(FNavigationSystem::DontCreate);
|
|
}
|
|
|
|
FPathFindingResult Result(ENavigationQueryResult::Error);
|
|
if (Query.NavData.IsValid())
|
|
{
|
|
if (Mode == EPathFindingMode::Regular)
|
|
{
|
|
Result = Query.NavData->FindPath(Query.NavAgentProperties, Query);
|
|
}
|
|
else // EPathFindingMode::Hierarchical
|
|
{
|
|
Result = Query.NavData->FindHierarchicalPath(Query.NavAgentProperties, Query);
|
|
}
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
bool UNavigationSystemV1::TestPathSync(FPathFindingQuery Query, EPathFindingMode::Type Mode, int32* NumVisitedNodes) const
|
|
{
|
|
SCOPE_CYCLE_COUNTER(STAT_Navigation_PathfindingSync);
|
|
|
|
if (Query.NavData.IsValid() == false)
|
|
{
|
|
Query.NavData = GetDefaultNavDataInstance();
|
|
}
|
|
|
|
bool bExists = false;
|
|
if (Query.NavData.IsValid())
|
|
{
|
|
if (Mode == EPathFindingMode::Hierarchical)
|
|
{
|
|
bExists = Query.NavData->TestHierarchicalPath(Query.NavAgentProperties, Query, NumVisitedNodes);
|
|
}
|
|
else
|
|
{
|
|
bExists = Query.NavData->TestPath(Query.NavAgentProperties, Query, NumVisitedNodes);
|
|
}
|
|
}
|
|
|
|
return bExists;
|
|
}
|
|
|
|
void UNavigationSystemV1::AddAsyncQuery(const FAsyncPathFindingQuery& Query)
|
|
{
|
|
check(IsInGameThread());
|
|
AsyncPathFindingQueries.Add(Query);
|
|
}
|
|
|
|
uint32 UNavigationSystemV1::FindPathAsync(const FNavAgentProperties& AgentProperties, FPathFindingQuery Query, const FNavPathQueryDelegate& ResultDelegate, EPathFindingMode::Type Mode)
|
|
{
|
|
SCOPE_CYCLE_COUNTER(STAT_Navigation_RequestingAsyncPathfinding);
|
|
|
|
if (Query.NavData.IsValid() == false)
|
|
{
|
|
Query.NavData = GetNavDataForProps(AgentProperties);
|
|
}
|
|
|
|
if (Query.NavData.IsValid())
|
|
{
|
|
FAsyncPathFindingQuery AsyncQuery(Query, ResultDelegate, Mode);
|
|
|
|
if (AsyncQuery.QueryID != INVALID_NAVQUERYID)
|
|
{
|
|
AddAsyncQuery(AsyncQuery);
|
|
}
|
|
|
|
return AsyncQuery.QueryID;
|
|
}
|
|
|
|
return INVALID_NAVQUERYID;
|
|
}
|
|
|
|
void UNavigationSystemV1::AbortAsyncFindPathRequest(uint32 AsynPathQueryID)
|
|
{
|
|
check(IsInGameThread());
|
|
FAsyncPathFindingQuery* Query = AsyncPathFindingQueries.GetData();
|
|
for (int32 Index = 0; Index < AsyncPathFindingQueries.Num(); ++Index, ++Query)
|
|
{
|
|
if (Query->QueryID == AsynPathQueryID)
|
|
{
|
|
AsyncPathFindingQueries.RemoveAtSwap(Index);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
FAutoConsoleTaskPriority CPrio_TriggerAsyncQueries(
|
|
TEXT("TaskGraph.TaskPriorities.NavTriggerAsyncQueries"),
|
|
TEXT("Task and thread priority for UNavigationSystemV1::PerformAsyncQueries."),
|
|
ENamedThreads::BackgroundThreadPriority, // if we have background priority task threads, then use them...
|
|
ENamedThreads::NormalTaskPriority, // .. at normal task priority
|
|
ENamedThreads::NormalTaskPriority // if we don't have background threads, then use normal priority threads at normal task priority instead
|
|
);
|
|
|
|
|
|
void UNavigationSystemV1::TriggerAsyncQueries(TArray<FAsyncPathFindingQuery>& PathFindingQueries)
|
|
{
|
|
DECLARE_CYCLE_STAT(TEXT("FSimpleDelegateGraphTask.NavigationSystem batched async queries"),
|
|
STAT_FSimpleDelegateGraphTask_NavigationSystemBatchedAsyncQueries,
|
|
STATGROUP_TaskGraphTasks);
|
|
|
|
FSimpleDelegateGraphTask::CreateAndDispatchWhenReady(
|
|
FSimpleDelegateGraphTask::FDelegate::CreateUObject(this, &UNavigationSystemV1::PerformAsyncQueries, PathFindingQueries),
|
|
GET_STATID(STAT_FSimpleDelegateGraphTask_NavigationSystemBatchedAsyncQueries), nullptr, CPrio_TriggerAsyncQueries.Get());
|
|
}
|
|
|
|
static void AsyncQueryDone(FAsyncPathFindingQuery Query)
|
|
{
|
|
Query.OnDoneDelegate.ExecuteIfBound(Query.QueryID, Query.Result.Result, Query.Result.Path);
|
|
}
|
|
|
|
void UNavigationSystemV1::PerformAsyncQueries(TArray<FAsyncPathFindingQuery> PathFindingQueries)
|
|
{
|
|
SCOPE_CYCLE_COUNTER(STAT_Navigation_PathfindingAsync);
|
|
|
|
if (PathFindingQueries.Num() == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
for (FAsyncPathFindingQuery& Query : PathFindingQueries)
|
|
{
|
|
// @todo this is not necessarily the safest way to use UObjects outside of main thread.
|
|
// think about something else.
|
|
const ANavigationData* NavData = Query.NavData.IsValid() ? Query.NavData.Get() : GetDefaultNavDataInstance(FNavigationSystem::DontCreate);
|
|
|
|
// perform query
|
|
if (NavData)
|
|
{
|
|
if (Query.Mode == EPathFindingMode::Hierarchical)
|
|
{
|
|
Query.Result = NavData->FindHierarchicalPath(Query.NavAgentProperties, Query);
|
|
}
|
|
else
|
|
{
|
|
Query.Result = NavData->FindPath(Query.NavAgentProperties, Query);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Query.Result = ENavigationQueryResult::Error;
|
|
}
|
|
|
|
// @todo make it return more informative results (bResult == false)
|
|
// trigger calling delegate on main thread - otherwise it may depend too much on stuff being thread safe
|
|
DECLARE_CYCLE_STAT(TEXT("FSimpleDelegateGraphTask.Async nav query finished"),
|
|
STAT_FSimpleDelegateGraphTask_AsyncNavQueryFinished,
|
|
STATGROUP_TaskGraphTasks);
|
|
|
|
FSimpleDelegateGraphTask::CreateAndDispatchWhenReady(
|
|
FSimpleDelegateGraphTask::FDelegate::CreateStatic(AsyncQueryDone, Query),
|
|
GET_STATID(STAT_FSimpleDelegateGraphTask_AsyncNavQueryFinished), NULL, ENamedThreads::GameThread);
|
|
}
|
|
}
|
|
|
|
bool UNavigationSystemV1::GetRandomPoint(FNavLocation& ResultLocation, ANavigationData* NavData, FSharedConstNavQueryFilter QueryFilter)
|
|
{
|
|
SCOPE_CYCLE_COUNTER(STAT_Navigation_QueriesTimeSync);
|
|
|
|
if (NavData == NULL)
|
|
{
|
|
NavData = MainNavData;
|
|
}
|
|
|
|
if (NavData != NULL)
|
|
{
|
|
ResultLocation = NavData->GetRandomPoint(QueryFilter);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool UNavigationSystemV1::GetRandomReachablePointInRadius(const FVector& Origin, float Radius, FNavLocation& ResultLocation, ANavigationData* NavData, FSharedConstNavQueryFilter QueryFilter) const
|
|
{
|
|
SCOPE_CYCLE_COUNTER(STAT_Navigation_QueriesTimeSync);
|
|
|
|
if (NavData == nullptr)
|
|
{
|
|
NavData = MainNavData;
|
|
}
|
|
|
|
return NavData != nullptr && NavData->GetRandomReachablePointInRadius(Origin, Radius, ResultLocation, QueryFilter);
|
|
}
|
|
|
|
bool UNavigationSystemV1::GetRandomPointInNavigableRadius(const FVector& Origin, float Radius, FNavLocation& ResultLocation, ANavigationData* NavData, FSharedConstNavQueryFilter QueryFilter) const
|
|
{
|
|
SCOPE_CYCLE_COUNTER(STAT_Navigation_QueriesTimeSync);
|
|
|
|
if (NavData == nullptr)
|
|
{
|
|
NavData = MainNavData;
|
|
}
|
|
|
|
return NavData != nullptr && NavData->GetRandomPointInNavigableRadius(Origin, Radius, ResultLocation, QueryFilter);
|
|
}
|
|
|
|
ENavigationQueryResult::Type UNavigationSystemV1::GetPathCost(const FVector& PathStart, const FVector& PathEnd, float& OutPathCost, const ANavigationData* NavData, FSharedConstNavQueryFilter QueryFilter) const
|
|
{
|
|
SCOPE_CYCLE_COUNTER(STAT_Navigation_QueriesTimeSync);
|
|
|
|
if (NavData == NULL)
|
|
{
|
|
NavData = GetDefaultNavDataInstance();
|
|
}
|
|
|
|
return NavData != NULL ? NavData->CalcPathCost(PathStart, PathEnd, OutPathCost, QueryFilter) : ENavigationQueryResult::Error;
|
|
}
|
|
|
|
ENavigationQueryResult::Type UNavigationSystemV1::GetPathLength(const FVector& PathStart, const FVector& PathEnd, float& OutPathLength, const ANavigationData* NavData, FSharedConstNavQueryFilter QueryFilter) const
|
|
{
|
|
SCOPE_CYCLE_COUNTER(STAT_Navigation_QueriesTimeSync);
|
|
|
|
if (NavData == NULL)
|
|
{
|
|
NavData = GetDefaultNavDataInstance();
|
|
}
|
|
|
|
return NavData != NULL ? NavData->CalcPathLength(PathStart, PathEnd, OutPathLength, QueryFilter) : ENavigationQueryResult::Error;
|
|
}
|
|
|
|
ENavigationQueryResult::Type UNavigationSystemV1::GetPathLengthAndCost(const FVector& PathStart, const FVector& PathEnd, float& OutPathLength, float& OutPathCost, const ANavigationData* NavData, FSharedConstNavQueryFilter QueryFilter) const
|
|
{
|
|
SCOPE_CYCLE_COUNTER(STAT_Navigation_QueriesTimeSync);
|
|
|
|
if (NavData == NULL)
|
|
{
|
|
NavData = GetDefaultNavDataInstance();
|
|
}
|
|
|
|
return NavData != NULL ? NavData->CalcPathLengthAndCost(PathStart, PathEnd, OutPathLength, OutPathCost, QueryFilter) : ENavigationQueryResult::Error;
|
|
}
|
|
|
|
bool UNavigationSystemV1::ProjectPointToNavigation(const FVector& Point, FNavLocation& OutLocation, const FVector& Extent, const ANavigationData* NavData, FSharedConstNavQueryFilter QueryFilter) const
|
|
{
|
|
SCOPE_CYCLE_COUNTER(STAT_Navigation_QueriesTimeSync);
|
|
|
|
if (NavData == NULL)
|
|
{
|
|
NavData = GetDefaultNavDataInstance();
|
|
}
|
|
|
|
return NavData != NULL && NavData->ProjectPoint(Point, OutLocation
|
|
, FNavigationSystem::IsValidExtent(Extent) ? Extent : NavData->GetConfig().DefaultQueryExtent
|
|
, QueryFilter);
|
|
}
|
|
|
|
UNavigationPath* UNavigationSystemV1::FindPathToActorSynchronously(UObject* WorldContextObject, const FVector& PathStart, AActor* GoalActor, float TetherDistance, AActor* PathfindingContext, TSubclassOf<UNavigationQueryFilter> FilterClass)
|
|
{
|
|
if (GoalActor == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
INavAgentInterface* NavAgent = Cast<INavAgentInterface>(GoalActor);
|
|
UNavigationPath* GeneratedPath = FindPathToLocationSynchronously(WorldContextObject, PathStart, NavAgent ? NavAgent->GetNavAgentLocation() : GoalActor->GetActorLocation(), PathfindingContext, FilterClass);
|
|
if (GeneratedPath != NULL && GeneratedPath->GetPath().IsValid() == true)
|
|
{
|
|
GeneratedPath->GetPath()->SetGoalActorObservation(*GoalActor, TetherDistance);
|
|
}
|
|
|
|
return GeneratedPath;
|
|
}
|
|
|
|
UNavigationPath* UNavigationSystemV1::FindPathToLocationSynchronously(UObject* WorldContextObject, const FVector& PathStart, const FVector& PathEnd, AActor* PathfindingContext, TSubclassOf<UNavigationQueryFilter> FilterClass)
|
|
{
|
|
UWorld* World = NULL;
|
|
|
|
if (WorldContextObject != NULL)
|
|
{
|
|
World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::LogAndReturnNull);
|
|
}
|
|
if (World == NULL && PathfindingContext != NULL)
|
|
{
|
|
World = GEngine->GetWorldFromContextObject(PathfindingContext, EGetWorldErrorMode::LogAndReturnNull);
|
|
}
|
|
|
|
UNavigationPath* ResultPath = NULL;
|
|
|
|
UNavigationSystemV1* NavSys = FNavigationSystem::GetCurrent<UNavigationSystemV1>(World);
|
|
|
|
if (NavSys != nullptr && NavSys->GetDefaultNavDataInstance() != nullptr)
|
|
{
|
|
ResultPath = NewObject<UNavigationPath>(NavSys);
|
|
bool bValidPathContext = false;
|
|
const ANavigationData* NavigationData = NULL;
|
|
|
|
if (PathfindingContext != NULL)
|
|
{
|
|
INavAgentInterface* NavAgent = Cast<INavAgentInterface>(PathfindingContext);
|
|
|
|
if (NavAgent != NULL)
|
|
{
|
|
const FNavAgentProperties& AgentProps = NavAgent->GetNavAgentPropertiesRef();
|
|
NavigationData = NavSys->GetNavDataForProps(AgentProps);
|
|
bValidPathContext = true;
|
|
}
|
|
else if (Cast<ANavigationData>(PathfindingContext))
|
|
{
|
|
NavigationData = (ANavigationData*)PathfindingContext;
|
|
bValidPathContext = true;
|
|
}
|
|
}
|
|
if (bValidPathContext == false)
|
|
{
|
|
// just use default
|
|
NavigationData = NavSys->GetDefaultNavDataInstance();
|
|
}
|
|
|
|
check(NavigationData);
|
|
|
|
const FPathFindingQuery Query(PathfindingContext, *NavigationData, PathStart, PathEnd, UNavigationQueryFilter::GetQueryFilter(*NavigationData, PathfindingContext, FilterClass));
|
|
const FPathFindingResult Result = NavSys->FindPathSync(Query, EPathFindingMode::Regular);
|
|
if (Result.IsSuccessful())
|
|
{
|
|
ResultPath->SetPath(Result.Path);
|
|
}
|
|
}
|
|
|
|
return ResultPath;
|
|
}
|
|
|
|
bool UNavigationSystemV1::NavigationRaycast(UObject* WorldContextObject, const FVector& RayStart, const FVector& RayEnd, FVector& HitLocation, TSubclassOf<UNavigationQueryFilter> FilterClass, AController* Querier)
|
|
{
|
|
UWorld* World = NULL;
|
|
|
|
if (WorldContextObject != NULL)
|
|
{
|
|
World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::LogAndReturnNull);
|
|
}
|
|
if (World == NULL && Querier != NULL)
|
|
{
|
|
World = GEngine->GetWorldFromContextObject(Querier, EGetWorldErrorMode::LogAndReturnNull);
|
|
}
|
|
|
|
// blocked, i.e. not traversable, by default
|
|
bool bRaycastBlocked = true;
|
|
HitLocation = RayStart;
|
|
|
|
const UNavigationSystemV1* NavSys = FNavigationSystem::GetCurrent<UNavigationSystemV1>(World);
|
|
|
|
if (NavSys)
|
|
{
|
|
// figure out which navigation data to use
|
|
const ANavigationData* NavData = NULL;
|
|
INavAgentInterface* MyNavAgent = Cast<INavAgentInterface>(Querier);
|
|
if (MyNavAgent)
|
|
{
|
|
const FNavAgentProperties& AgentProps = MyNavAgent->GetNavAgentPropertiesRef();
|
|
NavData = NavSys->GetNavDataForProps(AgentProps);
|
|
}
|
|
if (NavData == NULL)
|
|
{
|
|
NavData = NavSys->GetDefaultNavDataInstance();
|
|
}
|
|
|
|
if (NavData != NULL)
|
|
{
|
|
bRaycastBlocked = NavData->Raycast(RayStart, RayEnd, HitLocation, UNavigationQueryFilter::GetQueryFilter(*NavData, Querier, FilterClass));
|
|
}
|
|
}
|
|
|
|
return bRaycastBlocked;
|
|
}
|
|
|
|
void UNavigationSystemV1::GetNavAgentPropertiesArray(TArray<FNavAgentProperties>& OutNavAgentProperties) const
|
|
{
|
|
AgentToNavDataMap.GetKeys(OutNavAgentProperties);
|
|
}
|
|
|
|
ANavigationData* UNavigationSystemV1::GetNavDataForProps(const FNavAgentProperties& AgentProperties)
|
|
{
|
|
const UNavigationSystemV1* ConstThis = AsConst(this);
|
|
return const_cast<ANavigationData*>(ConstThis->GetNavDataForProps(AgentProperties));
|
|
}
|
|
|
|
// @todo could optimize this by having "SupportedAgentIndex" in FNavAgentProperties
|
|
const ANavigationData* UNavigationSystemV1::GetNavDataForProps(const FNavAgentProperties& AgentProperties) const
|
|
{
|
|
if (SupportedAgents.Num() <= 1)
|
|
{
|
|
return MainNavData;
|
|
}
|
|
|
|
const TWeakObjectPtr<ANavigationData>* NavDataForAgent = AgentToNavDataMap.Find(AgentProperties);
|
|
const ANavigationData* NavDataInstance = NavDataForAgent ? NavDataForAgent->Get() : nullptr;
|
|
|
|
if (NavDataInstance == nullptr)
|
|
{
|
|
TArray<FNavAgentProperties> AgentPropertiesList;
|
|
AgentToNavDataMap.GenerateKeyArray(AgentPropertiesList);
|
|
|
|
FNavAgentProperties BestFitNavAgent;
|
|
float BestExcessHeight = -FLT_MAX;
|
|
float BestExcessRadius = -FLT_MAX;
|
|
float ExcessRadius = -FLT_MAX;
|
|
float ExcessHeight = -FLT_MAX;
|
|
const float AgentHeight = bSkipAgentHeightCheckWhenPickingNavData ? 0.f : AgentProperties.AgentHeight;
|
|
|
|
for (TArray<FNavAgentProperties>::TConstIterator It(AgentPropertiesList); It; ++It)
|
|
{
|
|
const FNavAgentProperties& NavIt = *It;
|
|
const bool bNavClassMatch = NavIt.IsNavDataMatching(AgentProperties);
|
|
if (!bNavClassMatch)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
ExcessRadius = NavIt.AgentRadius - AgentProperties.AgentRadius;
|
|
ExcessHeight = bSkipAgentHeightCheckWhenPickingNavData ? 0.f : (NavIt.AgentHeight - AgentHeight);
|
|
|
|
const bool bExcessRadiusIsBetter = ((ExcessRadius == 0) && (BestExcessRadius != 0))
|
|
|| ((ExcessRadius > 0) && (BestExcessRadius < 0))
|
|
|| ((ExcessRadius > 0) && (BestExcessRadius > 0) && (ExcessRadius < BestExcessRadius))
|
|
|| ((ExcessRadius < 0) && (BestExcessRadius < 0) && (ExcessRadius > BestExcessRadius));
|
|
const bool bExcessHeightIsBetter = ((ExcessHeight == 0) && (BestExcessHeight != 0))
|
|
|| ((ExcessHeight > 0) && (BestExcessHeight < 0))
|
|
|| ((ExcessHeight > 0) && (BestExcessHeight > 0) && (ExcessHeight < BestExcessHeight))
|
|
|| ((ExcessHeight < 0) && (BestExcessHeight < 0) && (ExcessHeight > BestExcessHeight));
|
|
const bool bBestIsValid = (BestExcessRadius >= 0) && (BestExcessHeight >= 0);
|
|
const bool bRadiusEquals = (ExcessRadius == BestExcessRadius);
|
|
const bool bHeightEquals = (ExcessHeight == BestExcessHeight);
|
|
|
|
bool bValuesAreBest = ((bExcessRadiusIsBetter || bRadiusEquals) && (bExcessHeightIsBetter || bHeightEquals));
|
|
if (!bValuesAreBest && !bBestIsValid)
|
|
{
|
|
bValuesAreBest = bExcessRadiusIsBetter || (bRadiusEquals && bExcessHeightIsBetter);
|
|
}
|
|
|
|
if (bValuesAreBest)
|
|
{
|
|
BestFitNavAgent = NavIt;
|
|
BestExcessHeight = ExcessHeight;
|
|
BestExcessRadius = ExcessRadius;
|
|
}
|
|
}
|
|
|
|
if (BestFitNavAgent.IsValid())
|
|
{
|
|
NavDataForAgent = AgentToNavDataMap.Find(BestFitNavAgent);
|
|
NavDataInstance = NavDataForAgent ? NavDataForAgent->Get() : nullptr;
|
|
}
|
|
}
|
|
|
|
return NavDataInstance ? NavDataInstance : MainNavData;
|
|
}
|
|
|
|
ANavigationData* UNavigationSystemV1::GetDefaultNavDataInstance(FNavigationSystem::ECreateIfMissing CreateNewIfNoneFound)
|
|
{
|
|
checkSlow(IsInGameThread() == true);
|
|
|
|
if (MainNavData == NULL || MainNavData->IsPendingKill())
|
|
{
|
|
MainNavData = NULL;
|
|
|
|
// @TODO this should be done a differently. There should be specified a "default agent"
|
|
for (int32 NavDataIndex = 0; NavDataIndex < NavDataSet.Num(); ++NavDataIndex)
|
|
{
|
|
ANavigationData* NavData = NavDataSet[NavDataIndex];
|
|
if (NavData && !NavData->IsPendingKill() && NavData->CanBeMainNavData())
|
|
{
|
|
MainNavData = NavData;
|
|
break;
|
|
}
|
|
}
|
|
|
|
#if WITH_RECAST
|
|
if ( /*GIsEditor && */(MainNavData == NULL) && CreateNewIfNoneFound == FNavigationSystem::Create )
|
|
{
|
|
// Spawn a new one if we're in the editor. In-game, either we loaded one or we don't get one.
|
|
MainNavData = GetWorld()->SpawnActor<ANavigationData>(ARecastNavMesh::StaticClass());
|
|
}
|
|
#endif // WITH_RECAST
|
|
// either way make sure it's registered. Registration stores unique
|
|
// navmeshes, so we have nothing to lose
|
|
RegisterNavData(MainNavData);
|
|
}
|
|
|
|
return MainNavData;
|
|
}
|
|
|
|
FSharedNavQueryFilter UNavigationSystemV1::CreateDefaultQueryFilterCopy() const
|
|
{
|
|
return MainNavData ? MainNavData->GetDefaultQueryFilter()->GetCopy() : NULL;
|
|
}
|
|
|
|
bool UNavigationSystemV1::IsNavigationBuilt(const AWorldSettings* Settings) const
|
|
{
|
|
if (Settings == nullptr || Settings->IsNavigationSystemEnabled() == false || IsThereAnywhereToBuildNavigation() == false)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
bool bIsBuilt = true;
|
|
|
|
for (int32 NavDataIndex = 0; NavDataIndex < NavDataSet.Num(); ++NavDataIndex)
|
|
{
|
|
ANavigationData* NavData = NavDataSet[NavDataIndex];
|
|
if (NavData != NULL && NavData->GetWorldSettings() == Settings)
|
|
{
|
|
FNavDataGenerator* Generator = NavData->GetGenerator();
|
|
if ((NavData->GetRuntimeGenerationMode() != ERuntimeGenerationType::Static
|
|
#if WITH_EDITOR
|
|
|| GEditor != NULL
|
|
#endif // WITH_EDITOR
|
|
) && (Generator == NULL || Generator->IsBuildInProgress(/*bCheckDirtyToo=*/true) == true))
|
|
{
|
|
bIsBuilt = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return bIsBuilt;
|
|
}
|
|
|
|
bool UNavigationSystemV1::IsThereAnywhereToBuildNavigation() const
|
|
{
|
|
// not check if there are any volumes or other structures requiring/supporting navigation building
|
|
if (bWholeWorldNavigable == true)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
for (const FNavigationBounds& Bounds : RegisteredNavBounds)
|
|
{
|
|
if (Bounds.AreaBox.IsValid)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// @TODO this should be made more flexible to be able to trigger this from game-specific
|
|
// code (like Navigation System's subclass maybe)
|
|
bool bCreateNavigation = false;
|
|
|
|
for (TActorIterator<ANavMeshBoundsVolume> It(GetWorld()); It; ++It)
|
|
{
|
|
ANavMeshBoundsVolume const* const V = (*It);
|
|
if (V != NULL && !V->IsPendingKill())
|
|
{
|
|
bCreateNavigation = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return bCreateNavigation;
|
|
}
|
|
|
|
bool UNavigationSystemV1::IsNavigationRelevant(const AActor* TestActor) const
|
|
{
|
|
const INavRelevantInterface* NavInterface = Cast<const INavRelevantInterface>(TestActor);
|
|
if (NavInterface && NavInterface->IsNavigationRelevant())
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (TestActor)
|
|
{
|
|
TInlineComponentArray<UActorComponent*> Components;
|
|
for (int32 Idx = 0; Idx < Components.Num(); Idx++)
|
|
{
|
|
NavInterface = Cast<const INavRelevantInterface>(Components[Idx]);
|
|
if (NavInterface && NavInterface->IsNavigationRelevant())
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
FBox UNavigationSystemV1::GetWorldBounds() const
|
|
{
|
|
checkSlow(IsInGameThread() == true);
|
|
|
|
NavigableWorldBounds = FBox(ForceInit);
|
|
|
|
if (GetWorld() != nullptr)
|
|
{
|
|
if (bWholeWorldNavigable == false)
|
|
{
|
|
for (const FNavigationBounds& Bounds : RegisteredNavBounds)
|
|
{
|
|
NavigableWorldBounds += Bounds.AreaBox;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// @TODO - super slow! Need to ask tech guys where I can get this from
|
|
for (FActorIterator It(GetWorld()); It; ++It)
|
|
{
|
|
if (IsNavigationRelevant(*It))
|
|
{
|
|
NavigableWorldBounds += (*It)->GetComponentsBoundingBox();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return NavigableWorldBounds;
|
|
}
|
|
|
|
FBox UNavigationSystemV1::GetLevelBounds(ULevel* InLevel) const
|
|
{
|
|
FBox NavigableLevelBounds(ForceInit);
|
|
|
|
if (InLevel)
|
|
{
|
|
AActor** Actor = InLevel->Actors.GetData();
|
|
const int32 ActorCount = InLevel->Actors.Num();
|
|
for (int32 ActorIndex = 0; ActorIndex < ActorCount; ++ActorIndex, ++Actor)
|
|
{
|
|
if (IsNavigationRelevant(*Actor))
|
|
{
|
|
NavigableLevelBounds += (*Actor)->GetComponentsBoundingBox();
|
|
}
|
|
}
|
|
}
|
|
|
|
return NavigableLevelBounds;
|
|
}
|
|
|
|
const TSet<FNavigationBounds>& UNavigationSystemV1::GetNavigationBounds() const
|
|
{
|
|
return RegisteredNavBounds;
|
|
}
|
|
|
|
void UNavigationSystemV1::ApplyWorldOffset(const FVector& InOffset, bool bWorldShift)
|
|
{
|
|
// Attempt at generation of new nav mesh after the shift
|
|
// dynamic navmesh, we regenerate completely
|
|
if (GetRuntimeGenerationType() == ERuntimeGenerationType::Dynamic)
|
|
{
|
|
//stop generators from building navmesh
|
|
CancelBuild();
|
|
|
|
ConditionalPopulateNavOctree();
|
|
Build();
|
|
|
|
for (ANavigationData* NavData : NavDataSet)
|
|
{
|
|
if (NavData)
|
|
{
|
|
NavData->ConditionalConstructGenerator();
|
|
ARecastNavMesh* RecastNavMesh = Cast<ARecastNavMesh>(NavData);
|
|
if (RecastNavMesh) RecastNavMesh->RequestDrawingUpdate();
|
|
}
|
|
}
|
|
}
|
|
else // static navmesh
|
|
{
|
|
//not sure what happens when we shift farther than the extents of the NavOctree are
|
|
for (ANavigationData* NavData : NavDataSet)
|
|
{
|
|
if (NavData)
|
|
{
|
|
NavData->ApplyWorldOffset(InOffset, bWorldShift);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------//
|
|
// Bookkeeping
|
|
//----------------------------------------------------------------------//
|
|
void UNavigationSystemV1::RequestRegistration(ANavigationData* NavData, bool bTriggerRegistrationProcessing)
|
|
{
|
|
FScopeLock RegistrationLock(&NavDataRegistrationSection);
|
|
|
|
if (NavDataRegistrationQueue.Num() < REGISTRATION_QUEUE_SIZE)
|
|
{
|
|
NavDataRegistrationQueue.AddUnique(NavData);
|
|
|
|
// checking if bWorldInitDone since requesting out-of-order registration
|
|
// processing when we're still setting up can result in odd cases,
|
|
// like initializing navmesh generators while the nav system doesn't have
|
|
// the navmesh bounds collected yet.
|
|
if (bTriggerRegistrationProcessing && bWorldInitDone)
|
|
{
|
|
// trigger registration candidates processing
|
|
DECLARE_CYCLE_STAT(TEXT("FSimpleDelegateGraphTask.Process registration candidates"),
|
|
STAT_FSimpleDelegateGraphTask_ProcessRegistrationCandidates,
|
|
STATGROUP_TaskGraphTasks);
|
|
|
|
FSimpleDelegateGraphTask::CreateAndDispatchWhenReady(
|
|
FSimpleDelegateGraphTask::FDelegate::CreateUObject(this, &UNavigationSystemV1::ProcessRegistrationCandidates),
|
|
GET_STATID(STAT_FSimpleDelegateGraphTask_ProcessRegistrationCandidates), NULL, ENamedThreads::GameThread);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
UE_LOG(LogNavigation, Error, TEXT("Navigation System: registration queue full!"));
|
|
}
|
|
}
|
|
|
|
void UNavigationSystemV1::ProcessRegistrationCandidates()
|
|
{
|
|
//if (FUObjectThreadContext::Get().IsRoutingPostLoad)
|
|
//{
|
|
// // postopne
|
|
// return;
|
|
//}
|
|
|
|
FScopeLock RegistrationLock(&NavDataRegistrationSection);
|
|
|
|
if (NavDataRegistrationQueue.Num() == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
ANavigationData** NavDataPtr = NavDataRegistrationQueue.GetData();
|
|
const int CandidatesCount = NavDataRegistrationQueue.Num();
|
|
|
|
for (int32 CandidateIndex = 0; CandidateIndex < CandidatesCount; ++CandidateIndex, ++NavDataPtr)
|
|
{
|
|
if (*NavDataPtr != NULL)
|
|
{
|
|
ERegistrationResult Result = RegisterNavData(*NavDataPtr);
|
|
|
|
if (Result == RegistrationSuccessful)
|
|
{
|
|
continue;
|
|
}
|
|
else if (Result != RegistrationFailed_DataPendingKill)
|
|
{
|
|
(*NavDataPtr)->CleanUpAndMarkPendingKill();
|
|
if ((*NavDataPtr) == MainNavData)
|
|
{
|
|
MainNavData = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
MainNavData = GetDefaultNavDataInstance(FNavigationSystem::DontCreate);
|
|
|
|
// we processed all candidates so clear the queue
|
|
NavDataRegistrationQueue.Reset();
|
|
}
|
|
|
|
void UNavigationSystemV1::ProcessCustomLinkPendingRegistration()
|
|
{
|
|
FScopeLock AccessLock(&CustomLinkRegistrationSection);
|
|
|
|
TMap<INavLinkCustomInterface*, FWeakObjectPtr> TempPending = PendingCustomLinkRegistration;
|
|
PendingCustomLinkRegistration.Empty();
|
|
|
|
for (TMap<INavLinkCustomInterface*, FWeakObjectPtr>::TIterator It(TempPending); It; ++It)
|
|
{
|
|
INavLinkCustomInterface* ILink = It.Key();
|
|
FWeakObjectPtr LinkOb = It.Value();
|
|
|
|
if (LinkOb.IsValid() && ILink)
|
|
{
|
|
RegisterCustomLink(*ILink);
|
|
}
|
|
}
|
|
}
|
|
|
|
UNavigationSystemV1::ERegistrationResult UNavigationSystemV1::RegisterNavData(ANavigationData* NavData)
|
|
{
|
|
if (NavData == NULL)
|
|
{
|
|
return RegistrationError;
|
|
}
|
|
else if (NavData->IsPendingKill() == true)
|
|
{
|
|
return RegistrationFailed_DataPendingKill;
|
|
}
|
|
// still to be seen if this is really true, but feels right
|
|
else if (NavData->IsRegistered() == true)
|
|
{
|
|
return RegistrationSuccessful;
|
|
}
|
|
|
|
FScopeLock Lock(&NavDataRegistration);
|
|
|
|
UNavigationSystemV1::ERegistrationResult Result = RegistrationError;
|
|
|
|
// find out which, if any, navigation agents are supported by this nav data
|
|
// if none then fail the registration
|
|
FNavDataConfig NavConfig = NavData->GetConfig();
|
|
|
|
// not discarding navmesh when there's only one Supported Agent
|
|
if (NavConfig.IsValid() == false && SupportedAgents.Num() == 1)
|
|
{
|
|
// fill in AgentProps with whatever is the instance's setup
|
|
NavConfig = SupportedAgents[0];
|
|
NavData->SetConfig(SupportedAgents[0]);
|
|
NavData->SetSupportsDefaultAgent(true);
|
|
NavData->ProcessNavAreas(NavAreaClasses, 0);
|
|
}
|
|
|
|
if (NavConfig.IsValid() == true)
|
|
{
|
|
// check if this kind of agent has already its navigation implemented
|
|
TWeakObjectPtr<ANavigationData>* NavDataForAgent = AgentToNavDataMap.Find(NavConfig);
|
|
ANavigationData* NavDataInstanceForAgent = NavDataForAgent ? NavDataForAgent->Get() : nullptr;
|
|
|
|
if (NavDataInstanceForAgent == nullptr)
|
|
{
|
|
if (NavData->IsA(AAbstractNavData::StaticClass()) == false)
|
|
{
|
|
// ok, so this navigation agent doesn't have its navmesh registered yet, but do we want to support it?
|
|
bool bAgentSupported = false;
|
|
|
|
for (int32 AgentIndex = 0; AgentIndex < SupportedAgents.Num(); ++AgentIndex)
|
|
{
|
|
if (NavData->GetClass() == SupportedAgents[AgentIndex].NavigationDataClass && SupportedAgents[AgentIndex].IsEquivalent(NavConfig) == true)
|
|
{
|
|
// it's supported, then just in case it's not a precise match (IsEquivalent succeeds with some precision)
|
|
// update NavData with supported Agent
|
|
bAgentSupported = true;
|
|
|
|
NavData->SetConfig(SupportedAgents[AgentIndex]);
|
|
AgentToNavDataMap.Add(SupportedAgents[AgentIndex], NavData);
|
|
NavData->SetSupportsDefaultAgent(AgentIndex == 0);
|
|
NavData->ProcessNavAreas(NavAreaClasses, AgentIndex);
|
|
|
|
OnNavDataRegisteredEvent.Broadcast(NavData);
|
|
|
|
NavDataSet.AddUnique(NavData);
|
|
NavData->OnRegistered();
|
|
|
|
break;
|
|
}
|
|
}
|
|
Result = bAgentSupported == true ? RegistrationSuccessful : RegistrationFailed_AgentNotValid;
|
|
}
|
|
else
|
|
{
|
|
// fake registration since it's a special navigation data type
|
|
// and it would get discarded for not implementing any particular
|
|
// navigation agent
|
|
// Node that we don't add abstract navigation data to NavDataSet
|
|
NavData->OnRegistered();
|
|
|
|
Result = RegistrationSuccessful;
|
|
}
|
|
}
|
|
else if (NavDataInstanceForAgent == NavData)
|
|
{
|
|
ensure(NavDataSet.Find(NavData) != INDEX_NONE);
|
|
// let's treat double registration of the same nav data with the same agent as a success
|
|
Result = RegistrationSuccessful;
|
|
}
|
|
else
|
|
{
|
|
// otherwise specified agent type already has its navmesh implemented, fail redundant instance
|
|
Result = RegistrationFailed_AgentAlreadySupported;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Result = RegistrationFailed_AgentNotValid;
|
|
}
|
|
|
|
// @todo else might consider modifying this NavData to implement navigation for one of the supported agents
|
|
// care needs to be taken to not make it implement navigation for agent who's real implementation has
|
|
// not been loaded yet.
|
|
|
|
return Result;
|
|
}
|
|
|
|
void UNavigationSystemV1::UnregisterNavData(ANavigationData* NavData)
|
|
{
|
|
NavDataSet.RemoveSingle(NavData);
|
|
|
|
if (NavData == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
FScopeLock Lock(&NavDataRegistration);
|
|
NavData->OnUnregistered();
|
|
}
|
|
|
|
void UNavigationSystemV1::RegisterCustomLink(INavLinkCustomInterface& CustomLink)
|
|
{
|
|
uint32 LinkId = CustomLink.GetLinkId();
|
|
|
|
// if there's already a link with that Id registered, assign new Id and mark dirty area
|
|
// this won't fix baked data in static navmesh (in game), but every other case will regenerate affected tiles
|
|
if (CustomLinksMap.Contains(LinkId))
|
|
{
|
|
LinkId = INavLinkCustomInterface::GetUniqueId();
|
|
CustomLink.UpdateLinkId(LinkId);
|
|
|
|
UObject* CustomLinkOb = CustomLink.GetLinkOwner();
|
|
UActorComponent* OwnerComp = Cast<UActorComponent>(CustomLinkOb);
|
|
AActor* OwnerActor = OwnerComp ? OwnerComp->GetOwner() : Cast<AActor>(CustomLinkOb);
|
|
|
|
if (OwnerActor)
|
|
{
|
|
ENavLinkDirection::Type DummyDir = ENavLinkDirection::BothWays;
|
|
FVector RelativePtA, RelativePtB;
|
|
CustomLink.GetLinkData(RelativePtA, RelativePtB, DummyDir);
|
|
|
|
const FTransform OwnerActorTM = OwnerActor->GetTransform();
|
|
const FVector WorldPtA = OwnerActorTM.TransformPosition(RelativePtA);
|
|
const FVector WorldPtB = OwnerActorTM.TransformPosition(RelativePtB);
|
|
|
|
FBox LinkBounds(ForceInitToZero);
|
|
LinkBounds += WorldPtA;
|
|
LinkBounds += WorldPtB;
|
|
|
|
AddDirtyArea(LinkBounds, OctreeUpdate_Modifiers);
|
|
}
|
|
}
|
|
|
|
CustomLinksMap.Add(LinkId, FNavigationSystem::FCustomLinkOwnerInfo(&CustomLink));
|
|
}
|
|
|
|
void UNavigationSystemV1::UnregisterCustomLink(INavLinkCustomInterface& CustomLink)
|
|
{
|
|
CustomLinksMap.Remove(CustomLink.GetLinkId());
|
|
}
|
|
|
|
INavLinkCustomInterface* UNavigationSystemV1::GetCustomLink(uint32 UniqueLinkId) const
|
|
{
|
|
const FNavigationSystem::FCustomLinkOwnerInfo* LinkInfo = CustomLinksMap.Find(UniqueLinkId);
|
|
return (LinkInfo && LinkInfo->IsValid()) ? LinkInfo->LinkInterface : nullptr;
|
|
}
|
|
|
|
void UNavigationSystemV1::UpdateCustomLink(const INavLinkCustomInterface* CustomLink)
|
|
{
|
|
for (TMap<FNavAgentProperties, TWeakObjectPtr<ANavigationData> >::TIterator It(AgentToNavDataMap); It; ++It)
|
|
{
|
|
ANavigationData* NavData = It.Value().Get();
|
|
if (NavData)
|
|
{
|
|
NavData->UpdateCustomLink(CustomLink);
|
|
}
|
|
}
|
|
}
|
|
|
|
void UNavigationSystemV1::RequestCustomLinkRegistering(INavLinkCustomInterface& CustomLink, UObject* OwnerOb)
|
|
{
|
|
UNavigationSystemV1* NavSys = FNavigationSystem::GetCurrent<UNavigationSystemV1>(OwnerOb);
|
|
if (NavSys)
|
|
{
|
|
NavSys->RegisterCustomLink(CustomLink);
|
|
}
|
|
else
|
|
{
|
|
FScopeLock AccessLock(&CustomLinkRegistrationSection);
|
|
PendingCustomLinkRegistration.Add(&CustomLink, OwnerOb);
|
|
}
|
|
}
|
|
|
|
void UNavigationSystemV1::RequestCustomLinkUnregistering(INavLinkCustomInterface& CustomLink, UObject* OwnerOb)
|
|
{
|
|
UNavigationSystemV1* NavSys = FNavigationSystem::GetCurrent<UNavigationSystemV1>(OwnerOb);
|
|
if (NavSys)
|
|
{
|
|
NavSys->UnregisterCustomLink(CustomLink);
|
|
}
|
|
else
|
|
{
|
|
FScopeLock AccessLock(&CustomLinkRegistrationSection);
|
|
PendingCustomLinkRegistration.Remove(&CustomLink);
|
|
}
|
|
}
|
|
|
|
void UNavigationSystemV1::RequestAreaUnregistering(UClass* NavAreaClass)
|
|
{
|
|
for (TObjectIterator<UNavigationSystemV1> NavSysIt; NavSysIt; ++NavSysIt)
|
|
{
|
|
NavSysIt->UnregisterNavAreaClass(NavAreaClass);
|
|
}
|
|
}
|
|
|
|
void UNavigationSystemV1::UnregisterNavAreaClass(UClass* NavAreaClass)
|
|
{
|
|
// remove from known areas
|
|
if (NavAreaClasses.Remove(NavAreaClass) > 0)
|
|
{
|
|
// notify navigation data
|
|
// notify existing nav data
|
|
OnNavigationAreaEvent(NavAreaClass, ENavAreaEvent::Unregistered);
|
|
}
|
|
}
|
|
|
|
void UNavigationSystemV1::RequestAreaRegistering(UClass* NavAreaClass)
|
|
{
|
|
for (TObjectIterator<UNavigationSystemV1> NavSysIt; NavSysIt; ++NavSysIt)
|
|
{
|
|
NavSysIt->RegisterNavAreaClass(NavAreaClass);
|
|
}
|
|
}
|
|
|
|
void UNavigationSystemV1::RegisterNavAreaClass(UClass* AreaClass)
|
|
{
|
|
// can't be null
|
|
if (AreaClass == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// can't be abstract
|
|
if (AreaClass->HasAnyClassFlags(CLASS_Abstract))
|
|
{
|
|
return;
|
|
}
|
|
|
|
// special handling of blueprint based areas
|
|
if (AreaClass->HasAnyClassFlags(CLASS_CompiledFromBlueprint))
|
|
{
|
|
// can't be skeleton of blueprint class
|
|
if (AreaClass->GetName().Contains(TEXT("SKEL_")))
|
|
{
|
|
return;
|
|
}
|
|
|
|
// can't be class from Developers folder (won't be saved properly anyway)
|
|
const UPackage* Package = AreaClass->GetOutermost();
|
|
if (Package && Package->GetName().Contains(TEXT("/Developers/")))
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (NavAreaClasses.Contains(AreaClass))
|
|
{
|
|
// Already added
|
|
return;
|
|
}
|
|
|
|
UNavArea* AreaClassCDO = GetMutableDefault<UNavArea>(AreaClass);
|
|
check(AreaClassCDO);
|
|
|
|
// initialize flags
|
|
AreaClassCDO->InitializeArea();
|
|
|
|
// add to know areas
|
|
NavAreaClasses.Add(AreaClass);
|
|
|
|
// notify existing nav data
|
|
OnNavigationAreaEvent(AreaClass, ENavAreaEvent::Registered);
|
|
|
|
#if WITH_EDITOR
|
|
UNavAreaMeta_SwitchByAgent* SwitchByAgentCDO = Cast<UNavAreaMeta_SwitchByAgent>(AreaClassCDO);
|
|
// update area properties
|
|
if (SwitchByAgentCDO)
|
|
{
|
|
SwitchByAgentCDO->UpdateAgentConfig();
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void UNavigationSystemV1::OnNavigationAreaEvent(UClass* AreaClass, ENavAreaEvent::Type Event)
|
|
{
|
|
// notify existing nav data
|
|
for (auto NavigationData : NavDataSet)
|
|
{
|
|
if (NavigationData != NULL && NavigationData->IsPendingKillPending() == false)
|
|
{
|
|
NavigationData->OnNavAreaEvent(AreaClass, Event);
|
|
}
|
|
}
|
|
}
|
|
|
|
int32 UNavigationSystemV1::GetSupportedAgentIndex(const ANavigationData* NavData) const
|
|
{
|
|
if (SupportedAgents.Num() < 2)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
const FNavDataConfig& TestConfig = NavData->GetConfig();
|
|
for (int32 AgentIndex = 0; AgentIndex < SupportedAgents.Num(); AgentIndex++)
|
|
{
|
|
if (SupportedAgents[AgentIndex].IsEquivalent(TestConfig))
|
|
{
|
|
return AgentIndex;
|
|
}
|
|
}
|
|
|
|
return INDEX_NONE;
|
|
}
|
|
|
|
int32 UNavigationSystemV1::GetSupportedAgentIndex(const FNavAgentProperties& NavAgent) const
|
|
{
|
|
if (SupportedAgents.Num() < 2)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
for (int32 AgentIndex = 0; AgentIndex < SupportedAgents.Num(); AgentIndex++)
|
|
{
|
|
if (SupportedAgents[AgentIndex].IsEquivalent(NavAgent))
|
|
{
|
|
return AgentIndex;
|
|
}
|
|
}
|
|
|
|
return INDEX_NONE;
|
|
}
|
|
|
|
void UNavigationSystemV1::DescribeFilterFlags(UEnum* FlagsEnum) const
|
|
{
|
|
#if WITH_EDITOR
|
|
TArray<FString> FlagDesc;
|
|
FString EmptyStr;
|
|
FlagDesc.Init(EmptyStr, 16);
|
|
|
|
const int32 NumEnums = FMath::Min(16, FlagsEnum->NumEnums() - 1); // skip _MAX
|
|
for (int32 FlagIndex = 0; FlagIndex < NumEnums; FlagIndex++)
|
|
{
|
|
FlagDesc[FlagIndex] = FlagsEnum->GetDisplayNameTextByIndex(FlagIndex).ToString();
|
|
}
|
|
|
|
DescribeFilterFlags(FlagDesc);
|
|
#endif
|
|
}
|
|
|
|
void UNavigationSystemV1::DescribeFilterFlags(const TArray<FString>& FlagsDesc) const
|
|
{
|
|
#if WITH_EDITOR
|
|
const int32 MaxFlags = 16;
|
|
TArray<FString> UseDesc = FlagsDesc;
|
|
|
|
FString EmptyStr;
|
|
while (UseDesc.Num() < MaxFlags)
|
|
{
|
|
UseDesc.Add(EmptyStr);
|
|
}
|
|
|
|
// get special value from recast's navmesh
|
|
#if WITH_RECAST
|
|
uint16 NavLinkFlag = ARecastNavMesh::GetNavLinkFlag();
|
|
for (int32 FlagIndex = 0; FlagIndex < MaxFlags; FlagIndex++)
|
|
{
|
|
if ((NavLinkFlag >> FlagIndex) & 1)
|
|
{
|
|
UseDesc[FlagIndex] = TEXT("Navigation link");
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// setup properties
|
|
UStructProperty* StructProp1 = FindField<UStructProperty>(UNavigationQueryFilter::StaticClass(), TEXT("IncludeFlags"));
|
|
UStructProperty* StructProp2 = FindField<UStructProperty>(UNavigationQueryFilter::StaticClass(), TEXT("ExcludeFlags"));
|
|
check(StructProp1);
|
|
check(StructProp2);
|
|
|
|
UStruct* Structs[] = { StructProp1->Struct, StructProp2->Struct };
|
|
const FString CustomNameMeta = TEXT("DisplayName");
|
|
|
|
for (int32 StructIndex = 0; StructIndex < ARRAY_COUNT(Structs); StructIndex++)
|
|
{
|
|
for (int32 FlagIndex = 0; FlagIndex < MaxFlags; FlagIndex++)
|
|
{
|
|
FString PropName = FString::Printf(TEXT("bNavFlag%d"), FlagIndex);
|
|
UProperty* Prop = FindField<UProperty>(Structs[StructIndex], *PropName);
|
|
check(Prop);
|
|
|
|
if (UseDesc[FlagIndex].Len())
|
|
{
|
|
Prop->SetPropertyFlags(CPF_Edit);
|
|
Prop->SetMetaData(*CustomNameMeta, *UseDesc[FlagIndex]);
|
|
}
|
|
else
|
|
{
|
|
Prop->ClearPropertyFlags(CPF_Edit);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|
|
}
|
|
|
|
void UNavigationSystemV1::ResetCachedFilter(TSubclassOf<UNavigationQueryFilter> FilterClass)
|
|
{
|
|
for (int32 NavDataIndex = 0; NavDataIndex < NavDataSet.Num(); NavDataIndex++)
|
|
{
|
|
if (NavDataSet[NavDataIndex])
|
|
{
|
|
NavDataSet[NavDataIndex]->RemoveQueryFilter(FilterClass);
|
|
}
|
|
}
|
|
}
|
|
|
|
UNavigationSystemV1* UNavigationSystemV1::CreateNavigationSystem(UWorld* WorldOwner)
|
|
{
|
|
UNavigationSystemV1* NavSys = NULL;
|
|
|
|
// create navigation system for editor and server targets, but remove it from game clients
|
|
if (WorldOwner && (*GEngine->NavigationSystemClass != nullptr)
|
|
&& (GEngine->NavigationSystemClass->GetDefaultObject<UNavigationSystemV1>()->bAllowClientSideNavigation || WorldOwner->GetNetMode() != NM_Client))
|
|
{
|
|
AWorldSettings* WorldSettings = WorldOwner->GetWorldSettings();
|
|
if (WorldSettings == NULL || WorldSettings->IsNavigationSystemEnabled())
|
|
{
|
|
NavSys = NewObject<UNavigationSystemV1>(WorldOwner, GEngine->NavigationSystemClass);
|
|
WorldOwner->SetNavigationSystem(NavSys);
|
|
}
|
|
}
|
|
|
|
return NavSys;
|
|
}
|
|
|
|
void UNavigationSystemV1::InitializeForWorld(UWorld& World, FNavigationSystemRunMode Mode)
|
|
{
|
|
OnWorldInitDone(Mode);
|
|
}
|
|
|
|
UNavigationSystemV1* UNavigationSystemV1::GetCurrent(UWorld* World)
|
|
{
|
|
return FNavigationSystem::GetCurrent<UNavigationSystemV1>(World);
|
|
}
|
|
|
|
UNavigationSystemV1* UNavigationSystemV1::GetCurrent(UObject* WorldContextObject)
|
|
{
|
|
return FNavigationSystem::GetCurrent<UNavigationSystemV1>(WorldContextObject);
|
|
}
|
|
|
|
ANavigationData* UNavigationSystemV1::GetNavDataWithID(const uint16 NavDataID) const
|
|
{
|
|
for (int32 NavDataIndex = 0; NavDataIndex < NavDataSet.Num(); ++NavDataIndex)
|
|
{
|
|
const ANavigationData* NavData = NavDataSet[NavDataIndex];
|
|
if (NavData != NULL && NavData->GetNavDataUniqueID() == NavDataID)
|
|
{
|
|
return const_cast<ANavigationData*>(NavData);
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void UNavigationSystemV1::AddDirtyArea(const FBox& NewArea, int32 Flags)
|
|
{
|
|
if (Flags > 0 && bCanAccumulateDirtyAreas && NewArea.IsValid)
|
|
{
|
|
DirtyAreas.Add(FNavigationDirtyArea(NewArea, Flags));
|
|
}
|
|
#if !UE_BUILD_SHIPPING
|
|
bDirtyAreasReportedWhileAccumulationLocked = bDirtyAreasReportedWhileAccumulationLocked || (Flags > 0 && !bCanAccumulateDirtyAreas);
|
|
#endif // !UE_BUILD_SHIPPING
|
|
}
|
|
|
|
void UNavigationSystemV1::AddDirtyAreas(const TArray<FBox>& NewAreas, int32 Flags)
|
|
{
|
|
for (int32 NewAreaIndex = 0; NewAreaIndex < NewAreas.Num(); NewAreaIndex++)
|
|
{
|
|
AddDirtyArea(NewAreas[NewAreaIndex], Flags);
|
|
}
|
|
}
|
|
|
|
bool UNavigationSystemV1::HasDirtyAreasQueued() const
|
|
{
|
|
return DirtyAreas.Num() > 0;
|
|
}
|
|
|
|
int32 GetDirtyFlagHelper(int32 UpdateFlags, int32 DefaultValue)
|
|
{
|
|
return ((UpdateFlags & UNavigationSystemV1::OctreeUpdate_Geometry) != 0) ? ENavigationDirtyFlag::All :
|
|
((UpdateFlags & UNavigationSystemV1::OctreeUpdate_Modifiers) != 0) ? ENavigationDirtyFlag::DynamicModifier :
|
|
DefaultValue;
|
|
}
|
|
|
|
FSetElementId UNavigationSystemV1::RegisterNavOctreeElement(UObject* ElementOwner, INavRelevantInterface* ElementInterface, int32 UpdateFlags)
|
|
{
|
|
FSetElementId SetId;
|
|
|
|
#if WITH_EDITOR
|
|
if (IsNavigationRegisterLocked())
|
|
{
|
|
return SetId;
|
|
}
|
|
#endif
|
|
|
|
if (NavOctree.IsValid() == false || ElementOwner == NULL || ElementInterface == NULL)
|
|
{
|
|
return SetId;
|
|
}
|
|
|
|
if (IsNavigationOctreeLocked())
|
|
{
|
|
UE_LOG(LogNavOctree, Log, TEXT("IGNORE(RegisterNavOctreeElement) %s"), *GetPathNameSafe(ElementOwner));
|
|
return SetId;
|
|
}
|
|
|
|
const bool bIsRelevant = ElementInterface->IsNavigationRelevant();
|
|
UE_LOG(LogNavOctree, Log, TEXT("REG %s %s"), *GetNameSafe(ElementOwner), bIsRelevant ? TEXT("[relevant]") : TEXT(""));
|
|
|
|
if (bIsRelevant)
|
|
{
|
|
bool bCanAdd = false;
|
|
|
|
UObject* ParentNode = ElementInterface->GetNavigationParent();
|
|
if (ParentNode)
|
|
{
|
|
OctreeChildNodesMap.AddUnique(ParentNode, FWeakObjectPtr(ElementOwner));
|
|
bCanAdd = true;
|
|
}
|
|
else
|
|
{
|
|
const FOctreeElementId* ElementId = GetObjectsNavOctreeId(*ElementOwner);
|
|
bCanAdd = (ElementId == NULL);
|
|
}
|
|
|
|
if (bCanAdd)
|
|
{
|
|
FNavigationDirtyElement UpdateInfo(ElementOwner, ElementInterface, GetDirtyFlagHelper(UpdateFlags, 0));
|
|
|
|
SetId = PendingOctreeUpdates.FindId(UpdateInfo);
|
|
if (SetId.IsValidId())
|
|
{
|
|
// make sure this request stays, in case it has been invalidated already
|
|
PendingOctreeUpdates[SetId] = UpdateInfo;
|
|
}
|
|
else
|
|
{
|
|
SetId = PendingOctreeUpdates.Add(UpdateInfo);
|
|
}
|
|
}
|
|
}
|
|
|
|
return SetId;
|
|
}
|
|
|
|
void UNavigationSystemV1::AddElementToNavOctree(const FNavigationDirtyElement& DirtyElement)
|
|
{
|
|
// handle invalidated requests first
|
|
if (DirtyElement.bInvalidRequest)
|
|
{
|
|
if (DirtyElement.bHasPrevData)
|
|
{
|
|
AddDirtyArea(DirtyElement.PrevBounds, DirtyElement.PrevFlags);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
UObject* ElementOwner = DirtyElement.Owner.Get();
|
|
if (ElementOwner == NULL || ElementOwner->IsPendingKill() || DirtyElement.NavInterface == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
FNavigationOctreeElement GeneratedData(*ElementOwner);
|
|
const FBox ElementBounds = DirtyElement.NavInterface->GetNavigationBounds();
|
|
|
|
UObject* NavigationParent = DirtyElement.NavInterface->GetNavigationParent();
|
|
if (NavigationParent)
|
|
{
|
|
// check if parent node is waiting in queue
|
|
const FSetElementId ParentRequestId = PendingOctreeUpdates.FindId(FNavigationDirtyElement(NavigationParent));
|
|
const FOctreeElementId* ParentId = GetObjectsNavOctreeId(*NavigationParent);
|
|
if (ParentRequestId.IsValidId() && ParentId == NULL)
|
|
{
|
|
FNavigationDirtyElement& ParentNode = PendingOctreeUpdates[ParentRequestId];
|
|
AddElementToNavOctree(ParentNode);
|
|
|
|
// mark as invalid so it won't be processed twice
|
|
ParentNode.bInvalidRequest = true;
|
|
}
|
|
|
|
const FOctreeElementId* UseParentId = ParentId ? ParentId : GetObjectsNavOctreeId(*NavigationParent);
|
|
if (UseParentId && NavOctree->IsValidElementId(*UseParentId))
|
|
{
|
|
UE_LOG(LogNavOctree, Log, TEXT("ADD %s to %s"), *GetNameSafe(ElementOwner), *GetNameSafe(NavigationParent));
|
|
NavOctree->AppendToNode(*UseParentId, DirtyElement.NavInterface, ElementBounds, GeneratedData);
|
|
}
|
|
else
|
|
{
|
|
UE_LOG(LogNavOctree, Warning, TEXT("Can't add node [%s] - parent [%s] not found in octree!"), *GetNameSafe(ElementOwner), *GetNameSafe(NavigationParent));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
UE_LOG(LogNavOctree, Log, TEXT("ADD %s"), *GetNameSafe(ElementOwner));
|
|
NavOctree->AddNode(ElementOwner, DirtyElement.NavInterface, ElementBounds, GeneratedData);
|
|
}
|
|
|
|
const FBox BBox = GeneratedData.Bounds.GetBox();
|
|
const bool bValidBBox = BBox.IsValid && !BBox.GetSize().IsNearlyZero();
|
|
|
|
if (bValidBBox && !GeneratedData.IsEmpty())
|
|
{
|
|
const int32 DirtyFlag = DirtyElement.FlagsOverride ? DirtyElement.FlagsOverride : GeneratedData.Data->GetDirtyFlag();
|
|
AddDirtyArea(BBox, DirtyFlag);
|
|
}
|
|
}
|
|
|
|
bool UNavigationSystemV1::GetNavOctreeElementData(const UObject& NodeOwner, int32& DirtyFlags, FBox& DirtyBounds)
|
|
{
|
|
const FOctreeElementId* ElementId = GetObjectsNavOctreeId(NodeOwner);
|
|
if (ElementId != NULL)
|
|
{
|
|
if (NavOctree->IsValidElementId(*ElementId))
|
|
{
|
|
// mark area occupied by given actor as dirty
|
|
FNavigationOctreeElement& ElementData = NavOctree->GetElementById(*ElementId);
|
|
DirtyFlags = ElementData.Data->GetDirtyFlag();
|
|
DirtyBounds = ElementData.Bounds.GetBox();
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void UNavigationSystemV1::UnregisterNavOctreeElement(UObject* ElementOwner, INavRelevantInterface* ElementInterface, int32 UpdateFlags)
|
|
{
|
|
#if WITH_EDITOR
|
|
if (IsNavigationUnregisterLocked())
|
|
{
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
if (NavOctree.IsValid() == false || ElementOwner == NULL || ElementInterface == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (IsNavigationOctreeLocked())
|
|
{
|
|
UE_LOG(LogNavOctree, Log, TEXT("IGNORE(UnregisterNavOctreeElement) %s"), *GetPathNameSafe(ElementOwner));
|
|
return;
|
|
}
|
|
|
|
const FOctreeElementId* ElementId = GetObjectsNavOctreeId(*ElementOwner);
|
|
UE_LOG(LogNavOctree, Log, TEXT("UNREG %s %s"), *GetNameSafe(ElementOwner), ElementId ? TEXT("[exists]") : TEXT(""));
|
|
|
|
if (ElementId != NULL)
|
|
{
|
|
RemoveNavOctreeElementId(*ElementId, UpdateFlags);
|
|
RemoveObjectsNavOctreeId(*ElementOwner);
|
|
}
|
|
else
|
|
{
|
|
const bool bCanRemoveChildNode = (UpdateFlags & OctreeUpdate_ParentChain) == 0;
|
|
UObject* ParentNode = ElementInterface->GetNavigationParent();
|
|
if (ParentNode && bCanRemoveChildNode)
|
|
{
|
|
// if node has navigation parent (= doesn't exists in octree on its own)
|
|
// and it's not part of parent chain update
|
|
// remove it from map and force update on parent to rebuild octree element
|
|
|
|
OctreeChildNodesMap.RemoveSingle(ParentNode, FWeakObjectPtr(ElementOwner));
|
|
UpdateNavOctreeParentChain(ParentNode);
|
|
}
|
|
}
|
|
|
|
// mark pending update as invalid, it will be dirtied according to currently active settings
|
|
const bool bCanInvalidateQueue = (UpdateFlags & OctreeUpdate_Refresh) == 0;
|
|
if (bCanInvalidateQueue)
|
|
{
|
|
const FSetElementId RequestId = PendingOctreeUpdates.FindId(FNavigationDirtyElement(ElementOwner));
|
|
if (RequestId.IsValidId())
|
|
{
|
|
PendingOctreeUpdates[RequestId].bInvalidRequest = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
void UNavigationSystemV1::RemoveNavOctreeElementId(const FOctreeElementId& ElementId, int32 UpdateFlags)
|
|
{
|
|
if (NavOctree->IsValidElementId(ElementId))
|
|
{
|
|
const FNavigationOctreeElement& ElementData = NavOctree->GetElementById(ElementId);
|
|
const int32 DirtyFlag = GetDirtyFlagHelper(UpdateFlags, ElementData.Data->GetDirtyFlag());
|
|
// mark area occupied by given actor as dirty
|
|
AddDirtyArea(ElementData.Bounds.GetBox(), DirtyFlag);
|
|
NavOctree->RemoveNode(ElementId);
|
|
}
|
|
}
|
|
|
|
const FNavigationRelevantData* UNavigationSystemV1::GetDataForObject(const UObject& Object) const
|
|
{
|
|
check(NavOctree.IsValid());
|
|
|
|
const FOctreeElementId* OctreeID = GetObjectsNavOctreeId(Object);
|
|
|
|
if (OctreeID != nullptr && OctreeID->IsValidId() == true)
|
|
{
|
|
return NavOctree->GetDataForID(*OctreeID);
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
void UNavigationSystemV1::UpdateActorInNavOctree(AActor& Actor)
|
|
{
|
|
if (IsNavigationSystemStatic())
|
|
{
|
|
return;
|
|
}
|
|
SCOPE_CYCLE_COUNTER(STAT_DebugNavOctree);
|
|
|
|
INavRelevantInterface* NavElement = Cast<INavRelevantInterface>(&Actor);
|
|
if (NavElement)
|
|
{
|
|
UNavigationSystemV1* NavSys = FNavigationSystem::GetCurrent<UNavigationSystemV1>(Actor.GetWorld());
|
|
if (NavSys)
|
|
{
|
|
NavSys->UpdateNavOctreeElement(&Actor, NavElement, OctreeUpdate_Default);
|
|
}
|
|
}
|
|
}
|
|
|
|
void UNavigationSystemV1::UpdateComponentInNavOctree(UActorComponent& Comp)
|
|
{
|
|
SCOPE_CYCLE_COUNTER(STAT_DebugNavOctree);
|
|
|
|
if (ShouldUpdateNavOctreeOnComponentChange() == false)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// special case for early out: use cached nav relevancy
|
|
if (Comp.bNavigationRelevant == true)
|
|
{
|
|
INavRelevantInterface* NavElement = Cast<INavRelevantInterface>(&Comp);
|
|
if (NavElement)
|
|
{
|
|
AActor* OwnerActor = Comp.GetOwner();
|
|
if (OwnerActor)
|
|
{
|
|
UNavigationSystemV1* NavSys = FNavigationSystem::GetCurrent<UNavigationSystemV1>(OwnerActor->GetWorld());
|
|
if (NavSys)
|
|
{
|
|
if (OwnerActor->IsComponentRelevantForNavigation(&Comp))
|
|
{
|
|
NavSys->UpdateNavOctreeElement(&Comp, NavElement, OctreeUpdate_Default);
|
|
}
|
|
else
|
|
{
|
|
NavSys->UnregisterNavOctreeElement(&Comp, NavElement, OctreeUpdate_Default);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (Comp.CanEverAffectNavigation())
|
|
{
|
|
// could have been relevant before and not it isn't. Need to check if there's an octree element ID for it
|
|
INavRelevantInterface* NavElement = Cast<INavRelevantInterface>(&Comp);
|
|
if (NavElement)
|
|
{
|
|
AActor* OwnerActor = Comp.GetOwner();
|
|
if (OwnerActor)
|
|
{
|
|
UNavigationSystemV1* NavSys = FNavigationSystem::GetCurrent<UNavigationSystemV1>(OwnerActor->GetWorld());
|
|
if (NavSys)
|
|
{
|
|
NavSys->UnregisterNavOctreeElement(&Comp, NavElement, OctreeUpdate_Default);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void UNavigationSystemV1::UpdateActorAndComponentsInNavOctree(AActor& Actor, bool bUpdateAttachedActors)
|
|
{
|
|
UpdateActorInNavOctree(Actor);
|
|
|
|
for (UActorComponent* Component : Actor.GetComponents())
|
|
{
|
|
if (Component)
|
|
{
|
|
UpdateComponentInNavOctree(*Component);
|
|
}
|
|
}
|
|
|
|
if (bUpdateAttachedActors)
|
|
{
|
|
UpdateAttachedActorsInNavOctree(Actor);
|
|
}
|
|
}
|
|
|
|
void UNavigationSystemV1::UpdateNavOctreeAfterMove(USceneComponent* Comp)
|
|
{
|
|
AActor* OwnerActor = Comp->GetOwner();
|
|
if (OwnerActor && OwnerActor->GetRootComponent() == Comp)
|
|
{
|
|
UpdateActorAndComponentsInNavOctree(*OwnerActor, true);
|
|
}
|
|
}
|
|
|
|
void UNavigationSystemV1::UpdateAttachedActorsInNavOctree(AActor& RootActor)
|
|
{
|
|
TArray<AActor*> UniqueAttachedActors;
|
|
UniqueAttachedActors.Add(&RootActor);
|
|
|
|
TArray<AActor*> TempAttachedActors;
|
|
for (int32 ActorIndex = 0; ActorIndex < UniqueAttachedActors.Num(); ++ActorIndex)
|
|
{
|
|
check(UniqueAttachedActors[ActorIndex]);
|
|
// find all attached actors
|
|
UniqueAttachedActors[ActorIndex]->GetAttachedActors(TempAttachedActors);
|
|
|
|
for (int32 AttachmentIndex = 0; AttachmentIndex < TempAttachedActors.Num(); ++AttachmentIndex)
|
|
{
|
|
// and store the ones we don't know about yet
|
|
UniqueAttachedActors.AddUnique(TempAttachedActors[AttachmentIndex]);
|
|
}
|
|
}
|
|
|
|
// skipping the first item since that's the root, and we just care about the attached actors
|
|
for (int32 ActorIndex = 1; ActorIndex < UniqueAttachedActors.Num(); ++ActorIndex)
|
|
{
|
|
UpdateActorAndComponentsInNavOctree(*UniqueAttachedActors[ActorIndex], /*bUpdateAttachedActors = */false);
|
|
}
|
|
}
|
|
|
|
void UNavigationSystemV1::UpdateNavOctreeBounds(AActor* Actor)
|
|
{
|
|
for (UActorComponent* Component : Actor->GetComponents())
|
|
{
|
|
INavRelevantInterface* NavElement = Cast<INavRelevantInterface>(Component);
|
|
if (NavElement)
|
|
{
|
|
NavElement->UpdateNavigationBounds();
|
|
}
|
|
}
|
|
}
|
|
|
|
void UNavigationSystemV1::ClearNavOctreeAll(AActor* Actor)
|
|
{
|
|
if (Actor)
|
|
{
|
|
OnActorUnregistered(Actor);
|
|
|
|
TInlineComponentArray<UActorComponent*> Components;
|
|
Actor->GetComponents(Components);
|
|
|
|
for (int32 Idx = 0; Idx < Components.Num(); Idx++)
|
|
{
|
|
OnComponentUnregistered(Components[Idx]);
|
|
}
|
|
}
|
|
}
|
|
|
|
void UNavigationSystemV1::UpdateNavOctreeElement(UObject* ElementOwner, INavRelevantInterface* ElementInterface, int32 UpdateFlags)
|
|
{
|
|
INC_DWORD_STAT(STAT_Navigation_UpdateNavOctree);
|
|
|
|
if (IsNavigationOctreeLocked())
|
|
{
|
|
UE_LOG(LogNavOctree, Log, TEXT("IGNORE(UpdateNavOctreeElement) %s"), *GetPathNameSafe(ElementOwner));
|
|
return;
|
|
}
|
|
else if (ElementOwner == nullptr)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// grab existing octree data
|
|
FBox CurrentBounds;
|
|
int32 CurrentFlags;
|
|
const bool bAlreadyExists = GetNavOctreeElementData(*ElementOwner, CurrentFlags, CurrentBounds);
|
|
|
|
// don't invalidate pending requests
|
|
UpdateFlags |= OctreeUpdate_Refresh;
|
|
|
|
// always try to unregister, even if element owner doesn't exists in octree (parent nodes)
|
|
UnregisterNavOctreeElement(ElementOwner, ElementInterface, UpdateFlags);
|
|
|
|
const FSetElementId RequestId = RegisterNavOctreeElement(ElementOwner, ElementInterface, UpdateFlags);
|
|
|
|
// add original data to pending registration request
|
|
// so it could be dirtied properly when system receive unregister request while actor is still queued
|
|
if (RequestId.IsValidId())
|
|
{
|
|
FNavigationDirtyElement& UpdateInfo = PendingOctreeUpdates[RequestId];
|
|
UpdateInfo.PrevFlags = CurrentFlags;
|
|
if (UpdateInfo.PrevBounds.IsValid)
|
|
{
|
|
// Is we have something stored already we want to
|
|
// sum it up, since we care about the whole bounding
|
|
// box of changes that potentially took place
|
|
UpdateInfo.PrevBounds += CurrentBounds;
|
|
}
|
|
else
|
|
{
|
|
UpdateInfo.PrevBounds = CurrentBounds;
|
|
}
|
|
UpdateInfo.bHasPrevData = bAlreadyExists;
|
|
}
|
|
|
|
UpdateNavOctreeParentChain(ElementOwner, /*bSkipElementOwnerUpdate=*/ true);
|
|
}
|
|
|
|
void UNavigationSystemV1::UpdateNavOctreeParentChain(UObject* ElementOwner, bool bSkipElementOwnerUpdate)
|
|
{
|
|
const int32 UpdateFlags = OctreeUpdate_ParentChain | OctreeUpdate_Refresh;
|
|
|
|
TArray<FWeakObjectPtr> ChildNodes;
|
|
OctreeChildNodesMap.MultiFind(ElementOwner, ChildNodes);
|
|
|
|
if (ChildNodes.Num() == 0)
|
|
{
|
|
if (bSkipElementOwnerUpdate == false)
|
|
{
|
|
INavRelevantInterface* ElementInterface = Cast<INavRelevantInterface>(ElementOwner);
|
|
UpdateNavOctreeElement(ElementOwner, ElementInterface, UpdateFlags);
|
|
}
|
|
return;
|
|
}
|
|
|
|
INavRelevantInterface* ElementInterface = Cast<INavRelevantInterface>(ElementOwner);
|
|
TArray<INavRelevantInterface*> ChildNavInterfaces;
|
|
ChildNavInterfaces.AddZeroed(ChildNodes.Num());
|
|
|
|
for (int32 Idx = 0; Idx < ChildNodes.Num(); Idx++)
|
|
{
|
|
if (ChildNodes[Idx].IsValid())
|
|
{
|
|
UObject* ChildNodeOb = ChildNodes[Idx].Get();
|
|
ChildNavInterfaces[Idx] = Cast<INavRelevantInterface>(ChildNodeOb);
|
|
UnregisterNavOctreeElement(ChildNodeOb, ChildNavInterfaces[Idx], UpdateFlags);
|
|
}
|
|
}
|
|
|
|
if (bSkipElementOwnerUpdate == false)
|
|
{
|
|
UnregisterNavOctreeElement(ElementOwner, ElementInterface, UpdateFlags);
|
|
RegisterNavOctreeElement(ElementOwner, ElementInterface, UpdateFlags);
|
|
}
|
|
|
|
for (int32 Idx = 0; Idx < ChildNodes.Num(); Idx++)
|
|
{
|
|
if (ChildNodes[Idx].IsValid())
|
|
{
|
|
RegisterNavOctreeElement(ChildNodes[Idx].Get(), ChildNavInterfaces[Idx], UpdateFlags);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool UNavigationSystemV1::UpdateNavOctreeElementBounds(UActorComponent* Comp, const FBox& NewBounds, const FBox& DirtyArea)
|
|
{
|
|
if (Comp == nullptr)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
const FOctreeElementId* ElementId = GetObjectsNavOctreeId(*Comp);
|
|
if (ElementId && ElementId->IsValidId())
|
|
{
|
|
NavOctree->UpdateNode(*ElementId, NewBounds);
|
|
|
|
// Add dirty area
|
|
if (DirtyArea.IsValid)
|
|
{
|
|
ElementId = GetObjectsNavOctreeId(*Comp);
|
|
if (ElementId && ElementId->IsValidId())
|
|
{
|
|
FNavigationOctreeElement& ElementData = NavOctree->GetElementById(*ElementId);
|
|
AddDirtyArea(DirtyArea, ElementData.Data->GetDirtyFlag());
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void UNavigationSystemV1::OnComponentRegistered(UActorComponent* Comp)
|
|
{
|
|
if (IsNavigationSystemStatic())
|
|
{
|
|
return;
|
|
}
|
|
|
|
SCOPE_CYCLE_COUNTER(STAT_DebugNavOctree);
|
|
INavRelevantInterface* NavInterface = Cast<INavRelevantInterface>(Comp);
|
|
if (NavInterface)
|
|
{
|
|
AActor* OwnerActor = Comp ? Comp->GetOwner() : NULL;
|
|
if (OwnerActor && OwnerActor->IsComponentRelevantForNavigation(Comp))
|
|
{
|
|
UNavigationSystemV1* NavSys = FNavigationSystem::GetCurrent<UNavigationSystemV1>(OwnerActor->GetWorld());
|
|
if (NavSys)
|
|
{
|
|
NavSys->RegisterNavOctreeElement(Comp, NavInterface, OctreeUpdate_Default);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void UNavigationSystemV1::OnComponentUnregistered(UActorComponent* Comp)
|
|
{
|
|
if (IsNavigationSystemStatic())
|
|
{
|
|
return;
|
|
}
|
|
|
|
SCOPE_CYCLE_COUNTER(STAT_DebugNavOctree);
|
|
INavRelevantInterface* NavInterface = Cast<INavRelevantInterface>(Comp);
|
|
if (NavInterface)
|
|
{
|
|
AActor* OwnerActor = Comp ? Comp->GetOwner() : NULL;
|
|
if (OwnerActor)
|
|
{
|
|
// skip IsComponentRelevantForNavigation check, it's only for adding new stuff
|
|
|
|
UNavigationSystemV1* NavSys = FNavigationSystem::GetCurrent<UNavigationSystemV1>(OwnerActor->GetWorld());
|
|
if (NavSys)
|
|
{
|
|
NavSys->UnregisterNavOctreeElement(Comp, NavInterface, OctreeUpdate_Default);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void UNavigationSystemV1::OnActorRegistered(AActor* Actor)
|
|
{
|
|
if (IsNavigationSystemStatic())
|
|
{
|
|
return;
|
|
}
|
|
|
|
SCOPE_CYCLE_COUNTER(STAT_DebugNavOctree);
|
|
INavRelevantInterface* NavInterface = Cast<INavRelevantInterface>(Actor);
|
|
if (NavInterface)
|
|
{
|
|
UNavigationSystemV1* NavSys = FNavigationSystem::GetCurrent<UNavigationSystemV1>(Actor->GetWorld());
|
|
if (NavSys)
|
|
{
|
|
NavSys->RegisterNavOctreeElement(Actor, NavInterface, OctreeUpdate_Default);
|
|
}
|
|
}
|
|
}
|
|
|
|
void UNavigationSystemV1::OnActorUnregistered(AActor* Actor)
|
|
{
|
|
if (IsNavigationSystemStatic())
|
|
{
|
|
return;
|
|
}
|
|
|
|
SCOPE_CYCLE_COUNTER(STAT_DebugNavOctree);
|
|
INavRelevantInterface* NavInterface = Cast<INavRelevantInterface>(Actor);
|
|
if (NavInterface)
|
|
{
|
|
UNavigationSystemV1* NavSys = FNavigationSystem::GetCurrent<UNavigationSystemV1>(Actor->GetWorld());
|
|
if (NavSys)
|
|
{
|
|
NavSys->UnregisterNavOctreeElement(Actor, NavInterface, OctreeUpdate_Default);
|
|
}
|
|
}
|
|
}
|
|
|
|
void UNavigationSystemV1::FindElementsInNavOctree(const FBox& QueryBox, const FNavigationOctreeFilter& Filter, TArray<FNavigationOctreeElement>& Elements)
|
|
{
|
|
if (NavOctree.IsValid() == false)
|
|
{
|
|
UE_LOG(LogNavigation, Warning, TEXT("UNavigationSystemV1::FindElementsInNavOctree gets called while NavOctree is null"));
|
|
return;
|
|
}
|
|
|
|
for (FNavigationOctree::TConstElementBoxIterator<> It(*NavOctree, QueryBox); It.HasPendingElements(); It.Advance())
|
|
{
|
|
const FNavigationOctreeElement& Element = It.GetCurrentElement();
|
|
if (Element.IsMatchingFilter(Filter))
|
|
{
|
|
Elements.Add(Element);
|
|
}
|
|
}
|
|
}
|
|
|
|
void UNavigationSystemV1::ReleaseInitialBuildingLock()
|
|
{
|
|
RemoveNavigationBuildLock(ENavigationBuildLock::InitialLock);
|
|
}
|
|
|
|
void UNavigationSystemV1::InitializeLevelCollisions()
|
|
{
|
|
if (IsNavigationSystemStatic())
|
|
{
|
|
bInitialLevelsAdded = true;
|
|
return;
|
|
}
|
|
|
|
UWorld* World = GetWorld();
|
|
if (!bInitialLevelsAdded && FNavigationSystem::GetCurrent<UNavigationSystemV1>(World) == this)
|
|
{
|
|
// Process all visible levels
|
|
const auto& Levels = World->GetLevels();
|
|
for (ULevel* Level : Levels)
|
|
{
|
|
if (Level->bIsVisible)
|
|
{
|
|
AddLevelCollisionToOctree(Level);
|
|
}
|
|
}
|
|
|
|
bInitialLevelsAdded = true;
|
|
}
|
|
}
|
|
|
|
#if WITH_EDITOR
|
|
void UNavigationSystemV1::UpdateLevelCollision(ULevel* InLevel)
|
|
{
|
|
if (InLevel != NULL)
|
|
{
|
|
UWorld* World = GetWorld();
|
|
OnLevelRemovedFromWorld(InLevel, World);
|
|
OnLevelAddedToWorld(InLevel, World);
|
|
}
|
|
}
|
|
|
|
void UNavigationSystemV1::OnEditorModeChanged(FEdMode* Mode, bool IsEntering)
|
|
{
|
|
if (Mode == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (IsEntering == false && Mode->GetID() == FBuiltinEditorModes::EM_Geometry)
|
|
{
|
|
// check if any of modified brushes belongs to an ANavMeshBoundsVolume
|
|
FEdModeGeometry* GeometryMode = (FEdModeGeometry*)Mode;
|
|
for (auto GeomObjectIt = GeometryMode->GeomObjectItor(); GeomObjectIt; GeomObjectIt++)
|
|
{
|
|
ANavMeshBoundsVolume* Volume = Cast<ANavMeshBoundsVolume>((*GeomObjectIt)->GetActualBrush());
|
|
if (Volume)
|
|
{
|
|
OnNavigationBoundsUpdated(Volume);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
void UNavigationSystemV1::OnNavigationBoundsUpdated(ANavMeshBoundsVolume* NavVolume)
|
|
{
|
|
if (NavVolume == nullptr || IsNavigationSystemStatic())
|
|
{
|
|
return;
|
|
}
|
|
|
|
FNavigationBoundsUpdateRequest UpdateRequest;
|
|
UpdateRequest.NavBounds.UniqueID = NavVolume->GetUniqueID();
|
|
UpdateRequest.NavBounds.AreaBox = NavVolume->GetComponentsBoundingBox(true);
|
|
UpdateRequest.NavBounds.Level = NavVolume->GetLevel();
|
|
UpdateRequest.NavBounds.SupportedAgents = NavVolume->SupportedAgents;
|
|
|
|
UpdateRequest.UpdateRequest = FNavigationBoundsUpdateRequest::Updated;
|
|
AddNavigationBoundsUpdateRequest(UpdateRequest);
|
|
}
|
|
|
|
void UNavigationSystemV1::OnNavigationBoundsAdded(ANavMeshBoundsVolume* NavVolume)
|
|
{
|
|
if (NavVolume == nullptr || IsNavigationSystemStatic())
|
|
{
|
|
return;
|
|
}
|
|
|
|
FNavigationBoundsUpdateRequest UpdateRequest;
|
|
UpdateRequest.NavBounds.UniqueID = NavVolume->GetUniqueID();
|
|
UpdateRequest.NavBounds.AreaBox = NavVolume->GetComponentsBoundingBox(true);
|
|
UpdateRequest.NavBounds.Level = NavVolume->GetLevel();
|
|
UpdateRequest.NavBounds.SupportedAgents = NavVolume->SupportedAgents;
|
|
|
|
UpdateRequest.UpdateRequest = FNavigationBoundsUpdateRequest::Added;
|
|
AddNavigationBoundsUpdateRequest(UpdateRequest);
|
|
}
|
|
|
|
void UNavigationSystemV1::OnNavigationBoundsRemoved(ANavMeshBoundsVolume* NavVolume)
|
|
{
|
|
if (NavVolume == nullptr || IsNavigationSystemStatic())
|
|
{
|
|
return;
|
|
}
|
|
|
|
FNavigationBoundsUpdateRequest UpdateRequest;
|
|
UpdateRequest.NavBounds.UniqueID = NavVolume->GetUniqueID();
|
|
UpdateRequest.NavBounds.AreaBox = NavVolume->GetComponentsBoundingBox(true);
|
|
UpdateRequest.NavBounds.Level = NavVolume->GetLevel();
|
|
UpdateRequest.NavBounds.SupportedAgents = NavVolume->SupportedAgents;
|
|
|
|
UpdateRequest.UpdateRequest = FNavigationBoundsUpdateRequest::Removed;
|
|
AddNavigationBoundsUpdateRequest(UpdateRequest);
|
|
}
|
|
|
|
void UNavigationSystemV1::AddNavigationBoundsUpdateRequest(const FNavigationBoundsUpdateRequest& UpdateRequest)
|
|
{
|
|
int32 ExistingIdx = PendingNavBoundsUpdates.IndexOfByPredicate([&](const FNavigationBoundsUpdateRequest& Element) {
|
|
return UpdateRequest.NavBounds.UniqueID == Element.NavBounds.UniqueID;
|
|
});
|
|
|
|
if (ExistingIdx != INDEX_NONE)
|
|
{
|
|
// catch the case where the bounds was removed and immediately re-added with the same bounds as before
|
|
// in that case, we can cancel any update at all
|
|
bool bCanCancelUpdate = false;
|
|
if (PendingNavBoundsUpdates[ExistingIdx].UpdateRequest == FNavigationBoundsUpdateRequest::Removed && UpdateRequest.UpdateRequest == FNavigationBoundsUpdateRequest::Added)
|
|
{
|
|
for (TSet<FNavigationBounds>::TConstIterator It(RegisteredNavBounds); It; ++It)
|
|
{
|
|
if (*It == UpdateRequest.NavBounds)
|
|
{
|
|
bCanCancelUpdate = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (bCanCancelUpdate)
|
|
{
|
|
PendingNavBoundsUpdates.RemoveAt(ExistingIdx);
|
|
}
|
|
else
|
|
{
|
|
// Overwrite any previous updates
|
|
PendingNavBoundsUpdates[ExistingIdx] = UpdateRequest;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PendingNavBoundsUpdates.Add(UpdateRequest);
|
|
}
|
|
}
|
|
|
|
void UNavigationSystemV1::PerformNavigationBoundsUpdate(const TArray<FNavigationBoundsUpdateRequest>& UpdateRequests)
|
|
{
|
|
// NOTE: we used to create missing nav data first, before updating nav bounds,
|
|
// but some nav data classes (like RecastNavMesh) may depend on the nav bounds
|
|
// being already known at the moment of creation or serialization, so it makes more
|
|
// sense to update bounds first
|
|
|
|
// Create list of areas that needs to be updated
|
|
TArray<FBox> UpdatedAreas;
|
|
for (const FNavigationBoundsUpdateRequest& Request : UpdateRequests)
|
|
{
|
|
FSetElementId ExistingElementId = RegisteredNavBounds.FindId(Request.NavBounds);
|
|
|
|
switch (Request.UpdateRequest)
|
|
{
|
|
case FNavigationBoundsUpdateRequest::Removed:
|
|
{
|
|
if (ExistingElementId.IsValidId())
|
|
{
|
|
UpdatedAreas.Add(RegisteredNavBounds[ExistingElementId].AreaBox);
|
|
RegisteredNavBounds.Remove(ExistingElementId);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case FNavigationBoundsUpdateRequest::Added:
|
|
case FNavigationBoundsUpdateRequest::Updated:
|
|
{
|
|
if (ExistingElementId.IsValidId())
|
|
{
|
|
const FBox ExistingBox = RegisteredNavBounds[ExistingElementId].AreaBox;
|
|
const bool bSameArea = (Request.NavBounds.AreaBox == ExistingBox);
|
|
if (!bSameArea)
|
|
{
|
|
UpdatedAreas.Add(ExistingBox);
|
|
}
|
|
|
|
// always assign new bounds data, it may have different properties (like supported agents)
|
|
RegisteredNavBounds[ExistingElementId] = Request.NavBounds;
|
|
}
|
|
else
|
|
{
|
|
AddNavigationBounds(Request.NavBounds);
|
|
}
|
|
|
|
UpdatedAreas.Add(Request.NavBounds.AreaBox);
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!IsNavigationBuildingLocked())
|
|
{
|
|
if (UpdatedAreas.Num())
|
|
{
|
|
for (ANavigationData* NavData : NavDataSet)
|
|
{
|
|
if (NavData)
|
|
{
|
|
NavData->OnNavigationBoundsChanged();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Propagate to generators areas that needs to be updated
|
|
AddDirtyAreas(UpdatedAreas, ENavigationDirtyFlag::All | ENavigationDirtyFlag::NavigationBounds);
|
|
}
|
|
|
|
// I'm not sure why we even do the following as part of this function
|
|
// @TODO investigate if we can extract it into a separate function and
|
|
// call it directly
|
|
if (NavDataSet.Num() == 0)
|
|
{
|
|
//TODO: will hitch when user places first navigation volume in the world
|
|
|
|
if (NavDataRegistrationQueue.Num() > 0)
|
|
{
|
|
ProcessRegistrationCandidates();
|
|
}
|
|
|
|
if (NavDataSet.Num() == 0 && bAutoCreateNavigationData == true)
|
|
{
|
|
SpawnMissingNavigationData();
|
|
ProcessRegistrationCandidates();
|
|
}
|
|
|
|
ConditionalPopulateNavOctree();
|
|
}
|
|
}
|
|
|
|
void UNavigationSystemV1::AddNavigationBounds(const FNavigationBounds& NewBounds)
|
|
{
|
|
RegisteredNavBounds.Add(NewBounds);
|
|
}
|
|
|
|
void UNavigationSystemV1::GatherNavigationBounds()
|
|
{
|
|
// Gather all available navigation bounds
|
|
RegisteredNavBounds.Empty();
|
|
for (TActorIterator<ANavMeshBoundsVolume> It(GetWorld()); It; ++It)
|
|
{
|
|
ANavMeshBoundsVolume* V = (*It);
|
|
if (V != nullptr && !V->IsPendingKill())
|
|
{
|
|
FNavigationBounds NavBounds;
|
|
NavBounds.UniqueID = V->GetUniqueID();
|
|
NavBounds.AreaBox = V->GetComponentsBoundingBox(true);
|
|
NavBounds.Level = V->GetLevel();
|
|
NavBounds.SupportedAgents = V->SupportedAgents;
|
|
|
|
AddNavigationBounds(NavBounds);
|
|
}
|
|
}
|
|
}
|
|
|
|
void UNavigationSystemV1::Build()
|
|
{
|
|
UWorld* World = GetWorld();
|
|
if (!World)
|
|
{
|
|
UE_LOG(LogNavigation, Error, TEXT("Unable to build navigation due to missing World pointer"));
|
|
return;
|
|
}
|
|
|
|
FNavigationSystem::DiscardNavigationDataChunks(*World);
|
|
|
|
const bool bHasWork = IsThereAnywhereToBuildNavigation();
|
|
const bool bLockedIgnoreEditor = (NavBuildingLockFlags & ~ENavigationBuildLock::NoUpdateInEditor) != 0;
|
|
if (!bHasWork || bLockedIgnoreEditor)
|
|
{
|
|
return;
|
|
}
|
|
|
|
const double BuildStartTime = FPlatformTime::Seconds();
|
|
|
|
if (bAutoCreateNavigationData == true
|
|
#if WITH_EDITOR
|
|
|| OperationMode == FNavigationSystemRunMode::EditorMode
|
|
#endif // WITH_EDITOR
|
|
)
|
|
{
|
|
SpawnMissingNavigationData();
|
|
}
|
|
|
|
// make sure freshly created navigation instances are registered before we try to build them
|
|
ProcessRegistrationCandidates();
|
|
|
|
// and now iterate through all registered and just start building them
|
|
RebuildAll();
|
|
|
|
// Block until build is finished
|
|
for (ANavigationData* NavData : NavDataSet)
|
|
{
|
|
if (NavData)
|
|
{
|
|
NavData->EnsureBuildCompletion();
|
|
}
|
|
}
|
|
|
|
#if !UE_BUILD_SHIPPING
|
|
// no longer report that navmesh needs to be rebuild
|
|
bDirtyAreasReportedWhileAccumulationLocked = false;
|
|
#endif // !UE_BUILD_SHIPPING
|
|
|
|
UE_LOG(LogNavigation, Display, TEXT("UNavigationSystemV1::Build total execution time: %.5f"), float(FPlatformTime::Seconds() - BuildStartTime));
|
|
}
|
|
|
|
void UNavigationSystemV1::CancelBuild()
|
|
{
|
|
for (ANavigationData* NavData : NavDataSet)
|
|
{
|
|
if (NavData)
|
|
{
|
|
if (NavData->GetGenerator())
|
|
{
|
|
NavData->GetGenerator()->CancelBuild();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void UNavigationSystemV1::SpawnMissingNavigationData()
|
|
{
|
|
const int32 SupportedAgentsCount = SupportedAgents.Num();
|
|
check(SupportedAgentsCount >= 0);
|
|
|
|
// Bit array might be a bit of an overkill here, but this function will be called very rarely
|
|
TBitArray<> AlreadyInstantiated(false, SupportedAgentsCount);
|
|
uint8 NumberFound = 0;
|
|
UWorld* NavWorld = GetWorld();
|
|
|
|
// 1. check whether any of required navigation data has already been instantiated
|
|
for (TActorIterator<ANavigationData> It(NavWorld); It && NumberFound < SupportedAgentsCount; ++It)
|
|
{
|
|
ANavigationData* Nav = (*It);
|
|
if (Nav != nullptr
|
|
&& Nav->IsPendingKill() == false
|
|
// mz@todo the 'is level in' condition is temporary
|
|
&& (Nav->GetTypedOuter<UWorld>() == NavWorld || NavWorld->GetLevels().Contains(Nav->GetLevel())))
|
|
{
|
|
// find out which one it is
|
|
for (int32 AgentIndex = 0; AgentIndex < SupportedAgentsCount; ++AgentIndex)
|
|
{
|
|
if (AlreadyInstantiated[AgentIndex] == false
|
|
&& Nav->GetClass() == SupportedAgents[AgentIndex].NavigationDataClass
|
|
&& Nav->DoesSupportAgent(SupportedAgents[AgentIndex]) == true)
|
|
{
|
|
AlreadyInstantiated[AgentIndex] = true;
|
|
++NumberFound;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 2. for any not already instantiated navigation data call creator functions
|
|
if (NumberFound < SupportedAgentsCount)
|
|
{
|
|
for (int32 AgentIndex = 0; AgentIndex < SupportedAgentsCount; ++AgentIndex)
|
|
{
|
|
const FNavDataConfig& NavConfig = SupportedAgents[AgentIndex];
|
|
if (AlreadyInstantiated[AgentIndex] == false && NavConfig.NavigationDataClass != nullptr)
|
|
{
|
|
bool bHandled = false;
|
|
|
|
const ANavigationData* NavDataCDO = NavConfig.NavigationDataClass->GetDefaultObject<ANavigationData>();
|
|
if (NavDataCDO == nullptr || !NavDataCDO->CanSpawnOnRebuild())
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (NavWorld->WorldType != EWorldType::Editor && NavDataCDO->GetRuntimeGenerationMode() == ERuntimeGenerationType::Static)
|
|
{
|
|
// if we're not in the editor, and specified navigation class is configured
|
|
// to be static, then we don't want to create an instance
|
|
UE_LOG(LogNavigation, Log, TEXT("Not spawning navigation data for %s since indivated NavigationData type is not configured for dynamic generation")
|
|
, *NavConfig.Name.ToString());
|
|
continue;
|
|
}
|
|
|
|
ANavigationData* Instance = CreateNavigationDataInstance(NavConfig);
|
|
if (Instance)
|
|
{
|
|
RequestRegistration(Instance);
|
|
}
|
|
else
|
|
{
|
|
UE_LOG(LogNavigation, Warning, TEXT("Was not able to create navigation data for SupportedAgent[%d]: %s"), AgentIndex, *NavConfig.Name.ToString());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (MainNavData == nullptr || MainNavData->IsPendingKillPending())
|
|
{
|
|
// update
|
|
MainNavData = GetDefaultNavDataInstance(FNavigationSystem::DontCreate);
|
|
}
|
|
}
|
|
|
|
ANavigationData* UNavigationSystemV1::CreateNavigationDataInstance(const FNavDataConfig& NavConfig)
|
|
{
|
|
UWorld* World = GetWorld();
|
|
check(World);
|
|
|
|
FActorSpawnParameters SpawnInfo;
|
|
if (bSpawnNavDataInNavBoundsLevel && RegisteredNavBounds.Num() > 0)
|
|
{
|
|
// pick the first valid level
|
|
for (const FNavigationBounds& Bounds : RegisteredNavBounds)
|
|
{
|
|
if (Bounds.Level.IsValid())
|
|
{
|
|
SpawnInfo.OverrideLevel = Bounds.Level.Get();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (SpawnInfo.OverrideLevel == nullptr)
|
|
{
|
|
SpawnInfo.OverrideLevel = World->PersistentLevel;
|
|
}
|
|
ANavigationData* Instance = World->SpawnActor<ANavigationData>(*NavConfig.NavigationDataClass, SpawnInfo);
|
|
|
|
if (Instance != NULL)
|
|
{
|
|
Instance->SetConfig(NavConfig);
|
|
if (NavConfig.Name != NAME_None)
|
|
{
|
|
FString StrName = FString::Printf(TEXT("%s-%s"), *(Instance->GetFName().GetPlainNameString()), *(NavConfig.Name.ToString()));
|
|
// temporary solution to make sure we don't try to change name while there's already
|
|
// an object with this name
|
|
UObject* ExistingObject = StaticFindObject(/*Class=*/ NULL, Instance->GetOuter(), *StrName, true);
|
|
if (ExistingObject != NULL)
|
|
{
|
|
ANavigationData* ExistingNavigationData = Cast<ANavigationData>(ExistingObject);
|
|
if (ExistingNavigationData)
|
|
{
|
|
UnregisterNavData(ExistingNavigationData);
|
|
AgentToNavDataMap.Remove(ExistingNavigationData->GetConfig());
|
|
}
|
|
|
|
ExistingObject->Rename(NULL, NULL, REN_DontCreateRedirectors | REN_ForceGlobalUnique | REN_DoNotDirty | REN_NonTransactional | REN_ForceNoResetLoaders);
|
|
}
|
|
|
|
// Set descriptive name
|
|
Instance->Rename(*StrName, NULL, REN_DoNotDirty | REN_ForceNoResetLoaders);
|
|
#if WITH_EDITOR
|
|
if (World->WorldType == EWorldType::Editor)
|
|
{
|
|
const bool bMarkDirty = false;
|
|
Instance->SetActorLabel(StrName, bMarkDirty);
|
|
}
|
|
#endif // WITH_EDITOR
|
|
}
|
|
}
|
|
|
|
return Instance;
|
|
}
|
|
|
|
void UNavigationSystemV1::OnPIEStart()
|
|
{
|
|
bIsPIEActive = true;
|
|
// no updates for editor world while PIE is active
|
|
const UWorld* MyWorld = GetWorld();
|
|
if (MyWorld && !MyWorld->IsGameWorld())
|
|
{
|
|
bAsyncBuildPaused = true;
|
|
AddNavigationBuildLock(ENavigationBuildLock::NoUpdateInEditor);
|
|
}
|
|
}
|
|
|
|
void UNavigationSystemV1::OnPIEEnd()
|
|
{
|
|
bIsPIEActive = false;
|
|
const UWorld* MyWorld = GetWorld();
|
|
if (MyWorld && !MyWorld->IsGameWorld())
|
|
{
|
|
bAsyncBuildPaused = false;
|
|
// there's no need to request while navigation rebuilding just because PIE has ended
|
|
RemoveNavigationBuildLock(ENavigationBuildLock::NoUpdateInEditor, /*bSkipRebuildInEditor=*/true);
|
|
}
|
|
}
|
|
|
|
void UNavigationSystemV1::RemoveNavigationBuildLock(uint8 Flags, bool bSkipRebuildInEditor)
|
|
{
|
|
const bool bWasLocked = IsNavigationBuildingLocked();
|
|
|
|
NavBuildingLockFlags &= ~Flags;
|
|
|
|
const bool bIsLocked = IsNavigationBuildingLocked();
|
|
const bool bSkipRebuild = (OperationMode == FNavigationSystemRunMode::EditorMode) && bSkipRebuildInEditor;
|
|
if (bWasLocked && !bIsLocked && !bSkipRebuild)
|
|
{
|
|
RebuildAll();
|
|
}
|
|
}
|
|
|
|
void UNavigationSystemV1::RebuildAll(bool bIsLoadTime)
|
|
{
|
|
const bool bIsInGame = GetWorld()->IsGameWorld();
|
|
|
|
GatherNavigationBounds();
|
|
|
|
// make sure that octree is up to date
|
|
for (TSet<FNavigationDirtyElement>::TIterator It(PendingOctreeUpdates); It; ++It)
|
|
{
|
|
AddElementToNavOctree(*It);
|
|
}
|
|
PendingOctreeUpdates.Empty(32);
|
|
|
|
// discard all pending dirty areas, we are going to rebuild navmesh anyway
|
|
DirtyAreas.Reset();
|
|
PendingNavBoundsUpdates.Reset();
|
|
#if !UE_BUILD_SHIPPING
|
|
bDirtyAreasReportedWhileAccumulationLocked = false;
|
|
#endif // !UE_BUILD_SHIPPING
|
|
|
|
//
|
|
for (int32 NavDataIndex = 0; NavDataIndex < NavDataSet.Num(); ++NavDataIndex)
|
|
{
|
|
ANavigationData* NavData = NavDataSet[NavDataIndex];
|
|
|
|
if (NavData && (!bIsLoadTime || NavData->NeedsRebuildOnLoad()) && (!bIsInGame || NavData->SupportsRuntimeGeneration()))
|
|
{
|
|
NavData->RebuildAll();
|
|
}
|
|
}
|
|
}
|
|
|
|
bool UNavigationSystemV1::IsNavigationBuildInProgress(bool bCheckDirtyToo)
|
|
{
|
|
bool bRet = false;
|
|
|
|
if (NavDataSet.Num() == 0)
|
|
{
|
|
// @todo this is wrong! Should not need to create a navigation data instance in a "getter" like function
|
|
// update nav data. If none found this is the place to create one
|
|
GetDefaultNavDataInstance(FNavigationSystem::DontCreate);
|
|
}
|
|
|
|
for (int32 NavDataIndex = 0; NavDataIndex < NavDataSet.Num(); ++NavDataIndex)
|
|
{
|
|
ANavigationData* NavData = NavDataSet[NavDataIndex];
|
|
if (NavData != NULL && NavData->GetGenerator() != NULL
|
|
&& NavData->GetGenerator()->IsBuildInProgress(bCheckDirtyToo) == true)
|
|
{
|
|
bRet = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
void UNavigationSystemV1::OnNavigationGenerationFinished(ANavigationData& NavData)
|
|
{
|
|
OnNavigationGenerationFinishedDelegate.Broadcast(&NavData);
|
|
}
|
|
|
|
int32 UNavigationSystemV1::GetNumRemainingBuildTasks() const
|
|
{
|
|
int32 NumTasks = 0;
|
|
|
|
for (ANavigationData* NavData : NavDataSet)
|
|
{
|
|
if (NavData && NavData->GetGenerator())
|
|
{
|
|
NumTasks+= NavData->GetGenerator()->GetNumRemaningBuildTasks();
|
|
}
|
|
}
|
|
|
|
return NumTasks;
|
|
}
|
|
|
|
int32 UNavigationSystemV1::GetNumRunningBuildTasks() const
|
|
{
|
|
int32 NumTasks = 0;
|
|
|
|
for (ANavigationData* NavData : NavDataSet)
|
|
{
|
|
if (NavData && NavData->GetGenerator())
|
|
{
|
|
NumTasks+= NavData->GetGenerator()->GetNumRunningBuildTasks();
|
|
}
|
|
}
|
|
|
|
return NumTasks;
|
|
}
|
|
|
|
void UNavigationSystemV1::OnLevelAddedToWorld(ULevel* InLevel, UWorld* InWorld)
|
|
{
|
|
if ((IsNavigationSystemStatic() == false) && (InWorld == GetWorld()))
|
|
{
|
|
AddLevelCollisionToOctree(InLevel);
|
|
|
|
if (!InLevel->IsPersistentLevel())
|
|
{
|
|
for (ANavigationData* NavData : NavDataSet)
|
|
{
|
|
if (NavData)
|
|
{
|
|
NavData->OnStreamingLevelAdded(InLevel, InWorld);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void UNavigationSystemV1::OnLevelRemovedFromWorld(ULevel* InLevel, UWorld* InWorld)
|
|
{
|
|
if ((IsNavigationSystemStatic() == false) && (InWorld == GetWorld()))
|
|
{
|
|
RemoveLevelCollisionFromOctree(InLevel);
|
|
|
|
if (InLevel && !InLevel->IsPersistentLevel())
|
|
{
|
|
for (int32 DataIndex = NavDataSet.Num() - 1; DataIndex >= 0; --DataIndex)
|
|
{
|
|
ANavigationData* NavData = NavDataSet[DataIndex];
|
|
if (NavData)
|
|
{
|
|
if (NavData->GetLevel() != InLevel)
|
|
{
|
|
NavData->OnStreamingLevelRemoved(InLevel, InWorld);
|
|
}
|
|
else
|
|
{
|
|
NavDataSet.RemoveAt(DataIndex, 1, /*bAllowShrinking=*/false);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void UNavigationSystemV1::AddLevelCollisionToOctree(ULevel* Level)
|
|
{
|
|
#if WITH_RECAST
|
|
if (Level && NavOctree.IsValid() &&
|
|
NavOctree->GetNavGeometryStoringMode() == FNavigationOctree::StoreNavGeometry)
|
|
{
|
|
const TArray<FVector>* LevelGeom = Level->GetStaticNavigableGeometry();
|
|
const FOctreeElementId* ElementId = GetObjectsNavOctreeId(*Level);
|
|
|
|
if (!ElementId && LevelGeom && LevelGeom->Num() > 0)
|
|
{
|
|
FNavigationOctreeElement BSPElem(*Level);
|
|
FRecastNavMeshGenerator::ExportVertexSoupGeometry(*LevelGeom, *BSPElem.Data);
|
|
|
|
const auto& Bounds = BSPElem.Data->Bounds;
|
|
if (!Bounds.GetExtent().IsNearlyZero())
|
|
{
|
|
NavOctree->AddNode(Level, NULL, Bounds, BSPElem);
|
|
AddDirtyArea(Bounds, ENavigationDirtyFlag::All);
|
|
|
|
UE_LOG(LogNavOctree, Log, TEXT("ADD %s"), *GetNameSafe(Level));
|
|
}
|
|
}
|
|
}
|
|
#endif// WITH_RECAST
|
|
}
|
|
|
|
void UNavigationSystemV1::RemoveLevelCollisionFromOctree(ULevel* Level)
|
|
{
|
|
if (Level && NavOctree.IsValid())
|
|
{
|
|
const FOctreeElementId* ElementId = GetObjectsNavOctreeId(*Level);
|
|
UE_LOG(LogNavOctree, Log, TEXT("UNREG %s %s"), *GetNameSafe(Level), ElementId ? TEXT("[exists]") : TEXT(""));
|
|
|
|
if (ElementId != NULL)
|
|
{
|
|
if (NavOctree->IsValidElementId(*ElementId))
|
|
{
|
|
// mark area occupied by given actor as dirty
|
|
FNavigationOctreeElement& ElementData = NavOctree->GetElementById(*ElementId);
|
|
AddDirtyArea(ElementData.Bounds.GetBox(), ENavigationDirtyFlag::All);
|
|
}
|
|
|
|
NavOctree->RemoveNode(*ElementId);
|
|
RemoveObjectsNavOctreeId(*Level);
|
|
}
|
|
}
|
|
}
|
|
|
|
void UNavigationSystemV1::OnPostLoadMap(UWorld*)
|
|
{
|
|
UE_LOG(LogNavigation, Log, TEXT("UNavigationSystemV1::OnPostLoadMap"));
|
|
|
|
// if map has been loaded and there are some navigation bounds volumes
|
|
// then create appropriate navigation structured
|
|
ANavigationData* NavData = GetDefaultNavDataInstance(FNavigationSystem::DontCreate);
|
|
|
|
// Do this if there's currently no navigation
|
|
if (NavData == NULL && bAutoCreateNavigationData == true && IsThereAnywhereToBuildNavigation() == true)
|
|
{
|
|
NavData = GetDefaultNavDataInstance(FNavigationSystem::Create);
|
|
}
|
|
}
|
|
|
|
#if WITH_EDITOR
|
|
void UNavigationSystemV1::OnActorMoved(AActor* Actor)
|
|
{
|
|
if (Cast<ANavMeshBoundsVolume>(Actor) != NULL)
|
|
{
|
|
OnNavigationBoundsUpdated((ANavMeshBoundsVolume*)Actor);
|
|
}
|
|
}
|
|
#endif // WITH_EDITOR
|
|
|
|
void UNavigationSystemV1::OnNavigationDirtied(const FBox& Bounds)
|
|
{
|
|
AddDirtyArea(Bounds, ENavigationDirtyFlag::All);
|
|
}
|
|
|
|
#if WITH_HOT_RELOAD
|
|
void UNavigationSystemV1::OnHotReload(bool bWasTriggeredAutomatically)
|
|
{
|
|
if (RequiresNavOctree() && NavOctree.IsValid() == false)
|
|
{
|
|
ConditionalPopulateNavOctree();
|
|
|
|
if (bInitialBuildingLocked)
|
|
{
|
|
RemoveNavigationBuildLock(ENavigationBuildLock::InitialLock, /*bSkipRebuildInEditor=*/true);
|
|
}
|
|
}
|
|
}
|
|
#endif // WITH_HOT_RELOAD
|
|
|
|
void UNavigationSystemV1::CleanUp(FNavigationSystem::ECleanupMode Mode)
|
|
{
|
|
UE_LOG(LogNavigation, Log, TEXT("UNavigationSystemV1::CleanUp"));
|
|
|
|
#if WITH_EDITOR
|
|
if (GIsEditor && GEngine)
|
|
{
|
|
GEngine->OnActorMoved().RemoveAll(this);
|
|
}
|
|
#endif // WITH_EDITOR
|
|
|
|
FCoreUObjectDelegates::PostLoadMapWithWorld.RemoveAll(this);
|
|
UNavigationSystemV1::NavigationDirtyEvent.RemoveAll(this);
|
|
FWorldDelegates::LevelAddedToWorld.RemoveAll(this);
|
|
FWorldDelegates::LevelRemovedFromWorld.RemoveAll(this);
|
|
|
|
#if WITH_HOT_RELOAD
|
|
if (IHotReloadInterface* HotReloadSupport = FModuleManager::GetModulePtr<IHotReloadInterface>("HotReload"))
|
|
{
|
|
HotReloadSupport->OnHotReload().Remove(HotReloadDelegateHandle);
|
|
}
|
|
#endif
|
|
|
|
DestroyNavOctree();
|
|
|
|
SetCrowdManager(NULL);
|
|
|
|
NavDataSet.Reset();
|
|
|
|
// reset unique link Id for new map
|
|
const UWorld* MyWorld = (Mode == FNavigationSystem::ECleanupMode::CleanupWithWorld) ? GetWorld() : NULL;
|
|
if (MyWorld && (MyWorld->WorldType == EWorldType::Game || MyWorld->WorldType == EWorldType::Editor))
|
|
{
|
|
INavLinkCustomInterface::NextUniqueId = 1;
|
|
}
|
|
}
|
|
|
|
void UNavigationSystemV1::DestroyNavOctree()
|
|
{
|
|
if (NavOctree.IsValid())
|
|
{
|
|
NavOctree->Destroy();
|
|
NavOctree = NULL;
|
|
}
|
|
|
|
ObjectToOctreeId.Empty();
|
|
}
|
|
|
|
bool UNavigationSystemV1::RequiresNavOctree() const
|
|
{
|
|
UWorld* World = GetWorld();
|
|
check(World);
|
|
|
|
// We always require navoctree in editor worlds
|
|
if (!World->IsGameWorld())
|
|
{
|
|
return true;
|
|
}
|
|
|
|
for (ANavigationData* NavData : NavDataSet)
|
|
{
|
|
if (NavData && NavData->SupportsRuntimeGeneration())
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
ERuntimeGenerationType UNavigationSystemV1::GetRuntimeGenerationType() const
|
|
{
|
|
UWorld* World = GetWorld();
|
|
check(World);
|
|
|
|
// We always use ERuntimeGenerationType::Dynamic in editor worlds
|
|
if (!World->IsGameWorld())
|
|
{
|
|
return ERuntimeGenerationType::Dynamic;
|
|
}
|
|
|
|
ERuntimeGenerationType RuntimeGenerationType = ERuntimeGenerationType::Static;
|
|
|
|
for (ANavigationData* NavData : NavDataSet)
|
|
{
|
|
if (NavData && NavData->GetRuntimeGenerationMode() > RuntimeGenerationType)
|
|
{
|
|
RuntimeGenerationType = NavData->GetRuntimeGenerationMode();
|
|
}
|
|
}
|
|
|
|
return RuntimeGenerationType;
|
|
}
|
|
|
|
//----------------------------------------------------------------------//
|
|
// Blueprint functions
|
|
//----------------------------------------------------------------------//
|
|
UNavigationSystemV1* UNavigationSystemV1::GetNavigationSystem(UObject* WorldContextObject)
|
|
{
|
|
return GetCurrent(WorldContextObject);
|
|
}
|
|
|
|
bool UNavigationSystemV1::K2_ProjectPointToNavigation(UObject* WorldContextObject, const FVector& Point, FVector& ProjectedLocation, ANavigationData* NavData, TSubclassOf<UNavigationQueryFilter> FilterClass, const FVector QueryExtent)
|
|
{
|
|
UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::LogAndReturnNull);
|
|
UNavigationSystemV1* NavSys = FNavigationSystem::GetCurrent<UNavigationSystemV1>(World);
|
|
|
|
ProjectedLocation = Point;
|
|
bool bResult = false;
|
|
|
|
if (NavSys)
|
|
{
|
|
FNavLocation OutNavLocation;
|
|
ANavigationData* UseNavData = NavData ? NavData : NavSys->GetDefaultNavDataInstance(FNavigationSystem::DontCreate);
|
|
if (UseNavData)
|
|
{
|
|
bResult = NavSys->ProjectPointToNavigation(Point, OutNavLocation, QueryExtent, NavData
|
|
, UNavigationQueryFilter::GetQueryFilter(*UseNavData, WorldContextObject, FilterClass));
|
|
ProjectedLocation = OutNavLocation.Location;
|
|
}
|
|
}
|
|
|
|
return bResult;
|
|
}
|
|
|
|
bool UNavigationSystemV1::K2_GetRandomReachablePointInRadius(UObject* WorldContextObject, const FVector& Origin, FVector& RandomLocation, float Radius, ANavigationData* NavData, TSubclassOf<UNavigationQueryFilter> FilterClass)
|
|
{
|
|
FNavLocation RandomPoint(Origin);
|
|
bool bResult = false;
|
|
|
|
UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::LogAndReturnNull);
|
|
UNavigationSystemV1* NavSys = FNavigationSystem::GetCurrent<UNavigationSystemV1>(World);
|
|
if (NavSys)
|
|
{
|
|
ANavigationData* UseNavData = NavData ? NavData : NavSys->GetDefaultNavDataInstance(FNavigationSystem::DontCreate);
|
|
if (UseNavData)
|
|
{
|
|
bResult = NavSys->GetRandomReachablePointInRadius(Origin, Radius, RandomPoint, UseNavData, UNavigationQueryFilter::GetQueryFilter(*UseNavData, WorldContextObject, FilterClass));
|
|
RandomLocation = RandomPoint.Location;
|
|
}
|
|
}
|
|
|
|
return bResult;
|
|
}
|
|
|
|
bool UNavigationSystemV1::K2_GetRandomPointInNavigableRadius(UObject* WorldContextObject, const FVector& Origin, FVector& RandomLocation, float Radius, ANavigationData* NavData, TSubclassOf<UNavigationQueryFilter> FilterClass)
|
|
{
|
|
FNavLocation RandomPoint(Origin);
|
|
bool bResult = false;
|
|
|
|
UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::LogAndReturnNull);
|
|
UNavigationSystemV1* NavSys = FNavigationSystem::GetCurrent<UNavigationSystemV1>(World);
|
|
if (NavSys)
|
|
{
|
|
ANavigationData* UseNavData = NavData ? NavData : NavSys->GetDefaultNavDataInstance(FNavigationSystem::DontCreate);
|
|
if (UseNavData)
|
|
{
|
|
bResult = NavSys->GetRandomPointInNavigableRadius(Origin, Radius, RandomPoint, UseNavData, UNavigationQueryFilter::GetQueryFilter(*UseNavData, WorldContextObject, FilterClass));
|
|
RandomLocation = RandomPoint.Location;
|
|
}
|
|
}
|
|
|
|
return bResult;
|
|
}
|
|
|
|
ENavigationQueryResult::Type UNavigationSystemV1::GetPathCost(UObject* WorldContextObject, const FVector& PathStart, const FVector& PathEnd, float& OutPathCost, ANavigationData* NavData, TSubclassOf<UNavigationQueryFilter> FilterClass)
|
|
{
|
|
UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::LogAndReturnNull);
|
|
UNavigationSystemV1* NavSys = FNavigationSystem::GetCurrent<UNavigationSystemV1>(World);
|
|
if (NavSys)
|
|
{
|
|
ANavigationData* UseNavData = NavData ? NavData : NavSys->GetDefaultNavDataInstance(FNavigationSystem::DontCreate);
|
|
if (UseNavData)
|
|
{
|
|
return NavSys->GetPathCost(PathStart, PathEnd, OutPathCost, UseNavData, UNavigationQueryFilter::GetQueryFilter(*UseNavData, WorldContextObject, FilterClass));
|
|
}
|
|
}
|
|
|
|
return ENavigationQueryResult::Error;
|
|
}
|
|
|
|
ENavigationQueryResult::Type UNavigationSystemV1::GetPathLength(UObject* WorldContextObject, const FVector& PathStart, const FVector& PathEnd, float& OutPathLength, ANavigationData* NavData, TSubclassOf<UNavigationQueryFilter> FilterClass)
|
|
{
|
|
float PathLength = 0.f;
|
|
|
|
UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::LogAndReturnNull);
|
|
UNavigationSystemV1* NavSys = FNavigationSystem::GetCurrent<UNavigationSystemV1>(World);
|
|
if (NavSys)
|
|
{
|
|
ANavigationData* UseNavData = NavData ? NavData : NavSys->GetDefaultNavDataInstance(FNavigationSystem::DontCreate);
|
|
if (UseNavData)
|
|
{
|
|
return NavSys->GetPathLength(PathStart, PathEnd, OutPathLength, UseNavData, UNavigationQueryFilter::GetQueryFilter(*UseNavData, WorldContextObject, FilterClass));
|
|
}
|
|
}
|
|
|
|
return ENavigationQueryResult::Error;
|
|
}
|
|
|
|
bool UNavigationSystemV1::IsNavigationBeingBuilt(UObject* WorldContextObject)
|
|
{
|
|
UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::LogAndReturnNull);
|
|
UNavigationSystemV1* NavSys = FNavigationSystem::GetCurrent<UNavigationSystemV1>(World);
|
|
|
|
if (NavSys && !NavSys->IsNavigationBuildingPermanentlyLocked())
|
|
{
|
|
return NavSys->HasDirtyAreasQueued() || NavSys->IsNavigationBuildInProgress();
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool UNavigationSystemV1::IsNavigationBeingBuiltOrLocked(UObject* WorldContextObject)
|
|
{
|
|
UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::LogAndReturnNull);
|
|
UNavigationSystemV1* NavSys = FNavigationSystem::GetCurrent<UNavigationSystemV1>(World);
|
|
|
|
if (NavSys)
|
|
{
|
|
return NavSys->IsNavigationBuildingLocked() || NavSys->HasDirtyAreasQueued() || NavSys->IsNavigationBuildInProgress();
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//----------------------------------------------------------------------//
|
|
// HACKS!!!
|
|
//----------------------------------------------------------------------//
|
|
bool UNavigationSystemV1::ShouldGeneratorRun(const FNavDataGenerator* Generator) const
|
|
{
|
|
if (Generator != NULL && (IsNavigationSystemStatic() == false))
|
|
{
|
|
for (int32 NavDataIndex = 0; NavDataIndex < NavDataSet.Num(); ++NavDataIndex)
|
|
{
|
|
ANavigationData* NavData = NavDataSet[NavDataIndex];
|
|
if (NavData != NULL && NavData->GetGenerator() == Generator)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool UNavigationSystemV1::HandleCycleNavDrawnCommand( const TCHAR* Cmd, FOutputDevice& Ar )
|
|
{
|
|
CycleNavigationDataDrawn();
|
|
|
|
return true;
|
|
}
|
|
|
|
bool UNavigationSystemV1::HandleCountNavMemCommand()
|
|
{
|
|
UE_LOG(LogNavigation, Warning, TEXT("Logging NavigationSystem memory usage:"));
|
|
|
|
if (NavOctree.IsValid())
|
|
{
|
|
UE_LOG(LogNavigation, Warning, TEXT("NavOctree memory: %d"), NavOctree->GetSizeBytes());
|
|
}
|
|
|
|
for (int32 NavDataIndex = 0; NavDataIndex < NavDataSet.Num(); ++NavDataIndex)
|
|
{
|
|
ANavigationData* NavData = NavDataSet[NavDataIndex];
|
|
if (NavData != NULL)
|
|
{
|
|
NavData->LogMemUsed();
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//----------------------------------------------------------------------//
|
|
// Commands
|
|
//----------------------------------------------------------------------//
|
|
bool FNavigationSystemExec::Exec(UWorld* InWorld, const TCHAR* Cmd, FOutputDevice& Ar)
|
|
{
|
|
UNavigationSystemV1* NavSys = FNavigationSystem::GetCurrent<UNavigationSystemV1>(InWorld);
|
|
|
|
if (NavSys && NavSys->NavDataSet.Num() > 0)
|
|
{
|
|
if (FParse::Command(&Cmd, TEXT("CYCLENAVDRAWN")))
|
|
{
|
|
NavSys->HandleCycleNavDrawnCommand( Cmd, Ar );
|
|
// not returning true to enable all navigation systems to cycle their own data
|
|
return false;
|
|
}
|
|
else if (FParse::Command(&Cmd, TEXT("CountNavMem")))
|
|
{
|
|
NavSys->HandleCountNavMemCommand();
|
|
return false;
|
|
}
|
|
/** Builds the navigation mesh (or rebuilds it). **/
|
|
else if (FParse::Command(&Cmd, TEXT("RebuildNavigation")))
|
|
{
|
|
NavSys->Build();
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void UNavigationSystemV1::CycleNavigationDataDrawn()
|
|
{
|
|
++CurrentlyDrawnNavDataIndex;
|
|
if (CurrentlyDrawnNavDataIndex >= NavDataSet.Num())
|
|
{
|
|
CurrentlyDrawnNavDataIndex = INDEX_NONE;
|
|
}
|
|
|
|
for (int32 NavDataIndex = 0; NavDataIndex < NavDataSet.Num(); ++NavDataIndex)
|
|
{
|
|
ANavigationData* NavData = NavDataSet[NavDataIndex];
|
|
if (NavData != NULL)
|
|
{
|
|
const bool bNewEnabledDrawing = (CurrentlyDrawnNavDataIndex == INDEX_NONE) || (NavDataIndex == CurrentlyDrawnNavDataIndex);
|
|
NavData->SetNavRenderingEnabled(bNewEnabledDrawing);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool UNavigationSystemV1::IsNavigationDirty() const
|
|
{
|
|
#if !UE_BUILD_SHIPPING
|
|
if (bCanAccumulateDirtyAreas == false && bDirtyAreasReportedWhileAccumulationLocked)
|
|
{
|
|
return true;
|
|
}
|
|
#endif // !UE_BUILD_SHIPPING
|
|
|
|
for (int32 NavDataIndex=0; NavDataIndex < NavDataSet.Num(); ++NavDataIndex)
|
|
{
|
|
if (NavDataSet[NavDataIndex] && NavDataSet[NavDataIndex]->NeedsRebuild())
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool UNavigationSystemV1::CanRebuildDirtyNavigation() const
|
|
{
|
|
const bool bIsInGame = GetWorld()->IsGameWorld();
|
|
|
|
for (const ANavigationData* NavData : NavDataSet)
|
|
{
|
|
if (NavData)
|
|
{
|
|
const bool bIsDirty = NavData->NeedsRebuild();
|
|
const bool bCanRebuild = !bIsInGame || NavData->SupportsRuntimeGeneration();
|
|
|
|
if (bIsDirty && !bCanRebuild)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool UNavigationSystemV1::DoesPathIntersectBox(const FNavigationPath* Path, const FBox& Box, uint32 StartingIndex, FVector* AgentExtent)
|
|
{
|
|
return Path != NULL && Path->DoesIntersectBox(Box, StartingIndex, NULL, AgentExtent);
|
|
}
|
|
|
|
bool UNavigationSystemV1::DoesPathIntersectBox(const FNavigationPath* Path, const FBox& Box, const FVector& AgentLocation, uint32 StartingIndex, FVector* AgentExtent)
|
|
{
|
|
return Path != NULL && Path->DoesIntersectBox(Box, AgentLocation, StartingIndex, NULL, AgentExtent);
|
|
}
|
|
|
|
void UNavigationSystemV1::SetMaxSimultaneousTileGenerationJobsCount(int32 MaxNumberOfJobs)
|
|
{
|
|
#if WITH_RECAST
|
|
for (auto NavigationData : NavDataSet)
|
|
{
|
|
ARecastNavMesh* RecastNavMesh = Cast<ARecastNavMesh>(NavigationData);
|
|
if (RecastNavMesh)
|
|
{
|
|
RecastNavMesh->SetMaxSimultaneousTileGenerationJobsCount(MaxNumberOfJobs);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void UNavigationSystemV1::ResetMaxSimultaneousTileGenerationJobsCount()
|
|
{
|
|
#if WITH_RECAST
|
|
for (auto NavigationData : NavDataSet)
|
|
{
|
|
ARecastNavMesh* RecastNavMesh = Cast<ARecastNavMesh>(NavigationData);
|
|
if (RecastNavMesh)
|
|
{
|
|
const ARecastNavMesh* CDO = RecastNavMesh->GetClass()->GetDefaultObject<ARecastNavMesh>();
|
|
RecastNavMesh->SetMaxSimultaneousTileGenerationJobsCount(CDO->MaxSimultaneousTileGenerationJobsCount);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
//----------------------------------------------------------------------//
|
|
// Active tiles
|
|
//----------------------------------------------------------------------//
|
|
|
|
void UNavigationSystemV1::RegisterNavigationInvoker(AActor& Invoker, float TileGenerationRadius, float TileRemovalRadius)
|
|
{
|
|
UNavigationSystemV1* NavSys = FNavigationSystem::GetCurrent<UNavigationSystemV1>(Invoker.GetWorld());
|
|
if (NavSys)
|
|
{
|
|
NavSys->RegisterInvoker(Invoker, TileGenerationRadius, TileRemovalRadius);
|
|
}
|
|
}
|
|
|
|
void UNavigationSystemV1::UnregisterNavigationInvoker(AActor& Invoker)
|
|
{
|
|
UNavigationSystemV1* NavSys = FNavigationSystem::GetCurrent<UNavigationSystemV1>(Invoker.GetWorld());
|
|
if (NavSys)
|
|
{
|
|
NavSys->UnregisterInvoker(Invoker);
|
|
}
|
|
}
|
|
|
|
void UNavigationSystemV1::SetGeometryGatheringMode(ENavDataGatheringModeConfig NewMode)
|
|
{
|
|
DataGatheringMode = NewMode;
|
|
if (NavOctree.IsValid())
|
|
{
|
|
NavOctree->SetDataGatheringMode(DataGatheringMode);
|
|
}
|
|
}
|
|
|
|
void UNavigationSystemV1::RegisterInvoker(AActor& Invoker, float TileGenerationRadius, float TileRemovalRadius)
|
|
{
|
|
UE_CVLOG(bGenerateNavigationOnlyAroundNavigationInvokers == false, this, LogNavigation, Warning
|
|
, TEXT("Trying to register %s as enforcer, but NavigationSystem is not set up for enforcer-centric generation. See GenerateNavigationOnlyAroundNavigationInvokers in NavigationSystem's properties")
|
|
, *Invoker.GetName());
|
|
|
|
TileGenerationRadius = FMath::Clamp(TileGenerationRadius, 0.f, BIG_NUMBER);
|
|
TileRemovalRadius = FMath::Clamp(TileRemovalRadius, TileGenerationRadius, BIG_NUMBER);
|
|
|
|
FNavigationInvoker& Data = Invokers.FindOrAdd(&Invoker);
|
|
Data.Actor = &Invoker;
|
|
Data.GenerationRadius = TileGenerationRadius;
|
|
Data.RemovalRadius = TileRemovalRadius;
|
|
|
|
UE_VLOG_CYLINDER(this, LogNavigation, Log, Invoker.GetActorLocation(), Invoker.GetActorLocation() + FVector(0, 0, 20), TileGenerationRadius, FColorList::LimeGreen
|
|
, TEXT("%s %.0f %.0f"), *Invoker.GetName(), TileGenerationRadius, TileRemovalRadius);
|
|
UE_VLOG_CYLINDER(this, LogNavigation, Log, Invoker.GetActorLocation(), Invoker.GetActorLocation() + FVector(0, 0, 20), TileRemovalRadius, FColorList::IndianRed, TEXT(""));
|
|
}
|
|
|
|
void UNavigationSystemV1::UnregisterInvoker(AActor& Invoker)
|
|
{
|
|
UE_VLOG(this, LogNavigation, Log, TEXT("Removing %s from enforcers list"), *Invoker.GetName());
|
|
Invokers.Remove(&Invoker);
|
|
}
|
|
|
|
void UNavigationSystemV1::UpdateInvokers()
|
|
{
|
|
UWorld* World = GetWorld();
|
|
const float CurrentTime = World->GetTimeSeconds();
|
|
if (CurrentTime >= NextInvokersUpdateTime)
|
|
{
|
|
TArray<FNavigationInvokerRaw> InvokerLocations;
|
|
|
|
if (Invokers.Num() > 0)
|
|
{
|
|
QUICK_SCOPE_CYCLE_COUNTER(STAT_NavSys_Clusterize);
|
|
|
|
const double StartTime = FPlatformTime::Seconds();
|
|
|
|
InvokerLocations.Reserve(Invokers.Num());
|
|
|
|
for (auto ItemIterator = Invokers.CreateIterator(); ItemIterator; ++ItemIterator)
|
|
{
|
|
AActor* Actor = ItemIterator->Value.Actor.Get();
|
|
if (Actor != nullptr
|
|
#if WITH_EDITOR
|
|
// Would like to ignore objects in transactional buffer here, but there's no flag for it
|
|
//&& (GIsEditor == false || Item.Actor->HasAnyFlags(RF_Transactional | RF_PendingKill) == false)
|
|
#endif //WITH_EDITOR
|
|
)
|
|
{
|
|
InvokerLocations.Add(FNavigationInvokerRaw(Actor->GetActorLocation(), ItemIterator->Value.GenerationRadius, ItemIterator->Value.RemovalRadius));
|
|
}
|
|
else
|
|
{
|
|
ItemIterator.RemoveCurrent();
|
|
}
|
|
}
|
|
|
|
#if ENABLE_VISUAL_LOG
|
|
const double CachingFinishTime = FPlatformTime::Seconds();
|
|
UE_VLOG(this, LogNavigation, Log, TEXT("Caching time %fms"), (CachingFinishTime - StartTime) * 1000);
|
|
|
|
for (const auto& InvokerData : InvokerLocations)
|
|
{
|
|
UE_VLOG_CYLINDER(this, LogNavigation, Log, InvokerData.Location, InvokerData.Location + FVector(0, 0, 20), InvokerData.RadiusMax, FColorList::Blue, TEXT(""));
|
|
UE_VLOG_CYLINDER(this, LogNavigation, Log, InvokerData.Location, InvokerData.Location + FVector(0, 0, 20), InvokerData.RadiusMin, FColorList::CadetBlue, TEXT(""));
|
|
}
|
|
#endif // ENABLE_VISUAL_LOG
|
|
}
|
|
|
|
#if WITH_RECAST
|
|
const double UpdateStartTime = FPlatformTime::Seconds();
|
|
for (TActorIterator<ARecastNavMesh> It(GetWorld()); It; ++It)
|
|
{
|
|
It->UpdateActiveTiles(InvokerLocations);
|
|
}
|
|
const double UpdateEndTime = FPlatformTime::Seconds();
|
|
UE_VLOG(this, LogNavigation, Log, TEXT("Marking tiles to update %fms (%d invokers)"), (UpdateEndTime - UpdateStartTime) * 1000, InvokerLocations.Num());
|
|
#endif
|
|
|
|
// once per second
|
|
NextInvokersUpdateTime = CurrentTime + ActiveTilesUpdateInterval;
|
|
}
|
|
}
|
|
|
|
void UNavigationSystemV1::RegisterNavigationInvoker(AActor* Invoker, float TileGenerationRadius, float TileRemovalRadius)
|
|
{
|
|
if (Invoker != nullptr)
|
|
{
|
|
RegisterInvoker(*Invoker, TileGenerationRadius, TileRemovalRadius);
|
|
}
|
|
}
|
|
|
|
void UNavigationSystemV1::UnregisterNavigationInvoker(AActor* Invoker)
|
|
{
|
|
if (Invoker != nullptr)
|
|
{
|
|
UnregisterInvoker(*Invoker);
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------//
|
|
// DEPRECATED
|
|
//----------------------------------------------------------------------//
|
|
FVector UNavigationSystemV1::ProjectPointToNavigation(UObject* WorldContextObject, const FVector& Point, ANavigationData* NavData, TSubclassOf<UNavigationQueryFilter> FilterClass, const FVector QueryExtent)
|
|
{
|
|
FNavLocation ProjectedPoint(Point);
|
|
|
|
UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::LogAndReturnNull);
|
|
UNavigationSystemV1* NavSys = FNavigationSystem::GetCurrent<UNavigationSystemV1>(World);
|
|
if (NavSys)
|
|
{
|
|
ANavigationData* UseNavData = NavData ? NavData : NavSys->GetDefaultNavDataInstance(FNavigationSystem::DontCreate);
|
|
if (UseNavData)
|
|
{
|
|
NavSys->ProjectPointToNavigation(Point, ProjectedPoint, QueryExtent.IsNearlyZero() ? INVALID_NAVEXTENT : QueryExtent, UseNavData,
|
|
UNavigationQueryFilter::GetQueryFilter(*UseNavData, WorldContextObject, FilterClass));
|
|
}
|
|
}
|
|
|
|
return ProjectedPoint.Location;
|
|
}
|
|
|
|
FVector UNavigationSystemV1::GetRandomReachablePointInRadius(UObject* WorldContextObject, const FVector& Origin, float Radius, ANavigationData* NavData, TSubclassOf<UNavigationQueryFilter> FilterClass)
|
|
{
|
|
FNavLocation RandomPoint;
|
|
|
|
UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::LogAndReturnNull);
|
|
UNavigationSystemV1* NavSys = FNavigationSystem::GetCurrent<UNavigationSystemV1>(World);
|
|
if (NavSys)
|
|
{
|
|
ANavigationData* UseNavData = NavData ? NavData : NavSys->GetDefaultNavDataInstance(FNavigationSystem::DontCreate);
|
|
if (UseNavData)
|
|
{
|
|
NavSys->GetRandomReachablePointInRadius(Origin, Radius, RandomPoint, UseNavData, UNavigationQueryFilter::GetQueryFilter(*UseNavData, WorldContextObject, FilterClass));
|
|
}
|
|
}
|
|
|
|
return RandomPoint.Location;
|
|
}
|
|
|
|
FVector UNavigationSystemV1::GetRandomPointInNavigableRadius(UObject* WorldContextObject, const FVector& Origin, float Radius, ANavigationData* NavData, TSubclassOf<UNavigationQueryFilter> FilterClass)
|
|
{
|
|
FNavLocation RandomPoint;
|
|
|
|
UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::LogAndReturnNull);
|
|
UNavigationSystemV1* NavSys = FNavigationSystem::GetCurrent<UNavigationSystemV1>(World);
|
|
if (NavSys)
|
|
{
|
|
ANavigationData* UseNavData = NavData ? NavData : NavSys->GetDefaultNavDataInstance(FNavigationSystem::DontCreate);
|
|
if (UseNavData)
|
|
{
|
|
NavSys->GetRandomPointInNavigableRadius(Origin, Radius, RandomPoint, UseNavData, UNavigationQueryFilter::GetQueryFilter(*UseNavData, WorldContextObject, FilterClass));
|
|
}
|
|
}
|
|
|
|
return RandomPoint.Location;
|
|
}
|
|
|
|
void UNavigationSystemV1::SimpleMoveToActor(AController* Controller, const AActor* Goal)
|
|
{
|
|
UE_LOG(LogNavigation, Error, TEXT("SimpleMoveToActor is deprecated. Use UAIBlueprintHelperLibrary::SimpleMoveToActor instead"));
|
|
}
|
|
|
|
void UNavigationSystemV1::SimpleMoveToLocation(AController* Controller, const FVector& Goal)
|
|
{
|
|
UE_LOG(LogNavigation, Error, TEXT("SimpleMoveToLocation is deprecated. Use UAIBlueprintHelperLibrary::SimpleMoveToLocation instead"));
|
|
}
|
|
|
|
//----------------------------------------------------------------------//
|
|
// NEW STUFF!
|
|
//----------------------------------------------------------------------//
|
|
void UNavigationSystemV1::VerifyNavigationRenderingComponents(const bool bShow)
|
|
{
|
|
// make sure nav mesh has a rendering component
|
|
ANavigationData* const NavData = GetDefaultNavDataInstance(FNavigationSystem::DontCreate);
|
|
|
|
if (NavData && NavData->RenderingComp == nullptr)
|
|
{
|
|
NavData->RenderingComp = NavData->ConstructRenderingComponent();
|
|
if (NavData->RenderingComp)
|
|
{
|
|
NavData->RenderingComp->SetVisibility(bShow);
|
|
NavData->RenderingComp->RegisterComponent();
|
|
}
|
|
}
|
|
|
|
if (NavData == nullptr)
|
|
{
|
|
UE_LOG(LogNavigation, Warning, TEXT("No NavData found when calling UNavigationSystemV1::VerifyNavigationRenderingComponents()"));
|
|
}
|
|
}
|
|
|
|
#if !UE_BUILD_SHIPPING
|
|
void UNavigationSystemV1::GetOnScreenMessages(TMultiMap<FCoreDelegates::EOnScreenMessageSeverity, FText>& OutMessages)
|
|
{
|
|
// check navmesh
|
|
#if WITH_EDITOR
|
|
const bool bIsNavigationAutoUpdateEnabled = UNavigationSystemV1::GetIsNavigationAutoUpdateEnabled();
|
|
#else
|
|
const bool bIsNavigationAutoUpdateEnabled = true;
|
|
#endif
|
|
if (IsNavigationDirty()
|
|
&& ((OperationMode == FNavigationSystemRunMode::EditorMode && !bIsNavigationAutoUpdateEnabled)
|
|
|| !SupportsNavigationGeneration() || !CanRebuildDirtyNavigation()))
|
|
{
|
|
OutMessages.Add(FCoreDelegates::EOnScreenMessageSeverity::Error
|
|
, LOCTEXT("NAVMESHERROR", "NAVMESH NEEDS TO BE REBUILT"));
|
|
}
|
|
}
|
|
#endif // !UE_BUILD_SHIPPING
|
|
|
|
INavigationDataInterface* UNavigationSystemV1::GetNavDataForActor(const AActor& Actor)
|
|
{
|
|
UNavigationSystemV1* NavSys = FNavigationSystem::GetCurrent<UNavigationSystemV1>(Actor.GetWorld());
|
|
ANavigationData* NavData = nullptr;
|
|
const INavAgentInterface* AsNavAgent = CastChecked<INavAgentInterface>(&Actor);
|
|
if (AsNavAgent)
|
|
{
|
|
const FNavAgentProperties& AgentProps = AsNavAgent->GetNavAgentPropertiesRef();
|
|
NavData = NavSys->GetNavDataForProps(AgentProps);
|
|
}
|
|
if (NavData == nullptr)
|
|
{
|
|
NavData = NavSys->GetDefaultNavDataInstance(FNavigationSystem::DontCreate);
|
|
}
|
|
|
|
// Only RecastNavMesh supported
|
|
return (INavigationDataInterface*)(Cast<ARecastNavMesh>(NavData));
|
|
}
|
|
|
|
int UNavigationSystemV1::GetNavigationBoundsForNavData(const ANavigationData& NavData, TArray<FBox>& OutBounds) const
|
|
{
|
|
const int InitialBoundsCount = OutBounds.Num();
|
|
OutBounds.Reserve(InitialBoundsCount + RegisteredNavBounds.Num());
|
|
const int32 AgentIndex = GetSupportedAgentIndex(&NavData);
|
|
|
|
for (const FNavigationBounds& NavigationBounds : RegisteredNavBounds)
|
|
{
|
|
if (NavigationBounds.SupportedAgents.Contains(AgentIndex))
|
|
{
|
|
OutBounds.Add(NavigationBounds.AreaBox);
|
|
}
|
|
}
|
|
|
|
return OutBounds.Num() - InitialBoundsCount;
|
|
}
|
|
|
|
const FNavDataConfig& UNavigationSystemV1::GetDefaultSupportedAgent()
|
|
{
|
|
static const FNavDataConfig DefaultAgent;
|
|
const UNavigationSystemV1* NavSysCDO = GetDefault<UNavigationSystemV1>();
|
|
check(NavSysCDO);
|
|
return NavSysCDO->SupportedAgents.Num() > 0
|
|
? NavSysCDO->GetDefaultSupportedAgentConfig()
|
|
: DefaultAgent;
|
|
}
|
|
|
|
void UNavigationSystemV1::OverrideSupportedAgents(const TArray<FNavDataConfig>& NewSupportedAgents)
|
|
{
|
|
UE_CLOG(bWorldInitDone, LogNavigation, Warning, TEXT("Trying to override NavigationSystem\'s SupportedAgents past the World\'s initialization"));
|
|
|
|
SupportedAgents = NewSupportedAgents;
|
|
if (SupportedAgents.Num() == 0)
|
|
{
|
|
SupportedAgents.Add(FNavDataConfig(FNavigationSystem::FallbackAgentRadius, FNavigationSystem::FallbackAgentHeight));
|
|
}
|
|
}
|
|
|
|
void UNavigationSystemV1::Configure(const UNavigationSystemConfig& Config)
|
|
{
|
|
|
|
}
|
|
|
|
//----------------------------------------------------------------------//
|
|
// UNavigationSystemModuleConfig
|
|
//----------------------------------------------------------------------//
|
|
UNavigationSystemModuleConfig::UNavigationSystemModuleConfig(const FObjectInitializer& ObjectInitializer)
|
|
: Super(ObjectInitializer)
|
|
{
|
|
}
|
|
|
|
void UNavigationSystemModuleConfig::PostInitProperties()
|
|
{
|
|
Super::PostInitProperties();
|
|
|
|
const UNavigationSystemV1* NavSysCDO = GetDefault<UNavigationSystemV1>();
|
|
if (NavSysCDO)
|
|
{
|
|
UpdateWithNavSysCDO(*NavSysCDO);
|
|
}
|
|
}
|
|
|
|
void UNavigationSystemModuleConfig::UpdateWithNavSysCDO(const UNavigationSystemV1& NavSysCDO)
|
|
{
|
|
UClass* MyClass = NavigationSystemClass.ResolveClass();
|
|
if (MyClass != nullptr && MyClass->IsChildOf(NavSysCDO.GetClass()))
|
|
{
|
|
bStrictlyStatic = NavSysCDO.bStaticRuntimeNavigation;
|
|
bCreateOnClient = NavSysCDO.bAllowClientSideNavigation;
|
|
bAutoSpawnMissingNavData = NavSysCDO.bAutoCreateNavigationData;
|
|
bSpawnNavDataInNavBoundsLevel = NavSysCDO.bSpawnNavDataInNavBoundsLevel;
|
|
}
|
|
}
|
|
|
|
UNavigationSystemBase* UNavigationSystemModuleConfig::CreateAndConfigureNavigationSystem(UWorld& World) const
|
|
{
|
|
if (bCreateOnClient == false && World.GetNetMode() == NM_Client)
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
UNavigationSystemBase* NewNavSys = Super::CreateAndConfigureNavigationSystem(World);
|
|
UNavigationSystemV1* NavSysInstance = Cast<UNavigationSystemV1>(NewNavSys);
|
|
UE_CLOG(NavSysInstance == nullptr && NewNavSys != nullptr, LogNavigation, Error
|
|
, TEXT("Unable to spawn navsys instance of class %s - unable to cast to UNavigationSystemV1")
|
|
, *NavigationSystemClass.GetAssetName()
|
|
);
|
|
|
|
if (NavSysInstance)
|
|
{
|
|
NavSysInstance->bAutoCreateNavigationData = bAutoSpawnMissingNavData;
|
|
NavSysInstance->bSpawnNavDataInNavBoundsLevel = bSpawnNavDataInNavBoundsLevel;
|
|
if (bStrictlyStatic)
|
|
{
|
|
NavSysInstance->ConfigureAsStatic();
|
|
}
|
|
}
|
|
|
|
return NavSysInstance;
|
|
}
|
|
|
|
#if WITH_EDITOR
|
|
void UNavigationSystemModuleConfig::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
|
|
{
|
|
static const FName NAME_NavigationSystemClass = GET_MEMBER_NAME_CHECKED(UNavigationSystemConfig, NavigationSystemClass);
|
|
|
|
Super::PostEditChangeProperty(PropertyChangedEvent);
|
|
|
|
if (PropertyChangedEvent.Property)
|
|
{
|
|
FName PropName = PropertyChangedEvent.Property->GetFName();
|
|
if (PropName == NAME_NavigationSystemClass)
|
|
{
|
|
if (NavigationSystemClass.IsValid() == false)
|
|
{
|
|
NavigationSystemClass = *GEngine->NavigationSystemClass;
|
|
}
|
|
else
|
|
{
|
|
NavigationSystemClass.TryLoad();
|
|
TSubclassOf<UNavigationSystemBase> NavSysClass = NavigationSystemClass.ResolveClass();
|
|
const UNavigationSystemV1* NavSysCDO = *NavSysClass
|
|
? NavSysClass->GetDefaultObject<UNavigationSystemV1>()
|
|
: (UNavigationSystemV1*)nullptr;
|
|
if (NavSysCDO)
|
|
{
|
|
UpdateWithNavSysCDO(*NavSysCDO);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif // WITH_EDITOR
|
|
|
|
#undef LOCTEXT_NAMESPACE
|