Merge branch '1.2' into IconOverhaul
This commit is contained in:
BIN
Content/Shaders/BitonicSort.flax
LFS
BIN
Content/Shaders/BitonicSort.flax
LFS
Binary file not shown.
@@ -3,7 +3,7 @@
|
||||
"Version": {
|
||||
"Major": 1,
|
||||
"Minor": 1,
|
||||
"Build": 6217
|
||||
"Build": 6218
|
||||
},
|
||||
"Company": "Flax",
|
||||
"Copyright": "Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.",
|
||||
|
||||
@@ -234,6 +234,7 @@
|
||||
<s:String x:Key="/Default/PatternsAndTemplates/Todo/TodoPatterns/=EEA05B0ED8200E4BA9D2D3F1052EBFFD/Name/@EntryValue">Deprecated</s:String>
|
||||
<s:String x:Key="/Default/PatternsAndTemplates/Todo/TodoPatterns/=EEA05B0ED8200E4BA9D2D3F1052EBFFD/Pattern/@EntryValue">(?<=\W|^)(?<TAG>\[Deprecated)(\W|$)(.*)</s:String>
|
||||
<s:String x:Key="/Default/PatternsAndTemplates/Todo/TodoPatterns/=EEA05B0ED8200E4BA9D2D3F1052EBFFD/TodoIconStyle/@EntryValue">Normal</s:String>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Ackermann/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=analytics/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Antialiasing/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=backbuffer/@EntryIndexedValue">True</s:Boolean>
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "Editor/Editor.h"
|
||||
#include "Editor/ProjectInfo.h"
|
||||
#include "Engine/Engine/EngineService.h"
|
||||
#include "Engine/Engine/Globals.h"
|
||||
#include "Engine/Graphics/GPUDevice.h"
|
||||
#include "Engine/Utilities/StringConverter.h"
|
||||
#include "FlaxEngine.Gen.h"
|
||||
|
||||
@@ -53,6 +53,11 @@ namespace FlaxEditor.Content.Create
|
||||
/// </summary>
|
||||
NavigationSettings,
|
||||
|
||||
/// <summary>
|
||||
/// The localization settings.
|
||||
/// </summary>
|
||||
LocalizationSettings,
|
||||
|
||||
/// <summary>
|
||||
/// The build settings.
|
||||
/// </summary>
|
||||
@@ -92,6 +97,11 @@ namespace FlaxEditor.Content.Create
|
||||
/// The Android settings
|
||||
/// </summary>
|
||||
AndroidPlatformSettings,
|
||||
|
||||
/// <summary>
|
||||
/// The Switch settings
|
||||
/// </summary>
|
||||
SwitchPlatformSettings,
|
||||
}
|
||||
|
||||
private static readonly Type[] _types =
|
||||
@@ -103,6 +113,7 @@ namespace FlaxEditor.Content.Create
|
||||
typeof(PhysicsSettings),
|
||||
typeof(GraphicsSettings),
|
||||
typeof(NavigationSettings),
|
||||
typeof(LocalizationSettings),
|
||||
typeof(BuildSettings),
|
||||
typeof(InputSettings),
|
||||
typeof(WindowsPlatformSettings),
|
||||
@@ -111,6 +122,7 @@ namespace FlaxEditor.Content.Create
|
||||
TypeUtils.GetManagedType(GameSettings.PS4PlatformSettingsTypename),
|
||||
TypeUtils.GetManagedType(GameSettings.XboxScarlettPlatformSettingsTypename),
|
||||
typeof(AndroidPlatformSettings),
|
||||
TypeUtils.GetManagedType(GameSettings.SwitchPlatformSettingsTypename),
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -116,8 +116,7 @@ namespace FlaxEditor.Content.Import
|
||||
if (FileTypes.TryGetValue(extension, out ImportFileEntryHandler createDelegate))
|
||||
return createDelegate(ref request);
|
||||
|
||||
// Use default type
|
||||
return request.IsBinaryAsset ? new AssetImportEntry(ref request) : new ImportFileEntry(ref request);
|
||||
return request.IsInBuilt ? new AssetImportEntry(ref request) : new ImportFileEntry(ref request);
|
||||
}
|
||||
|
||||
internal static void RegisterDefaultTypes()
|
||||
|
||||
@@ -21,9 +21,9 @@ namespace FlaxEditor.Content.Import
|
||||
public string OutputPath;
|
||||
|
||||
/// <summary>
|
||||
/// Flag set to true for binary assets handled by the engine internally.
|
||||
/// Flag set to true for the assets handled by the engine internally.
|
||||
/// </summary>
|
||||
public bool IsBinaryAsset;
|
||||
public bool IsInBuilt;
|
||||
|
||||
/// <summary>
|
||||
/// Flag used to skip showing import settings dialog to used. Can be used for importing assets from code by plugins.
|
||||
|
||||
@@ -75,6 +75,7 @@ namespace FlaxEditor.Content
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public int MetadataToken => 0;
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -76,7 +76,7 @@ void PreviewsCache::FlushTask::OnEnd()
|
||||
ThreadPoolTask::OnEnd();
|
||||
}
|
||||
|
||||
REGISTER_BINARY_ASSET(PreviewsCache, "FlaxEditor.PreviewsCache", ::New<TextureAssetUpgrader>(), false);
|
||||
REGISTER_BINARY_ASSET_WITH_UPGRADER(PreviewsCache, "FlaxEditor.PreviewsCache", TextureAssetUpgrader, false);
|
||||
|
||||
PreviewsCache::PreviewsCache(const SpawnParams& params, const AssetInfo* info)
|
||||
: SpriteAtlas(params, info)
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
using System;
|
||||
using FlaxEditor.Content.Create;
|
||||
using FlaxEditor.Content.Settings;
|
||||
using FlaxEditor.CustomEditors;
|
||||
using FlaxEditor.CustomEditors.Editors;
|
||||
using FlaxEditor.Windows;
|
||||
@@ -45,18 +44,12 @@ namespace FlaxEditor.Content
|
||||
/// <inheritdoc />
|
||||
public override bool IsProxyFor(ContentItem item)
|
||||
{
|
||||
return item is JsonAssetItem;
|
||||
return item is JsonAssetItem json && json.TypeName == TypeName;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Color AccentColor => Color.FromRGB(0xd14f67);
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool AcceptsAsset(string typeName, string path)
|
||||
{
|
||||
return typeName == TypeName && base.AcceptsAsset(typeName, path);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override AssetItem ConstructItem(string path, string typeName, ref Guid id)
|
||||
{
|
||||
@@ -143,6 +136,12 @@ namespace FlaxEditor.Content
|
||||
return path.EndsWith(FileExtension, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool IsProxyFor(ContentItem item)
|
||||
{
|
||||
return item is JsonAssetItem;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool CanCreate(ContentFolder targetLocation)
|
||||
{
|
||||
|
||||
24
Source/Editor/Content/Proxy/LocalizedStringTableProxy.cs
Normal file
24
Source/Editor/Content/Proxy/LocalizedStringTableProxy.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
|
||||
using FlaxEditor.Windows;
|
||||
using FlaxEditor.Windows.Assets;
|
||||
using FlaxEngine;
|
||||
|
||||
namespace FlaxEditor.Content
|
||||
{
|
||||
/// <summary>
|
||||
/// <see cref="LocalizedStringTable"/> proxy.
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEditor.Content.JsonAssetProxy" />
|
||||
public class LocalizedStringTableProxy : JsonAssetProxy
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override EditorWindow Open(Editor editor, ContentItem item)
|
||||
{
|
||||
return new LocalizedStringTableWindow(editor, (JsonAssetItem)item);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string TypeName => "FlaxEngine.LocalizedStringTable";
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "Engine/Core/Collections/Array.h"
|
||||
#include "Engine/Core/Collections/HashSet.h"
|
||||
#include "Engine/Core/Collections/Dictionary.h"
|
||||
#include "Engine/Core/Types/Guid.h"
|
||||
|
||||
class GameCooker;
|
||||
class PlatformTools;
|
||||
@@ -87,34 +88,14 @@ API_ENUM() enum class BuildPlatform
|
||||
/// </summary>
|
||||
API_ENUM(Attributes="EditorDisplay(null, \"Android ARM64 (arm64-v8a)\")")
|
||||
AndroidARM64 = 9,
|
||||
|
||||
/// <summary>
|
||||
/// Switch.
|
||||
/// </summary>
|
||||
Switch = 10,
|
||||
};
|
||||
|
||||
inline const Char* ToString(const BuildPlatform platform)
|
||||
{
|
||||
switch (platform)
|
||||
{
|
||||
case BuildPlatform::Windows32:
|
||||
return TEXT("Windows x86");
|
||||
case BuildPlatform::Windows64:
|
||||
return TEXT("Windows x64");
|
||||
case BuildPlatform::UWPx86:
|
||||
return TEXT("Windows Store x86");
|
||||
case BuildPlatform::UWPx64:
|
||||
return TEXT("Windows Store x64");
|
||||
case BuildPlatform::XboxOne:
|
||||
return TEXT("Xbox One");
|
||||
case BuildPlatform::LinuxX64:
|
||||
return TEXT("Linux x64");
|
||||
case BuildPlatform::PS4:
|
||||
return TEXT("PlayStation 4");
|
||||
case BuildPlatform::XboxScarlett:
|
||||
return TEXT("Xbox Scarlett");
|
||||
case BuildPlatform::AndroidARM64:
|
||||
return TEXT("Android ARM64");
|
||||
default:
|
||||
return TEXT("?");
|
||||
}
|
||||
}
|
||||
extern FLAXENGINE_API const Char* ToString(const BuildPlatform platform);
|
||||
|
||||
/// <summary>
|
||||
/// Game build configuration modes.
|
||||
@@ -137,20 +118,7 @@ API_ENUM() enum class BuildConfiguration
|
||||
Release = 2,
|
||||
};
|
||||
|
||||
inline const Char* ToString(const BuildConfiguration configuration)
|
||||
{
|
||||
switch (configuration)
|
||||
{
|
||||
case BuildConfiguration::Debug:
|
||||
return TEXT("Debug");
|
||||
case BuildConfiguration::Development:
|
||||
return TEXT("Development");
|
||||
case BuildConfiguration::Release:
|
||||
return TEXT("Release");
|
||||
default:
|
||||
return TEXT("?");
|
||||
}
|
||||
}
|
||||
extern FLAXENGINE_API const Char* ToString(const BuildConfiguration configuration);
|
||||
|
||||
#define BUILD_STEP_CANCEL_CHECK if (GameCooker::IsCancelRequested()) return true
|
||||
|
||||
@@ -185,9 +153,14 @@ struct FLAXENGINE_API CookingData
|
||||
String OriginalOutputPath;
|
||||
|
||||
/// <summary>
|
||||
/// The output path.
|
||||
/// The output path for data files (Content, Mono, etc.).
|
||||
/// </summary>
|
||||
String OutputPath;
|
||||
String DataOutputPath;
|
||||
|
||||
/// <summary>
|
||||
/// The output path for binaries (executable and code libraries).
|
||||
/// </summary>
|
||||
String CodeOutputPath;
|
||||
|
||||
/// <summary>
|
||||
/// The platform tools.
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "Engine/Serialization/JsonTools.h"
|
||||
#include "Engine/Content/Content.h"
|
||||
#include "Engine/Engine/EngineService.h"
|
||||
#include "Engine/Engine/Globals.h"
|
||||
#include "Engine/Threading/ThreadSpawner.h"
|
||||
#include "Engine/Platform/FileSystem.h"
|
||||
#include "Steps/ValidateStep.h"
|
||||
@@ -39,7 +40,6 @@
|
||||
#endif
|
||||
#if PLATFORM_TOOLS_PS4
|
||||
#include "Platforms/PS4/Editor/PlatformTools/PS4PlatformTools.h"
|
||||
#include "Platforms/PS4/Engine/Platform/PS4PlatformSettings.h"
|
||||
#endif
|
||||
#if PLATFORM_TOOLS_XBOX_SCARLETT
|
||||
#include "Platforms/XboxScarlett/Editor/PlatformTools/XboxScarlettPlatformTools.h"
|
||||
@@ -47,6 +47,9 @@
|
||||
#if PLATFORM_TOOLS_ANDROID
|
||||
#include "Platform/Android/AndroidPlatformTools.h"
|
||||
#endif
|
||||
#if PLATFORM_TOOLS_SWITCH
|
||||
#include "Platforms/Switch/Editor/PlatformTools/SwitchPlatformTools.h"
|
||||
#endif
|
||||
|
||||
namespace GameCookerImpl
|
||||
{
|
||||
@@ -89,6 +92,50 @@ using namespace GameCookerImpl;
|
||||
Delegate<GameCooker::EventType> GameCooker::OnEvent;
|
||||
Delegate<const String&, float> GameCooker::OnProgress;
|
||||
|
||||
const Char* ToString(const BuildPlatform platform)
|
||||
{
|
||||
switch (platform)
|
||||
{
|
||||
case BuildPlatform::Windows32:
|
||||
return TEXT("Windows x86");
|
||||
case BuildPlatform::Windows64:
|
||||
return TEXT("Windows x64");
|
||||
case BuildPlatform::UWPx86:
|
||||
return TEXT("Windows Store x86");
|
||||
case BuildPlatform::UWPx64:
|
||||
return TEXT("Windows Store x64");
|
||||
case BuildPlatform::XboxOne:
|
||||
return TEXT("Xbox One");
|
||||
case BuildPlatform::LinuxX64:
|
||||
return TEXT("Linux x64");
|
||||
case BuildPlatform::PS4:
|
||||
return TEXT("PlayStation 4");
|
||||
case BuildPlatform::XboxScarlett:
|
||||
return TEXT("Xbox Scarlett");
|
||||
case BuildPlatform::AndroidARM64:
|
||||
return TEXT("Android ARM64");
|
||||
case BuildPlatform::Switch:
|
||||
return TEXT("Switch");
|
||||
default:
|
||||
return TEXT("?");
|
||||
}
|
||||
}
|
||||
|
||||
const Char* ToString(const BuildConfiguration configuration)
|
||||
{
|
||||
switch (configuration)
|
||||
{
|
||||
case BuildConfiguration::Debug:
|
||||
return TEXT("Debug");
|
||||
case BuildConfiguration::Development:
|
||||
return TEXT("Development");
|
||||
case BuildConfiguration::Release:
|
||||
return TEXT("Release");
|
||||
default:
|
||||
return TEXT("?");
|
||||
}
|
||||
}
|
||||
|
||||
bool CookingData::AssetTypeStatistics::operator<(const AssetTypeStatistics& other) const
|
||||
{
|
||||
if (ContentSize != other.ContentSize)
|
||||
@@ -250,6 +297,11 @@ PlatformTools* GameCooker::GetTools(BuildPlatform platform)
|
||||
case BuildPlatform::AndroidARM64:
|
||||
result = New<AndroidPlatformTools>(ArchitectureType::ARM64);
|
||||
break;
|
||||
#endif
|
||||
#if PLATFORM_TOOLS_SWITCH
|
||||
case BuildPlatform::Switch:
|
||||
result = New<SwitchPlatformTools>();
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
Tools.Add(platform, result);
|
||||
@@ -282,9 +334,10 @@ void GameCooker::Build(BuildPlatform platform, BuildConfiguration configuration,
|
||||
data.Configuration = configuration;
|
||||
data.Options = options;
|
||||
data.CustomDefines = customDefines;
|
||||
data.OutputPath = outputPath;
|
||||
FileSystem::NormalizePath(data.OutputPath);
|
||||
data.OutputPath = data.OriginalOutputPath = FileSystem::ConvertRelativePathToAbsolute(Globals::ProjectFolder, data.OutputPath);
|
||||
data.OriginalOutputPath = outputPath;
|
||||
FileSystem::NormalizePath(data.OriginalOutputPath);
|
||||
data.OriginalOutputPath = FileSystem::ConvertRelativePathToAbsolute(Globals::ProjectFolder, data.OriginalOutputPath);
|
||||
data.CodeOutputPath = data.DataOutputPath = data.OriginalOutputPath;
|
||||
data.CacheDirectory = Globals::ProjectCacheFolder / TEXT("Cooker") / tools->GetName();
|
||||
if (!FileSystem::DirectoryExists(data.CacheDirectory))
|
||||
{
|
||||
@@ -367,7 +420,7 @@ bool GameCookerImpl::Build()
|
||||
CookingData& data = Data;
|
||||
LOG(Info, "Starting Game Cooker...");
|
||||
LOG(Info, "Platform: {0}, Configuration: {2}, Options: {1}", ::ToString(data.Platform), (int32)data.Options, ::ToString(data.Configuration));
|
||||
LOG(Info, "Output Path: {0}", data.OutputPath);
|
||||
LOG(Info, "Output Path: {0}", data.OriginalOutputPath);
|
||||
|
||||
// Late init feature
|
||||
if (Steps.IsEmpty())
|
||||
|
||||
@@ -104,7 +104,8 @@ PixelFormat AndroidPlatformTools::GetTextureFormat(CookingData& data, TextureBas
|
||||
void AndroidPlatformTools::OnBuildStarted(CookingData& data)
|
||||
{
|
||||
// Adjust the cooking output folder to be located inside the Gradle assets directory
|
||||
data.OutputPath /= TEXT("app/assets");
|
||||
data.DataOutputPath /= TEXT("app/assets");
|
||||
data.CodeOutputPath /= TEXT("app/assets");
|
||||
|
||||
PlatformTools::OnBuildStarted(data);
|
||||
}
|
||||
@@ -114,7 +115,7 @@ bool AndroidPlatformTools::OnPostProcess(CookingData& data)
|
||||
const auto gameSettings = GameSettings::Get();
|
||||
const auto platformSettings = AndroidPlatformSettings::Get();
|
||||
const auto platformDataPath = data.GetPlatformBinariesRoot();
|
||||
const auto assetsPath = data.OutputPath;
|
||||
const auto assetsPath = data.DataOutputPath;
|
||||
const auto jniLibsPath = data.OriginalOutputPath / TEXT("app/jniLibs");
|
||||
const auto projectVersion = Editor::Project->Version.ToString();
|
||||
const Char* abi;
|
||||
|
||||
@@ -38,7 +38,7 @@ bool LinuxPlatformTools::OnDeployBinaries(CookingData& data)
|
||||
{
|
||||
const auto gameSettings = GameSettings::Get();
|
||||
const auto platformSettings = LinuxPlatformSettings::Get();
|
||||
const auto outputPath = data.OutputPath;
|
||||
const auto outputPath = data.DataOutputPath;
|
||||
|
||||
// Copy binaries
|
||||
{
|
||||
|
||||
@@ -25,7 +25,7 @@ bool UWPPlatformTools::OnScriptsStepDone(CookingData& data)
|
||||
{
|
||||
// Override Newtonsoft.Json.dll for some platforms (that don't support runtime code generation)
|
||||
const String customBinPath = data.GetPlatformBinariesRoot() / TEXT("Newtonsoft.Json.dll");
|
||||
const String assembliesPath = data.OutputPath;
|
||||
const String assembliesPath = data.CodeOutputPath;
|
||||
if (FileSystem::CopyFile(assembliesPath / TEXT("Newtonsoft.Json.dll"), customBinPath))
|
||||
{
|
||||
data.Error(TEXT("Failed to copy deploy custom assembly."));
|
||||
@@ -43,7 +43,7 @@ bool UWPPlatformTools::OnDeployBinaries(CookingData& data)
|
||||
const auto uwpDataPath = platformDataPath / (isXboxOne ? TEXT("XboxOne") : TEXT("UWP")) / TEXT("Binaries");
|
||||
const auto gameSettings = GameSettings::Get();
|
||||
const auto platformSettings = UWPPlatformSettings::Get();
|
||||
Array<byte> fileTemplate;
|
||||
StringAnsi fileTemplate;
|
||||
|
||||
// Copy binaries
|
||||
const auto binPath = data.GetGameBinariesPath();
|
||||
@@ -64,7 +64,7 @@ bool UWPPlatformTools::OnDeployBinaries(CookingData& data)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (FileSystem::CopyFile(data.OutputPath / StringUtils::GetFileName(files[i]), files[i]))
|
||||
if (FileSystem::CopyFile(data.DataOutputPath / StringUtils::GetFileName(files[i]), files[i]))
|
||||
{
|
||||
data.Error(TEXT("Failed to setup output directory."));
|
||||
return true;
|
||||
@@ -92,7 +92,7 @@ bool UWPPlatformTools::OnDeployBinaries(CookingData& data)
|
||||
|
||||
// Prepare certificate
|
||||
const auto srcCertificatePath = Globals::ProjectFolder / platformSettings->CertificateLocation;
|
||||
const auto dstCertificatePath = data.OutputPath / TEXT("WSACertificate.pfx");
|
||||
const auto dstCertificatePath = data.DataOutputPath / TEXT("WSACertificate.pfx");
|
||||
if (platformSettings->CertificateLocation.HasChars() && FileSystem::FileExists(srcCertificatePath))
|
||||
{
|
||||
// Use cert from settings
|
||||
@@ -115,7 +115,7 @@ bool UWPPlatformTools::OnDeployBinaries(CookingData& data)
|
||||
}
|
||||
|
||||
// Copy assets
|
||||
const auto dstAssetsPath = data.OutputPath / TEXT("Assets");
|
||||
const auto dstAssetsPath = data.DataOutputPath / TEXT("Assets");
|
||||
const auto srcAssetsPath = uwpDataPath / TEXT("Assets");
|
||||
if (!FileSystem::DirectoryExists(dstAssetsPath))
|
||||
{
|
||||
@@ -125,7 +125,7 @@ bool UWPPlatformTools::OnDeployBinaries(CookingData& data)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
const auto dstPropertiesPath = data.OutputPath / TEXT("Properties");
|
||||
const auto dstPropertiesPath = data.DataOutputPath / TEXT("Properties");
|
||||
if (!FileSystem::DirectoryExists(dstPropertiesPath))
|
||||
{
|
||||
if (FileSystem::CreateDirectory(dstPropertiesPath))
|
||||
@@ -149,12 +149,11 @@ bool UWPPlatformTools::OnDeployBinaries(CookingData& data)
|
||||
if (!FileSystem::FileExists(dstAssemblyInfoPath))
|
||||
{
|
||||
// Get template
|
||||
if (File::ReadAllBytes(srcAssemblyInfoPath, fileTemplate))
|
||||
if (File::ReadAllText(srcAssemblyInfoPath, fileTemplate))
|
||||
{
|
||||
data.Error(TEXT("Failed to load AssemblyInfo.cs template."));
|
||||
return true;
|
||||
}
|
||||
fileTemplate[fileTemplate.Count() - 1] = 0;
|
||||
|
||||
// Write data to file
|
||||
auto file = FileWriteStream::Open(dstAssemblyInfoPath);
|
||||
@@ -163,7 +162,7 @@ bool UWPPlatformTools::OnDeployBinaries(CookingData& data)
|
||||
{
|
||||
auto now = DateTime::Now();
|
||||
file->WriteTextFormatted(
|
||||
(char*)fileTemplate.Get()
|
||||
fileTemplate.Get()
|
||||
, gameSettings->ProductName.ToStringAnsi()
|
||||
, gameSettings->CompanyName.ToStringAnsi()
|
||||
, now.GetYear()
|
||||
@@ -177,17 +176,16 @@ bool UWPPlatformTools::OnDeployBinaries(CookingData& data)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
const auto dstAppPath = data.OutputPath / TEXT("App.cs");
|
||||
const auto dstAppPath = data.DataOutputPath / TEXT("App.cs");
|
||||
const auto srcAppPath = uwpDataPath / TEXT("App.cs");
|
||||
if (!FileSystem::FileExists(dstAppPath))
|
||||
{
|
||||
// Get template
|
||||
if (File::ReadAllBytes(srcAppPath, fileTemplate))
|
||||
if (File::ReadAllText(srcAppPath, fileTemplate))
|
||||
{
|
||||
data.Error(TEXT("Failed to load App.cs template."));
|
||||
return true;
|
||||
}
|
||||
fileTemplate[fileTemplate.Count() - 1] = 0;
|
||||
|
||||
// Write data to file
|
||||
auto file = FileWriteStream::Open(dstAppPath);
|
||||
@@ -195,7 +193,7 @@ bool UWPPlatformTools::OnDeployBinaries(CookingData& data)
|
||||
if (file)
|
||||
{
|
||||
file->WriteTextFormatted(
|
||||
(char*)fileTemplate.Get()
|
||||
fileTemplate.Get()
|
||||
, defaultNamespace.ToStringAnsi() // {0} Default Namespace
|
||||
);
|
||||
hasError = file->HasError();
|
||||
@@ -207,16 +205,15 @@ bool UWPPlatformTools::OnDeployBinaries(CookingData& data)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
const auto dstFlaxGeneratedPath = data.OutputPath / TEXT("FlaxGenerated.cs");
|
||||
const auto dstFlaxGeneratedPath = data.DataOutputPath / TEXT("FlaxGenerated.cs");
|
||||
const auto srcFlaxGeneratedPath = uwpDataPath / TEXT("FlaxGenerated.cs");
|
||||
{
|
||||
// Get template
|
||||
if (File::ReadAllBytes(srcFlaxGeneratedPath, fileTemplate))
|
||||
if (File::ReadAllText(srcFlaxGeneratedPath, fileTemplate))
|
||||
{
|
||||
data.Error(TEXT("Failed to load FlaxGenerated.cs template."));
|
||||
return true;
|
||||
}
|
||||
fileTemplate[fileTemplate.Count() - 1] = 0;
|
||||
|
||||
// Prepare
|
||||
StringAnsi autoRotationPreferences;
|
||||
@@ -252,7 +249,7 @@ bool UWPPlatformTools::OnDeployBinaries(CookingData& data)
|
||||
if (file)
|
||||
{
|
||||
file->WriteTextFormatted(
|
||||
(char*)fileTemplate.Get()
|
||||
fileTemplate.Get()
|
||||
, autoRotationPreferences.Get()
|
||||
, preferredLaunchWindowingMode.Get()
|
||||
);
|
||||
@@ -267,17 +264,16 @@ bool UWPPlatformTools::OnDeployBinaries(CookingData& data)
|
||||
}
|
||||
|
||||
// Create solution
|
||||
const auto dstSolutionPath = data.OutputPath / projectName + TEXT(".sln");
|
||||
const auto dstSolutionPath = data.DataOutputPath / projectName + TEXT(".sln");
|
||||
const auto srcSolutionPath = uwpDataPath / TEXT("Solution.sln");
|
||||
if (!FileSystem::FileExists(dstSolutionPath))
|
||||
{
|
||||
// Get template
|
||||
if (File::ReadAllBytes(srcSolutionPath, fileTemplate))
|
||||
if (File::ReadAllText(srcSolutionPath, fileTemplate))
|
||||
{
|
||||
data.Error(TEXT("Failed to load Solution.sln template."));
|
||||
return true;
|
||||
}
|
||||
fileTemplate[fileTemplate.Count() - 1] = 0;
|
||||
|
||||
// Write data to file
|
||||
auto file = FileWriteStream::Open(dstSolutionPath);
|
||||
@@ -285,7 +281,7 @@ bool UWPPlatformTools::OnDeployBinaries(CookingData& data)
|
||||
if (file)
|
||||
{
|
||||
file->WriteTextFormatted(
|
||||
(char*)fileTemplate.Get()
|
||||
fileTemplate.Get()
|
||||
, projectName.ToStringAnsi() // {0} Project Name
|
||||
, mode // {1} Platform Mode
|
||||
, projectGuid.ToStringAnsi() // {2} Project ID
|
||||
@@ -301,16 +297,15 @@ bool UWPPlatformTools::OnDeployBinaries(CookingData& data)
|
||||
}
|
||||
|
||||
// Create project
|
||||
const auto dstProjectPath = data.OutputPath / projectName + TEXT(".csproj");
|
||||
const auto dstProjectPath = data.DataOutputPath / projectName + TEXT(".csproj");
|
||||
const auto srcProjectPath = uwpDataPath / TEXT("Project.csproj");
|
||||
{
|
||||
// Get template
|
||||
if (File::ReadAllBytes(srcProjectPath, fileTemplate))
|
||||
if (File::ReadAllText(srcProjectPath, fileTemplate))
|
||||
{
|
||||
data.Error(TEXT("Failed to load Project.csproj template."));
|
||||
return true;
|
||||
}
|
||||
fileTemplate[fileTemplate.Count() - 1] = 0;
|
||||
|
||||
// Build included files data
|
||||
StringBuilder filesInclude(2048);
|
||||
@@ -334,7 +329,7 @@ bool UWPPlatformTools::OnDeployBinaries(CookingData& data)
|
||||
if (file)
|
||||
{
|
||||
file->WriteTextFormatted(
|
||||
(char*)fileTemplate.Get()
|
||||
fileTemplate.Get()
|
||||
, projectName.ToStringAnsi() // {0} Project Name
|
||||
, mode // {1} Platform Mode
|
||||
, projectGuid.Get() // {2} Project ID
|
||||
@@ -352,17 +347,16 @@ bool UWPPlatformTools::OnDeployBinaries(CookingData& data)
|
||||
}
|
||||
|
||||
// Create manifest
|
||||
const auto dstManifestPath = data.OutputPath / TEXT("Package.appxmanifest");
|
||||
const auto dstManifestPath = data.DataOutputPath / TEXT("Package.appxmanifest");
|
||||
const auto srcManifestPath = uwpDataPath / TEXT("Package.appxmanifest");
|
||||
if (!FileSystem::FileExists(dstManifestPath))
|
||||
{
|
||||
// Get template
|
||||
if (File::ReadAllBytes(srcManifestPath, fileTemplate))
|
||||
if (File::ReadAllText(srcManifestPath, fileTemplate))
|
||||
{
|
||||
data.Error(TEXT("Failed to load Package.appxmanifest template."));
|
||||
return true;
|
||||
}
|
||||
fileTemplate[fileTemplate.Count() - 1] = 0;
|
||||
|
||||
// Build included files data
|
||||
StringBuilder filesInclude(2048);
|
||||
@@ -385,7 +379,7 @@ bool UWPPlatformTools::OnDeployBinaries(CookingData& data)
|
||||
if (file)
|
||||
{
|
||||
file->WriteTextFormatted(
|
||||
(char*)fileTemplate.Get()
|
||||
fileTemplate.Get()
|
||||
, projectName.ToStringAnsi() // {0} Display Name
|
||||
, gameSettings->CompanyName.ToStringAnsi() // {1} Company Name
|
||||
, productId.ToStringAnsi() // {2} Product ID
|
||||
@@ -490,8 +484,8 @@ bool UWPPlatformTools::OnPostProcess(CookingData& data)
|
||||
// Special case for UWP
|
||||
// FlaxEngine.dll cannot be added to the solution as `Content` item (due to conflicts with C++ /CX FlaxEngine.dll)
|
||||
// Use special directory for it (generated UWP project handles this case and copies lib to the output)
|
||||
const String assembliesPath = data.OutputPath;
|
||||
const auto dstPath1 = data.OutputPath / TEXT("DataSecondary");
|
||||
const String assembliesPath = data.DataOutputPath;
|
||||
const auto dstPath1 = data.DataOutputPath / TEXT("DataSecondary");
|
||||
if (!FileSystem::DirectoryExists(dstPath1))
|
||||
{
|
||||
if (FileSystem::CreateDirectory(dstPath1))
|
||||
|
||||
@@ -36,7 +36,7 @@ ArchitectureType WindowsPlatformTools::GetArchitecture() const
|
||||
bool WindowsPlatformTools::OnDeployBinaries(CookingData& data)
|
||||
{
|
||||
const auto platformSettings = WindowsPlatformSettings::Get();
|
||||
const auto& outputPath = data.OutputPath;
|
||||
const auto& outputPath = data.CodeOutputPath;
|
||||
|
||||
// Apply executable icon
|
||||
Array<String> files;
|
||||
|
||||
@@ -144,8 +144,8 @@ public:
|
||||
AotConfig(CookingData& data)
|
||||
{
|
||||
Platform::GetEnvironmentVariables(EnvVars);
|
||||
EnvVars[TEXT("MONO_PATH")] = data.OutputPath / TEXT("Mono/lib/mono/4.5");
|
||||
AssembliesSearchDirs.Add(data.OutputPath / TEXT("Mono/lib/mono/4.5"));
|
||||
EnvVars[TEXT("MONO_PATH")] = data.DataOutputPath / TEXT("Mono/lib/mono/4.5");
|
||||
AssembliesSearchDirs.Add(data.DataOutputPath / TEXT("Mono/lib/mono/4.5"));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -119,7 +119,7 @@ bool CompileScriptsStep::DeployBinaries(CookingData& data, const String& path, c
|
||||
}
|
||||
for (auto& file : files)
|
||||
{
|
||||
const String dst = data.OutputPath / StringUtils::GetFileName(file);
|
||||
const String dst = data.CodeOutputPath / StringUtils::GetFileName(file);
|
||||
if (dst != file && FileSystem::CopyFile(dst, file))
|
||||
{
|
||||
data.Error(TEXT("Failed to copy file from {0} to {1}."), file, dst);
|
||||
@@ -180,7 +180,12 @@ bool CompileScriptsStep::Perform(CookingData& data)
|
||||
platform = TEXT("Android");
|
||||
architecture = TEXT("ARM64");
|
||||
break;
|
||||
case BuildPlatform::Switch:
|
||||
platform = TEXT("Switch");
|
||||
architecture = TEXT("ARM64");
|
||||
break;
|
||||
default:
|
||||
LOG(Error, "Unknown or unsupported build platform.");
|
||||
return true;
|
||||
}
|
||||
_extensionsToSkip.Clear();
|
||||
@@ -289,7 +294,7 @@ bool CompileScriptsStep::Perform(CookingData& data)
|
||||
}
|
||||
writer.EndObject();
|
||||
|
||||
const String outputBuildInfo = data.OutputPath / TEXT("Game.Build.json");
|
||||
const String outputBuildInfo = data.CodeOutputPath / TEXT("Game.Build.json");
|
||||
if (File::WriteAllBytes(outputBuildInfo, (byte*)buffer.GetString(), (int32)buffer.GetSize()))
|
||||
{
|
||||
LOG(Error, "Failed to save binary modules info file {0}.", outputBuildInfo);
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "Engine/Graphics/RenderTools.h"
|
||||
#include "Engine/Graphics/Textures/TextureData.h"
|
||||
#include "Engine/Engine/Base/GameBase.h"
|
||||
#include "Engine/Engine/Globals.h"
|
||||
#include "Engine/Tools/TextureTool/TextureTool.h"
|
||||
#if PLATFORM_TOOLS_WINDOWS
|
||||
#include "Engine/Platform/Windows/WindowsPlatformSettings.h"
|
||||
@@ -453,6 +454,14 @@ bool ProcessShaderBase(CookAssetsStep::AssetCookData& data, ShaderAssetBase* ass
|
||||
COMPILE_PROFILE(Vulkan_SM5, SHADER_FILE_CHUNK_INTERNAL_VULKAN_SM5_CACHE);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#if PLATFORM_TOOLS_SWITCH
|
||||
case BuildPlatform::Switch:
|
||||
{
|
||||
const char* platformDefineName = "PLATFORM_SWITCH";
|
||||
COMPILE_PROFILE(Vulkan_SM5, SHADER_FILE_CHUNK_INTERNAL_VULKAN_SM5_CACHE);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
{
|
||||
@@ -861,7 +870,7 @@ public:
|
||||
// Create package
|
||||
// Note: FlaxStorage::Create overrides chunks locations in file so don't use files anymore (only readonly)
|
||||
const String localPath = String::Format(TEXT("Content/Data_{0}.{1}"), _packageIndex, PACKAGE_FILES_EXTENSION);
|
||||
const String path = data.OutputPath / localPath;
|
||||
const String path = data.DataOutputPath / localPath;
|
||||
if (FlaxStorage::Create(path, assetsData, false, &CustomData))
|
||||
{
|
||||
data.Error(TEXT("Failed to create assets package."));
|
||||
@@ -1027,7 +1036,7 @@ bool CookAssetsStep::Perform(CookingData& data)
|
||||
gameFlags |= GameHeaderFlags::ShowSplashScreen;
|
||||
|
||||
// Open file
|
||||
auto stream = FileWriteStream::Open(data.OutputPath / TEXT("Content/head"));
|
||||
auto stream = FileWriteStream::Open(data.DataOutputPath / TEXT("Content/head"));
|
||||
if (stream == nullptr)
|
||||
{
|
||||
data.Error(TEXT("Failed to create game data file."));
|
||||
@@ -1121,7 +1130,7 @@ bool CookAssetsStep::Perform(CookingData& data)
|
||||
BUILD_STEP_CANCEL_CHECK;
|
||||
|
||||
// Save assets cache
|
||||
if (AssetsCache::Save(data.OutputPath / TEXT("Content/AssetsCache.dat"), AssetsRegistry, AssetPathsMapping, AssetsCacheFlags::RelativePaths))
|
||||
if (AssetsCache::Save(data.DataOutputPath / TEXT("Content/AssetsCache.dat"), AssetsRegistry, AssetPathsMapping, AssetsCacheFlags::RelativePaths))
|
||||
{
|
||||
data.Error(TEXT("Failed to create assets registry."));
|
||||
return true;
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "Engine/Core/Config/GameSettings.h"
|
||||
#include "Engine/Renderer/ReflectionsPass.h"
|
||||
#include "Engine/Renderer/AntiAliasing/SMAA.h"
|
||||
#include "Engine/Engine/Globals.h"
|
||||
|
||||
bool DeployDataStep::Perform(CookingData& data)
|
||||
{
|
||||
@@ -15,7 +16,7 @@ bool DeployDataStep::Perform(CookingData& data)
|
||||
const auto gameSettings = GameSettings::Get();
|
||||
|
||||
// Setup output folders and copy required data
|
||||
const auto contentDir = data.OutputPath / TEXT("Content");
|
||||
const auto contentDir = data.DataOutputPath / TEXT("Content");
|
||||
if (FileSystem::DirectoryExists(contentDir))
|
||||
{
|
||||
// Remove old content files
|
||||
@@ -26,7 +27,7 @@ bool DeployDataStep::Perform(CookingData& data)
|
||||
}
|
||||
FileSystem::CreateDirectory(contentDir);
|
||||
const auto srcMono = depsRoot / TEXT("Mono");
|
||||
const auto dstMono = data.OutputPath / TEXT("Mono");
|
||||
const auto dstMono = data.DataOutputPath / TEXT("Mono");
|
||||
if (!FileSystem::DirectoryExists(dstMono))
|
||||
{
|
||||
if (!FileSystem::DirectoryExists(srcMono))
|
||||
|
||||
@@ -24,7 +24,7 @@ bool PrecompileAssembliesStep::Perform(CookingData& data)
|
||||
data.Tools->OnConfigureAOT(data, config);
|
||||
|
||||
// Prepare output directory
|
||||
config.AotCachePath = data.OutputPath / TEXT("Mono/lib/mono/aot-cache");
|
||||
config.AotCachePath = data.DataOutputPath / TEXT("Mono/lib/mono/aot-cache");
|
||||
switch (data.Tools->GetArchitecture())
|
||||
{
|
||||
case ArchitectureType::x86:
|
||||
@@ -52,9 +52,9 @@ bool PrecompileAssembliesStep::Perform(CookingData& data)
|
||||
FileSystem::DirectoryGetFiles(config.Assemblies, dir, TEXT("*.dll"), DirectorySearchOption::TopDirectoryOnly);
|
||||
for (auto& binaryModule : data.BinaryModules)
|
||||
if (binaryModule.ManagedPath.HasChars())
|
||||
config.Assemblies.Add(data.OutputPath / binaryModule.ManagedPath);
|
||||
config.Assemblies.Add(data.CodeOutputPath / binaryModule.ManagedPath);
|
||||
// TODO: move AOT to Flax.Build and perform it on all C# assemblies used in target build
|
||||
config.Assemblies.Add(data.OutputPath / TEXT("Newtonsoft.Json.dll"));
|
||||
config.Assemblies.Add(data.CodeOutputPath / TEXT("Newtonsoft.Json.dll"));
|
||||
|
||||
// Perform AOT for the assemblies
|
||||
for (int32 i = 0; i < config.Assemblies.Count(); i++)
|
||||
|
||||
@@ -11,9 +11,17 @@ bool ValidateStep::Perform(CookingData& data)
|
||||
data.StepProgress(TEXT("Performing validation"), 0);
|
||||
|
||||
// Ensure output and cache directories exist
|
||||
if (!FileSystem::DirectoryExists(data.OutputPath))
|
||||
if (!FileSystem::DirectoryExists(data.CodeOutputPath))
|
||||
{
|
||||
if (FileSystem::CreateDirectory(data.OutputPath))
|
||||
if (FileSystem::CreateDirectory(data.CodeOutputPath))
|
||||
{
|
||||
data.Error(TEXT("Failed to create build output directory."));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (!FileSystem::DirectoryExists(data.DataOutputPath))
|
||||
{
|
||||
if (FileSystem::CreateDirectory(data.DataOutputPath))
|
||||
{
|
||||
data.Error(TEXT("Failed to create build output directory."));
|
||||
return true;
|
||||
|
||||
@@ -250,6 +250,15 @@ namespace FlaxEditor.CustomEditors
|
||||
_children[i].RefreshInternal();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Synchronizes the value of the <see cref="Values"/> container. Called during Refresh to flush property after editing it in UI.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to set.</param>
|
||||
protected virtual void SynchronizeValue(object value)
|
||||
{
|
||||
_values.Set(_parent.Values, value);
|
||||
}
|
||||
|
||||
internal virtual void RefreshInternal()
|
||||
{
|
||||
if (_values == null)
|
||||
@@ -264,7 +273,7 @@ namespace FlaxEditor.CustomEditors
|
||||
_valueToSet = null;
|
||||
|
||||
// Assign value
|
||||
_values.Set(_parent.Values, val);
|
||||
SynchronizeValue(val);
|
||||
|
||||
// Propagate values up (eg. when member of structure gets modified, also structure should be updated as a part of the other object)
|
||||
var obj = _parent;
|
||||
|
||||
@@ -139,7 +139,7 @@ namespace FlaxEditor.CustomEditors
|
||||
/// <inheritdoc />
|
||||
protected override void OnModified()
|
||||
{
|
||||
Presenter.Modified?.Invoke();
|
||||
Presenter.OnModified();
|
||||
|
||||
base.OnModified();
|
||||
}
|
||||
@@ -354,6 +354,14 @@ namespace FlaxEditor.CustomEditors
|
||||
ExpandGroups(this, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invokes <see cref="Modified"/> event.
|
||||
/// </summary>
|
||||
public void OnModified()
|
||||
{
|
||||
Modified?.Invoke();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when selection gets changed.
|
||||
/// </summary>
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "CustomEditorsUtil.h"
|
||||
#include "Engine/Core/Log.h"
|
||||
#include "Engine/Core/Types/DateTime.h"
|
||||
#include "Engine/Core/Types/TimeSpan.h"
|
||||
#include "Engine/Core/Collections/Dictionary.h"
|
||||
#include "Engine/Engine/EngineService.h"
|
||||
#include "Engine/Scripting/Scripting.h"
|
||||
|
||||
@@ -0,0 +1,429 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using FlaxEditor.Content.Settings;
|
||||
using FlaxEditor.CustomEditors.Editors;
|
||||
using FlaxEditor.Scripting;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
using FlaxEngine.Utilities;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Object = FlaxEngine.Object;
|
||||
|
||||
namespace FlaxEditor.CustomEditors.Dedicated
|
||||
{
|
||||
[CustomEditor(typeof(LocalizationSettings))]
|
||||
sealed class LocalizationSettingsEditor : GenericEditor
|
||||
{
|
||||
private CultureInfo _theMostTranslatedCulture;
|
||||
private int _theMostTranslatedCultureCount;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Initialize(LayoutElementsContainer layout)
|
||||
{
|
||||
Profiler.BeginEvent("LocalizationSettingsEditor.Initialize");
|
||||
var settings = (LocalizationSettings)Values[0];
|
||||
var tablesLength = settings.LocalizedStringTables?.Length ?? 0;
|
||||
var tables = new List<LocalizedStringTable>(tablesLength);
|
||||
for (int i = 0; i < tablesLength; i++)
|
||||
{
|
||||
var table = settings.LocalizedStringTables[i];
|
||||
if (table && !table.WaitForLoaded())
|
||||
tables.Add(table);
|
||||
}
|
||||
var locales = tables.GroupBy(x => x.Locale);
|
||||
var tableEntries = new Dictionary<LocalizedStringTable, Dictionary<string, string[]>>();
|
||||
var allKeys = new HashSet<string>();
|
||||
foreach (var e in locales)
|
||||
{
|
||||
foreach (var table in e)
|
||||
{
|
||||
var entries = table.Entries;
|
||||
tableEntries[table] = entries;
|
||||
allKeys.AddRange(entries.Keys);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
var group = layout.Group("Preview");
|
||||
|
||||
// Current language and culture preview management
|
||||
group.Object("Current Language", new CustomValueContainer(new ScriptType(typeof(CultureInfo)), Localization.CurrentLanguage, (instance, index) => Localization.CurrentLanguage, (instance, index, value) => Localization.CurrentLanguage = value as CultureInfo), null, "Current UI display language for the game preview.");
|
||||
group.Object("Current Culture", new CustomValueContainer(new ScriptType(typeof(CultureInfo)), Localization.CurrentCulture, (instance, index) => Localization.CurrentCulture, (instance, index, value) => Localization.CurrentCulture = value as CultureInfo), null, "Current values formatting culture for the game preview.");
|
||||
}
|
||||
|
||||
{
|
||||
var group = layout.Group("Locales");
|
||||
|
||||
// Show all existing locales
|
||||
_theMostTranslatedCulture = null;
|
||||
_theMostTranslatedCultureCount = -1;
|
||||
foreach (var e in locales)
|
||||
{
|
||||
var culture = new CultureInfo(e.Key);
|
||||
var prop = group.AddPropertyItem(CultureInfoEditor.GetName(culture), culture.NativeName);
|
||||
int count = e.Sum(x => tableEntries[x].Count);
|
||||
int validCount = e.Sum(x => tableEntries[x].Values.Count(y => y != null && y.Length != 0 && !string.IsNullOrEmpty(y[0])));
|
||||
if (count > _theMostTranslatedCultureCount)
|
||||
{
|
||||
_theMostTranslatedCulture = culture;
|
||||
_theMostTranslatedCultureCount = count;
|
||||
}
|
||||
prop.Label(string.Format("Progress: {0}% ({1}/{2})", (int)(((float)validCount / allKeys.Count * 100.0f)), validCount, allKeys.Count));
|
||||
prop.Label("Tables:");
|
||||
foreach (var table in e)
|
||||
{
|
||||
var namePath = table.Path;
|
||||
if (namePath.StartsWith(Globals.ProjectFolder))
|
||||
namePath = namePath.Substring(Globals.ProjectFolder.Length + 1);
|
||||
var tableLabel = prop.ClickableLabel(namePath).CustomControl;
|
||||
tableLabel.TextColorHighlighted = Color.Wheat;
|
||||
tableLabel.DoubleClick += delegate { Editor.Instance.Windows.ContentWin.Select(table); };
|
||||
}
|
||||
group.Space(10);
|
||||
}
|
||||
|
||||
// Update add button
|
||||
var update = group.Button("Update").Button;
|
||||
update.TooltipText = "Refreshes the dashboard statistics";
|
||||
update.Height = 16.0f;
|
||||
update.Clicked += RebuildLayout;
|
||||
|
||||
// New locale add button
|
||||
var addLocale = group.Button("Add Locale...").Button;
|
||||
addLocale.TooltipText = "Shows a locale picker and creates new localization for it with not translated string tables";
|
||||
addLocale.Height = 16.0f;
|
||||
addLocale.ButtonClicked += delegate(Button button)
|
||||
{
|
||||
var menu = CultureInfoEditor.CreatePicker(null, culture =>
|
||||
{
|
||||
var displayName = CultureInfoEditor.GetName(culture);
|
||||
if (locales.Any(x => x.Key == culture.Name))
|
||||
{
|
||||
MessageBox.Show($"Culture '{displayName}' is already added.");
|
||||
return;
|
||||
}
|
||||
Profiler.BeginEvent("LocalizationSettingsEditor.AddLocale");
|
||||
Editor.Log($"Adding culture '{displayName}' to localization settings");
|
||||
var newTables = settings.LocalizedStringTables.ToList();
|
||||
if (_theMostTranslatedCulture != null)
|
||||
{
|
||||
// Duplicate localization for culture with the highest amount of keys
|
||||
var g = locales.First(x => x.Key == _theMostTranslatedCulture.Name);
|
||||
foreach (var e in g)
|
||||
{
|
||||
var path = e.Path;
|
||||
var filename = Path.GetFileNameWithoutExtension(path);
|
||||
if (filename.EndsWith(_theMostTranslatedCulture.Name))
|
||||
filename = filename.Substring(0, filename.Length - _theMostTranslatedCulture.Name.Length);
|
||||
path = Path.Combine(Path.GetDirectoryName(path), filename + culture.Name + ".json");
|
||||
var table = FlaxEngine.Content.CreateVirtualAsset<LocalizedStringTable>();
|
||||
table.Locale = culture.Name;
|
||||
var entries = new Dictionary<string, string[]>();
|
||||
foreach (var ee in tableEntries[e])
|
||||
{
|
||||
var vv = (string[])ee.Value.Clone();
|
||||
for (var i = 0; i < vv.Length; i++)
|
||||
vv[i] = string.Empty;
|
||||
entries.Add(ee.Key, vv);
|
||||
}
|
||||
table.Entries = entries;
|
||||
if (!table.Save(path))
|
||||
{
|
||||
Object.Destroy(table);
|
||||
newTables.Add(FlaxEngine.Content.LoadAsync<LocalizedStringTable>(path));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// No localization so initialize with empty table
|
||||
var path = Path.Combine(Path.Combine(Path.GetDirectoryName(GameSettings.Load().Localization.Path), "Localization", culture.Name + ".json"));
|
||||
var table = FlaxEngine.Content.CreateVirtualAsset<LocalizedStringTable>();
|
||||
table.Locale = culture.Name;
|
||||
if (!table.Save(path))
|
||||
{
|
||||
Object.Destroy(table);
|
||||
newTables.Add(FlaxEngine.Content.LoadAsync<LocalizedStringTable>(path));
|
||||
}
|
||||
}
|
||||
settings.LocalizedStringTables = newTables.ToArray();
|
||||
Presenter.OnModified();
|
||||
RebuildLayout();
|
||||
Profiler.EndEvent();
|
||||
});
|
||||
menu.Show(button, new Vector2(0, button.Height));
|
||||
};
|
||||
|
||||
// Export button
|
||||
var exportLocalization = group.Button("Export...").Button;
|
||||
exportLocalization.TooltipText = "Exports the localization strings into .pot file for translation";
|
||||
exportLocalization.Height = 16.0f;
|
||||
exportLocalization.Clicked += delegate
|
||||
{
|
||||
if (FileSystem.ShowSaveFileDialog(null, null, "*.pot", false, "Export localization for translation to .pot file", out var filenames))
|
||||
return;
|
||||
Profiler.BeginEvent("LocalizationSettingsEditor.Export");
|
||||
if (!filenames[0].EndsWith(".pot"))
|
||||
filenames[0] += ".pot";
|
||||
var nplurals = 1;
|
||||
foreach (var e in tableEntries)
|
||||
{
|
||||
foreach (var value in e.Value.Values)
|
||||
{
|
||||
if (value != null && value.Length > nplurals)
|
||||
nplurals = value.Length;
|
||||
}
|
||||
}
|
||||
using (var writer = new StreamWriter(filenames[0], false, Encoding.UTF8))
|
||||
{
|
||||
writer.WriteLine("msgid \"\"");
|
||||
writer.WriteLine("msgstr \"\"");
|
||||
writer.WriteLine("\"Language: English\\n\"");
|
||||
writer.WriteLine("\"MIME-Version: 1.0\\n\"");
|
||||
writer.WriteLine("\"Content-Type: text/plain; charset=UTF-8\\n\"");
|
||||
writer.WriteLine("\"Content-Transfer-Encoding: 8bit\\n\"");
|
||||
writer.WriteLine($"\"Plural-Forms: nplurals={nplurals}; plural=(n != 1);\\n\"");
|
||||
writer.WriteLine("\"X-Generator: FlaxEngine\\n\"");
|
||||
var written = new HashSet<string>();
|
||||
foreach (var e in tableEntries)
|
||||
{
|
||||
foreach (var pair in e.Value)
|
||||
{
|
||||
if (written.Contains(pair.Key))
|
||||
continue;
|
||||
written.Add(pair.Key);
|
||||
|
||||
writer.WriteLine("");
|
||||
writer.WriteLine($"msgid \"{pair.Key}\"");
|
||||
if (pair.Value == null || pair.Value.Length < 2)
|
||||
{
|
||||
writer.WriteLine("msgstr \"\"");
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.WriteLine("msgid_plural \"\"");
|
||||
for (int i = 0; i < pair.Value.Length; i++)
|
||||
writer.WriteLine($"msgstr[{i}] \"\"");
|
||||
}
|
||||
}
|
||||
if (written.Count == allKeys.Count)
|
||||
break;
|
||||
}
|
||||
}
|
||||
Profiler.EndEvent();
|
||||
};
|
||||
|
||||
// Find localized strings in code button
|
||||
var findStringsCode = group.Button("Find localized strings in code").Button;
|
||||
findStringsCode.TooltipText = "Searches for localized string usage in inside a project source files";
|
||||
findStringsCode.Height = 16.0f;
|
||||
findStringsCode.Clicked += delegate
|
||||
{
|
||||
var newKeys = new Dictionary<string, string>();
|
||||
Profiler.BeginEvent("LocalizationSettingsEditor.FindLocalizedStringsInSource");
|
||||
|
||||
// C#
|
||||
var files = Directory.GetFiles(Globals.ProjectSourceFolder, "*.cs", SearchOption.AllDirectories);
|
||||
var filesCount = files.Length;
|
||||
foreach (var file in files)
|
||||
FindNewKeysCSharp(file, newKeys, allKeys);
|
||||
|
||||
// C++
|
||||
files = Directory.GetFiles(Globals.ProjectSourceFolder, "*.cpp", SearchOption.AllDirectories);
|
||||
filesCount += files.Length;
|
||||
foreach (var file in files)
|
||||
FindNewKeysCpp(file, newKeys, allKeys);
|
||||
files = Directory.GetFiles(Globals.ProjectSourceFolder, "*.h", SearchOption.AllDirectories);
|
||||
filesCount += files.Length;
|
||||
foreach (var file in files)
|
||||
FindNewKeysCpp(file, newKeys, allKeys);
|
||||
|
||||
AddNewKeys(newKeys, filesCount, locales, tableEntries);
|
||||
Profiler.EndEvent();
|
||||
};
|
||||
|
||||
// Find localized strings in content button
|
||||
var findStringsContent = group.Button("Find localized strings in content").Button;
|
||||
findStringsContent.TooltipText = "Searches for localized string usage in inside a project content files (scenes, prefabs)";
|
||||
findStringsContent.Height = 16.0f;
|
||||
findStringsContent.Clicked += delegate
|
||||
{
|
||||
var newKeys = new Dictionary<string, string>();
|
||||
Profiler.BeginEvent("LocalizationSettingsEditor.FindLocalizedStringsInContent");
|
||||
|
||||
// Scenes
|
||||
var files = Directory.GetFiles(Globals.ProjectContentFolder, "*.scene", SearchOption.AllDirectories);
|
||||
var filesCount = files.Length;
|
||||
foreach (var file in files)
|
||||
FindNewKeysJson(file, newKeys, allKeys);
|
||||
|
||||
// Prefabs
|
||||
files = Directory.GetFiles(Globals.ProjectContentFolder, "*.prefab", SearchOption.AllDirectories);
|
||||
filesCount += files.Length;
|
||||
foreach (var file in files)
|
||||
FindNewKeysJson(file, newKeys, allKeys);
|
||||
|
||||
AddNewKeys(newKeys, filesCount, locales, tableEntries);
|
||||
Profiler.EndEvent();
|
||||
};
|
||||
}
|
||||
|
||||
{
|
||||
// Raw asset data editing
|
||||
var group = layout.Group("Data");
|
||||
base.Initialize(group);
|
||||
}
|
||||
|
||||
Profiler.EndEvent();
|
||||
}
|
||||
|
||||
private static void FindNewKeysCSharp(string file, Dictionary<string, string> newKeys, HashSet<string> allKeys)
|
||||
{
|
||||
var startToken = "Localization.GetString";
|
||||
var textToken = "\"";
|
||||
FindNewKeys(file, newKeys, allKeys, startToken, textToken);
|
||||
}
|
||||
|
||||
private static void FindNewKeysCpp(string file, Dictionary<string, string> newKeys, HashSet<string> allKeys)
|
||||
{
|
||||
var startToken = "Localization::GetString";
|
||||
var textToken = "TEXT(\"";
|
||||
FindNewKeys(file, newKeys, allKeys, startToken, textToken);
|
||||
}
|
||||
|
||||
private static void FindNewKeys(string file, Dictionary<string, string> newKeys, HashSet<string> allKeys, string startToken, string textToken)
|
||||
{
|
||||
var contents = File.ReadAllText(file);
|
||||
var idx = contents.IndexOf(startToken);
|
||||
while (idx != -1)
|
||||
{
|
||||
idx += startToken.Length + 1;
|
||||
int braces = 1;
|
||||
int start = idx;
|
||||
while (idx < contents.Length && braces != 0)
|
||||
{
|
||||
if (contents[idx] == '(')
|
||||
braces++;
|
||||
if (contents[idx] == ')')
|
||||
braces--;
|
||||
idx++;
|
||||
}
|
||||
if (idx == contents.Length)
|
||||
break;
|
||||
var inside = contents.Substring(start, idx - start - 1);
|
||||
var textStart = inside.IndexOf(textToken);
|
||||
if (textStart != -1)
|
||||
{
|
||||
textStart += textToken.Length;
|
||||
var textEnd = textStart;
|
||||
while (textEnd < inside.Length && inside[textEnd] != '\"')
|
||||
{
|
||||
if (inside[textEnd] == '\\')
|
||||
textEnd++;
|
||||
textEnd++;
|
||||
}
|
||||
var id = inside.Substring(textStart, textEnd - textStart);
|
||||
textStart = inside.Length > textEnd + 2 ? inside.IndexOf(textToken, textEnd + 2) : -1;
|
||||
string value = null;
|
||||
if (textStart != -1)
|
||||
{
|
||||
textStart += textToken.Length;
|
||||
textEnd = textStart;
|
||||
while (textEnd < inside.Length && inside[textEnd] != '\"')
|
||||
{
|
||||
if (inside[textEnd] == '\\')
|
||||
textEnd++;
|
||||
textEnd++;
|
||||
}
|
||||
value = inside.Substring(textStart, textEnd - textStart);
|
||||
}
|
||||
|
||||
if (!allKeys.Contains(id))
|
||||
newKeys[id] = value;
|
||||
}
|
||||
|
||||
idx = contents.IndexOf(startToken, idx);
|
||||
}
|
||||
}
|
||||
|
||||
private static void FindNewKeysJson(Dictionary<string, string> newKeys, HashSet<string> allKeys, JToken token)
|
||||
{
|
||||
if (token is JObject o)
|
||||
{
|
||||
foreach (var p in o)
|
||||
{
|
||||
if (string.Equals(p.Key, "Id", StringComparison.Ordinal) && p.Value is JValue i && i.Value is string id && !allKeys.Contains(id))
|
||||
{
|
||||
var count = o.Properties().Count();
|
||||
if (count == 1)
|
||||
{
|
||||
newKeys[id] = null;
|
||||
return;
|
||||
}
|
||||
if (count == 2)
|
||||
{
|
||||
var v = o.Property("Value")?.Value as JValue;
|
||||
if (v?.Value is string value)
|
||||
{
|
||||
newKeys[id] = value;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
FindNewKeysJson(newKeys, allKeys, p.Value);
|
||||
}
|
||||
}
|
||||
else if (token is JArray a)
|
||||
{
|
||||
foreach (var p in a)
|
||||
{
|
||||
FindNewKeysJson(newKeys, allKeys, p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void FindNewKeysJson(string file, Dictionary<string, string> newKeys, HashSet<string> allKeys)
|
||||
{
|
||||
using (var reader = new StreamReader(file))
|
||||
using (var jsonReader = new JsonTextReader(reader))
|
||||
{
|
||||
var token = JToken.ReadFrom(jsonReader);
|
||||
FindNewKeysJson(newKeys, allKeys, token);
|
||||
}
|
||||
}
|
||||
|
||||
private void AddNewKeys(Dictionary<string, string> newKeys, int filesCount, IEnumerable<IGrouping<string, LocalizedStringTable>> locales, Dictionary<LocalizedStringTable, Dictionary<string, string[]>> tableEntries)
|
||||
{
|
||||
Editor.Log($"Found {newKeys.Count} new localized strings in {filesCount} files");
|
||||
if (newKeys.Count == 0)
|
||||
return;
|
||||
foreach (var e in newKeys)
|
||||
Editor.Log(e.Key + (e.Value != null ? " = " + e.Value : string.Empty));
|
||||
foreach (var locale in locales)
|
||||
{
|
||||
var table = locale.First();
|
||||
var entries = tableEntries[table];
|
||||
if (table.Locale == "en")
|
||||
{
|
||||
foreach (var e in newKeys)
|
||||
entries[e.Key] = new[] { e.Value };
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var e in newKeys)
|
||||
entries[e.Key] = new[] { string.Empty };
|
||||
}
|
||||
table.Entries = entries;
|
||||
table.Save();
|
||||
}
|
||||
RebuildLayout();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -32,17 +32,13 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
if (_presets != value)
|
||||
{
|
||||
_presets = value;
|
||||
OnPresetsChanged();
|
||||
TooltipText = CustomEditorsUtil.GetPropertyNameUI(_presets.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsSelected;
|
||||
|
||||
private void OnPresetsChanged()
|
||||
{
|
||||
TooltipText = CustomEditorsUtil.GetPropertyNameUI(_presets.ToString());
|
||||
}
|
||||
public bool SupportsShiftModulation;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Draw()
|
||||
@@ -79,6 +75,11 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
borderColor = BorderColorHighlighted;
|
||||
}
|
||||
|
||||
if (SupportsShiftModulation && Input.GetKey(KeyboardKeys.Shift))
|
||||
{
|
||||
backgroundColor = BackgroundColorSelected;
|
||||
}
|
||||
|
||||
// Calculate fill area
|
||||
float fillSize = rect.Width / 3;
|
||||
Rectangle fillArea;
|
||||
@@ -154,24 +155,83 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
{
|
||||
Render2D.DrawRectangle(rect, style.BackgroundSelected.AlphaMultiplied(0.8f), 1.1f);
|
||||
}
|
||||
|
||||
// Draw pivot point
|
||||
if (SupportsShiftModulation && Input.GetKey(KeyboardKeys.Control))
|
||||
{
|
||||
Vector2 pivotPoint;
|
||||
switch (_presets)
|
||||
{
|
||||
case AnchorPresets.Custom:
|
||||
pivotPoint = Vector2.Minimum;
|
||||
break;
|
||||
case AnchorPresets.TopLeft:
|
||||
pivotPoint = new Vector2(0, 0);
|
||||
break;
|
||||
case AnchorPresets.TopCenter:
|
||||
case AnchorPresets.HorizontalStretchTop:
|
||||
pivotPoint = new Vector2(rect.Width / 2, 0);
|
||||
break;
|
||||
case AnchorPresets.TopRight:
|
||||
pivotPoint = new Vector2(rect.Width, 0);
|
||||
break;
|
||||
case AnchorPresets.MiddleLeft:
|
||||
case AnchorPresets.VerticalStretchLeft:
|
||||
pivotPoint = new Vector2(0, rect.Height / 2);
|
||||
break;
|
||||
case AnchorPresets.MiddleCenter:
|
||||
case AnchorPresets.VerticalStretchCenter:
|
||||
case AnchorPresets.HorizontalStretchMiddle:
|
||||
case AnchorPresets.StretchAll:
|
||||
pivotPoint = new Vector2(rect.Width / 2, rect.Height / 2);
|
||||
break;
|
||||
case AnchorPresets.MiddleRight:
|
||||
case AnchorPresets.VerticalStretchRight:
|
||||
pivotPoint = new Vector2(rect.Width, rect.Height / 2);
|
||||
break;
|
||||
case AnchorPresets.BottomLeft:
|
||||
pivotPoint = new Vector2(0, rect.Height);
|
||||
break;
|
||||
case AnchorPresets.BottomCenter:
|
||||
case AnchorPresets.HorizontalStretchBottom:
|
||||
pivotPoint = new Vector2(rect.Width / 2, rect.Height);
|
||||
break;
|
||||
case AnchorPresets.BottomRight:
|
||||
pivotPoint = new Vector2(rect.Width, rect.Height);
|
||||
break;
|
||||
default: throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
var pivotPointSize = new Vector2(3.0f);
|
||||
Render2D.DrawRectangle(new Rectangle(pivotPoint - pivotPointSize * 0.5f, pivotPointSize), style.ProgressNormal, 1.1f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class AnchorPresetsEditorPopup : ContextMenuBase
|
||||
/// <summary>
|
||||
/// Context menu for anchors presets editing.
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEditor.GUI.ContextMenu.ContextMenuBase" />
|
||||
public sealed class AnchorPresetsEditorPopup : ContextMenuBase
|
||||
{
|
||||
const float ButtonsMargin = 10.0f;
|
||||
const float ButtonsMarginStretch = 8.0f;
|
||||
const float ButtonsSize = 32.0f;
|
||||
const float TitleHeight = 23.0f;
|
||||
const float InfoHeight = 23.0f;
|
||||
const float DialogWidth = ButtonsSize * 4 + ButtonsMargin * 5 + ButtonsMarginStretch;
|
||||
const float DialogHeight = TitleHeight + ButtonsSize * 4 + ButtonsMargin * 5 + ButtonsMarginStretch;
|
||||
const float DialogHeight = TitleHeight + InfoHeight + ButtonsSize * 4 + ButtonsMargin * 5 + ButtonsMarginStretch;
|
||||
|
||||
private readonly bool _supportsShiftModulation;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AnchorPresetsEditorPopup"/> class.
|
||||
/// </summary>
|
||||
/// <param name="presets">The initial value.</param>
|
||||
public AnchorPresetsEditorPopup(AnchorPresets presets)
|
||||
/// <param name="supportsShiftModulation">If the popup should react to shift</param>
|
||||
public AnchorPresetsEditorPopup(AnchorPresets presets, bool supportsShiftModulation = true)
|
||||
{
|
||||
_supportsShiftModulation = supportsShiftModulation;
|
||||
|
||||
var style = FlaxEngine.GUI.Style.Current;
|
||||
Tag = presets;
|
||||
Size = new Vector2(DialogWidth, DialogHeight);
|
||||
@@ -184,9 +244,17 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
Parent = this
|
||||
};
|
||||
|
||||
// Info
|
||||
var info = new Label(0, title.Bottom, DialogWidth, InfoHeight)
|
||||
{
|
||||
Font = new FontReference(style.FontSmall),
|
||||
Text = "Shift: also set bounds\nControl: also set pivot",
|
||||
Parent = this
|
||||
};
|
||||
|
||||
// Buttons
|
||||
var buttonsX = ButtonsMargin;
|
||||
var buttonsY = title.Bottom + ButtonsMargin;
|
||||
var buttonsY = info.Bottom + ButtonsMargin;
|
||||
var buttonsSpacingX = ButtonsSize + ButtonsMargin;
|
||||
var buttonsSpacingY = ButtonsSize + ButtonsMargin;
|
||||
//
|
||||
@@ -219,6 +287,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
Parent = this,
|
||||
Presets = presets,
|
||||
IsSelected = presets == (AnchorPresets)Tag,
|
||||
SupportsShiftModulation = _supportsShiftModulation,
|
||||
Tag = presets,
|
||||
};
|
||||
button.ButtonClicked += OnButtonClicked;
|
||||
@@ -278,7 +347,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
private void OnButtonClicked()
|
||||
{
|
||||
var location = _button.Center + new Vector2(3.0f);
|
||||
var editor = new AnchorPresetsEditorPopup(_button.Presets);
|
||||
var editor = new AnchorPresetsEditorPopup(_button.Presets, true);
|
||||
editor.VisibleChanged += OnEditorVisibleChanged;
|
||||
editor.Show(_button.Parent, location);
|
||||
}
|
||||
@@ -290,6 +359,30 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
SetValue(control.Tag);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void SynchronizeValue(object value)
|
||||
{
|
||||
// Custom anchors editing for Control to handle bounds preservation via key modifiers
|
||||
if (ParentEditor != null)
|
||||
{
|
||||
var centerToPosition = Input.GetKey(KeyboardKeys.Shift);
|
||||
var setPivot = Input.GetKey(KeyboardKeys.Control);
|
||||
var editedAny = false;
|
||||
foreach (var parentValue in ParentEditor.Values)
|
||||
{
|
||||
if (parentValue is Control parentControl)
|
||||
{
|
||||
parentControl.SetAnchorPreset((AnchorPresets)value, !centerToPosition, setPivot);
|
||||
editedAny = true;
|
||||
}
|
||||
}
|
||||
if (editedAny)
|
||||
return;
|
||||
}
|
||||
|
||||
base.SynchronizeValue(value);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Refresh()
|
||||
{
|
||||
@@ -311,7 +404,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
/// Dedicated custom editor for <see cref="UIControl.Control"/> object.
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEditor.CustomEditors.Editors.GenericEditor" />
|
||||
public sealed class UIControlControlEditor : GenericEditor
|
||||
public class UIControlControlEditor : GenericEditor
|
||||
{
|
||||
private Type _cachedType;
|
||||
|
||||
@@ -423,9 +516,9 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
|
||||
private void BuildLocationSizeOffsets(LayoutElementsContainer horUp, LayoutElementsContainer horDown, bool xEq, bool yEq, ScriptType[] valueTypes)
|
||||
{
|
||||
ScriptMemberInfo xInfo = valueTypes[0].GetProperty("X");
|
||||
ScriptMemberInfo xInfo = valueTypes[0].GetProperty("LocalX");
|
||||
ItemInfo xItem = new ItemInfo(xInfo);
|
||||
ScriptMemberInfo yInfo = valueTypes[0].GetProperty("Y");
|
||||
ScriptMemberInfo yInfo = valueTypes[0].GetProperty("LocalY");
|
||||
ItemInfo yItem = new ItemInfo(yInfo);
|
||||
ScriptMemberInfo widthInfo = valueTypes[0].GetProperty("Width");
|
||||
ItemInfo widthItem = new ItemInfo(widthInfo);
|
||||
|
||||
@@ -154,9 +154,20 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
if (i != 0 && spacing > 0f)
|
||||
{
|
||||
if (layout.Children.Count > 0 && layout.Children[layout.Children.Count - 1] is PropertiesListElement propertiesListElement)
|
||||
{
|
||||
if (propertiesListElement.Labels.Count > 0)
|
||||
{
|
||||
var label = propertiesListElement.Labels[propertiesListElement.Labels.Count - 1];
|
||||
var margin = label.Margin;
|
||||
margin.Bottom += spacing;
|
||||
label.Margin = margin;
|
||||
}
|
||||
propertiesListElement.Space(spacing);
|
||||
}
|
||||
else
|
||||
{
|
||||
layout.Space(spacing);
|
||||
}
|
||||
}
|
||||
|
||||
var overrideEditor = overrideEditorType != null ? (CustomEditor)Activator.CreateInstance(overrideEditorType) : null;
|
||||
|
||||
164
Source/Editor/CustomEditors/Editors/CultureInfoEditor.cs
Normal file
164
Source/Editor/CustomEditors/Editors/CultureInfoEditor.cs
Normal file
@@ -0,0 +1,164 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using FlaxEditor.GUI;
|
||||
using FlaxEditor.GUI.ContextMenu;
|
||||
using FlaxEditor.GUI.Tree;
|
||||
using FlaxEditor.Utilities;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
|
||||
namespace FlaxEditor.CustomEditors.Editors
|
||||
{
|
||||
/// <summary>
|
||||
/// Default implementation of the inspector used to edit <see cref="CultureInfo"/> value type properties. Supports editing property of <see cref="string"/> type (as culture name).
|
||||
/// </summary>
|
||||
[CustomEditor(typeof(CultureInfo)), DefaultEditor]
|
||||
internal class CultureInfoEditor : CustomEditor
|
||||
{
|
||||
private ClickableLabel _label;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override DisplayStyle Style => DisplayStyle.Inline;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Initialize(LayoutElementsContainer layout)
|
||||
{
|
||||
_label = layout.ClickableLabel(GetName(Culture)).CustomControl;
|
||||
_label.RightClick += ShowPicker;
|
||||
var button = new Button
|
||||
{
|
||||
Width = 16.0f,
|
||||
Text = "...",
|
||||
Parent = _label,
|
||||
};
|
||||
button.SetAnchorPreset(AnchorPresets.MiddleRight, false, true);
|
||||
button.Clicked += ShowPicker;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Refresh()
|
||||
{
|
||||
base.Refresh();
|
||||
|
||||
_label.Text = GetName(Culture);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Deinitialize()
|
||||
{
|
||||
_label = null;
|
||||
|
||||
base.Deinitialize();
|
||||
}
|
||||
|
||||
private CultureInfo Culture
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Values[0] is CultureInfo asCultureInfo)
|
||||
return asCultureInfo;
|
||||
if (Values[0] is string asString)
|
||||
return new CultureInfo(asString);
|
||||
return null;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (Values[0] is CultureInfo)
|
||||
SetValue(value);
|
||||
else if (Values[0] is string)
|
||||
SetValue(value.Name);
|
||||
}
|
||||
}
|
||||
|
||||
private class CultureInfoComparer : IComparer<CultureInfo>
|
||||
{
|
||||
public int Compare(CultureInfo a, CultureInfo b)
|
||||
{
|
||||
return string.Compare(a.Name, b.Name, StringComparison.Ordinal);
|
||||
}
|
||||
}
|
||||
|
||||
private static void UpdateFilter(TreeNode node, string filterText)
|
||||
{
|
||||
// Update children
|
||||
bool isAnyChildVisible = false;
|
||||
for (int i = 0; i < node.Children.Count; i++)
|
||||
{
|
||||
if (node.Children[i] is TreeNode child)
|
||||
{
|
||||
UpdateFilter(child, filterText);
|
||||
isAnyChildVisible |= child.Visible;
|
||||
}
|
||||
}
|
||||
|
||||
// Update itself
|
||||
bool noFilter = string.IsNullOrWhiteSpace(filterText);
|
||||
bool isThisVisible = noFilter || QueryFilterHelper.Match(filterText, node.Text);
|
||||
bool isExpanded = isAnyChildVisible;
|
||||
if (isExpanded)
|
||||
node.Expand(true);
|
||||
else
|
||||
node.Collapse(true);
|
||||
node.Visible = isThisVisible | isAnyChildVisible;
|
||||
}
|
||||
|
||||
private void ShowPicker()
|
||||
{
|
||||
var menu = CreatePicker(Culture, value => { Culture = value; });
|
||||
menu.Show(_label, new Vector2(0, _label.Height));
|
||||
}
|
||||
|
||||
internal static ContextMenuBase CreatePicker(CultureInfo value, Action<CultureInfo> changed)
|
||||
{
|
||||
var menu = Utilities.Utils.CreateSearchPopup(out var searchBox, out var tree);
|
||||
tree.Margin = new Margin(-16.0f, 0.0f, -16.0f, -0.0f); // Hide root node
|
||||
var root = tree.AddChild<TreeNode>();
|
||||
var cultures = CultureInfo.GetCultures(CultureTypes.AllCultures);
|
||||
Array.Sort(cultures, 1, cultures.Length - 2, new CultureInfoComparer()); // at 0 there is Invariant Culture
|
||||
var lcidToNode = new Dictionary<int, ContainerControl>();
|
||||
for (var i = 0; i < cultures.Length; i++)
|
||||
{
|
||||
var culture = cultures[i];
|
||||
var node = new TreeNode
|
||||
{
|
||||
Tag = culture,
|
||||
Text = GetName(culture),
|
||||
};
|
||||
if (!lcidToNode.TryGetValue(culture.Parent.LCID, out ContainerControl parent))
|
||||
parent = root;
|
||||
node.Parent = parent;
|
||||
lcidToNode[culture.LCID] = node;
|
||||
}
|
||||
if (value != null)
|
||||
tree.Select((TreeNode)lcidToNode[value.LCID]);
|
||||
tree.SelectedChanged += delegate(List<TreeNode> before, List<TreeNode> after)
|
||||
{
|
||||
if (after.Count == 1)
|
||||
{
|
||||
menu.Hide();
|
||||
changed((CultureInfo)after[0].Tag);
|
||||
}
|
||||
};
|
||||
searchBox.TextChanged += delegate
|
||||
{
|
||||
if (tree.IsLayoutLocked)
|
||||
return;
|
||||
root.LockChildrenRecursive();
|
||||
var query = searchBox.Text;
|
||||
UpdateFilter(root, query);
|
||||
root.UnlockChildrenRecursive();
|
||||
menu.PerformLayout();
|
||||
};
|
||||
root.ExpandAll(true);
|
||||
return menu;
|
||||
}
|
||||
|
||||
internal static string GetName(CultureInfo value)
|
||||
{
|
||||
return value != null ? string.Format("{0} - {1}", value.Name, value.EnglishName) : null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -61,7 +61,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
var keyType = _editor.Values.Type.GetGenericArguments()[0];
|
||||
if (keyType == typeof(string) || keyType.IsPrimitive)
|
||||
{
|
||||
var popup = RenamePopup.Show(Parent, Bounds, Text, false);
|
||||
var popup = RenamePopup.Show(Parent, Rectangle.Margin(Bounds, Margin), Text, false);
|
||||
popup.Validate += (renamePopup, value) =>
|
||||
{
|
||||
object newKey;
|
||||
@@ -86,7 +86,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
}
|
||||
else if (keyType.IsEnum)
|
||||
{
|
||||
var popup = RenamePopup.Show(Parent, Bounds, Text, false);
|
||||
var popup = RenamePopup.Show(Parent, Rectangle.Margin(Bounds, Margin), Text, false);
|
||||
var picker = new EnumComboBox(keyType)
|
||||
{
|
||||
AnchorPreset = AnchorPresets.StretchAll,
|
||||
@@ -220,9 +220,20 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
if (i != 0 && spacing > 0f)
|
||||
{
|
||||
if (layout.Children.Count > 0 && layout.Children[layout.Children.Count - 1] is PropertiesListElement propertiesListElement)
|
||||
{
|
||||
if (propertiesListElement.Labels.Count > 0)
|
||||
{
|
||||
var label = propertiesListElement.Labels[propertiesListElement.Labels.Count - 1];
|
||||
var margin = label.Margin;
|
||||
margin.Bottom += spacing;
|
||||
label.Margin = margin;
|
||||
}
|
||||
propertiesListElement.Space(spacing);
|
||||
}
|
||||
else
|
||||
{
|
||||
layout.Space(spacing);
|
||||
}
|
||||
}
|
||||
|
||||
var key = keys.ElementAt(i);
|
||||
|
||||
@@ -9,7 +9,7 @@ using FlaxEngine;
|
||||
namespace FlaxEditor.CustomEditors.Editors
|
||||
{
|
||||
/// <summary>
|
||||
/// Default implementation of the inspector used to edit float value type properties.
|
||||
/// Default implementation of the inspector used to edit enum value type properties.
|
||||
/// </summary>
|
||||
[CustomEditor(typeof(Enum)), DefaultEditor]
|
||||
public class EnumEditor : CustomEditor
|
||||
|
||||
@@ -214,6 +214,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
public ScriptMemberInfo Target;
|
||||
public ScriptMemberInfo Source;
|
||||
public PropertiesListElement PropertiesList;
|
||||
public GroupElement Group;
|
||||
public bool Invert;
|
||||
public int LabelIndex;
|
||||
|
||||
@@ -379,26 +380,22 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
}
|
||||
}
|
||||
}
|
||||
if (item.VisibleIf != null)
|
||||
if (item.VisibleIf != null && itemLayout.Children.Count > 0)
|
||||
{
|
||||
PropertiesListElement list;
|
||||
if (itemLayout.Children.Count > 0 && itemLayout.Children[itemLayout.Children.Count - 1] is PropertiesListElement list1)
|
||||
{
|
||||
PropertiesListElement list = null;
|
||||
GroupElement group = null;
|
||||
if (itemLayout.Children[itemLayout.Children.Count - 1] is PropertiesListElement list1)
|
||||
list = list1;
|
||||
}
|
||||
else if (itemLayout.Children[itemLayout.Children.Count - 1] is GroupElement group1)
|
||||
group = group1;
|
||||
else
|
||||
{
|
||||
// TODO: support inlined objects hiding?
|
||||
return;
|
||||
}
|
||||
|
||||
// Get source member used to check rule
|
||||
var sourceMember = GetVisibleIfSource(item.Info.DeclaringType, item.VisibleIf);
|
||||
if (sourceMember == ScriptType.Null)
|
||||
return;
|
||||
|
||||
// Find the target control to show/hide
|
||||
|
||||
// Resize cache
|
||||
if (_visibleIfCaches == null)
|
||||
_visibleIfCaches = new VisibleIfCache[8];
|
||||
@@ -414,6 +411,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
Target = item.Info,
|
||||
Source = sourceMember,
|
||||
PropertiesList = list,
|
||||
Group = group,
|
||||
LabelIndex = labelIndex,
|
||||
Invert = item.VisibleIf.Invert,
|
||||
};
|
||||
@@ -569,8 +567,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
{
|
||||
for (int i = 0; i < _visibleIfCaches.Length; i++)
|
||||
{
|
||||
var c = _visibleIfCaches[i];
|
||||
|
||||
ref var c = ref _visibleIfCaches[i];
|
||||
if (c.Target == ScriptMemberInfo.Null)
|
||||
break;
|
||||
|
||||
@@ -586,7 +583,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
}
|
||||
|
||||
// Apply the visibility (note: there may be no label)
|
||||
if (c.LabelIndex != -1 && c.PropertiesList.Labels.Count > c.LabelIndex)
|
||||
if (c.LabelIndex != -1 && c.PropertiesList != null && c.PropertiesList.Labels.Count > c.LabelIndex)
|
||||
{
|
||||
var label = c.PropertiesList.Labels[c.LabelIndex];
|
||||
label.Visible = visible;
|
||||
@@ -599,6 +596,10 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
child.Visible = visible;
|
||||
}
|
||||
}
|
||||
if (c.Group != null)
|
||||
{
|
||||
c.Group.Panel.Visible = visible;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
234
Source/Editor/CustomEditors/Editors/LocalizedStringEditor.cs
Normal file
234
Source/Editor/CustomEditors/Editors/LocalizedStringEditor.cs
Normal file
@@ -0,0 +1,234 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using FlaxEditor.Content.Settings;
|
||||
using FlaxEditor.CustomEditors.Elements;
|
||||
using FlaxEditor.GUI.Tree;
|
||||
using FlaxEditor.Scripting;
|
||||
using FlaxEditor.Utilities;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
using Utils = FlaxEditor.Utilities.Utils;
|
||||
|
||||
namespace FlaxEditor.CustomEditors.Editors
|
||||
{
|
||||
/// <summary>
|
||||
/// Default implementation of the inspector used to edit localized string properties.
|
||||
/// </summary>
|
||||
[CustomEditor(typeof(LocalizedString)), DefaultEditor]
|
||||
public sealed class LocalizedStringEditor : GenericEditor
|
||||
{
|
||||
private TextBoxElement _idElement, _valueElement;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override DisplayStyle Style => DisplayStyle.Inline;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Initialize(LayoutElementsContainer layout)
|
||||
{
|
||||
base.Initialize(layout);
|
||||
|
||||
if (layout.Children.Count == 0)
|
||||
return;
|
||||
var propList = layout.Children[layout.Children.Count - 1] as PropertiesListElement;
|
||||
if (propList == null || propList.Children.Count != 2)
|
||||
return;
|
||||
var idElement = propList.Children[0] as TextBoxElement;
|
||||
var valueElement = propList.Children[1] as TextBoxElement;
|
||||
if (idElement == null || valueElement == null)
|
||||
return;
|
||||
_idElement = idElement;
|
||||
_valueElement = valueElement;
|
||||
|
||||
var attributes = Values.GetAttributes();
|
||||
var multiLine = attributes?.FirstOrDefault(x => x is MultilineTextAttribute);
|
||||
if (multiLine != null)
|
||||
{
|
||||
valueElement.TextBox.IsMultiline = true;
|
||||
valueElement.TextBox.Height *= 3;
|
||||
}
|
||||
|
||||
var selectString = new Button
|
||||
{
|
||||
Width = 16.0f,
|
||||
Text = "...",
|
||||
TooltipText = "Select localized text from Localization Settings...",
|
||||
Parent = idElement.TextBox,
|
||||
};
|
||||
selectString.SetAnchorPreset(AnchorPresets.MiddleRight, false, true);
|
||||
selectString.ButtonClicked += OnSelectStringClicked;
|
||||
|
||||
var addString = new Button
|
||||
{
|
||||
Width = 16.0f,
|
||||
Text = "+",
|
||||
TooltipText = "Add new localized text to Localization Settings (all used locales)",
|
||||
Parent = _valueElement.TextBox,
|
||||
Enabled = IsSingleObject,
|
||||
};
|
||||
addString.SetAnchorPreset(AnchorPresets.MiddleRight, false, true);
|
||||
addString.ButtonClicked += OnAddStringClicked;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
internal override void RefreshInternal()
|
||||
{
|
||||
base.RefreshInternal();
|
||||
|
||||
if (_valueElement != null)
|
||||
{
|
||||
_valueElement.TextBox.WatermarkText = Localization.GetString(_idElement.Text);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Deinitialize()
|
||||
{
|
||||
base.Deinitialize();
|
||||
|
||||
_idElement = null;
|
||||
_valueElement = null;
|
||||
}
|
||||
|
||||
private void OnSelectStringClicked(Button button)
|
||||
{
|
||||
var settings = GameSettings.Load<LocalizationSettings>();
|
||||
if (settings?.LocalizedStringTables == null || settings.LocalizedStringTables.Length == 0)
|
||||
{
|
||||
MessageBox.Show("No valid localization settings setup.");
|
||||
return;
|
||||
}
|
||||
Profiler.BeginEvent("LocalizedStringEditor.OnSelectStringClicked");
|
||||
var allKeys = new HashSet<string>();
|
||||
for (int i = 0; i < settings.LocalizedStringTables.Length; i++)
|
||||
{
|
||||
var table = settings.LocalizedStringTables[i];
|
||||
if (table && !table.WaitForLoaded())
|
||||
{
|
||||
var entries = table.Entries;
|
||||
foreach (var e in entries)
|
||||
allKeys.Add(e.Key);
|
||||
}
|
||||
}
|
||||
var allKeysSorted = allKeys.ToList();
|
||||
allKeysSorted.Sort();
|
||||
var value = _idElement?.TextBox.Text;
|
||||
var menu = Utils.CreateSearchPopup(out var searchBox, out var tree);
|
||||
var idToNode = new TreeNode[allKeysSorted.Count];
|
||||
for (var i = 0; i < allKeysSorted.Count; i++)
|
||||
{
|
||||
var key = allKeysSorted[i];
|
||||
var node = new TreeNode
|
||||
{
|
||||
Text = key,
|
||||
TooltipText = Localization.GetString(key),
|
||||
Parent = tree,
|
||||
};
|
||||
if (key == value)
|
||||
tree.Select(node);
|
||||
idToNode[i] = node;
|
||||
}
|
||||
tree.SelectedChanged += delegate(List<TreeNode> before, List<TreeNode> after)
|
||||
{
|
||||
if (after.Count == 1)
|
||||
{
|
||||
menu.Hide();
|
||||
_idElement.TextBox.SetTextAsUser(after[0].Text);
|
||||
}
|
||||
};
|
||||
searchBox.TextChanged += delegate
|
||||
{
|
||||
if (tree.IsLayoutLocked)
|
||||
return;
|
||||
tree.LockChildrenRecursive();
|
||||
var query = searchBox.Text;
|
||||
for (int i = 0; i < idToNode.Length; i++)
|
||||
{
|
||||
var node = idToNode[i];
|
||||
node.Visible = string.IsNullOrWhiteSpace(query) || QueryFilterHelper.Match(query, node.Text);
|
||||
}
|
||||
tree.UnlockChildrenRecursive();
|
||||
menu.PerformLayout();
|
||||
};
|
||||
menu.Show(button, new Vector2(0, button.Height));
|
||||
Profiler.EndEvent();
|
||||
}
|
||||
|
||||
private void OnAddStringClicked(Button button)
|
||||
{
|
||||
var settings = GameSettings.Load<LocalizationSettings>();
|
||||
if (settings?.LocalizedStringTables == null || settings.LocalizedStringTables.Length == 0)
|
||||
{
|
||||
MessageBox.Show("No valid localization settings setup.");
|
||||
return;
|
||||
}
|
||||
Profiler.BeginEvent("LocalizedStringEditor.OnAddStringClicked");
|
||||
var allKeys = new HashSet<string>();
|
||||
for (int i = 0; i < settings.LocalizedStringTables.Length; i++)
|
||||
{
|
||||
var table = settings.LocalizedStringTables[i];
|
||||
if (table && !table.WaitForLoaded())
|
||||
{
|
||||
var entries = table.Entries;
|
||||
foreach (var e in entries)
|
||||
allKeys.Add(e.Key);
|
||||
}
|
||||
}
|
||||
_valueElement.TextBox.SetTextAsUser(null);
|
||||
string newKey = null;
|
||||
if (string.IsNullOrEmpty(_idElement.Text))
|
||||
{
|
||||
CustomEditor customEditor = this;
|
||||
while (customEditor?.Values != null)
|
||||
{
|
||||
if (customEditor.Values.Info != ScriptMemberInfo.Null)
|
||||
if (newKey == null)
|
||||
newKey = customEditor.Values.Info.Name;
|
||||
else
|
||||
newKey = customEditor.Values.Info.Name + '.' + newKey;
|
||||
else if (customEditor.Values[0] is SceneObject sceneObject)
|
||||
if (newKey == null)
|
||||
newKey = sceneObject.GetNamePath('.');
|
||||
else
|
||||
newKey = sceneObject.GetNamePath('.') + '.' + newKey;
|
||||
else
|
||||
break;
|
||||
customEditor = customEditor.ParentEditor;
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(newKey))
|
||||
newKey = Guid.NewGuid().ToString("N");
|
||||
}
|
||||
else
|
||||
{
|
||||
newKey = _idElement.Text;
|
||||
}
|
||||
if (allKeys.Contains(newKey))
|
||||
{
|
||||
Profiler.EndEvent();
|
||||
if (_idElement.Text != newKey)
|
||||
_idElement.TextBox.SetTextAsUser(newKey);
|
||||
else
|
||||
MessageBox.Show("Already added.");
|
||||
return;
|
||||
}
|
||||
var newValue = _valueElement.Text;
|
||||
Editor.Log(newKey + (newValue != null ? " = " + newValue : string.Empty));
|
||||
var locales = settings.LocalizedStringTables.GroupBy(x => x.Locale);
|
||||
foreach (var locale in locales)
|
||||
{
|
||||
var table = locale.First();
|
||||
var entries = table.Entries;
|
||||
if (table.Locale == "en")
|
||||
entries[newKey] = new[] { newValue };
|
||||
else
|
||||
entries[newKey] = new[] { string.Empty };
|
||||
table.Entries = entries;
|
||||
table.Save();
|
||||
}
|
||||
_idElement.TextBox.SetTextAsUser(newKey);
|
||||
Profiler.EndEvent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,6 @@
|
||||
using System;
|
||||
using FlaxEditor.GUI;
|
||||
using FlaxEditor.Scripting;
|
||||
using FlaxEngine;
|
||||
|
||||
namespace FlaxEditor.CustomEditors.Editors
|
||||
{
|
||||
|
||||
@@ -12,6 +12,9 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
[CustomEditor(typeof(Quaternion)), DefaultEditor]
|
||||
public class QuaternionEditor : CustomEditor
|
||||
{
|
||||
private Vector3 _cachedAngles = Vector3.Zero;
|
||||
private object _cachedToken;
|
||||
|
||||
/// <summary>
|
||||
/// The X component element
|
||||
/// </summary>
|
||||
@@ -58,15 +61,36 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
if (IsSetBlocked)
|
||||
return;
|
||||
|
||||
float x = XElement.FloatValue.Value;
|
||||
float y = YElement.FloatValue.Value;
|
||||
float z = ZElement.FloatValue.Value;
|
||||
var isSliding = XElement.IsSliding || YElement.IsSliding || ZElement.IsSliding;
|
||||
var token = isSliding ? this : null;
|
||||
var useCachedAngles = isSliding && token == _cachedToken;
|
||||
|
||||
float x = (useCachedAngles && !XElement.IsSliding) ? _cachedAngles.X : XElement.FloatValue.Value;
|
||||
float y = (useCachedAngles && !YElement.IsSliding) ? _cachedAngles.Y : YElement.FloatValue.Value;
|
||||
float z = (useCachedAngles && !ZElement.IsSliding) ? _cachedAngles.Z : ZElement.FloatValue.Value;
|
||||
|
||||
x = Mathf.UnwindDegrees(x);
|
||||
y = Mathf.UnwindDegrees(y);
|
||||
z = Mathf.UnwindDegrees(z);
|
||||
|
||||
if (!useCachedAngles)
|
||||
{
|
||||
_cachedAngles = new Vector3(x, y, z);
|
||||
}
|
||||
|
||||
_cachedToken = token;
|
||||
|
||||
Quaternion.Euler(x, y, z, out Quaternion value);
|
||||
SetValue(value, token);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void ClearToken()
|
||||
{
|
||||
_cachedToken = null;
|
||||
base.ClearToken();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Refresh()
|
||||
{
|
||||
|
||||
@@ -5,15 +5,15 @@ using FlaxEngine.GUI;
|
||||
namespace FlaxEditor.CustomEditors.Elements
|
||||
{
|
||||
/// <summary>
|
||||
/// The vertical panel element.
|
||||
/// The horizontal panel element.
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEditor.CustomEditors.LayoutElement" />
|
||||
public class VerticalPanelElement : LayoutElementsContainer
|
||||
public class HorizontalPanelElement : LayoutElementsContainer
|
||||
{
|
||||
/// <summary>
|
||||
/// The panel.
|
||||
/// </summary>
|
||||
public readonly VerticalPanel Panel = new VerticalPanel();
|
||||
public readonly HorizontalPanel Panel = new HorizontalPanel();
|
||||
|
||||
/// <inheritdoc />
|
||||
public override ContainerControl ContainerControl => Panel;
|
||||
|
||||
@@ -5,15 +5,15 @@ using FlaxEngine.GUI;
|
||||
namespace FlaxEditor.CustomEditors.Elements
|
||||
{
|
||||
/// <summary>
|
||||
/// The horizontal panel element.
|
||||
/// The vertical panel element.
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEditor.CustomEditors.LayoutElement" />
|
||||
public class HorizontalPanelElement : LayoutElementsContainer
|
||||
public class VerticalPanelElement : LayoutElementsContainer
|
||||
{
|
||||
/// <summary>
|
||||
/// The panel.
|
||||
/// </summary>
|
||||
public readonly HorizontalPanel Panel = new HorizontalPanel();
|
||||
public readonly VerticalPanel Panel = new VerticalPanel();
|
||||
|
||||
/// <inheritdoc />
|
||||
public override ContainerControl ContainerControl => Panel;
|
||||
|
||||
@@ -112,7 +112,7 @@ namespace FlaxEditor.CustomEditors
|
||||
OnAddElement(element);
|
||||
return element;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Adds new horizontal panel element.
|
||||
/// </summary>
|
||||
@@ -690,6 +690,17 @@ namespace FlaxEditor.CustomEditors
|
||||
return element;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds custom element to the layout.
|
||||
/// </summary>
|
||||
/// <param name="element">The element.</param>
|
||||
public void AddElement(LayoutElement element)
|
||||
{
|
||||
if (element == null)
|
||||
throw new ArgumentNullException();
|
||||
OnAddElement(element);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when element is added to the layout.
|
||||
/// </summary>
|
||||
|
||||
@@ -46,10 +46,7 @@ namespace FlaxEditor.CustomEditors
|
||||
|
||||
if (values.HasReferenceValue)
|
||||
{
|
||||
var v = (IList)values.ReferenceValue;
|
||||
|
||||
// Get the reference value if collections are the same size
|
||||
if (v != null && values.Count == v.Count)
|
||||
if (values.ReferenceValue is IList v && values.Count == v.Count && v.Count > index)
|
||||
{
|
||||
_referenceValue = v[index];
|
||||
_hasReferenceValue = true;
|
||||
|
||||
@@ -59,6 +59,7 @@ public class Editor : EditorModule
|
||||
AddPlatformTools(options, platformToolsRoot, platformToolsRootExternal, "PS4", "PLATFORM_TOOLS_PS4");
|
||||
AddPlatformTools(options, platformToolsRoot, platformToolsRootExternal, "XboxScarlett", "PLATFORM_TOOLS_XBOX_SCARLETT");
|
||||
AddPlatformTools(options, platformToolsRoot, platformToolsRootExternal, "Android", "PLATFORM_TOOLS_ANDROID");
|
||||
AddPlatformTools(options, platformToolsRoot, platformToolsRootExternal, "Switch", "PLATFORM_TOOLS_SWITCH");
|
||||
}
|
||||
AddPlatformTools(options, platformToolsRoot, platformToolsRootExternal, "Linux", "PLATFORM_TOOLS_LINUX");
|
||||
|
||||
|
||||
@@ -752,10 +752,11 @@ namespace FlaxEditor
|
||||
/// <param name="type">The collision data type.</param>
|
||||
/// <param name="model">The source model.</param>
|
||||
/// <param name="modelLodIndex">The source model LOD index.</param>
|
||||
/// <param name="materialSlotsMask">The source model material slots mask. One bit per-slot. Can be sued to exclude particular material slots from collision cooking.</param>
|
||||
/// <param name="convexFlags">The convex mesh generation flags.</param>
|
||||
/// <param name="convexVertexLimit">The convex mesh vertex limit. Use values in range [8;255]</param>
|
||||
/// <returns>True if failed, otherwise false.</returns>
|
||||
public static bool CookMeshCollision(string path, CollisionDataType type, Model model, int modelLodIndex = 0, ConvexMeshGenerationFlags convexFlags = ConvexMeshGenerationFlags.None, int convexVertexLimit = 255)
|
||||
public static bool CookMeshCollision(string path, CollisionDataType type, ModelBase model, int modelLodIndex = 0, uint materialSlotsMask = uint.MaxValue, ConvexMeshGenerationFlags convexFlags = ConvexMeshGenerationFlags.None, int convexVertexLimit = 255)
|
||||
{
|
||||
if (string.IsNullOrEmpty(path))
|
||||
throw new ArgumentNullException(nameof(path));
|
||||
@@ -764,7 +765,7 @@ namespace FlaxEditor
|
||||
if (type == CollisionDataType.None)
|
||||
throw new ArgumentException(nameof(type));
|
||||
|
||||
return Internal_CookMeshCollision(path, type, FlaxEngine.Object.GetUnmanagedPtr(model), modelLodIndex, convexFlags, convexVertexLimit);
|
||||
return Internal_CookMeshCollision(path, type, FlaxEngine.Object.GetUnmanagedPtr(model), modelLodIndex, materialSlotsMask, convexFlags, convexVertexLimit);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -877,10 +878,12 @@ namespace FlaxEditor
|
||||
/// Checks if can import asset with the given extension.
|
||||
/// </summary>
|
||||
/// <param name="extension">The file extension.</param>
|
||||
/// <param name="outputExtension">The output file extension (flax, json, etc.).</param>
|
||||
/// <returns>True if can import files with given extension, otherwise false.</returns>
|
||||
public static bool CanImport(string extension)
|
||||
public static bool CanImport(string extension, out string outputExtension)
|
||||
{
|
||||
return Internal_CanImport(extension);
|
||||
outputExtension = Internal_CanImport(extension);
|
||||
return outputExtension != null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1344,7 +1347,7 @@ namespace FlaxEditor
|
||||
internal static extern string Internal_GetShaderAssetSourceCode(IntPtr obj);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern bool Internal_CookMeshCollision(string path, CollisionDataType type, IntPtr model, int modelLodIndex, ConvexMeshGenerationFlags convexFlags, int convexVertexLimit);
|
||||
internal static extern bool Internal_CookMeshCollision(string path, CollisionDataType type, IntPtr model, int modelLodIndex, uint materialSlotsMask, ConvexMeshGenerationFlags convexFlags, int convexVertexLimit);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Internal_GetCollisionWires(IntPtr collisionData, out Vector3[] triangles, out int[] indices);
|
||||
@@ -1368,7 +1371,7 @@ namespace FlaxEditor
|
||||
internal static extern bool Internal_CreateVisualScript(string outputPath, string baseTypename);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern bool Internal_CanImport(string extension);
|
||||
internal static extern string Internal_CanImport(string extension);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern bool Internal_CanExport(string path);
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace FlaxEditor.GUI
|
||||
/// <summary>
|
||||
/// The cached value from the UI.
|
||||
/// </summary>
|
||||
protected int _cachedValue;
|
||||
protected long _cachedValue;
|
||||
|
||||
/// <summary>
|
||||
/// True if has value cached, otherwise false.
|
||||
@@ -54,7 +54,7 @@ namespace FlaxEditor.GUI
|
||||
/// <summary>
|
||||
/// The value.
|
||||
/// </summary>
|
||||
public int Value;
|
||||
public long Value;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Entry"/> struct.
|
||||
@@ -62,7 +62,7 @@ namespace FlaxEditor.GUI
|
||||
/// <param name="name">The name.</param>
|
||||
/// <param name="tooltip">The tooltip.</param>
|
||||
/// <param name="value">The value.</param>
|
||||
public Entry(string name, int value, string tooltip = null)
|
||||
public Entry(string name, long value, string tooltip = null)
|
||||
{
|
||||
Name = name;
|
||||
Tooltip = tooltip;
|
||||
@@ -88,13 +88,13 @@ namespace FlaxEditor.GUI
|
||||
public object EnumTypeValue
|
||||
{
|
||||
get => Enum.ToObject(_enumType, Value);
|
||||
set => Value = Convert.ToInt32(value);
|
||||
set => Value = Convert.ToInt64(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the value.
|
||||
/// </summary>
|
||||
public int Value
|
||||
public long Value
|
||||
{
|
||||
get => _cachedValue;
|
||||
set
|
||||
@@ -209,13 +209,13 @@ namespace FlaxEditor.GUI
|
||||
/// </summary>
|
||||
protected void CacheValue()
|
||||
{
|
||||
int value = 0;
|
||||
long value = 0;
|
||||
if (IsFlags)
|
||||
{
|
||||
var selection = Selection;
|
||||
for (int i = 0; i < selection.Count; i++)
|
||||
{
|
||||
int index = selection[i];
|
||||
var index = selection[i];
|
||||
value |= _entries[index].Value;
|
||||
}
|
||||
}
|
||||
@@ -276,7 +276,7 @@ namespace FlaxEditor.GUI
|
||||
tooltip = tooltipAttr.Text;
|
||||
}
|
||||
|
||||
entries.Add(new Entry(name, Convert.ToInt32(field.GetRawConstantValue()), tooltip));
|
||||
entries.Add(new Entry(name, Convert.ToInt64(field.GetRawConstantValue()), tooltip));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -295,9 +295,9 @@ namespace FlaxEditor.GUI
|
||||
}
|
||||
|
||||
// Calculate value that will be set after change
|
||||
int valueAfter = 0;
|
||||
long valueAfter = 0;
|
||||
bool isSelected = _selectedIndices.Contains(index);
|
||||
int selectedValue = entries[index].Value;
|
||||
long selectedValue = entries[index].Value;
|
||||
for (int i = 0; i < _selectedIndices.Count; i++)
|
||||
{
|
||||
int selectedIndex = _selectedIndices[i];
|
||||
|
||||
@@ -89,6 +89,8 @@ namespace FlaxEditor.GUI
|
||||
new PlatformData(PlatformType.PS4, icons.PS4Icon128, "PlayStation 4"),
|
||||
new PlatformData(PlatformType.XboxScarlett, icons.XBoxScarletIcon128, "Xbox Scarlett"),
|
||||
new PlatformData(PlatformType.Android, icons.AndroidIcon128, "Android"),
|
||||
new PlatformData(PlatformType.Switch, icons.ColorWheel128, "Switch"),
|
||||
|
||||
};
|
||||
|
||||
const float IconSize = 48.0f;
|
||||
|
||||
@@ -4,6 +4,8 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using FlaxEditor.Utilities;
|
||||
using FlaxEngine;
|
||||
using Newtonsoft.Json;
|
||||
using JsonSerializer = FlaxEngine.Json.JsonSerializer;
|
||||
|
||||
namespace FlaxEditor.History
|
||||
{
|
||||
@@ -114,6 +116,8 @@ namespace FlaxEditor.History
|
||||
public object TargetInstance;
|
||||
}
|
||||
|
||||
internal static JsonSerializerSettings JsonSettings;
|
||||
|
||||
// For objects that cannot be referenced in undo action like: FlaxEngine.Object or SceneGraphNode we store them in DataStorage,
|
||||
// otherwise here:
|
||||
private readonly object TargetInstance;
|
||||
@@ -177,6 +181,24 @@ namespace FlaxEditor.History
|
||||
};
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override DataStorage Data
|
||||
{
|
||||
protected set
|
||||
{
|
||||
// Inject objects typename serialization to prevent data type mismatch when loading from saved state
|
||||
var settings = JsonSettings;
|
||||
if (settings == null)
|
||||
{
|
||||
settings = JsonSerializer.CreateDefaultSettings(false);
|
||||
settings.TypeNameHandling = TypeNameHandling.All;
|
||||
JsonSettings = settings;
|
||||
}
|
||||
_data = JsonConvert.SerializeObject(value, Formatting.Indented, settings);
|
||||
//Editor.Log(_data);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ActionString { get; }
|
||||
|
||||
|
||||
@@ -521,13 +521,14 @@ public:
|
||||
return AssetsImportingManager::Create(AssetsImportingManager::CreateVisualScriptTag, outputPath, &baseTypename);
|
||||
}
|
||||
|
||||
static bool CanImport(MonoString* extensionObj)
|
||||
static MonoString* CanImport(MonoString* extensionObj)
|
||||
{
|
||||
String extension;
|
||||
MUtils::ToString(extensionObj, extension);
|
||||
if (extension.Length() > 0 && extension[0] == '.')
|
||||
extension.Remove(0, 1);
|
||||
return AssetsImportingManager::GetImporter(extension) != nullptr;
|
||||
const AssetImporter* importer = AssetsImportingManager::GetImporter(extension);
|
||||
return importer ? MUtils::ToString(importer->ResultExtension) : nullptr;
|
||||
}
|
||||
|
||||
static bool Import(MonoString* inputPathObj, MonoString* outputPathObj, void* arg)
|
||||
@@ -715,7 +716,7 @@ public:
|
||||
return str;
|
||||
}
|
||||
|
||||
static bool CookMeshCollision(MonoString* pathObj, CollisionDataType type, Model* modelObj, int32 modelLodIndex, ConvexMeshGenerationFlags convexFlags, int32 convexVertexLimit)
|
||||
static bool CookMeshCollision(MonoString* pathObj, CollisionDataType type, ModelBase* modelObj, int32 modelLodIndex, uint32 materialSlotsMask, ConvexMeshGenerationFlags convexFlags, int32 convexVertexLimit)
|
||||
{
|
||||
#if COMPILE_WITH_PHYSICS_COOKING
|
||||
CollisionCooking::Argument arg;
|
||||
@@ -725,9 +726,9 @@ public:
|
||||
arg.Type = type;
|
||||
arg.Model = modelObj;
|
||||
arg.ModelLodIndex = modelLodIndex;
|
||||
arg.MaterialSlotsMask = materialSlotsMask;
|
||||
arg.ConvexFlags = convexFlags;
|
||||
arg.ConvexVertexLimit = convexVertexLimit;
|
||||
|
||||
return CreateCollisionData::CookMeshCollision(path, arg);
|
||||
#else
|
||||
LOG(Warning, "Collision cooking is disabled.");
|
||||
@@ -743,8 +744,8 @@ public:
|
||||
const auto& debugLines = collisionData->GetDebugLines();
|
||||
|
||||
const int32 linesCount = debugLines.Count() / 2;
|
||||
*triangles = mono_array_new(mono_domain_get(), StdTypesContainer::Instance()->Vector3Class->GetNative(), debugLines.Count());
|
||||
*indices = mono_array_new(mono_domain_get(), mono_get_int32_class(), linesCount * 3);
|
||||
mono_gc_wbarrier_generic_store(triangles, (MonoObject*)mono_array_new(mono_domain_get(), StdTypesContainer::Instance()->Vector3Class->GetNative(), debugLines.Count()));
|
||||
mono_gc_wbarrier_generic_store(indices, (MonoObject*)mono_array_new(mono_domain_get(), mono_get_int32_class(), linesCount * 3));
|
||||
|
||||
// Use one triangle per debug line
|
||||
for (int32 i = 0; i < debugLines.Count(); i++)
|
||||
|
||||
@@ -923,6 +923,7 @@ namespace FlaxEditor.Modules
|
||||
Proxy.Add(new SkeletonMaskProxy());
|
||||
Proxy.Add(new GameplayGlobalsProxy());
|
||||
Proxy.Add(new VisualScriptProxy());
|
||||
Proxy.Add(new LocalizedStringTableProxy());
|
||||
Proxy.Add(new FileProxy());
|
||||
Proxy.Add(new SpawnableJsonAssetProxy<PhysicalMaterial>());
|
||||
|
||||
@@ -933,6 +934,7 @@ namespace FlaxEditor.Modules
|
||||
Proxy.Add(new SettingsProxy(typeof(PhysicsSettings)));
|
||||
Proxy.Add(new SettingsProxy(typeof(GraphicsSettings)));
|
||||
Proxy.Add(new SettingsProxy(typeof(NavigationSettings)));
|
||||
Proxy.Add(new SettingsProxy(typeof(LocalizationSettings)));
|
||||
Proxy.Add(new SettingsProxy(typeof(BuildSettings)));
|
||||
Proxy.Add(new SettingsProxy(typeof(InputSettings)));
|
||||
Proxy.Add(new SettingsProxy(typeof(WindowsPlatformSettings)));
|
||||
@@ -945,6 +947,9 @@ namespace FlaxEditor.Modules
|
||||
if (typeXboxScarlettPlatformSettings != null)
|
||||
Proxy.Add(new SettingsProxy(typeXboxScarlettPlatformSettings));
|
||||
Proxy.Add(new SettingsProxy(typeof(AndroidPlatformSettings)));
|
||||
var typeSwitchPlatformSettings = TypeUtils.GetManagedType(GameSettings.SwitchPlatformSettingsTypename);
|
||||
if (typeSwitchPlatformSettings != null)
|
||||
Proxy.Add(new SettingsProxy(typeSwitchPlatformSettings));
|
||||
Proxy.Add(new SettingsProxy(typeof(AudioSettings)));
|
||||
|
||||
// Last add generic json (won't override other json proxies)
|
||||
|
||||
@@ -309,6 +309,7 @@ namespace FlaxEditor.Modules
|
||||
{ "FlaxEditor.Content.Settings.InputSettings", "Settings" },
|
||||
{ "FlaxEditor.Content.Settings.LayersAndTagsSettings", "Settings" },
|
||||
{ "FlaxEditor.Content.Settings.NavigationSettings", "Settings" },
|
||||
{ "FlaxEditor.Content.Settings.LocalizationSettings", "Settings" },
|
||||
{ "FlaxEditor.Content.Settings.PhysicsSettings", "Settings" },
|
||||
{ "FlaxEditor.Content.Settings.TimeSettings", "Settings" },
|
||||
{ "FlaxEditor.Content.Settings.UWPPlatformSettings", "Settings" },
|
||||
|
||||
@@ -193,12 +193,10 @@ namespace FlaxEditor.Modules
|
||||
var extension = System.IO.Path.GetExtension(inputPath) ?? string.Empty;
|
||||
|
||||
// Check if given file extension is a binary asset (.flax files) and can be imported by the engine
|
||||
bool isBinaryAsset = Editor.CanImport(extension);
|
||||
string outputExtension;
|
||||
if (isBinaryAsset)
|
||||
bool isBuilt = Editor.CanImport(extension, out var outputExtension);
|
||||
if (isBuilt)
|
||||
{
|
||||
// Flax it up!
|
||||
outputExtension = ".flax";
|
||||
outputExtension = '.' + outputExtension;
|
||||
|
||||
if (!targetLocation.CanHaveAssets)
|
||||
{
|
||||
@@ -234,7 +232,7 @@ namespace FlaxEditor.Modules
|
||||
var shortName = System.IO.Path.GetFileNameWithoutExtension(inputPath);
|
||||
var outputPath = System.IO.Path.Combine(targetLocation.Path, shortName + outputExtension);
|
||||
|
||||
Import(inputPath, outputPath, isBinaryAsset, skipSettingsDialog, settings);
|
||||
Import(inputPath, outputPath, isBuilt, skipSettingsDialog, settings);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -243,10 +241,10 @@ namespace FlaxEditor.Modules
|
||||
/// </summary>
|
||||
/// <param name="inputPath">The input path.</param>
|
||||
/// <param name="outputPath">The output path.</param>
|
||||
/// <param name="isBinaryAsset">True if output file is a binary asset.</param>
|
||||
/// <param name="isInBuilt">True if use in-built importer (engine backend).</param>
|
||||
/// <param name="skipSettingsDialog">True if skip any popup dialogs showing for import options adjusting. Can be used when importing files from code.</param>
|
||||
/// <param name="settings">Import settings to override. Use null to skip this value.</param>
|
||||
private void Import(string inputPath, string outputPath, bool isBinaryAsset, bool skipSettingsDialog = false, object settings = null)
|
||||
private void Import(string inputPath, string outputPath, bool isInBuilt, bool skipSettingsDialog = false, object settings = null)
|
||||
{
|
||||
lock (_requests)
|
||||
{
|
||||
@@ -254,7 +252,7 @@ namespace FlaxEditor.Modules
|
||||
{
|
||||
InputPath = inputPath,
|
||||
OutputPath = outputPath,
|
||||
IsBinaryAsset = isBinaryAsset,
|
||||
IsInBuilt = isInBuilt,
|
||||
SkipSettingsDialog = skipSettingsDialog,
|
||||
Settings = settings,
|
||||
});
|
||||
|
||||
@@ -22,14 +22,25 @@ namespace FlaxEditor.Modules
|
||||
/// <seealso cref="FlaxEditor.SceneGraph.RootNode" />
|
||||
public class ScenesRootNode : RootNode
|
||||
{
|
||||
private readonly Editor _editor;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ScenesRootNode()
|
||||
{
|
||||
_editor = Editor.Instance;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Spawn(Actor actor, Actor parent)
|
||||
{
|
||||
Editor.Instance.SceneEditing.Spawn(actor, parent);
|
||||
_editor.SceneEditing.Spawn(actor, parent);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Undo Undo => Editor.Instance.Undo;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override List<SceneGraphNode> Selection => _editor.SceneEditing.Selection;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -150,7 +150,10 @@ namespace FlaxEditor.Options
|
||||
private void Save()
|
||||
{
|
||||
// Update file
|
||||
Editor.SaveJsonAsset(_optionsFilePath, Options);
|
||||
if (Editor.SaveJsonAsset(_optionsFilePath, Options))
|
||||
{
|
||||
MessageBox.Show(string.Format("Failed to save editor option to '{0}'. Ensure that directory exists and program has access to it.", _optionsFilePath), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
}
|
||||
|
||||
// Special case for editor analytics
|
||||
var editorAnalyticsTrackingFile = Path.Combine(Editor.LocalCachePath, "noTracking");
|
||||
|
||||
@@ -194,7 +194,7 @@ namespace FlaxEditor.SceneGraph
|
||||
{
|
||||
get
|
||||
{
|
||||
var scene = _actor.Scene;
|
||||
var scene = _actor ? _actor.Scene : null;
|
||||
return scene != null ? SceneGraphFactory.FindNode(scene.ID) as SceneNode : null;
|
||||
}
|
||||
}
|
||||
@@ -235,7 +235,6 @@ namespace FlaxEditor.SceneGraph
|
||||
{
|
||||
if (!(value is ActorNode))
|
||||
throw new InvalidOperationException("ActorNode can have only ActorNode as a parent node.");
|
||||
|
||||
base.ParentNode = value;
|
||||
}
|
||||
}
|
||||
@@ -289,6 +288,13 @@ namespace FlaxEditor.SceneGraph
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Action called after pasting actor in editor.
|
||||
/// </summary>
|
||||
public virtual void PostPaste()
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnParentChanged()
|
||||
{
|
||||
@@ -299,6 +305,7 @@ namespace FlaxEditor.SceneGraph
|
||||
// (eg. we build new node for spawned actor and link it to the game)
|
||||
if (_treeNode.Parent != null && !_treeNode.Parent.IsLayoutLocked)
|
||||
{
|
||||
_treeNode.IndexInParent = _actor.OrderInParent;
|
||||
_treeNode.Parent.SortChildren();
|
||||
|
||||
// Update UI
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace FlaxEditor.SceneGraph.Actors
|
||||
|
||||
public override bool CanBeSelectedDirectly => true;
|
||||
|
||||
public override bool CanDuplicate => true;
|
||||
public override bool CanDuplicate => !Root?.Selection.Contains(ParentNode) ?? true;
|
||||
|
||||
public override bool CanDelete => true;
|
||||
|
||||
|
||||
@@ -25,5 +25,20 @@ namespace FlaxEditor.SceneGraph.Actors
|
||||
if (Actor is UIControl uiControl)
|
||||
DebugDraw.DrawWireBox(uiControl.Bounds, Color.BlueViolet);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void PostPaste()
|
||||
{
|
||||
base.PostPaste();
|
||||
|
||||
var control = ((UIControl)Actor).Control;
|
||||
if (control != null)
|
||||
{
|
||||
if (control.Parent != null)
|
||||
control.Parent.PerformLayout();
|
||||
else
|
||||
control.PerformLayout();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,6 +86,10 @@ namespace FlaxEditor.SceneGraph.GUI
|
||||
}
|
||||
parent.SortChildren();
|
||||
}
|
||||
else if (Actor)
|
||||
{
|
||||
_orderInParent = Actor.OrderInParent;
|
||||
}
|
||||
}
|
||||
|
||||
internal void OnNameChanged()
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using FlaxEditor.SceneGraph.Actors;
|
||||
using FlaxEngine;
|
||||
|
||||
@@ -146,5 +147,10 @@ namespace FlaxEditor.SceneGraph
|
||||
/// Gets the undo.
|
||||
/// </summary>
|
||||
public abstract Undo Undo { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of selected scene graph nodes in the editor context.
|
||||
/// </summary>
|
||||
public abstract List<SceneGraphNode> Selection { get; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,7 +57,9 @@ namespace FlaxEditor.SceneGraph
|
||||
/// </summary>
|
||||
public virtual RootNode Root => ParentNode?.Root;
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <summary>
|
||||
/// Gets or sets the transform of the node.
|
||||
/// </summary>
|
||||
public abstract Transform Transform { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -110,18 +112,9 @@ namespace FlaxEditor.SceneGraph
|
||||
{
|
||||
if (parentNode != value)
|
||||
{
|
||||
if (parentNode != null)
|
||||
{
|
||||
parentNode.ChildNodes.Remove(this);
|
||||
}
|
||||
|
||||
parentNode?.ChildNodes.Remove(this);
|
||||
parentNode = value;
|
||||
|
||||
if (parentNode != null)
|
||||
{
|
||||
parentNode.ChildNodes.Add(this);
|
||||
}
|
||||
|
||||
parentNode?.ChildNodes.Add(this);
|
||||
OnParentChanged();
|
||||
}
|
||||
}
|
||||
@@ -372,6 +365,7 @@ namespace FlaxEditor.SceneGraph
|
||||
/// <summary>
|
||||
/// Gets or sets the node state.
|
||||
/// </summary>
|
||||
[NoSerialize]
|
||||
public virtual StateData State
|
||||
{
|
||||
get => throw new NotImplementedException();
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "Engine/Core/Types/StringBuilder.h"
|
||||
#include "Engine/Debug/Exceptions/FileNotFoundException.h"
|
||||
#include "Engine/Engine/Engine.h"
|
||||
#include "Engine/Engine/Globals.h"
|
||||
#include "Engine/Platform/FileSystem.h"
|
||||
#include "Engine/Platform/FileSystemWatcher.h"
|
||||
#include "Engine/Threading/ThreadPool.h"
|
||||
|
||||
@@ -137,7 +137,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
{
|
||||
int* dataValues = (int*)dataPtr;
|
||||
for (int i = 0; i < entries.Count; i++)
|
||||
dataValues[i] = entries[i].Value;
|
||||
dataValues[i] = (int)entries[i].Value;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -177,7 +177,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
{
|
||||
int* dataValues = (int*)dataPtr;
|
||||
for (int i = 0; i < entries.Count; i++)
|
||||
dataValues[i] = entries[i].Value;
|
||||
dataValues[i] = (int)entries[i].Value;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -576,7 +576,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
for (int i = 0; i < _parameters.Length; i++)
|
||||
{
|
||||
writer.Write(_parameters[i].Name); // Parameter name
|
||||
Utilities.Utils.WriteVariantType(writer, TypeUtils.GetType(_parameters[i].Type)); // Box type
|
||||
Utilities.VariantUtils.WriteVariantType(writer, TypeUtils.GetType(_parameters[i].Type)); // Box type
|
||||
}
|
||||
SetValue(2, stream.ToArray());
|
||||
}
|
||||
@@ -594,7 +594,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
for (int i = 0; i < parametersCount; i++)
|
||||
{
|
||||
var parameterName = reader.ReadString(); // Parameter name
|
||||
var boxType = Utilities.Utils.ReadVariantType(reader); // Box type
|
||||
var boxType = Utilities.VariantUtils.ReadVariantType(reader); // Box type
|
||||
MakeBox(i + 1, parameterName, boxType);
|
||||
}
|
||||
}
|
||||
@@ -778,14 +778,14 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
{
|
||||
reader.ReadByte(); // Version
|
||||
signature.IsStatic = reader.ReadBoolean(); // Is Static
|
||||
signature.ReturnType = Utilities.Utils.ReadVariantScriptType(reader); // Return type
|
||||
signature.ReturnType = Utilities.VariantUtils.ReadVariantScriptType(reader); // Return type
|
||||
var parametersCount = reader.ReadInt32(); // Parameters count
|
||||
signature.Params = parametersCount != 0 ? new SignatureParamInfo[parametersCount] : Utils.GetEmptyArray<SignatureParamInfo>();
|
||||
for (int i = 0; i < parametersCount; i++)
|
||||
{
|
||||
ref var param = ref signature.Params[i];
|
||||
param.Name = Utilities.Utils.ReadStr(reader, 11); // Parameter name
|
||||
param.Type = Utilities.Utils.ReadVariantScriptType(reader); // Parameter type
|
||||
param.Type = Utilities.VariantUtils.ReadVariantScriptType(reader); // Parameter type
|
||||
param.IsOut = reader.ReadByte() != 0; // Is parameter out
|
||||
}
|
||||
}
|
||||
@@ -799,14 +799,14 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
{
|
||||
reader.ReadByte(); // Version
|
||||
signature.IsStatic = reader.ReadBoolean(); // Is Static
|
||||
signature.ReturnType = Utilities.Utils.ReadVariantScriptType(reader); // Return type
|
||||
signature.ReturnType = Utilities.VariantUtils.ReadVariantScriptType(reader); // Return type
|
||||
var parametersCount = reader.ReadInt32(); // Parameters count
|
||||
signature.Params = parametersCount != 0 ? new SignatureParamInfo[parametersCount] : Utils.GetEmptyArray<SignatureParamInfo>();
|
||||
for (int i = 0; i < parametersCount; i++)
|
||||
{
|
||||
ref var param = ref signature.Params[i];
|
||||
param.Name = reader.ReadString(); // Parameter name
|
||||
param.Type = Utilities.Utils.ReadVariantScriptType(reader); // Parameter type
|
||||
param.Type = Utilities.VariantUtils.ReadVariantScriptType(reader); // Parameter type
|
||||
param.IsOut = reader.ReadByte() != 0; // Is parameter out
|
||||
}
|
||||
}
|
||||
@@ -823,13 +823,13 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
{
|
||||
writer.Write((byte)4); // Version
|
||||
writer.Write(methodInfo.IsStatic); // Is Static
|
||||
Utilities.Utils.WriteVariantType(writer, methodInfo.ValueType); // Return type
|
||||
Utilities.VariantUtils.WriteVariantType(writer, methodInfo.ValueType); // Return type
|
||||
writer.Write(parameters.Length); // Parameters count
|
||||
for (int i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
ref var param = ref parameters[i];
|
||||
Utilities.Utils.WriteStr(writer, param.Name, 11); // Parameter name
|
||||
Utilities.Utils.WriteVariantType(writer, param.Type); // Parameter type
|
||||
Utilities.VariantUtils.WriteVariantType(writer, param.Type); // Parameter type
|
||||
writer.Write((byte)(param.IsOut ? 1 : 0)); // Is parameter out
|
||||
}
|
||||
return stream.ToArray();
|
||||
@@ -1434,14 +1434,14 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
if (_signature.IsVirtual)
|
||||
flags |= Flags.Virtual;
|
||||
writer.Write((byte)flags); // Flags
|
||||
Utilities.Utils.WriteVariantType(writer, _signature.ReturnType); // Return Type
|
||||
Utilities.VariantUtils.WriteVariantType(writer, _signature.ReturnType); // Return Type
|
||||
var parametersCount = _signature.Parameters?.Length ?? 0;
|
||||
writer.Write(parametersCount); // Parameters count
|
||||
for (int i = 0; i < parametersCount; i++)
|
||||
{
|
||||
ref var param = ref _signature.Parameters[i];
|
||||
Utilities.Utils.WriteStrAnsi(writer, param.Name, 13); // Parameter name
|
||||
Utilities.Utils.WriteVariantType(writer, param.Type); // Parameter type
|
||||
Utilities.VariantUtils.WriteVariantType(writer, param.Type); // Parameter type
|
||||
writer.Write((byte)0); // Is parameter out
|
||||
writer.Write((byte)0); // Has default value
|
||||
}
|
||||
@@ -1470,13 +1470,13 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
var flags = (Flags)reader.ReadByte(); // Flags
|
||||
_signature.IsStatic = (flags & Flags.Static) == Flags.Static;
|
||||
_signature.IsVirtual = (flags & Flags.Virtual) == Flags.Virtual;
|
||||
_signature.ReturnType = Utilities.Utils.ReadVariantScriptType(reader); // Return Type
|
||||
_signature.ReturnType = Utilities.VariantUtils.ReadVariantScriptType(reader); // Return Type
|
||||
var parametersCount = reader.ReadInt32(); // Parameters count
|
||||
_signature.Parameters = new Parameter[parametersCount];
|
||||
for (int i = 0; i < parametersCount; i++)
|
||||
{
|
||||
var paramName = Utilities.Utils.ReadStrAnsi(reader, 13); // Parameter name
|
||||
var paramType = Utilities.Utils.ReadVariantScriptType(reader); // Parameter type
|
||||
var paramType = Utilities.VariantUtils.ReadVariantScriptType(reader); // Parameter type
|
||||
var isOut = reader.ReadByte() != 0; // Is parameter out
|
||||
var hasDefaultValue = reader.ReadByte() != 0; // Has default value
|
||||
_signature.Parameters[i] = new Parameter
|
||||
|
||||
@@ -171,7 +171,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
for (int i = 0; i < fieldsLength; i++)
|
||||
{
|
||||
Utilities.Utils.WriteStr(writer, fields[i].Name, 11); // Field type
|
||||
Utilities.Utils.WriteVariantType(writer, fields[i].ValueType); // Field type
|
||||
Utilities.VariantUtils.WriteVariantType(writer, fields[i].ValueType); // Field type
|
||||
}
|
||||
Values[1] = stream.ToArray();
|
||||
}
|
||||
@@ -188,7 +188,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
for (int i = 0; i < fieldsLength; i++)
|
||||
{
|
||||
var fieldName = Utilities.Utils.ReadStr(reader, 11); // Field name
|
||||
var fieldType = Utilities.Utils.ReadVariantType(reader); // Field type
|
||||
var fieldType = Utilities.VariantUtils.ReadVariantType(reader); // Field type
|
||||
MakeBox(i + 1, fieldName, new ScriptType(fieldType));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -672,6 +672,24 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
}
|
||||
}
|
||||
|
||||
private class ThisNode : SurfaceNode
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public ThisNode(uint id, VisjectSurfaceContext context, NodeArchetype nodeArch, GroupArchetype groupArch)
|
||||
: base(id, context, nodeArch, groupArch)
|
||||
{}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnLoaded()
|
||||
{
|
||||
base.OnLoaded();
|
||||
var vss = (VisualScriptSurface)this.Context.Surface;
|
||||
var type = TypeUtils.GetType(vss.Script.ScriptTypeName);
|
||||
var box = (OutputBox)GetBox(0);
|
||||
box.CurrentType = type ? type : new ScriptType(typeof(VisualScript));
|
||||
}
|
||||
}
|
||||
|
||||
private class AssetReferenceNode : SurfaceNode
|
||||
{
|
||||
/// <inheritdoc />
|
||||
@@ -1326,9 +1344,9 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
Title = "Platform Switch",
|
||||
Description = "Gets the input value based on the runtime-platform type",
|
||||
Flags = NodeFlags.AllGraphs,
|
||||
Size = new Vector2(220, 160),
|
||||
Size = new Vector2(220, 180),
|
||||
ConnectionsHints = ConnectionsHint.Value,
|
||||
IndependentBoxes = new[] { 1, 2, 3, 4, 5, 6, 7, 8 },
|
||||
IndependentBoxes = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 },
|
||||
DependentBoxes = new[] { 0 },
|
||||
Elements = new[]
|
||||
{
|
||||
@@ -1341,6 +1359,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
NodeElementArchetype.Factory.Input(5, "PlayStation 4", true, null, 6),
|
||||
NodeElementArchetype.Factory.Input(6, "Xbox Scarlett", true, null, 7),
|
||||
NodeElementArchetype.Factory.Input(7, "Android", true, null, 8),
|
||||
NodeElementArchetype.Factory.Input(8, "Switch", true, null, 9),
|
||||
}
|
||||
},
|
||||
new NodeArchetype
|
||||
@@ -1365,6 +1384,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
{
|
||||
TypeID = 19,
|
||||
Title = "This Instance",
|
||||
Create = (id, context, arch, groupArch) => new ThisNode(id, context, arch, groupArch),
|
||||
Description = "Gets the reference to this script object instance (self).",
|
||||
Flags = NodeFlags.VisualScriptGraph,
|
||||
Size = new Vector2(140, 20),
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace FlaxEditor.Surface.Elements
|
||||
/// <inheritdoc />
|
||||
protected override void OnValueChanged()
|
||||
{
|
||||
if ((int)ParentNode.Values[Archetype.ValueIndex] != Value)
|
||||
if ((int)ParentNode.Values[Archetype.ValueIndex] != (int)Value)
|
||||
{
|
||||
// Edit value
|
||||
ParentNode.SetValue(Archetype.ValueIndex, Value);
|
||||
|
||||
@@ -140,22 +140,27 @@ namespace FlaxEditor.Actions
|
||||
|
||||
for (int i = 0; i < nodeParents.Count; i++)
|
||||
{
|
||||
// Fix name collisions (only for parents)
|
||||
var node = nodeParents[i];
|
||||
var parent = node.Actor?.Parent;
|
||||
if (parent != null)
|
||||
{
|
||||
// Fix name collisions
|
||||
string name = node.Name;
|
||||
Actor[] children = parent.Children;
|
||||
if (children.Any(x => x.Name == name))
|
||||
{
|
||||
// Generate new name
|
||||
node.Actor.Name = StringUtils.IncrementNameNumber(name, x => children.All(y => y.Name != x));
|
||||
}
|
||||
}
|
||||
|
||||
Editor.Instance.Scene.MarkSceneEdited(node.ParentScene);
|
||||
}
|
||||
|
||||
for (int i = 0; i < nodeParents.Count; i++)
|
||||
{
|
||||
var node = nodeParents[i];
|
||||
node.PostPaste();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -4,7 +4,6 @@ using System;
|
||||
using FlaxEditor.SceneGraph;
|
||||
using FlaxEngine;
|
||||
using Newtonsoft.Json;
|
||||
using JsonSerializer = FlaxEngine.Json.JsonSerializer;
|
||||
|
||||
namespace FlaxEditor
|
||||
{
|
||||
@@ -28,7 +27,6 @@ namespace FlaxEditor
|
||||
var id = Guid.Parse((string)reader.Value);
|
||||
return SceneGraphFactory.FindNode(id);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -56,19 +54,11 @@ namespace FlaxEditor
|
||||
/// <summary>
|
||||
/// Gets or sets the serialized undo data.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The data.
|
||||
/// </value>
|
||||
[NoSerialize]
|
||||
public TData Data
|
||||
public virtual TData Data
|
||||
{
|
||||
get => JsonConvert.DeserializeObject<TData>(_data, JsonSerializer.Settings);
|
||||
protected set => _data = JsonConvert.SerializeObject(value, Formatting.None, JsonSerializer.Settings);
|
||||
/*protected set
|
||||
{
|
||||
_data = JsonConvert.SerializeObject(value, Formatting.Indented, JsonSerializer.Settings);
|
||||
Debug.Info(_data);
|
||||
}*/
|
||||
get => JsonConvert.DeserializeObject<TData>(_data, FlaxEngine.Json.JsonSerializer.Settings);
|
||||
protected set => _data = JsonConvert.SerializeObject(value, Formatting.None, FlaxEngine.Json.JsonSerializer.Settings);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "EditorUtilities.h"
|
||||
#include "Engine/Engine/Globals.h"
|
||||
#include "Engine/Platform/File.h"
|
||||
#include "Engine/Platform/FileSystem.h"
|
||||
#include "Engine/Core/Log.h"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
1072
Source/Editor/Utilities/VariantUtils.cs
Normal file
1072
Source/Editor/Utilities/VariantUtils.cs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -974,7 +974,8 @@ namespace FlaxEditor.Viewport
|
||||
// Get input buttons and keys (skip if viewport has no focus or mouse is over a child control)
|
||||
bool useMouse = Mathf.IsInRange(_viewMousePos.X, 0, Width) && Mathf.IsInRange(_viewMousePos.Y, 0, Height);
|
||||
_prevInput = _input;
|
||||
if (ContainsFocus && GetChildAt(_viewMousePos, c => c.Visible) == null)
|
||||
var hit = GetChildAt(_viewMousePos, c => c.Visible && !(c is CanvasRootControl));
|
||||
if (ContainsFocus && hit == null)
|
||||
_input.Gather(win.Window, useMouse);
|
||||
else
|
||||
_input.Clear();
|
||||
|
||||
@@ -26,6 +26,7 @@ namespace FlaxEditor.Viewport
|
||||
/// <seealso cref="IGizmoOwner" />
|
||||
public class PrefabWindowViewport : PrefabPreview, IEditorPrimitivesOwner
|
||||
{
|
||||
[HideInEditor]
|
||||
private sealed class PrefabSpritesRenderer : MainEditorGizmoViewport.EditorSpritesRenderer
|
||||
{
|
||||
public PrefabWindowViewport Viewport;
|
||||
|
||||
122
Source/Editor/Viewport/Previews/ModelBasePreview.cs
Normal file
122
Source/Editor/Viewport/Previews/ModelBasePreview.cs
Normal file
@@ -0,0 +1,122 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
|
||||
using FlaxEditor.GUI.Input;
|
||||
using FlaxEngine;
|
||||
using Object = FlaxEngine.Object;
|
||||
|
||||
namespace FlaxEditor.Viewport.Previews
|
||||
{
|
||||
/// <summary>
|
||||
/// Model Base asset preview editor viewport.
|
||||
/// </summary>
|
||||
/// <seealso cref="AssetPreview" />
|
||||
public class ModelBasePreview : AssetPreview
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the model asset to preview.
|
||||
/// </summary>
|
||||
public ModelBase Asset
|
||||
{
|
||||
get => (ModelBase)StaticModel.Model ?? AnimatedModel.SkinnedModel;
|
||||
set
|
||||
{
|
||||
StaticModel.Model = value as Model;
|
||||
AnimatedModel.SkinnedModel = value as SkinnedModel;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The static model for display.
|
||||
/// </summary>
|
||||
public StaticModel StaticModel;
|
||||
|
||||
/// <summary>
|
||||
/// The animated model for display.
|
||||
/// </summary>
|
||||
public AnimatedModel AnimatedModel;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether scale the model to the normalized bounds.
|
||||
/// </summary>
|
||||
public bool ScaleToFit { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ModelBasePreview"/> class.
|
||||
/// </summary>
|
||||
/// <param name="useWidgets">if set to <c>true</c> use widgets.</param>
|
||||
public ModelBasePreview(bool useWidgets)
|
||||
: base(useWidgets)
|
||||
{
|
||||
Task.Begin += OnBegin;
|
||||
|
||||
// Setup preview scene
|
||||
StaticModel = new StaticModel();
|
||||
AnimatedModel = new AnimatedModel();
|
||||
|
||||
// Link actors for rendering
|
||||
Task.AddCustomActor(StaticModel);
|
||||
Task.AddCustomActor(AnimatedModel);
|
||||
|
||||
if (useWidgets)
|
||||
{
|
||||
// Preview LOD
|
||||
{
|
||||
var previewLOD = ViewWidgetButtonMenu.AddButton("Preview LOD");
|
||||
var previewLODValue = new IntValueBox(-1, 90, 2, 70.0f, -1, 10, 0.02f)
|
||||
{
|
||||
Parent = previewLOD
|
||||
};
|
||||
previewLODValue.ValueChanged += () =>
|
||||
{
|
||||
StaticModel.ForcedLOD = previewLODValue.Value;
|
||||
AnimatedModel.ForcedLOD = previewLODValue.Value;
|
||||
};
|
||||
ViewWidgetButtonMenu.VisibleChanged += control => previewLODValue.Value = StaticModel.ForcedLOD;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnBegin(RenderTask task, GPUContext context)
|
||||
{
|
||||
var position = Vector3.Zero;
|
||||
var scale = Vector3.One;
|
||||
|
||||
// Update preview model scale to fit the preview
|
||||
var model = Asset;
|
||||
if (ScaleToFit && model && model.IsLoaded)
|
||||
{
|
||||
float targetSize = 50.0f;
|
||||
BoundingBox box = model is Model ? ((Model)model).GetBox() : ((SkinnedModel)model).GetBox();
|
||||
float maxSize = Mathf.Max(0.001f, box.Size.MaxValue);
|
||||
scale = new Vector3(targetSize / maxSize);
|
||||
position = box.Center * (-0.5f * scale.X) + new Vector3(0, -10, 0);
|
||||
}
|
||||
|
||||
StaticModel.Transform = new Transform(position, StaticModel.Orientation, scale);
|
||||
AnimatedModel.Transform = new Transform(position, AnimatedModel.Orientation, scale);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnKeyDown(KeyboardKeys key)
|
||||
{
|
||||
switch (key)
|
||||
{
|
||||
case KeyboardKeys.F:
|
||||
// Pay respect..
|
||||
ViewportCamera.SetArcBallView(StaticModel.Model != null ? StaticModel.Box : AnimatedModel.Box);
|
||||
break;
|
||||
}
|
||||
return base.OnKeyDown(key);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnDestroy()
|
||||
{
|
||||
// Ensure to cleanup created actor objects
|
||||
Object.Destroy(ref StaticModel);
|
||||
Object.Destroy(ref AnimatedModel);
|
||||
|
||||
base.OnDestroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -131,6 +131,7 @@ namespace FlaxEditor.Windows
|
||||
"LZ4 Library - Copyright (c) Yann Collet. All rights reserved.",
|
||||
"fmt - www.fmtlib.net",
|
||||
"minimp3 - www.github.com/lieff/minimp3",
|
||||
"Tracy Profiler - www.github.com/wolfpld/tracy",
|
||||
"Ogg and Vorbis - Xiph.org Foundation",
|
||||
"OpenAL Soft - www.github.com/kcat/openal-soft",
|
||||
"OpenFBX - www.github.com/nem0/OpenFBX",
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Xml;
|
||||
using FlaxEditor.Content;
|
||||
using FlaxEditor.Content.Create;
|
||||
@@ -10,6 +11,7 @@ using FlaxEditor.Viewport.Cameras;
|
||||
using FlaxEditor.Viewport.Previews;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
using Object = FlaxEngine.Object;
|
||||
|
||||
namespace FlaxEditor.Windows.Assets
|
||||
{
|
||||
@@ -20,6 +22,15 @@ namespace FlaxEditor.Windows.Assets
|
||||
/// <seealso cref="FlaxEditor.Windows.Assets.AssetEditorWindow" />
|
||||
public sealed class CollisionDataWindow : AssetEditorWindowBase<CollisionData>
|
||||
{
|
||||
[Flags]
|
||||
private enum MaterialSlotsMask : uint
|
||||
{
|
||||
// @formatter:off
|
||||
Slot0=1u<<0,Slot1=1u<<1,Slot2=1u<<2,Slot3=1u<<3,Slot4=1u<<4,Slot5=1u<<5,Slot6=1u<<6,Slot7=1u<<7,Slot8=1u<<8,Slot9=1u<<9,Slot10=1u<<10,Slot11=1u<<11,Slot12=1u<<12,Slot13=1u<<13,Slot14=1u<<14,Slot15=1u<<15,Slot16=1u<<16,Slot17=1u<<17,Slot18=1u<<18,Slot19=1u<<19,Slot20=1u<<20,Slot21=1u<<21,Slot22=1u<<22,Slot23=1u<<23,Slot24=1u<<24,Slot25=1u<<25,Slot26=1u<<26,Slot27=1u<<27,Slot28=1u<<28,Slot29=1u<<29,Slot30=1u<<30,Slot31=1u<<31,
|
||||
// @formatter:on
|
||||
All = uint.MaxValue,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The asset properties proxy object.
|
||||
/// </summary>
|
||||
@@ -34,11 +45,14 @@ namespace FlaxEditor.Windows.Assets
|
||||
public CollisionDataType Type;
|
||||
|
||||
[EditorOrder(10), EditorDisplay("General"), Tooltip("Source model asset to use for collision data generation")]
|
||||
public Model Model;
|
||||
public ModelBase Model;
|
||||
|
||||
[EditorOrder(20), Limit(0, 5), EditorDisplay("General", "Model LOD Index"), Tooltip("Source model LOD index to use for collision data generation (will be clamped to the actual model LODs collection size)")]
|
||||
public int ModelLodIndex;
|
||||
|
||||
[EditorOrder(30), EditorDisplay("General"), Tooltip("The source model material slots mask. One bit per-slot. Can be sued to exclude particular material slots from collision cooking.")]
|
||||
public MaterialSlotsMask MaterialSlotsMask = MaterialSlotsMask.All;
|
||||
|
||||
[EditorOrder(100), EditorDisplay("Convex Mesh", "Convex Flags"), Tooltip("Convex mesh generation flags")]
|
||||
public ConvexMeshGenerationFlags ConvexFlags;
|
||||
|
||||
@@ -88,28 +102,23 @@ namespace FlaxEditor.Windows.Assets
|
||||
|
||||
private class CookData : CreateFileEntry
|
||||
{
|
||||
private PropertiesProxy Proxy;
|
||||
private CollisionDataType Type;
|
||||
private Model Model;
|
||||
private int ModelLodIndex;
|
||||
private ConvexMeshGenerationFlags ConvexFlags;
|
||||
private int ConvexVertexLimit;
|
||||
public PropertiesProxy Proxy;
|
||||
public CollisionDataType Type;
|
||||
public ModelBase Model;
|
||||
public int ModelLodIndex;
|
||||
public uint MaterialSlotsMask;
|
||||
public ConvexMeshGenerationFlags ConvexFlags;
|
||||
public int ConvexVertexLimit;
|
||||
|
||||
public CookData(PropertiesProxy proxy, string resultUrl, CollisionDataType type, Model model, int modelLodIndex, ConvexMeshGenerationFlags convexFlags, int convexVertexLimit)
|
||||
public CookData(string resultUrl)
|
||||
: base("Collision Data", resultUrl)
|
||||
{
|
||||
Proxy = proxy;
|
||||
Type = type;
|
||||
Model = model;
|
||||
ModelLodIndex = modelLodIndex;
|
||||
ConvexFlags = convexFlags;
|
||||
ConvexVertexLimit = convexVertexLimit;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool Create()
|
||||
{
|
||||
bool failed = FlaxEditor.Editor.CookMeshCollision(ResultUrl, Type, Model, ModelLodIndex, ConvexFlags, ConvexVertexLimit);
|
||||
bool failed = FlaxEditor.Editor.CookMeshCollision(ResultUrl, Type, Model, ModelLodIndex, MaterialSlotsMask, ConvexFlags, ConvexVertexLimit);
|
||||
|
||||
Proxy._isCooking = false;
|
||||
Proxy.Window.UpdateWiresModel();
|
||||
@@ -121,7 +130,16 @@ namespace FlaxEditor.Windows.Assets
|
||||
public void Cook()
|
||||
{
|
||||
_isCooking = true;
|
||||
Window.Editor.ContentImporting.Create(new CookData(this, Asset.Path, Type, Model, ModelLodIndex, ConvexFlags, ConvexVertexLimit));
|
||||
Window.Editor.ContentImporting.Create(new CookData(Asset.Path)
|
||||
{
|
||||
Proxy = this,
|
||||
Type = Type,
|
||||
Model = Model,
|
||||
ModelLodIndex = ModelLodIndex,
|
||||
MaterialSlotsMask = (uint)MaterialSlotsMask,
|
||||
ConvexFlags = ConvexFlags,
|
||||
ConvexVertexLimit = ConvexVertexLimit,
|
||||
});
|
||||
}
|
||||
|
||||
public void OnLoad(CollisionDataWindow window)
|
||||
@@ -135,7 +153,7 @@ namespace FlaxEditor.Windows.Assets
|
||||
Type = options.Type;
|
||||
if (Type == CollisionDataType.None)
|
||||
Type = CollisionDataType.ConvexMesh;
|
||||
Model = FlaxEngine.Content.LoadAsync<Model>(options.Model);
|
||||
Model = FlaxEngine.Content.LoadAsync<ModelBase>(options.Model);
|
||||
ModelLodIndex = options.ModelLodIndex;
|
||||
ConvexFlags = options.ConvexFlags;
|
||||
ConvexVertexLimit = options.ConvexVertexLimit;
|
||||
@@ -151,7 +169,7 @@ namespace FlaxEditor.Windows.Assets
|
||||
}
|
||||
|
||||
private readonly SplitPanel _split;
|
||||
private readonly ModelPreview _preview;
|
||||
private readonly ModelBasePreview _preview;
|
||||
private readonly CustomEditorPresenter _propertiesPresenter;
|
||||
private readonly PropertiesProxy _properties;
|
||||
private Model _collisionWiresModel;
|
||||
@@ -176,7 +194,7 @@ namespace FlaxEditor.Windows.Assets
|
||||
};
|
||||
|
||||
// Model preview
|
||||
_preview = new ModelPreview(true)
|
||||
_preview = new ModelBasePreview(true)
|
||||
{
|
||||
ViewportCamera = new FPSCamera(),
|
||||
Parent = _split.Panel1
|
||||
@@ -195,7 +213,7 @@ namespace FlaxEditor.Windows.Assets
|
||||
// Sync helper actor size with actual preview model (preview scales model for better usage experience)
|
||||
if (_collisionWiresShowActor && _collisionWiresShowActor.IsActive)
|
||||
{
|
||||
_collisionWiresShowActor.Transform = _preview.PreviewActor.Transform;
|
||||
_collisionWiresShowActor.Transform = _preview.StaticModel.Transform;
|
||||
}
|
||||
|
||||
base.Update(deltaTime);
|
||||
@@ -230,14 +248,14 @@ namespace FlaxEditor.Windows.Assets
|
||||
}
|
||||
_collisionWiresShowActor.Model = _collisionWiresModel;
|
||||
_collisionWiresShowActor.SetMaterial(0, FlaxEngine.Content.LoadAsyncInternal<MaterialBase>(EditorAssets.WiresDebugMaterial));
|
||||
_preview.Model = FlaxEngine.Content.LoadAsync<Model>(_asset.Options.Model);
|
||||
_preview.Asset = FlaxEngine.Content.LoadAsync<ModelBase>(_asset.Options.Model);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void UnlinkItem()
|
||||
{
|
||||
_properties.OnClean();
|
||||
_preview.Model = null;
|
||||
_preview.Asset = null;
|
||||
|
||||
base.UnlinkItem();
|
||||
}
|
||||
@@ -245,7 +263,7 @@ namespace FlaxEditor.Windows.Assets
|
||||
/// <inheritdoc />
|
||||
protected override void OnAssetLinked()
|
||||
{
|
||||
_preview.Model = null;
|
||||
_preview.Asset = null;
|
||||
|
||||
base.OnAssetLinked();
|
||||
}
|
||||
|
||||
@@ -17,6 +17,9 @@ namespace FlaxEditor.Windows.Assets
|
||||
{
|
||||
private readonly CustomEditorPresenter _presenter;
|
||||
private readonly ToolStripButton _saveButton;
|
||||
private readonly ToolStripButton _undoButton;
|
||||
private readonly ToolStripButton _redoButton;
|
||||
private readonly Undo _undo;
|
||||
private object _object;
|
||||
private bool _isRegisteredForScriptsReload;
|
||||
|
||||
@@ -24,8 +27,16 @@ namespace FlaxEditor.Windows.Assets
|
||||
public JsonAssetWindow(Editor editor, AssetItem item)
|
||||
: base(editor, item)
|
||||
{
|
||||
// Undo
|
||||
_undo = new Undo();
|
||||
_undo.UndoDone += OnUndoRedo;
|
||||
_undo.RedoDone += OnUndoRedo;
|
||||
|
||||
// Toolstrip
|
||||
_saveButton = (ToolStripButton)_toolstrip.AddButton(editor.Icons.Save64, Save).LinkTooltip("Save");
|
||||
_toolstrip.AddSeparator();
|
||||
_undoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Undo64, _undo.PerformUndo).LinkTooltip("Undo (Ctrl+Z)");
|
||||
_redoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Redo64, _undo.PerformRedo).LinkTooltip("Redo (Ctrl+Y)");
|
||||
|
||||
// Panel
|
||||
var panel = new Panel(ScrollBars.Vertical)
|
||||
@@ -36,9 +47,19 @@ namespace FlaxEditor.Windows.Assets
|
||||
};
|
||||
|
||||
// Properties
|
||||
_presenter = new CustomEditorPresenter(null, "Loading...");
|
||||
_presenter = new CustomEditorPresenter(_undo, "Loading...");
|
||||
_presenter.Panel.Parent = panel;
|
||||
_presenter.Modified += MarkAsEdited;
|
||||
|
||||
// Setup input actions
|
||||
InputActions.Add(options => options.Undo, _undo.PerformUndo);
|
||||
InputActions.Add(options => options.Redo, _undo.PerformRedo);
|
||||
}
|
||||
|
||||
private void OnUndoRedo(IUndoAction action)
|
||||
{
|
||||
MarkAsEdited();
|
||||
UpdateToolstrip();
|
||||
}
|
||||
|
||||
private void OnScriptsReloadBegin()
|
||||
@@ -64,13 +85,14 @@ namespace FlaxEditor.Windows.Assets
|
||||
}
|
||||
|
||||
ClearEditedFlag();
|
||||
_item.RefreshThumbnail();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void UpdateToolstrip()
|
||||
{
|
||||
_saveButton.Enabled = IsEdited;
|
||||
_undoButton.Enabled = _undo.CanUndo;
|
||||
_redoButton.Enabled = _undo.CanRedo;
|
||||
|
||||
base.UpdateToolstrip();
|
||||
}
|
||||
@@ -80,6 +102,7 @@ namespace FlaxEditor.Windows.Assets
|
||||
{
|
||||
_object = Asset.CreateInstance();
|
||||
_presenter.Select(_object);
|
||||
_undo.Clear();
|
||||
ClearEditedFlag();
|
||||
|
||||
// Auto-close on scripting reload if json asset is from game scripts (it might be reloaded)
|
||||
|
||||
212
Source/Editor/Windows/Assets/LocalizedStringTableWindow.cs
Normal file
212
Source/Editor/Windows/Assets/LocalizedStringTableWindow.cs
Normal file
@@ -0,0 +1,212 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using FlaxEditor.Content;
|
||||
using FlaxEditor.CustomEditors;
|
||||
using FlaxEditor.GUI;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
using FlaxEngine.Utilities;
|
||||
|
||||
namespace FlaxEditor.Windows.Assets
|
||||
{
|
||||
/// <summary>
|
||||
/// Editor window to view/modify <see cref="LocalizedStringTable"/> asset.
|
||||
/// </summary>
|
||||
/// <seealso cref="LocalizedStringTable" />
|
||||
/// <seealso cref="FlaxEditor.Windows.Assets.AssetEditorWindow" />
|
||||
public sealed class LocalizedStringTableWindow : AssetEditorWindowBase<LocalizedStringTable>
|
||||
{
|
||||
private readonly CustomEditorPresenter _presenter;
|
||||
private readonly ToolStripButton _saveButton;
|
||||
private readonly ToolStripButton _undoButton;
|
||||
private readonly ToolStripButton _redoButton;
|
||||
private readonly Undo _undo;
|
||||
private Proxy _proxy;
|
||||
|
||||
private class EntryEditor : CustomEditor
|
||||
{
|
||||
private TextBox[] _textBoxes;
|
||||
private bool _isRefreshing;
|
||||
|
||||
public override void Initialize(LayoutElementsContainer layout)
|
||||
{
|
||||
var values = (string[])Values[0];
|
||||
if (values == null || values.Length == 0)
|
||||
{
|
||||
values = new string[1];
|
||||
values[0] = string.Empty;
|
||||
}
|
||||
if (_textBoxes == null || _textBoxes.Length != values.Length)
|
||||
_textBoxes = new TextBox[values.Length];
|
||||
for (int i = 0; i < values.Length; i++)
|
||||
{
|
||||
var value = values[i];
|
||||
var textBox = layout.TextBox(value.IsMultiline());
|
||||
textBox.TextBox.Tag = i;
|
||||
textBox.TextBox.Text = value;
|
||||
textBox.TextBox.TextBoxEditEnd += OnEditEnd;
|
||||
_textBoxes[i] = textBox.TextBox;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Refresh()
|
||||
{
|
||||
base.Refresh();
|
||||
|
||||
var values = (string[])Values[0];
|
||||
if (values != null && values.Length == _textBoxes.Length)
|
||||
{
|
||||
_isRefreshing = true;
|
||||
var style = FlaxEngine.GUI.Style.Current;
|
||||
var wrongColor = new Color(1.0f, 0.0f, 0.02745f, 1.0f);
|
||||
var wrongColorBorder = Color.Lerp(wrongColor, style.TextBoxBackground, 0.6f);
|
||||
for (int i = 0; i < _textBoxes.Length; i++)
|
||||
{
|
||||
var textBox = _textBoxes[i];
|
||||
if (!textBox.IsEditing)
|
||||
{
|
||||
textBox.Text = values[i];
|
||||
if (string.IsNullOrEmpty(textBox.Text))
|
||||
{
|
||||
textBox.BorderColor = wrongColorBorder;
|
||||
textBox.BorderSelectedColor = wrongColor;
|
||||
}
|
||||
else
|
||||
{
|
||||
textBox.BorderColor = Color.Transparent;
|
||||
textBox.BorderSelectedColor = style.BackgroundSelected;
|
||||
}
|
||||
}
|
||||
}
|
||||
_isRefreshing = false;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Deinitialize()
|
||||
{
|
||||
base.Deinitialize();
|
||||
|
||||
_textBoxes = null;
|
||||
_isRefreshing = false;
|
||||
}
|
||||
|
||||
private void OnEditEnd(TextBoxBase textBox)
|
||||
{
|
||||
if (_isRefreshing)
|
||||
return;
|
||||
var values = (string[])Values[0];
|
||||
var length = Mathf.Max(values?.Length ?? 0, 1);
|
||||
var toSet = new string[length];
|
||||
if (values != null && values.Length == length)
|
||||
Array.Copy(values, toSet, length);
|
||||
var index = (int)textBox.Tag;
|
||||
toSet[index] = textBox.Text;
|
||||
SetValue(toSet);
|
||||
}
|
||||
}
|
||||
|
||||
private class Proxy
|
||||
{
|
||||
[EditorOrder(0), EditorDisplay("General"), Tooltip("The locale of the localized string table (eg. pl-PL)."),]
|
||||
[CustomEditor(typeof(FlaxEditor.CustomEditors.Editors.CultureInfoEditor))]
|
||||
public string Locale;
|
||||
|
||||
[EditorOrder(10), EditorDisplay("Entries", EditorDisplayAttribute.InlineStyle), Tooltip("The string table. Maps the message id into the localized text. For plural messages the list contains separate items for value numbers.")]
|
||||
[Collection(Spacing = 10, OverrideEditorTypeName = "FlaxEditor.Windows.Assets.LocalizedStringTableWindow+EntryEditor")]
|
||||
public Dictionary<string, string[]> Entries;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public LocalizedStringTableWindow(Editor editor, AssetItem item)
|
||||
: base(editor, item)
|
||||
{
|
||||
// Undo
|
||||
_undo = new Undo();
|
||||
_undo.UndoDone += OnUndoRedo;
|
||||
_undo.RedoDone += OnUndoRedo;
|
||||
|
||||
// Toolstrip
|
||||
_saveButton = (ToolStripButton)_toolstrip.AddButton(editor.Icons.Save32, Save).LinkTooltip("Save");
|
||||
_toolstrip.AddSeparator();
|
||||
_undoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Undo32, _undo.PerformUndo).LinkTooltip("Undo (Ctrl+Z)");
|
||||
_redoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Redo32, _undo.PerformRedo).LinkTooltip("Redo (Ctrl+Y)");
|
||||
|
||||
// Panel
|
||||
var panel = new Panel(ScrollBars.Vertical)
|
||||
{
|
||||
AnchorPreset = AnchorPresets.StretchAll,
|
||||
Offsets = new Margin(0, 0, _toolstrip.Bottom, 0),
|
||||
Parent = this
|
||||
};
|
||||
|
||||
// Properties
|
||||
_presenter = new CustomEditorPresenter(_undo, "Loading...");
|
||||
_presenter.Panel.Parent = panel;
|
||||
_presenter.Modified += MarkAsEdited;
|
||||
|
||||
// Setup input actions
|
||||
InputActions.Add(options => options.Undo, _undo.PerformUndo);
|
||||
InputActions.Add(options => options.Redo, _undo.PerformRedo);
|
||||
}
|
||||
|
||||
private void OnUndoRedo(IUndoAction action)
|
||||
{
|
||||
MarkAsEdited();
|
||||
UpdateToolstrip();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Save()
|
||||
{
|
||||
if (!IsEdited)
|
||||
return;
|
||||
|
||||
_asset.Locale = _proxy.Locale;
|
||||
_asset.Entries = _proxy.Entries;
|
||||
if (_asset.Save(_item.Path))
|
||||
{
|
||||
Editor.LogError("Cannot save asset.");
|
||||
return;
|
||||
}
|
||||
|
||||
ClearEditedFlag();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void UpdateToolstrip()
|
||||
{
|
||||
_saveButton.Enabled = IsEdited;
|
||||
_undoButton.Enabled = _undo.CanUndo;
|
||||
_redoButton.Enabled = _undo.CanRedo;
|
||||
|
||||
base.UpdateToolstrip();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnAssetLoaded()
|
||||
{
|
||||
_proxy = new Proxy
|
||||
{
|
||||
Locale = _asset.Locale,
|
||||
Entries = _asset.Entries,
|
||||
};
|
||||
_presenter.Select(_proxy);
|
||||
_undo.Clear();
|
||||
ClearEditedFlag();
|
||||
|
||||
base.OnAssetLoaded();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnItemReimported(ContentItem item)
|
||||
{
|
||||
// Refresh the properties (will get new data in OnAssetLoaded)
|
||||
_presenter.Deselect();
|
||||
ClearEditedFlag();
|
||||
|
||||
base.OnItemReimported(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -565,7 +565,6 @@ namespace FlaxEditor.Windows.Assets
|
||||
public UVsLayoutPreviewControl()
|
||||
{
|
||||
Offsets = new Margin(4);
|
||||
AnchorPreset = AnchorPresets.HorizontalStretchMiddle;
|
||||
AutomaticInvalidate = false;
|
||||
}
|
||||
|
||||
@@ -619,9 +618,9 @@ namespace FlaxEditor.Windows.Assets
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void DrawChildren()
|
||||
public override void DrawSelf()
|
||||
{
|
||||
base.DrawChildren();
|
||||
base.DrawSelf();
|
||||
|
||||
var size = Size;
|
||||
if (_channel == UVChannel.None || size.MaxValue < 5.0f)
|
||||
|
||||
@@ -36,6 +36,9 @@ namespace FlaxEditor.Windows.Assets
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Undo Undo => _window.Undo;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override List<SceneGraphNode> Selection => _window.Selection;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -114,9 +114,9 @@ namespace FlaxEditor.Windows.Assets
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Draw()
|
||||
public override void DrawSelf()
|
||||
{
|
||||
base.Draw();
|
||||
base.DrawSelf();
|
||||
|
||||
var style = Style.Current;
|
||||
var asset = _window.Asset;
|
||||
@@ -676,7 +676,6 @@ namespace FlaxEditor.Windows.Assets
|
||||
public UVsLayoutPreviewControl()
|
||||
{
|
||||
Offsets = new Margin(4);
|
||||
AnchorPreset = AnchorPresets.HorizontalStretchMiddle;
|
||||
AutomaticInvalidate = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -43,6 +43,7 @@ namespace FlaxEditor.Windows
|
||||
{ PlatformType.PS4, new PS4() },
|
||||
{ PlatformType.XboxScarlett, new XboxScarlett() },
|
||||
{ PlatformType.Android, new Android() },
|
||||
{ PlatformType.Switch, new Switch() },
|
||||
};
|
||||
|
||||
public BuildTabProxy(GameCookerWindow win, PlatformSelector platformSelector)
|
||||
@@ -57,6 +58,7 @@ namespace FlaxEditor.Windows
|
||||
PerPlatformOptions[PlatformType.PS4].Init("Output/PS4", "PS4");
|
||||
PerPlatformOptions[PlatformType.XboxScarlett].Init("Output/XboxScarlett", "XboxScarlett");
|
||||
PerPlatformOptions[PlatformType.Android].Init("Output/Android", "Android");
|
||||
PerPlatformOptions[PlatformType.Switch].Init("Output/Switch", "Switch");
|
||||
}
|
||||
|
||||
public abstract class Platform
|
||||
@@ -188,6 +190,11 @@ namespace FlaxEditor.Windows
|
||||
protected override BuildPlatform BuildPlatform => BuildPlatform.AndroidARM64;
|
||||
}
|
||||
|
||||
public class Switch : Platform
|
||||
{
|
||||
protected override BuildPlatform BuildPlatform => BuildPlatform.Switch;
|
||||
}
|
||||
|
||||
public class Editor : CustomEditor
|
||||
{
|
||||
private PlatformType _platform;
|
||||
@@ -229,6 +236,9 @@ namespace FlaxEditor.Windows
|
||||
case PlatformType.Android:
|
||||
name = "Android";
|
||||
break;
|
||||
case PlatformType.Switch:
|
||||
name = "Switch";
|
||||
break;
|
||||
default:
|
||||
name = CustomEditorsUtil.GetPropertyNameUI(_platform.ToString());
|
||||
break;
|
||||
|
||||
@@ -5,6 +5,29 @@ using FlaxEditor.GUI;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
|
||||
namespace FlaxEngine
|
||||
{
|
||||
partial class ProfilerCPU
|
||||
{
|
||||
partial struct Event
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the event name.
|
||||
/// </summary>
|
||||
public unsafe string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
fixed (char* name = &Name0)
|
||||
{
|
||||
return new string(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace FlaxEditor.Windows.Profiler
|
||||
{
|
||||
/// <summary>
|
||||
@@ -204,7 +227,7 @@ namespace FlaxEditor.Windows.Profiler
|
||||
{
|
||||
var e = events[i];
|
||||
|
||||
if (e.Depth == 0 && new string(e.Name) == "Update")
|
||||
if (e.Depth == 0 && e.Name == "Update")
|
||||
{
|
||||
return new ViewRange(ref e);
|
||||
}
|
||||
@@ -225,7 +248,7 @@ namespace FlaxEditor.Windows.Profiler
|
||||
double scale = 100.0;
|
||||
float x = (float)((e.Start - startTime) * scale);
|
||||
float width = (float)(length * scale);
|
||||
string name = new string(e.Name).Replace("::", ".");
|
||||
string name = e.Name.Replace("::", ".");
|
||||
|
||||
var control = new Timeline.Event(x + xOffset, e.Depth + depthOffset, width)
|
||||
{
|
||||
@@ -399,7 +422,7 @@ namespace FlaxEditor.Windows.Profiler
|
||||
subEventsMemoryTotal += sub.ManagedMemoryAllocation + e.NativeMemoryAllocation;
|
||||
}
|
||||
|
||||
string name = new string(e.Name).Replace("::", ".");
|
||||
string name = e.Name.Replace("::", ".");
|
||||
|
||||
var row = new Row
|
||||
{
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
|
||||
#include "SplashScreen.h"
|
||||
#include "Engine/Core/Log.h"
|
||||
#include "Engine/Core/Types/TimeSpan.h"
|
||||
#include "Engine/Engine/CommandLine.h"
|
||||
#include "Engine/Engine/Globals.h"
|
||||
#include "Engine/Render2D/FontAsset.h"
|
||||
#include "Engine/Render2D/Font.h"
|
||||
#include "Engine/Render2D/TextLayoutOptions.h"
|
||||
@@ -120,6 +122,17 @@ const Char* SplashScreenQuotes[] =
|
||||
TEXT("All we had to do was follow the damn train, CJ"),
|
||||
TEXT("28 stab wounds"),
|
||||
TEXT("Here we go again"),
|
||||
TEXT("@everyone"),
|
||||
TEXT("uwu some spiders on the ceiling"),
|
||||
TEXT("There you are you little shit"),
|
||||
TEXT("potato"),
|
||||
TEXT("python is a programming snek"),
|
||||
TEXT("Flax will start when pigs will fly"),
|
||||
TEXT("I'm the android sent by CyberLife"),
|
||||
TEXT("fancy-ass ray tracing rtx on lighting"),
|
||||
TEXT("ZOINKS"),
|
||||
TEXT("Scooby dooby doo"),
|
||||
TEXT("You shall not load"),
|
||||
};
|
||||
|
||||
SplashScreen::~SplashScreen()
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Curve.h"
|
||||
#include "Engine/Core/Types/String.h"
|
||||
#include "Engine/Animations/Curve.h"
|
||||
#include "Engine/Core/Math/Transform.h"
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "Engine/Scripting/ManagedCLR/MUtils.h"
|
||||
#include "Engine/Scripting/Scripting.h"
|
||||
#include "Engine/Scripting/MException.h"
|
||||
#include "Engine/Content/Assets/SkinnedModel.h"
|
||||
#include <ThirdParty/mono-2.0/mono/metadata/appdomain.h>
|
||||
|
||||
struct InternalInitData
|
||||
@@ -144,6 +145,17 @@ void AnimGraphExecutor::ProcessGroupCustom(Box* boxBase, Node* nodeBase, Value&
|
||||
box->Cache = value;
|
||||
}
|
||||
|
||||
bool AnimGraph::IsReady() const
|
||||
{
|
||||
return BaseModel && BaseModel->IsLoaded();
|
||||
}
|
||||
|
||||
bool AnimGraph::CanUseWithSkeleton(SkinnedModel* other) const
|
||||
{
|
||||
// All data loaded and bones count the same
|
||||
return IsReady() && other && other->IsLoaded() && other->Skeleton.Bones.Count() == BaseModel->Skeleton.Bones.Count();
|
||||
}
|
||||
|
||||
void AnimGraph::ClearCustomNode(Node* node)
|
||||
{
|
||||
// Clear data
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "AnimGraph.h"
|
||||
#include "Engine/Engine/Time.h"
|
||||
#include "Engine/Content/Assets/SkinnedModel.h"
|
||||
#include "Engine/Graphics/Models/SkeletonData.h"
|
||||
#include "Engine/Scripting/Scripting.h"
|
||||
#include "Engine/Engine/Time.h"
|
||||
|
||||
RootMotionData RootMotionData::Identity = { Vector3(0.0f), Quaternion(0.0f, 0.0f, 0.0f, 1.0f) };
|
||||
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "Engine/Visject/VisjectGraph.h"
|
||||
#include "Engine/Content/Assets/SkinnedModel.h"
|
||||
#include "Engine/Content/Assets/Animation.h"
|
||||
#include "Engine/Animations/AlphaBlend.h"
|
||||
#include "Engine/Core/Math/Matrix.h"
|
||||
#include "../Config.h"
|
||||
|
||||
#define ANIM_GRAPH_PARAM_BASE_MODEL_ID Guid(1000, 0, 0, 0)
|
||||
@@ -21,6 +21,8 @@ class AnimSubGraph;
|
||||
class AnimGraphBase;
|
||||
class AnimGraphNode;
|
||||
class AnimGraphExecutor;
|
||||
class SkinnedModel;
|
||||
class SkeletonData;
|
||||
|
||||
/// <summary>
|
||||
/// The root motion data container. Supports displacement and rotation (no scale component).
|
||||
@@ -777,22 +779,14 @@ public:
|
||||
/// <summary>
|
||||
/// Determines whether this graph is ready for the animation evaluation.
|
||||
/// </summary>
|
||||
/// <returns>True if is ready and can be used for the animation evaluation, otherwise false.</returns>
|
||||
bool IsReady() const
|
||||
{
|
||||
return BaseModel && BaseModel->IsLoaded();
|
||||
}
|
||||
bool IsReady() const;
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether this graph can be used with the specified skeleton.
|
||||
/// </summary>
|
||||
/// <param name="other">The other skinned model to check.</param>
|
||||
/// <returns>True if can perform the update, otherwise false.</returns>
|
||||
bool CanUseWithSkeleton(SkinnedModel* other) const
|
||||
{
|
||||
// All data loaded and bones count the same
|
||||
return IsReady() && other && other->IsLoaded() && other->Skeleton.Bones.Count() == BaseModel->Skeleton.Bones.Count();
|
||||
}
|
||||
bool CanUseWithSkeleton(SkinnedModel* other) const;
|
||||
|
||||
private:
|
||||
|
||||
|
||||
@@ -636,7 +636,7 @@ void AnimGraphExecutor::ProcessGroupAnimation(Box* boxBase, Node* nodeBase, Valu
|
||||
transform.Scale = (Vector3)tryGetValue(node->GetBox(4), Vector3::One);
|
||||
|
||||
// Skip if no change will be performed
|
||||
if (boneIndex < 0 || boneIndex >= _skeletonBonesCount || transformMode == BoneTransformMode::None || transform.IsIdentity())
|
||||
if (boneIndex < 0 || boneIndex >= _skeletonBonesCount || transformMode == BoneTransformMode::None || (transformMode == BoneTransformMode::Add && transform.IsIdentity()))
|
||||
{
|
||||
// Pass through the input
|
||||
value = Value::Null;
|
||||
@@ -1628,7 +1628,7 @@ void AnimGraphExecutor::ProcessGroupAnimation(Box* boxBase, Node* nodeBase, Valu
|
||||
transform.Scale = (Vector3)tryGetValue(node->GetBox(4), Vector3::One);
|
||||
|
||||
// Skip if no change will be performed
|
||||
if (nodeIndex < 0 || nodeIndex >= _skeletonNodesCount || transformMode == BoneTransformMode::None || transform.IsIdentity())
|
||||
if (nodeIndex < 0 || nodeIndex >= _skeletonNodesCount || transformMode == BoneTransformMode::None || (transformMode == BoneTransformMode::Add && transform.IsIdentity()))
|
||||
{
|
||||
// Pass through the input
|
||||
value = Value::Null;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include "Engine/Audio/AudioClip.h"
|
||||
#include "Engine/Graphics/PostProcessSettings.h"
|
||||
|
||||
REGISTER_BINARY_ASSET(SceneAnimation, "FlaxEngine.SceneAnimation", nullptr, false);
|
||||
REGISTER_BINARY_ASSET(SceneAnimation, "FlaxEngine.SceneAnimation", false);
|
||||
|
||||
SceneAnimation::SceneAnimation(const SpawnParams& params, const AssetInfo* info)
|
||||
: BinaryAsset(params, info)
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "Engine/Serialization/Serialization.h"
|
||||
#include "Engine/Audio/AudioClip.h"
|
||||
#include "Engine/Audio/AudioSource.h"
|
||||
#include "Engine/Graphics/RenderTask.h"
|
||||
#include "Engine/Renderer/RenderList.h"
|
||||
#include "Engine/Scripting/Scripting.h"
|
||||
#include "Engine/Scripting/Script.h"
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "Engine/Level/Actor.h"
|
||||
#include "Engine/Core/Collections/Dictionary.h"
|
||||
#include "Engine/Content/AssetReference.h"
|
||||
#include "Engine/Level/Actors/PostFxVolume.h"
|
||||
#include "SceneAnimation.h"
|
||||
|
||||
@@ -46,6 +46,10 @@ public class Audio : EngineModule
|
||||
case TargetPlatform.Android:
|
||||
useOpenAL = true;
|
||||
break;
|
||||
case TargetPlatform.Switch:
|
||||
options.SourcePaths.Add(Path.Combine(Globals.EngineRoot, "Source", "Platforms", "Switch", "Engine", "Audio"));
|
||||
options.CompileEnv.PreprocessorDefinitions.Add("AUDIO_API_SWITCH");
|
||||
break;
|
||||
default: throw new InvalidPlatformException(options.Platform.Target);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "Audio.h"
|
||||
#include "AudioSource.h"
|
||||
#include "AudioBackend.h"
|
||||
#include "Engine/Core/Log.h"
|
||||
#include "Engine/Content/Upgraders/AudioClipUpgrader.h"
|
||||
#include "Engine/Content/Factories/BinaryAssetFactory.h"
|
||||
#include "Engine/Scripting/ManagedCLR/MUtils.h"
|
||||
@@ -12,7 +13,7 @@
|
||||
#include "Engine/Tools/AudioTool/OggVorbisDecoder.h"
|
||||
#include "Engine/Tools/AudioTool/AudioTool.h"
|
||||
|
||||
REGISTER_BINARY_ASSET(AudioClip, "FlaxEngine.AudioClip", ::New<AudioClipUpgrader>(), false);
|
||||
REGISTER_BINARY_ASSET_WITH_UPGRADER(AudioClip, "FlaxEngine.AudioClip", AudioClipUpgrader, false);
|
||||
|
||||
bool AudioClip::StreamingTask::Run()
|
||||
{
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#include <OpenAL/al.h>
|
||||
#include <OpenAL/alc.h>
|
||||
|
||||
#define FLAX_POS_TO_OAL(vec) -vec.X * 0.01f, vec.Y * 0.01f, vec.Z * 0.01f
|
||||
#define FLAX_POS_TO_OAL(vec) -vec.X * 0.01f, vec.Y * 0.01f, -vec.Z * 0.01f
|
||||
|
||||
namespace ALC
|
||||
{
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
#define MAX_OUTPUT_CHANNELS 8
|
||||
#define MAX_CHANNELS_MATRIX_SIZE (MAX_INPUT_CHANNELS*MAX_OUTPUT_CHANNELS)
|
||||
|
||||
#define FLAX_POS_TO_XAUDIO(vec) X3DAUDIO_VECTOR(-vec.X * 0.01f, vec.Y * 0.01f, vec.Z * 0.01f)
|
||||
#define FLAX_POS_TO_XAUDIO(vec) X3DAUDIO_VECTOR(vec.X * 0.01f, vec.Y * 0.01f, vec.Z * 0.01f)
|
||||
#define FLAX_VEC_TO_XAUDIO(vec) (*((X3DAUDIO_VECTOR*)&vec))
|
||||
|
||||
namespace XAudio2
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "Engine/Level/SceneQuery.h"
|
||||
#include "Engine/Level/Actor.h"
|
||||
#include "Engine/Core/Log.h"
|
||||
#include "Engine/Core/Types/TimeSpan.h"
|
||||
#include "Engine/Graphics/Models/ModelData.h"
|
||||
#include "Engine/Content/Content.h"
|
||||
#include "Engine/Content/Assets/Model.h"
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Engine/Core/Types/BaseTypes.h"
|
||||
|
||||
namespace CSG
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -38,9 +38,10 @@ void Asset::OnDeleteObject()
|
||||
if (!IsInternalType())
|
||||
Content::AssetDisposing(this);
|
||||
|
||||
// Cache data
|
||||
const bool wasMarkedToDelete = _deleteFileOnUnload != 0;
|
||||
#if USE_EDITOR
|
||||
const String path = wasMarkedToDelete ? GetPath() : String::Empty;
|
||||
#endif
|
||||
const Guid id = GetID();
|
||||
|
||||
// Fire unload event (every object referencing this asset or it's data should release reference so later actions are safe)
|
||||
@@ -66,7 +67,7 @@ void Asset::OnDeleteObject()
|
||||
// Base (after it `this` is invalid)
|
||||
ManagedScriptingObject::OnDeleteObject();
|
||||
|
||||
// Check if asset was marked to delete
|
||||
#if USE_EDITOR
|
||||
if (wasMarkedToDelete)
|
||||
{
|
||||
LOG(Info, "Deleting asset '{0}':{1}.", path, id.ToString());
|
||||
@@ -77,6 +78,7 @@ void Asset::OnDeleteObject()
|
||||
// Delete file
|
||||
Content::deleteFileSafety(path, id);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void Asset::CreateManaged()
|
||||
@@ -131,6 +133,20 @@ void Asset::ChangeID(const Guid& newId)
|
||||
CRASH;
|
||||
}
|
||||
|
||||
bool Asset::LastLoadFailed() const
|
||||
{
|
||||
return _loadFailed != 0;
|
||||
}
|
||||
|
||||
#if USE_EDITOR
|
||||
|
||||
bool Asset::ShouldDeleteFileOnUnload() const
|
||||
{
|
||||
return _deleteFileOnUnload != 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void Asset::Reload()
|
||||
{
|
||||
// It's better to call it from the main thread
|
||||
@@ -225,7 +241,7 @@ bool Asset::WaitForLoaded(double timeoutInMilliseconds)
|
||||
while (!Engine::ShouldExit())
|
||||
{
|
||||
// Try to execute content tasks
|
||||
while (task->IsQueued())
|
||||
while (task->IsQueued() && !Engine::ShouldExit())
|
||||
{
|
||||
// Pick this task from the queue
|
||||
ContentLoadTask* tmp;
|
||||
@@ -335,13 +351,21 @@ void Asset::startLoading()
|
||||
bool Asset::onLoad(LoadAssetTask* task)
|
||||
{
|
||||
// It may fail when task is cancelled and new one is created later (don't crash but just end with an error)
|
||||
if (task->GetAsset() != this || _loadingTask == nullptr)
|
||||
if (task->Asset.Get() != this || _loadingTask == nullptr)
|
||||
return true;
|
||||
|
||||
Locker.Lock();
|
||||
|
||||
// Load asset
|
||||
const LoadResult result = loadAsset();
|
||||
LoadResult result;
|
||||
{
|
||||
#if TRACY_ENABLE
|
||||
ZoneScoped;
|
||||
const StringView name(GetPath());
|
||||
ZoneName(*name, name.Length());
|
||||
#endif
|
||||
result = loadAsset();
|
||||
}
|
||||
const bool isLoaded = result == LoadResult::Ok;
|
||||
const bool failed = !isLoaded;
|
||||
_loadFailed = failed;
|
||||
|
||||
@@ -82,7 +82,6 @@ public:
|
||||
/// <summary>
|
||||
/// Gets asset's reference count. Asset will be automatically unloaded when this reaches zero.
|
||||
/// </summary>
|
||||
/// <returns>The amount of references to that asset.</returns>
|
||||
API_PROPERTY() int32 GetReferencesCount() const
|
||||
{
|
||||
return (int32)Platform::AtomicRead(const_cast<int64 volatile*>(&_refCount));
|
||||
@@ -107,21 +106,18 @@ public:
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Gets the path to the asset storage.
|
||||
/// Gets the path to the asset storage file. In Editor it reflects the actual file, in cooked Game, it fakes the Editor path to be informative for developers.
|
||||
/// </summary>
|
||||
/// <returns>The asset file.</returns>
|
||||
API_PROPERTY() virtual const String& GetPath() const = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the asset type name.
|
||||
/// </summary>
|
||||
/// <returns>The typename.</returns>
|
||||
virtual const String& GetTypeName() const = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if asset is loaded, otherwise false.
|
||||
/// </summary>
|
||||
/// <returns><c>true</c> if this asset is loaded; otherwise, <c>false</c>.</returns>
|
||||
API_PROPERTY() FORCE_INLINE bool IsLoaded() const
|
||||
{
|
||||
return _isLoaded != 0;
|
||||
@@ -130,16 +126,11 @@ public:
|
||||
/// <summary>
|
||||
/// Returns true if last asset loading failed, otherwise false.
|
||||
/// </summary>
|
||||
/// <returns><c>true</c> if last asset loading failed; otherwise, <c>false</c>.</returns>
|
||||
API_PROPERTY() FORCE_INLINE bool LastLoadFailed() const
|
||||
{
|
||||
return _loadFailed != 0;
|
||||
}
|
||||
API_PROPERTY() bool LastLoadFailed() const;
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether this asset is virtual (generated or temporary, has no storage so it won't be saved).
|
||||
/// </summary>
|
||||
/// <returns><c>true</c> if this asset is virtual; otherwise, <c>false</c>.</returns>
|
||||
API_PROPERTY() FORCE_INLINE bool IsVirtual() const
|
||||
{
|
||||
return _isVirtual != 0;
|
||||
@@ -150,11 +141,7 @@ public:
|
||||
/// <summary>
|
||||
/// Determines whether this asset was marked to be deleted on unload.
|
||||
/// </summary>
|
||||
/// <returns><c>true</c> if this asset file was marked to be deleted on asset unload; otherwise, <c>false</c>.</returns>
|
||||
API_PROPERTY() FORCE_INLINE bool ShouldDeleteFileOnUnload() const
|
||||
{
|
||||
return _deleteFileOnUnload != 0;
|
||||
}
|
||||
API_PROPERTY() bool ShouldDeleteFileOnUnload() const;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -274,3 +274,9 @@ public:
|
||||
OnSet(asset);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
uint32 GetHash(const AssetReference<T>& key)
|
||||
{
|
||||
return GetHash(key.GetID());
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#include "Engine/Serialization/MemoryWriteStream.h"
|
||||
#endif
|
||||
|
||||
REGISTER_BINARY_ASSET(Animation, "FlaxEngine.Animation", nullptr, false);
|
||||
REGISTER_BINARY_ASSET(Animation, "FlaxEngine.Animation", false);
|
||||
|
||||
Animation::Animation(const SpawnParams& params, const AssetInfo* info)
|
||||
: BinaryAsset(params, info)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user