Merge branch 'FlaxEngine:master' into visject_grid_snap
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
|
||||
#include "../Collections/Array.h"
|
||||
#include "../Collections/Dictionary.h"
|
||||
#include <functional>
|
||||
#include "../Delegate.h"
|
||||
|
||||
class ArrayExtensions;
|
||||
|
||||
@@ -23,7 +23,6 @@ public:
|
||||
/// <summary>
|
||||
/// Gets the common key.
|
||||
/// </summary>
|
||||
/// <returns>The key.</returns>
|
||||
FORCE_INLINE const TKey& GetKey() const
|
||||
{
|
||||
return _key;
|
||||
@@ -32,7 +31,6 @@ public:
|
||||
/// <summary>
|
||||
/// Gets the common key.
|
||||
/// </summary>
|
||||
/// <returns>The key.</returns>
|
||||
FORCE_INLINE TKey GetKey()
|
||||
{
|
||||
return _key;
|
||||
@@ -52,7 +50,7 @@ public:
|
||||
/// <param name="predicate">The prediction function. Should return true for the target element to find.</param>
|
||||
/// <returns>The index of the element or -1 if nothing found.</returns>
|
||||
template<typename T, typename AllocationType>
|
||||
static int32 IndexOf(const Array<T, AllocationType>& obj, const std::function<bool(const T&)>& predicate)
|
||||
static int32 IndexOf(const Array<T, AllocationType>& obj, const Function<bool(const T&)>& predicate)
|
||||
{
|
||||
for (int32 i = 0; i < obj.Count(); i++)
|
||||
{
|
||||
@@ -71,7 +69,7 @@ public:
|
||||
/// <param name="predicate">The prediction function.</param>
|
||||
/// <returns>True if any element in the collection matches the prediction, otherwise false.</returns>
|
||||
template<typename T, typename AllocationType>
|
||||
static bool Any(const Array<T, AllocationType>& obj, const std::function<bool(const T&)>& predicate)
|
||||
static bool Any(const Array<T, AllocationType>& obj, const Function<bool(const T&)>& predicate)
|
||||
{
|
||||
for (int32 i = 0; i < obj.Count(); i++)
|
||||
{
|
||||
@@ -90,7 +88,7 @@ public:
|
||||
/// <param name="predicate">The prediction function.</param>
|
||||
/// <returns>True if all elements in the collection matches the prediction, otherwise false.</returns>
|
||||
template<typename T, typename AllocationType>
|
||||
static int32 All(const Array<T, AllocationType>& obj, const std::function<bool(const T&)>& predicate)
|
||||
static int32 All(const Array<T, AllocationType>& obj, const Function<bool(const T&)>& predicate)
|
||||
{
|
||||
for (int32 i = 0; i < obj.Count(); i++)
|
||||
{
|
||||
@@ -109,7 +107,7 @@ public:
|
||||
/// <param name="keySelector">A function to extract the key for each element.</param>
|
||||
/// <param name="result">The result collection with groups.</param>
|
||||
template<typename TSource, typename TKey, typename AllocationType>
|
||||
static void GroupBy(const Array<TSource, AllocationType>& obj, const std::function<TKey(TSource const&)>& keySelector, Array<IGrouping<TKey, TSource>, AllocationType>& result)
|
||||
static void GroupBy(const Array<TSource, AllocationType>& obj, const Function<TKey(TSource const&)>& keySelector, Array<IGrouping<TKey, TSource>, AllocationType>& result)
|
||||
{
|
||||
Dictionary<TKey, IGrouping<TKey, TSource>> data(static_cast<int32>(obj.Count() * 3.0f));
|
||||
for (int32 i = 0; i < obj.Count(); i++)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
|
||||
namespace FlaxEngine
|
||||
{
|
||||
/// <summary>
|
||||
@@ -23,11 +25,17 @@ namespace FlaxEngine
|
||||
/// </summary>
|
||||
public float ValueRaw => Input.GetAxisRaw(Name);
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when axis is changed. Called before scripts update.
|
||||
/// </summary>
|
||||
public event Action ValueChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="InputAxis"/> class.
|
||||
/// </summary>
|
||||
public InputAxis()
|
||||
{
|
||||
Input.AxisValueChanged += Handler;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -36,7 +44,31 @@ namespace FlaxEngine
|
||||
/// <param name="name">The axis name.</param>
|
||||
public InputAxis(string name)
|
||||
{
|
||||
Input.AxisValueChanged += Handler;
|
||||
Name = name;
|
||||
}
|
||||
|
||||
private void Handler(string name)
|
||||
{
|
||||
if (string.Equals(Name, name, StringComparison.OrdinalIgnoreCase))
|
||||
ValueChanged?.Invoke();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finalizes an instance of the <see cref="InputAxis"/> class.
|
||||
/// </summary>
|
||||
~InputAxis()
|
||||
{
|
||||
Input.AxisValueChanged -= Handler;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Releases this object.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
Input.AxisValueChanged -= Handler;
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,15 +16,36 @@ namespace FlaxEngine
|
||||
public string Name;
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the event has been triggered during the current frame (e.g. user pressed a key). Use <see cref="Triggered"/> 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 <see cref="Pressed"/> to catch events without active waiting.
|
||||
/// </summary>
|
||||
public bool Active => Input.GetAction(Name);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the event state. Use Use <see cref="Pressed"/>, <see cref="Pressing"/>, <see cref="Released"/> to catch events without active waiting.
|
||||
/// </summary>
|
||||
public InputActionState State => Input.GetActionState(Name);
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when event is triggered (e.g. user pressed a key). Called before scripts update.
|
||||
/// </summary>
|
||||
[System.Obsolete("Depreciated in 1.7, use Pressed Action.")]
|
||||
public event Action Triggered;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when event is pressed (e.g. user pressed a key). Called before scripts update.
|
||||
/// </summary>
|
||||
public event Action Pressed;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when event is being pressing (e.g. user pressing a key). Called before scripts update.
|
||||
/// </summary>
|
||||
public event Action Pressing;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when event is released (e.g. user releases a key). Called before scripts update.
|
||||
/// </summary>
|
||||
public event Action Released;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="InputEvent"/> class.
|
||||
/// </summary>
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -130,7 +130,7 @@ void FoliageType::Serialize(SerializeStream& stream, const void* otherObj)
|
||||
|
||||
SERIALIZE(Model);
|
||||
|
||||
const std::function<bool(const ModelInstanceEntry&)> IsValidMaterial = [](const ModelInstanceEntry& e) -> bool
|
||||
const Function<bool(const ModelInstanceEntry&)> IsValidMaterial = [](const ModelInstanceEntry& e) -> bool
|
||||
{
|
||||
return e.Material;
|
||||
};
|
||||
|
||||
@@ -66,7 +66,7 @@ public:
|
||||
const auto parentModelIndex = node.ParentIndex;
|
||||
|
||||
// Find matching node in skeleton (or map to best parent)
|
||||
const std::function<bool(const T&)> f = [node](const T& x) -> bool
|
||||
const Function<bool(const T&)> f = [node](const T& x) -> bool
|
||||
{
|
||||
return x.Name == node.Name;
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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<const char*>& de
|
||||
|
||||
const auto HasExtension = [&deviceExtensions](const char* name) -> bool
|
||||
{
|
||||
const std::function<bool(const char* const&)> CheckCallback = [&name](const char* const& extension) -> bool
|
||||
const Function<bool(const char* const&)> CheckCallback = [&name](const char* const& extension) -> bool
|
||||
{
|
||||
return StringUtils::Compare(extension, name) == 0;
|
||||
};
|
||||
|
||||
@@ -431,7 +431,7 @@ void DeferredDeletionQueueVulkan::EnqueueGenericResource(Type type, uint64 handl
|
||||
ScopeLock lock(_locker);
|
||||
|
||||
#if BUILD_DEBUG
|
||||
const std::function<bool(const Entry&)> ContainsHandle = [handle](const Entry& e)
|
||||
const Function<bool(const Entry&)> 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<const char*>& extensions, const char* name) -> bool
|
||||
{
|
||||
const std::function<bool(const char* const&)> callback = [&name](const char* const& extension) -> bool
|
||||
const Function<bool(const char* const&)> callback = [&name](const char* const& extension) -> bool
|
||||
{
|
||||
return extension && StringUtils::Compare(extension, name) == 0;
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -41,4 +41,15 @@
|
||||
#define VMA_NOT_NULL
|
||||
#include <ThirdParty/VulkanMemoryAllocator/vk_mem_alloc.h>
|
||||
|
||||
#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
|
||||
|
||||
@@ -97,7 +97,8 @@ Action Input::MouseLeave;
|
||||
Delegate<const Float2&, int32> Input::TouchDown;
|
||||
Delegate<const Float2&, int32> Input::TouchMove;
|
||||
Delegate<const Float2&, int32> Input::TouchUp;
|
||||
Delegate<StringView> Input::ActionTriggered;
|
||||
Delegate<StringView, InputActionState> Input::ActionTriggered;
|
||||
Delegate<StringView> Input::AxisValueChanged;
|
||||
Array<ActionConfig> Input::ActionMappings;
|
||||
Array<AxisConfig> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -293,7 +293,13 @@ public:
|
||||
/// Event fired when virtual input action is triggered. Called before scripts update. See <see cref="ActionMappings"/> to edit configuration.
|
||||
/// </summary>
|
||||
/// <seealso cref="InputEvent"/>
|
||||
API_EVENT() static Delegate<StringView> ActionTriggered;
|
||||
API_EVENT() static Delegate<StringView, InputActionState> ActionTriggered;
|
||||
|
||||
/// <summary>
|
||||
/// Event fired when virtual input axis is changed. Called before scripts update. See <see cref="AxisMappings"/> to edit configuration.
|
||||
/// </summary>
|
||||
/// <seealso cref="InputAxis"/>
|
||||
API_EVENT() static Delegate<StringView> AxisValueChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value of the virtual action identified by name. Use <see cref="ActionMappings"/> to get the current config.
|
||||
|
||||
65
Source/Engine/Level/Components/MissingScript.h
Normal file
65
Source/Engine/Level/Components/MissingScript.h
Normal file
@@ -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"
|
||||
|
||||
/// <summary>
|
||||
/// Actor script component that represents missing script.
|
||||
/// </summary>
|
||||
API_CLASS(Attributes="HideInEditor") class FLAXENGINE_API MissingScript : public Script
|
||||
{
|
||||
API_AUTO_SERIALIZATION();
|
||||
DECLARE_SCRIPTING_TYPE(MissingScript);
|
||||
|
||||
private:
|
||||
ScriptingObjectReference<Script> _referenceScript;
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
/// Namespace and type name of missing script.
|
||||
/// </summary>
|
||||
API_FIELD(Attributes="ReadOnly") String MissingTypeName;
|
||||
|
||||
/// <summary>
|
||||
/// Missing script serialized data.
|
||||
/// </summary>
|
||||
API_FIELD(Hidden, Attributes="HideInEditor") String Data;
|
||||
|
||||
/// <summary>
|
||||
/// Field for assigning new script to transfer data to.
|
||||
/// </summary>
|
||||
API_PROPERTY() ScriptingObjectReference<Script> GetReferenceScript() const
|
||||
{
|
||||
return _referenceScript;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Field for assigning new script to transfer data to.
|
||||
/// </summary>
|
||||
API_PROPERTY() void SetReferenceScript(const ScriptingObjectReference<Script>& value)
|
||||
{
|
||||
_referenceScript = value;
|
||||
if (Data.IsEmpty())
|
||||
return;
|
||||
rapidjson_flax::Document document;
|
||||
document.Parse(Data.ToStringAnsi().GetText());
|
||||
|
||||
auto modifier = Cache::ISerializeModifier.Get();
|
||||
_referenceScript->Deserialize(document, modifier.Value);
|
||||
|
||||
DeleteObject();
|
||||
}
|
||||
};
|
||||
|
||||
inline MissingScript::MissingScript(const SpawnParams& params)
|
||||
: Script(params)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "SceneObjectsFactory.h"
|
||||
#include "Components/MissingScript.h"
|
||||
#include "Engine/Level/Actor.h"
|
||||
#include "Engine/Level/Prefabs/Prefab.h"
|
||||
#include "Engine/Content/Content.h"
|
||||
@@ -230,7 +231,8 @@ void SceneObjectsFactory::HandleObjectDeserializationError(const ISerializable::
|
||||
rapidjson_flax::StringBuffer buffer;
|
||||
PrettyJsonWriter writer(buffer);
|
||||
value.Accept(writer.GetWriter());
|
||||
LOG(Warning, "Failed to deserialize scene object from data: {0}", String(buffer.GetString()));
|
||||
String bufferStr(buffer.GetString());
|
||||
LOG(Warning, "Failed to deserialize scene object from data: {0}", bufferStr);
|
||||
|
||||
// Try to log some useful info about missing object (eg. it's parent name for faster fixing)
|
||||
const auto parentIdMember = value.FindMember("ParentID");
|
||||
@@ -240,6 +242,14 @@ void SceneObjectsFactory::HandleObjectDeserializationError(const ISerializable::
|
||||
Actor* parent = Scripting::FindObject<Actor>(parentId);
|
||||
if (parent)
|
||||
{
|
||||
#if USE_EDITOR
|
||||
// Add dummy script
|
||||
auto* dummyScript = parent->AddScript<MissingScript>();
|
||||
const auto parentIdMember = value.FindMember("TypeName");
|
||||
if (parentIdMember != value.MemberEnd() && parentIdMember->value.IsString())
|
||||
dummyScript->MissingTypeName = parentIdMember->value.GetString();
|
||||
dummyScript->Data = MoveTemp(bufferStr);
|
||||
#endif
|
||||
LOG(Warning, "Parent actor of the missing object: {0}", parent->GetName());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#include <mach/mach_time.h>
|
||||
#include <mach-o/dyld.h>
|
||||
#include <uuid/uuid.h>
|
||||
@@ -316,6 +317,14 @@ bool ApplePlatform::Init()
|
||||
OnPlatformUserAdd(New<User>(username));
|
||||
}
|
||||
|
||||
// Increase the maximum number of simultaneously open files
|
||||
{
|
||||
struct rlimit limit;
|
||||
limit.rlim_cur = OPEN_MAX;
|
||||
limit.rlim_max = RLIM_INFINITY;
|
||||
setrlimit(RLIMIT_NOFILE, &limit);
|
||||
}
|
||||
|
||||
AutoreleasePool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
return false;
|
||||
|
||||
@@ -351,6 +351,34 @@ namespace FlaxEngine.Json
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serialize <see cref="Tag"/> as inlined text.
|
||||
/// </summary>
|
||||
/// <seealso cref="Newtonsoft.Json.JsonConverter" />
|
||||
internal class TagConverter : JsonConverter
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override void WriteJson(JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer)
|
||||
{
|
||||
var tag = (Tag)value;
|
||||
writer.WriteValue(tag.ToString());
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer)
|
||||
{
|
||||
if (reader.TokenType == JsonToken.String)
|
||||
return Tags.Get((string)reader.Value);
|
||||
return Tag.Default;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return objectType == typeof(Tag);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
/// <summary>
|
||||
/// Serialize Guid values using `N` format
|
||||
|
||||
@@ -127,6 +127,7 @@ namespace FlaxEngine.Json
|
||||
settings.Converters.Add(new MarginConverter());
|
||||
settings.Converters.Add(new VersionConverter());
|
||||
settings.Converters.Add(new LocalizedStringConverter());
|
||||
settings.Converters.Add(new TagConverter());
|
||||
//settings.Converters.Add(new GuidConverter());
|
||||
return settings;
|
||||
}
|
||||
|
||||
@@ -705,8 +705,15 @@ bool ModelTool::ImportDataAssimp(const char* path, ImportedModelData& data, Opti
|
||||
return true;
|
||||
}
|
||||
|
||||
// Create root node
|
||||
AssimpNode& rootNode = context->Nodes.AddOne();
|
||||
rootNode.ParentIndex = -1;
|
||||
rootNode.LodIndex = 0;
|
||||
rootNode.Name = TEXT("Root");
|
||||
rootNode.LocalTransform = Transform::Identity;
|
||||
|
||||
// Process imported scene nodes
|
||||
ProcessNodes(*context, context->Scene->mRootNode, -1);
|
||||
ProcessNodes(*context, context->Scene->mRootNode, 0);
|
||||
}
|
||||
DeleteMe<AssimpImporterData> contextCleanup(options.SplitContext ? nullptr : context);
|
||||
|
||||
@@ -822,7 +829,13 @@ bool ModelTool::ImportDataAssimp(const char* path, ImportedModelData& data, Opti
|
||||
const auto animations = context->Scene->mAnimations[animIndex];
|
||||
data.Animation.Channels.Resize(animations->mNumChannels, false);
|
||||
data.Animation.Duration = animations->mDuration;
|
||||
data.Animation.FramesPerSecond = animations->mTicksPerSecond != 0.0 ? animations->mTicksPerSecond : 25.0;
|
||||
data.Animation.FramesPerSecond = animations->mTicksPerSecond;
|
||||
if (data.Animation.FramesPerSecond <= 0)
|
||||
{
|
||||
data.Animation.FramesPerSecond = context->Options.DefaultFrameRate;
|
||||
if (data.Animation.FramesPerSecond <= 0)
|
||||
data.Animation.FramesPerSecond = 30.0f;
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < animations->mNumChannels; i++)
|
||||
{
|
||||
|
||||
@@ -1474,7 +1474,7 @@ bool ModelTool::ImportModel(const String& path, ModelData& meshData, Options& op
|
||||
|
||||
// Group meshes that can be merged together
|
||||
typedef Pair<int32, int32> MeshGroupKey;
|
||||
const std::function<MeshGroupKey(MeshData* const&)> f = [](MeshData* const& x) -> MeshGroupKey
|
||||
const Function<MeshGroupKey(MeshData* const&)> f = [](MeshData* const& x) -> MeshGroupKey
|
||||
{
|
||||
return MeshGroupKey(x->NodeIndex, x->MaterialSlotIndex);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user