diff --git a/Source/Editor/Content/Import/ImportFilesDialog.cs b/Source/Editor/Content/Import/ImportFilesDialog.cs index ab2c7be15..967583cf6 100644 --- a/Source/Editor/Content/Import/ImportFilesDialog.cs +++ b/Source/Editor/Content/Import/ImportFilesDialog.cs @@ -139,7 +139,7 @@ namespace FlaxEditor.Content.Import var menu = new ContextMenu(); menu.AddButton("Rename", OnRenameClicked); menu.AddButton("Don't import", OnDontImportClicked); - menu.AddButton("Show in Explorer", OnShowInExplorerClicked); + menu.AddButton(Utilities.Constants.ShowInExplorer, OnShowInExplorerClicked); menu.Tag = node; menu.Show(node, location); } diff --git a/Source/Editor/Content/Tree/MainContentTreeNode.cs b/Source/Editor/Content/Tree/MainContentTreeNode.cs index 43b36986d..def873622 100644 --- a/Source/Editor/Content/Tree/MainContentTreeNode.cs +++ b/Source/Editor/Content/Tree/MainContentTreeNode.cs @@ -29,7 +29,7 @@ namespace FlaxEditor.Content //_watcher.Changed += OnEvent; _watcher.Created += OnEvent; _watcher.Deleted += OnEvent; - //_watcher.Renamed += OnEvent; + _watcher.Renamed += OnEvent; } private void OnEvent(object sender, FileSystemEventArgs e) diff --git a/Source/Editor/CustomEditors/Dedicated/MissingScriptEditor.cs b/Source/Editor/CustomEditors/Dedicated/MissingScriptEditor.cs new file mode 100644 index 000000000..03d5ddd55 --- /dev/null +++ b/Source/Editor/CustomEditors/Dedicated/MissingScriptEditor.cs @@ -0,0 +1,26 @@ +using FlaxEditor.CustomEditors.Editors; +using FlaxEngine; +using FlaxEngine.GUI; + +namespace FlaxEditor.CustomEditors.Dedicated; + +/// +/// The missing script editor. +/// +[CustomEditor(typeof(MissingScript)), DefaultEditor] +public class MissingScriptEditor : GenericEditor +{ + /// + public override void Initialize(LayoutElementsContainer layout) + { + if (layout.ContainerControl is not DropPanel dropPanel) + { + base.Initialize(layout); + return; + } + + dropPanel.HeaderTextColor = Color.OrangeRed; + + base.Initialize(layout); + } +} diff --git a/Source/Editor/Modules/ContentDatabaseModule.cs b/Source/Editor/Modules/ContentDatabaseModule.cs index 143352421..552658aa1 100644 --- a/Source/Editor/Modules/ContentDatabaseModule.cs +++ b/Source/Editor/Modules/ContentDatabaseModule.cs @@ -931,6 +931,11 @@ namespace FlaxEditor.Modules // Check if node already has that element (skip during init when we want to walk project dir very fast) if (_isDuringFastSetup || !parent.Folder.ContainsChild(path)) { +#if PLATFORM_MAC + if (path.EndsWith(".DS_Store", StringComparison.Ordinal)) + continue; +#endif + // Create file item ContentItem item; if (path.EndsWith(".cs")) @@ -972,6 +977,11 @@ namespace FlaxEditor.Modules // Check if node already has that element (skip during init when we want to walk project dir very fast) if (_isDuringFastSetup || !parent.Folder.ContainsChild(path)) { +#if PLATFORM_MAC + if (path.EndsWith(".DS_Store", StringComparison.Ordinal)) + continue; +#endif + // Create file item ContentItem item = null; if (FlaxEngine.Content.GetAssetInfo(path, out var assetInfo)) @@ -1197,6 +1207,7 @@ namespace FlaxEditor.Modules { case WatcherChangeTypes.Created: case WatcherChangeTypes.Deleted: + case WatcherChangeTypes.Renamed: { lock (_dirtyNodes) { diff --git a/Source/Editor/Utilities/Constants.cs b/Source/Editor/Utilities/Constants.cs index 176fed5f7..fb9f82cf5 100644 --- a/Source/Editor/Utilities/Constants.cs +++ b/Source/Editor/Utilities/Constants.cs @@ -14,5 +14,11 @@ namespace FlaxEditor.Utilities public const string FacebookUrl = "https://facebook.com/FlaxEngine"; public const string YoutubeUrl = "https://youtube.com/c/FlaxEngine"; public const string TwitterUrl = "https://twitter.com/FlaxEngine"; + +#if PLATFORM_MAC + public const string ShowInExplorer = "Show in Finder"; +#else + public const string ShowInExplorer = "Show in explorer"; +#endif } } diff --git a/Source/Editor/Windows/ContentWindow.ContextMenu.cs b/Source/Editor/Windows/ContentWindow.ContextMenu.cs index 6923d634d..1dd26ecf5 100644 --- a/Source/Editor/Windows/ContentWindow.ContextMenu.cs +++ b/Source/Editor/Windows/ContentWindow.ContextMenu.cs @@ -58,7 +58,7 @@ namespace FlaxEditor.Windows if (item is ContentFolder contentFolder && contentFolder.Node is ProjectTreeNode) { - cm.AddButton("Show in explorer", () => FileSystem.ShowFileExplorer(CurrentViewFolder.Path)); + cm.AddButton(Utilities.Constants.ShowInExplorer, () => FileSystem.ShowFileExplorer(CurrentViewFolder.Path)); } else if (isValidElement) { @@ -72,7 +72,7 @@ namespace FlaxEditor.Windows Open(e); }); - cm.AddButton("Show in explorer", () => FileSystem.ShowFileExplorer(System.IO.Path.GetDirectoryName(item.Path))); + cm.AddButton(Utilities.Constants.ShowInExplorer, () => FileSystem.ShowFileExplorer(System.IO.Path.GetDirectoryName(item.Path))); if (item.HasDefaultThumbnail == false) { @@ -135,7 +135,7 @@ namespace FlaxEditor.Windows } else { - cm.AddButton("Show in explorer", () => FileSystem.ShowFileExplorer(CurrentViewFolder.Path)); + cm.AddButton(Utilities.Constants.ShowInExplorer, () => FileSystem.ShowFileExplorer(CurrentViewFolder.Path)); b = cm.AddButton("Paste", _view.Paste); b.Enabled = _view.CanPaste(); diff --git a/Source/Editor/Windows/OutputLogWindow.cs b/Source/Editor/Windows/OutputLogWindow.cs index 1d188a32c..3665b7073 100644 --- a/Source/Editor/Windows/OutputLogWindow.cs +++ b/Source/Editor/Windows/OutputLogWindow.cs @@ -195,7 +195,7 @@ namespace FlaxEditor.Windows _contextMenu.AddButton("Clear log", Clear); _contextMenu.AddButton("Copy selection", _output.Copy); _contextMenu.AddButton("Select All", _output.SelectAll); - _contextMenu.AddButton("Show in explorer", () => FileSystem.ShowFileExplorer(Path.Combine(Globals.ProjectFolder, "Logs"))); + _contextMenu.AddButton(Utilities.Constants.ShowInExplorer, () => FileSystem.ShowFileExplorer(Path.Combine(Globals.ProjectFolder, "Logs"))); _contextMenu.AddButton("Scroll to bottom", () => { _vScroll.TargetValue = _vScroll.Maximum; }).Icon = Editor.Icons.ArrowDown12; // Setup editor options diff --git a/Source/Editor/Windows/Profiler/Assets.cs b/Source/Editor/Windows/Profiler/Assets.cs index e2a65d496..3ccf6e2eb 100644 --- a/Source/Editor/Windows/Profiler/Assets.cs +++ b/Source/Editor/Windows/Profiler/Assets.cs @@ -274,7 +274,7 @@ namespace FlaxEditor.Windows.Profiler ContextMenuButton b; b = cm.AddButton("Open", () => Editor.Instance.ContentEditing.Open(assetItem)); cm.AddButton("Show in content window", () => Editor.Instance.Windows.ContentWin.Select(assetItem)); - cm.AddButton("Show in explorer", () => FileSystem.ShowFileExplorer(System.IO.Path.GetDirectoryName(assetItem.Path))); + cm.AddButton(Utilities.Constants.ShowInExplorer, () => FileSystem.ShowFileExplorer(System.IO.Path.GetDirectoryName(assetItem.Path))); cm.AddButton("Select actors using this asset", () => Editor.Instance.SceneEditing.SelectActorsUsingAsset(assetItem.ID)); cm.AddButton("Show asset references graph", () => Editor.Instance.Windows.Open(new AssetReferencesGraphWindow(Editor.Instance, assetItem))); cm.AddButton("Copy name", () => Clipboard.Text = assetItem.NamePath); diff --git a/Source/Editor/Windows/Search/SearchItem.cs b/Source/Editor/Windows/Search/SearchItem.cs index e8bdc4e56..506d30d0d 100644 --- a/Source/Editor/Windows/Search/SearchItem.cs +++ b/Source/Editor/Windows/Search/SearchItem.cs @@ -157,7 +157,7 @@ namespace FlaxEditor.Windows.Search var cm = new FlaxEditor.GUI.ContextMenu.ContextMenu { Tag = assetItem }; b = cm.AddButton("Open", () => Editor.Instance.ContentFinding.Open(Item)); cm.AddSeparator(); - cm.AddButton("Show in explorer", () => FileSystem.ShowFileExplorer(System.IO.Path.GetDirectoryName(assetItem.Path))); + cm.AddButton(Utilities.Constants.ShowInExplorer, () => FileSystem.ShowFileExplorer(System.IO.Path.GetDirectoryName(assetItem.Path))); cm.AddButton("Show in Content window", () => Editor.Instance.Windows.ContentWin.Select(assetItem, true)); b.Enabled = proxy != null && proxy.CanReimport(assetItem); if (assetItem is BinaryAssetItem binaryAsset) diff --git a/Source/Engine/Core/Collections/ArrayExtensions.h b/Source/Engine/Core/Collections/ArrayExtensions.h index 788b31edb..2ae6da9c8 100644 --- a/Source/Engine/Core/Collections/ArrayExtensions.h +++ b/Source/Engine/Core/Collections/ArrayExtensions.h @@ -4,7 +4,7 @@ #include "../Collections/Array.h" #include "../Collections/Dictionary.h" -#include +#include "../Delegate.h" class ArrayExtensions; @@ -23,7 +23,6 @@ public: /// /// Gets the common key. /// - /// The key. FORCE_INLINE const TKey& GetKey() const { return _key; @@ -32,7 +31,6 @@ public: /// /// Gets the common key. /// - /// The key. FORCE_INLINE TKey GetKey() { return _key; @@ -52,7 +50,7 @@ public: /// The prediction function. Should return true for the target element to find. /// The index of the element or -1 if nothing found. template - static int32 IndexOf(const Array& obj, const std::function& predicate) + static int32 IndexOf(const Array& obj, const Function& predicate) { for (int32 i = 0; i < obj.Count(); i++) { @@ -71,7 +69,7 @@ public: /// The prediction function. /// True if any element in the collection matches the prediction, otherwise false. template - static bool Any(const Array& obj, const std::function& predicate) + static bool Any(const Array& obj, const Function& predicate) { for (int32 i = 0; i < obj.Count(); i++) { @@ -90,7 +88,7 @@ public: /// The prediction function. /// True if all elements in the collection matches the prediction, otherwise false. template - static int32 All(const Array& obj, const std::function& predicate) + static int32 All(const Array& obj, const Function& predicate) { for (int32 i = 0; i < obj.Count(); i++) { @@ -109,7 +107,7 @@ public: /// A function to extract the key for each element. /// The result collection with groups. template - static void GroupBy(const Array& obj, const std::function& keySelector, Array, AllocationType>& result) + static void GroupBy(const Array& obj, const Function& keySelector, Array, AllocationType>& result) { Dictionary> data(static_cast(obj.Count() * 3.0f)); for (int32 i = 0; i < obj.Count(); i++) diff --git a/Source/Engine/Engine/Engine.cpp b/Source/Engine/Engine/Engine.cpp index ec56861ba..5b93ab588 100644 --- a/Source/Engine/Engine/Engine.cpp +++ b/Source/Engine/Engine/Engine.cpp @@ -105,6 +105,14 @@ int32 Engine::Main(const Char* cmdLine) Globals::StartupFolder = Globals::BinariesFolder = Platform::GetMainDirectory(); #if USE_EDITOR Globals::StartupFolder /= TEXT("../../../.."); +#if PLATFORM_MAC + if (Globals::BinariesFolder.EndsWith(TEXT(".app/Contents"))) + { + // If running editor from application package on macOS + Globals::StartupFolder = Globals::BinariesFolder; + Globals::BinariesFolder /= TEXT("MacOS"); + } +#endif #endif StringUtils::PathRemoveRelativeParts(Globals::StartupFolder); FileSystem::NormalizePath(Globals::BinariesFolder); @@ -122,7 +130,6 @@ int32 Engine::Main(const Char* cmdLine) } EngineImpl::InitPaths(); - EngineImpl::InitLog(); #if USE_EDITOR @@ -542,7 +549,8 @@ void EngineImpl::InitLog() LOG(Info, "Product: {0}, Company: {1}", Globals::ProductName, Globals::CompanyName); LOG(Info, "Current culture: {0}", Platform::GetUserLocaleName()); LOG(Info, "Command line: {0}", CommandLine); - LOG(Info, "Base directory: {0}", Globals::StartupFolder); + LOG(Info, "Base folder: {0}", Globals::StartupFolder); + LOG(Info, "Binaries folder: {0}", Globals::BinariesFolder); LOG(Info, "Temporary folder: {0}", Globals::TemporaryFolder); LOG(Info, "Project folder: {0}", Globals::ProjectFolder); #if USE_EDITOR diff --git a/Source/Engine/Engine/InputAxis.cs b/Source/Engine/Engine/InputAxis.cs index f8ba7e72b..c70bada74 100644 --- a/Source/Engine/Engine/InputAxis.cs +++ b/Source/Engine/Engine/InputAxis.cs @@ -1,5 +1,7 @@ // Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. +using System; + namespace FlaxEngine { /// @@ -23,11 +25,17 @@ namespace FlaxEngine /// public float ValueRaw => Input.GetAxisRaw(Name); + /// + /// Occurs when axis is changed. Called before scripts update. + /// + public event Action ValueChanged; + /// /// Initializes a new instance of the class. /// public InputAxis() { + Input.AxisValueChanged += Handler; } /// @@ -36,7 +44,31 @@ namespace FlaxEngine /// The axis name. public InputAxis(string name) { + Input.AxisValueChanged += Handler; Name = name; } + + private void Handler(string name) + { + if (string.Equals(Name, name, StringComparison.OrdinalIgnoreCase)) + ValueChanged?.Invoke(); + } + + /// + /// Finalizes an instance of the class. + /// + ~InputAxis() + { + Input.AxisValueChanged -= Handler; + } + + /// + /// Releases this object. + /// + public void Dispose() + { + Input.AxisValueChanged -= Handler; + GC.SuppressFinalize(this); + } } } diff --git a/Source/Engine/Engine/InputEvent.cs b/Source/Engine/Engine/InputEvent.cs index 176d21fd0..0267aed96 100644 --- a/Source/Engine/Engine/InputEvent.cs +++ b/Source/Engine/Engine/InputEvent.cs @@ -16,15 +16,36 @@ namespace FlaxEngine public string Name; /// - /// Returns true if the event has been triggered during the current frame (e.g. user pressed a key). Use to catch events without active waiting. + /// Returns true if the event has been triggered during the current frame (e.g. user pressed a key). Use to catch events without active waiting. /// public bool Active => Input.GetAction(Name); + /// + /// Returns the event state. Use Use , , to catch events without active waiting. + /// + public InputActionState State => Input.GetActionState(Name); + /// /// Occurs when event is triggered (e.g. user pressed a key). Called before scripts update. /// + [System.Obsolete("Depreciated in 1.7, use Pressed Action.")] public event Action Triggered; + /// + /// Occurs when event is pressed (e.g. user pressed a key). Called before scripts update. + /// + public event Action Pressed; + + /// + /// Occurs when event is being pressing (e.g. user pressing a key). Called before scripts update. + /// + public event Action Pressing; + + /// + /// Occurs when event is released (e.g. user releases a key). Called before scripts update. + /// + public event Action Released; + /// /// Initializes a new instance of the class. /// @@ -51,10 +72,26 @@ namespace FlaxEngine Input.ActionTriggered -= Handler; } - private void Handler(string name) + private void Handler(string name, InputActionState state) { - if (string.Equals(name, Name, StringComparison.OrdinalIgnoreCase)) + if (!string.Equals(name, Name, StringComparison.OrdinalIgnoreCase)) + return; + switch (state) + { + case InputActionState.None: break; + case InputActionState.Waiting: break; + case InputActionState.Pressing: + Pressing?.Invoke(); + break; + case InputActionState.Press: Triggered?.Invoke(); + Pressed?.Invoke(); + break; + case InputActionState.Release: + Released?.Invoke(); + break; + default: break; + } } /// diff --git a/Source/Engine/Foliage/FoliageType.cpp b/Source/Engine/Foliage/FoliageType.cpp index 785010c44..7d530dfed 100644 --- a/Source/Engine/Foliage/FoliageType.cpp +++ b/Source/Engine/Foliage/FoliageType.cpp @@ -130,7 +130,7 @@ void FoliageType::Serialize(SerializeStream& stream, const void* otherObj) SERIALIZE(Model); - const std::function IsValidMaterial = [](const ModelInstanceEntry& e) -> bool + const Function IsValidMaterial = [](const ModelInstanceEntry& e) -> bool { return e.Material; }; diff --git a/Source/Engine/Graphics/Models/SkeletonMapping.h b/Source/Engine/Graphics/Models/SkeletonMapping.h index ac2af245b..e3ec0c793 100644 --- a/Source/Engine/Graphics/Models/SkeletonMapping.h +++ b/Source/Engine/Graphics/Models/SkeletonMapping.h @@ -66,7 +66,7 @@ public: const auto parentModelIndex = node.ParentIndex; // Find matching node in skeleton (or map to best parent) - const std::function f = [node](const T& x) -> bool + const Function f = [node](const T& x) -> bool { return x.Name == node.Name; }; diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.cpp b/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.cpp index d52b446e3..b0bb1c733 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.cpp +++ b/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.cpp @@ -459,9 +459,9 @@ void GPUContextVulkan::UpdateDescriptorSets(const SpirvShaderDescriptorInfo& des { case VK_DESCRIPTOR_TYPE_SAMPLER: { - const VkSampler sampler = _samplerHandles[slot]; - ASSERT(sampler); - needsWrite |= dsWriter.WriteSampler(descriptorIndex, sampler, index); + const VkSampler handle = _samplerHandles[slot]; + ASSERT(handle); + needsWrite |= dsWriter.WriteSampler(descriptorIndex, handle, index); break; } case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: @@ -547,12 +547,18 @@ void GPUContextVulkan::UpdateDescriptorSets(const SpirvShaderDescriptorInfo& des } case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC: { - auto cb = handles[slot]; - ASSERT(cb); - VkBuffer buffer; - VkDeviceSize offset, range; - uint32 dynamicOffset; - cb->DescriptorAsDynamicUniformBuffer(this, buffer, offset, range, dynamicOffset); + auto handle = handles[slot]; + VkBuffer buffer = VK_NULL_HANDLE; + VkDeviceSize offset = 0, range = 0; + uint32 dynamicOffset = 0; + if (handle) + handle->DescriptorAsDynamicUniformBuffer(this, buffer, offset, range, dynamicOffset); + else + { + const auto dummy = _device->HelperResources.GetDummyBuffer(); + buffer = dummy->GetHandle(); + range = dummy->GetSize(); + } needsWrite |= dsWriter.WriteDynamicUniformBuffer(descriptorIndex, buffer, offset, range, dynamicOffset, index); break; } diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.Layers.cpp b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.Layers.cpp index bdd92c762..0b857d394 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.Layers.cpp +++ b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.Layers.cpp @@ -35,6 +35,10 @@ static const char* GValidationLayers[] = static const char* GInstanceExtensions[] = { +#if PLATFORM_APPLE_FAMILY && defined(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME) + VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME, + VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, +#endif #if VK_EXT_validation_cache VK_EXT_VALIDATION_CACHE_EXTENSION_NAME, #endif @@ -46,6 +50,9 @@ static const char* GInstanceExtensions[] = static const char* GDeviceExtensions[] = { +#if PLATFORM_APPLE_FAMILY && defined(VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME) + VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME, +#endif VK_KHR_SWAPCHAIN_EXTENSION_NAME, #if VK_KHR_maintenance1 VK_KHR_MAINTENANCE1_EXTENSION_NAME, @@ -571,7 +578,7 @@ void GPUDeviceVulkan::ParseOptionalDeviceExtensions(const Array& de const auto HasExtension = [&deviceExtensions](const char* name) -> bool { - const std::function CheckCallback = [&name](const char* const& extension) -> bool + const Function CheckCallback = [&name](const char* const& extension) -> bool { return StringUtils::Compare(extension, name) == 0; }; diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp index eb23c0871..b4a6112a9 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp +++ b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp @@ -431,7 +431,7 @@ void DeferredDeletionQueueVulkan::EnqueueGenericResource(Type type, uint64 handl ScopeLock lock(_locker); #if BUILD_DEBUG - const std::function ContainsHandle = [handle](const Entry& e) + const Function ContainsHandle = [handle](const Entry& e) { return e.Handle == handle; }; @@ -868,7 +868,7 @@ GPUBufferVulkan* HelperResourcesVulkan::GetDummyBuffer() if (!_dummyBuffer) { _dummyBuffer = (GPUBufferVulkan*)_device->CreateBuffer(TEXT("DummyBuffer")); - _dummyBuffer->Init(GPUBufferDescription::Buffer(sizeof(int32), GPUBufferFlags::ShaderResource | GPUBufferFlags::UnorderedAccess, PixelFormat::R32_SInt)); + _dummyBuffer->Init(GPUBufferDescription::Buffer(sizeof(int32) * 256, GPUBufferFlags::ShaderResource | GPUBufferFlags::UnorderedAccess, PixelFormat::R32_SInt)); } return _dummyBuffer; @@ -1078,13 +1078,16 @@ GPUDevice* GPUDeviceVulkan::Create() VkInstanceCreateInfo instInfo; RenderToolsVulkan::ZeroStruct(instInfo, VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO); +#if PLATFORM_APPLE_FAMILY + instInfo.flags |= VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR; +#endif instInfo.pApplicationInfo = &appInfo; GetInstanceLayersAndExtensions(InstanceExtensions, InstanceLayers, SupportsDebugUtilsExt); const auto hasExtension = [](const Array& extensions, const char* name) -> bool { - const std::function callback = [&name](const char* const& extension) -> bool + const Function callback = [&name](const char* const& extension) -> bool { return extension && StringUtils::Compare(extension, name) == 0; }; diff --git a/Source/Engine/GraphicsDevice/Vulkan/GraphicsDeviceVulkan.Build.cs b/Source/Engine/GraphicsDevice/Vulkan/GraphicsDeviceVulkan.Build.cs index 252652978..9ffa68272 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/GraphicsDeviceVulkan.Build.cs +++ b/Source/Engine/GraphicsDevice/Vulkan/GraphicsDeviceVulkan.Build.cs @@ -51,7 +51,8 @@ public sealed class VulkanSdk : Sdk var subDirs = Directory.GetDirectories(path); if (subDirs.Length != 0) { - path = Path.Combine(subDirs[0], "macOS"); + Flax.Build.Utilities.SortVersionDirectories(subDirs); + path = Path.Combine(subDirs.Last(), "macOS"); if (Directory.Exists(path)) vulkanSdk = path; } diff --git a/Source/Engine/GraphicsDevice/Vulkan/IncludeVulkanHeaders.h b/Source/Engine/GraphicsDevice/Vulkan/IncludeVulkanHeaders.h index 3a1b6a615..4e2694aab 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/IncludeVulkanHeaders.h +++ b/Source/Engine/GraphicsDevice/Vulkan/IncludeVulkanHeaders.h @@ -41,4 +41,15 @@ #define VMA_NOT_NULL #include +#if PLATFORM_APPLE_FAMILY +// Declare potentially missing extensions from newer SDKs +#ifndef VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME +#define VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME "VK_KHR_portability_enumeration" +#define VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR 0x00000001 +#endif +#ifndef VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME +#define VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME "VK_KHR_portability_subset" +#endif +#endif + #endif diff --git a/Source/Engine/Input/Input.cpp b/Source/Engine/Input/Input.cpp index 81411ed76..dbcdf66bd 100644 --- a/Source/Engine/Input/Input.cpp +++ b/Source/Engine/Input/Input.cpp @@ -97,7 +97,8 @@ Action Input::MouseLeave; Delegate Input::TouchDown; Delegate Input::TouchMove; Delegate Input::TouchUp; -Delegate Input::ActionTriggered; +Delegate Input::ActionTriggered; +Delegate Input::AxisValueChanged; Array Input::ActionMappings; Array Input::AxisMappings; @@ -1017,14 +1018,22 @@ void InputService::Update() Input::SetMousePosition(Screen::GetSize() * 0.5f); } - // Send events for the active actions (send events only in play mode) + // Send events for the active actions and axes (send events only in play mode) if (!Time::GetGamePaused()) { + for (auto i = Axes.Begin(); i.IsNotEnd(); ++i) + { + if (Math::NotNearEqual(i->Value.Value, i->Value.PrevKeyValue)) + { + Input::AxisValueChanged(i->Key); + } + } + for (auto i = Actions.Begin(); i.IsNotEnd(); ++i) { - if (i->Value.Active) + if (i->Value.State != InputActionState::Waiting) { - Input::ActionTriggered(i->Key); + Input::ActionTriggered(i->Key, i->Value.State); } } } diff --git a/Source/Engine/Input/Input.h b/Source/Engine/Input/Input.h index 84d312fa3..c11026eff 100644 --- a/Source/Engine/Input/Input.h +++ b/Source/Engine/Input/Input.h @@ -293,7 +293,13 @@ public: /// Event fired when virtual input action is triggered. Called before scripts update. See to edit configuration. /// /// - API_EVENT() static Delegate ActionTriggered; + API_EVENT() static Delegate ActionTriggered; + + /// + /// Event fired when virtual input axis is changed. Called before scripts update. See to edit configuration. + /// + /// + API_EVENT() static Delegate AxisValueChanged; /// /// Gets the value of the virtual action identified by name. Use to get the current config. diff --git a/Source/Engine/Level/Components/MissingScript.h b/Source/Engine/Level/Components/MissingScript.h new file mode 100644 index 000000000..bfb73498f --- /dev/null +++ b/Source/Engine/Level/Components/MissingScript.h @@ -0,0 +1,65 @@ +// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. + +#pragma once + +#if USE_EDITOR + +#include "Engine/Core/Cache.h" +#include "Engine/Scripting/Script.h" +#include "Engine/Scripting/ScriptingObjectReference.h" +#include "Engine/Serialization/JsonWriters.h" + +/// +/// Actor script component that represents missing script. +/// +API_CLASS(Attributes="HideInEditor") class FLAXENGINE_API MissingScript : public Script +{ + API_AUTO_SERIALIZATION(); + DECLARE_SCRIPTING_TYPE(MissingScript); + +private: + ScriptingObjectReference